Adafruit I2C QT Rotary Encoder with NeoPixel - STEMMA QT / Qwiic

Hi All
I recently purchased a couple of these as I thought what a great idea, saves decoding the switches and dealing with switch bounce etc. Not greatly interested in the fancy coloured LED but that doesn’t matter.

Currently trying with Arduino UNO R3 (Freetronics version).

The device works very well. produces nice clean numbers with no sign of mis decoding or other instability. Produces these numbers nicely on the serial monitor or some sort of display.

BUT my query is. Has anyone had any success in doing something useful with it. A severe limiting factor here is the physical time it takes to recover the encoder position info. I measured this at 1.14mSec. Quite a long time and for what I was trying to do is completely unusable.

For interest the method of measuring this is as follows.
I used a modified version of the single encoder example provided. I inserted a timing pulse of 50µSec immediately before the recovery process and another of 10µSec after. The 2 different widths are for identification purposes. I then measured the time (with an oscilloscope which can measure these parameters) between the falling edge of the first and the rising edge of the second to be 1.14mSec. I believe this to be a valid method.
The relevant portion of the sketch follows

void loop() {
   //generate pulse at start of processing time
    digitalWrite(TIMING_PIN, HIGH);
    digitalWrite(TIMING_PIN, LOW);
  //Time between here and start of next timer pulse is 1.14mSec

  int32_t new_position = ss.getEncoderPosition();
  // did we move arounde?
  if (encoder_position != new_position) {
    encoder_position = new_position;
    digitalWrite(TIMING_PIN, HIGH);
    digitalWrite(TIMING_PIN, LOW);
    digitalWrite(OUTPUT_PIN, HIGH);
    digitalWrite(OUTPUT_PIN, LOW);


Note there is another positive pulse on another pin to visually indicate the completion of the loop
Also note these pulses finish up being 54µSec, 14µSec, 504µSec respectively. This is (as I discovered) the Arduino time (4µSec) to execute the digitalWrite function. This also shows up as a delay between the falling edge of the OUTPUT_PIN pulse and the rising edge of the TIMING_PIN pulse.

This 4µSec is explained if you dive down deep enough into Arduino documentation and there is apparently a work around which could be beyond my expertise but that will be the subject of another post.
At the moment I am more interested in finding out if anyone has found a practical use for this device apart from displaying nice numbers on a display.
Possible use could be servo control where the position recovery delay could be tolerated.
Interested in ideas.
Cheers Bob


Hi Bob,

Great findings!

Your method for timing seems far more than sufficient for a hobby level.
If you are looking to get the loop time down it might be worth adding an interrupt line so that the Arduino isnt stuck reading the I2C bus: attachInterrupt() - Arduino Reference

I personally haven’t used this device but it would be great for projects where you might want to power down the main microcontroller and read how much something has moved after re-powering it - perhaps a door sensor or DIY turnstyle.

By chance does your application relate to some additions to your flight sim controller? Super keen to see any and all updates!!



Hi Liam

Not exactly rocket science but you do need a reasonable oscilloscope. Mine is nothing extraordinary but can measure the pulse timing and display results on the right of screen which is useful. Like this.

As you can see it is measuring the high period ov pulse on Ch 2 (blue) at 54.4µSec and the low period at 1.15mSec which is the Encoder processing time.

As I understand it using interrupts won’t reduce this time as the Arduino loop pauses while the interrupt routine carries out its task Interrupts just allow you to stop the loop anywhere to carry out another task then resume. The Seesaw board does provide an interrupt when anything happens which is good. I did try this approach but with no joy. I haven’t researched this thoroughly but I don’t think the interrupt routine returns anything. For my purpose I do need to have the rotary encoder position returned so I can use it.

Your scenario outlined in the second paragraph would not work as in my projected application I need the control to be continuously variable and not have to wait until Arduino starts up.

My application would actually use 2 encoders so you can see that this 1.15mSec doubles and is actually added to the required off time in a pulse string. So if I were truing to generate a stream of 1kHz and 50% duty cycle which is 0.5mSec on and 0.5mSec off I finish up with 0.5mSec on and 2.8mSec off. A very long way from what is wanted.

After recovering the encoder positions I have no problem generating the numbers I require. Pulse on time and pulse off time. I have discovered the Arduino (UNO, Freetronics Eleven) seems to have a 4µSec error in the digitalWrite command and as long as this is consistent can be allowed for.
I am toying with a couple off ideas. Using a second Arduino,
One recovers the 2 Encoder information and generates the required numbers and somehow depositing these straight into positions in a second Arduino which does nothing except generate the pulse string. I will have to try to find out how to do this.
The second is to come to grips with a Pico (I have purchased a couple of these with a development set up) and utilise the dual core. Interesting to see if this is truly “Multitasking”. I will have to dive into the Pico basics first then find out about using each core to carry out the different functions.

My Flight Sim Controller. I thought I updated that, I will have to check.
Yes I do use rotary encoders here. 9 of them for ILS, VOR and NDB tuning but I cheat a bit here and use a Leo Bodnar controller board which allows 8 analog and 32 switch (or up to 16 rotary encoders) inputs plus 4 switch inputs dedicated to a hat switch. The initial problem was I could not use an encoder for elevator trim as these switches are in polled matrix form and to use my LED indicator system the encoder had to switch to ground. This was overcome by using another Leo Bodnar board (larger) in which the encoders do switch to ground so was able to parallel my indicator system with this and I now have encoder operation of elevator trim.

These encoder boards present pair of button presses to the sim software each one of a pair operates for CW and CCW rotation. You just have to allocate each button to a function in the Flt Sim. All the decoding and switch bounce is taken care of within the board. Very convenient.

My apologies if I have neglected to update the Flt Sim project and will rectify when I get a bit of time (between household chores).
Cheers Bob
Edit 06/11/22, Changed Arduino “NanoEvery” to UNO, “Freetronics Eleven”


Hey Bob,

Would it be possible to give a bit more of a backstory as to what you are trying to achieve?
(And what limitations do you hit trying to use a single Arduino)

Spot on, the interrupt would be beneficial if update events were to take place less often than 1.14mSec. so that any other code is free to run in the background.
I had a quick look at the library that the I2C encoder board uses and from uninitiated eyes it seems efficient for the Uno.
To speed things up you might be able to use a higher I2C clock speed

It’d be worth giving UART a go for this - Here’s some reading for a high-speed USART interface:

Some microcontrollers with direct memory access controllers (not the main core) can run a UART or I2C interface without stopping the main loop, also might be worth a look into but might also be out of scope. We used an MCU with the capability in Uni: (On the Core Store)

Just popped back to your post and you had made an awesome update in Feb, was just wondering if it was perhaps part of the same project. Very keen to see everything that you create :smiley:

1 Like

Hi Liam

I am playing with a simple pulse generator with 2 variable controls, Frequency and Duty Cycle without any interaction between controls.
One of the ideas I had (actually plan B) is to use 2 rotary encoders. A starting or switch on default of 1kHz and duty cycle 50% and go from there. Now with these break outs this is not difficult to massage the encoder numbers and finish up with the required pulse on and off times for pulse generation. Currently I am changing the period time in 100µSec increments and 0.5% duty cycle increments and recovering the required pulse timing from there. This is all fine.

The problem is to be anything like accurate I can’t tolerate the processing time which is effectively added to the OFF time so you can see that the 1.15mSec processing time is intolerable. This I might add is without displaying the info somewhere ( the whole exercise would be pretty useless if you don’t know things like freq and duty cycle).

The ideal situation would be some true multitasking where one unit generated the timing numbers (microseconds) and handled the display while the other unit just process these 2 numbers High time and Low time) into a pulse stream. If using Arduino the 4µSec time to carry out “digitalWrite” commands would be adjusted during the calculating process in the first unit. This processing time restricts Arduino to an 8µSec period or 125kHz with 50% duty which is no drama as my intention is to have a small unit to provide the pulses to test brushed DC motors, steppers and servos so 20 to 30kHz should be plenty.

I will probably revert to plan A which is to generate the pulses in hardware and use the “pulseIn” command to measure them. I have been somewhat successful doing this but is presenting its own problems which will be another subject. This post started out to find out if anyone has found a practical use for these Seesaw decoder boards.
Cheers Bob


Hi all
Been quite a while now so I assume that no one has found a practical use for these devices yet.
Maybe useful for servo control where the operation and changes are much slower.
If the time taken can be tolerated it should be useful somewhere as it is very convenient.
Cheers Bob

1 Like