Hi everyone,
I’ve published a new TinyCLR‑compatible hardware quadrature decoder package for the LS7366R counter IC.
It provides true 32‑bit hardware decoding for mechanical rotary encoders (e.g., EC11) and avoids the typical issues of software‑based solutions such as missed steps, jitter, or inconsistent detent detection.
NuGet Package:
ImplicateX.TinyCLR.Devices.Decoder.Ls7366
https://github.com/Implicate-X/ImplicateX.TinyCLR.Devices.Decoder.Ls7366
What it does
-
Uses the LS7366R hardware counter via TinyCLR Software‑SPI
-
Supports 1× / 2× / 4× quadrature decoding
-
Provides stable 32‑bit counting without dropouts
-
Includes detent alignment (default divider: 4)
-
Reports direction via the LS7366R status register
-
Raises a
CounterChangedevent only on detent boundaries -
Fully thread‑safe SPI access
-
Designed for TinyCLR OS 3.x (SITCore)
This makes it ideal for tuning knobs, menu navigation, or any application where encoder precision and reliability matter.
Modern C# usage example
csharp
// LS7366R Quadrature Decoder/Counter
quadDecoder_ = new(
gpioController_,
ControllerPin.DecoderCS,
ControllerPin.DecoderSCLK,
ControllerPin.DecoderMOSI,
ControllerPin.DecoderMISO
);
// Handle detent events
quadDecoder_.CounterChanged += decoderEvent =>
{
double frequency = decoderEvent.Direction switch
{
Direction.Up => ApplyTuneStep(+0.1, "Tune Up command received."),
Direction.Down => ApplyTuneStep(-0.1, "Tune Down command received."),
_ => tuner_.GetFrequencyMHz()
};
};
// Reset and start polling
quadDecoder_.ResetCounter();
quadDecoder_.Start();
The decoder polls every 5 ms, latches the counter into OTR, reads the 32‑bit value, checks the status register, and fires the event only when a new detent boundary is reached.
Repository
The full source code, README, and .nuspec are available here:
GitHub:
https://github.com/Implicate-X/ImplicateX.TinyCLR.Devices.Decoder.Ls7366
If anyone is working with mechanical encoders on TinyCLR and needs reliable hardware‑level decoding, feel free to try it out.
Feedback or improvements are welcome.
Minimal TinyCLR Example Application from the repo
using System;
using GHIElectronics.TinyCLR.Pins;
using GHIElectronics.TinyCLR.Devices.Gpio;
using ImplicateX.Devices.Decoder;
namespace Ls7366App
{
internal class Program
{
public static class ControllerPin
{
public const int DecoderSCLK = FEZFeather.GpioPin.PC8;
public const int DecoderMOSI = FEZFeather.GpioPin.PC9;
public const int DecoderMISO = FEZFeather.GpioPin.PC10;
public const int DecoderCS = FEZFeather.GpioPin.PC11;
}
private static GpioController gpioController_;
private static Ls7366 quadDecoder_;
static void Main()
{
gpioController_ = GpioController.GetDefault();
quadDecoder_ = new(
gpioController_,
ControllerPin.DecoderCS,
ControllerPin.DecoderSCLK,
ControllerPin.DecoderMOSI,
ControllerPin.DecoderMISO
);
quadDecoder_.CounterChanged += e =>
{
Console.WriteLine(
$"Counter: {e.Count}, Direction: {e.Direction}, Status: {e.Status}"
);
};
quadDecoder_.ResetCounter();
quadDecoder_.Start();
}
}
}