Teensy 4.x H/W Quadrature Encoder Library

I'm slightly retarded when it comes to anything programming related sooo...
Not sure what to do to setup for the index pin

Code:
The full constructor allows for the INDEX, HOME and TRIGGER pins if available:
QuadEncoder(uint8_t encoder_ch = 255, uint8_t PhaseA_pin = 255, uint8_t PhaseB_pin = 255, uint8_t pin_pus = 0, uint8_t index_pin = 255, uint8_t home_pin = 255, uint8_t trigger_pin = 255);

I'm using encoder channel "1" with A-B-Z on pins 0-1-2, the unsigned integer thing is throwing me off, I only need the phase AB and index

If you look at some of the examples and check the readme you will find what you are looking for. But simple answer to get you started is that you put the pin numbers in the order indicated, and unused pins you either leave blank or put in 255. In your case the format would be

Code:
QuadEncoder myEnc1(1, 0, 1, 0, 2)

Which means use encoder channel1 , phaseA pin = 0, phaseB pin =1, use pullups = 0, index pin = 2.
 
@Blackaddr

Went ahead and merged your changes since those were the tables that had to be created for the MicroMod. Made one change for the io-mux value for pins 36/37 and its now working:
View attachment 26624

Thanks for taking the changes and doing the leg work. Let me know if its working for you.

Hi mjs513, I tried your latest code. It still isn't working for me, but I don't know why. Based on what I see in the RT1060 programming guide, and what I see in your latest code, I can't figure out why it's not working. Basically, the behavior I'm getting is the encoder only counts up, not down. My three other encoders work correctly with your library. So it's something to do with Pin 31 or 36 or both on the Teensy MicroMod.

I'll double and triple check the troublesome encoder works fine with the SW Encoder object (to ensure it's not a hardware/soldering issue) then take another look at the library again.
 
Hi mjs513, I tried your latest code. It still isn't working for me, but I don't know why. Based on what I see in the RT1060 programming guide, and what I see in your latest code, I can't figure out why it's not working. Basically, the behavior I'm getting is the encoder only counts up, not down. My three other encoders work correctly with your library. So it's something to do with Pin 31 or 36 or both on the Teensy MicroMod.

I'll double and triple check the troublesome encoder works fine with the SW Encoder object (to ensure it's not a hardware/soldering issue) then take another look at the library again.

Will give it a try I can't remember if it worked in both directions - sorry - too many projects and distractions

EDIT: Just checked and its working as it should be from what I can see. I am using KY-040 Rotary Encoders to test with as a reference.
 
According to the spec its a 32-bit counter - unsigned int - so probably somewhere around 4,294,967,295 as a guess, I thing a uint32 is 232 - 1
 
According to the spec its a 32-bit counter - unsigned int - so probably somewhere around 4,294,967,295 as a guess, I thing a uint32 is 232 - 1

Sorry, now that I look at what I wrote it was probably worded poorly. I meant what speed can it reliably count at without missing counts, ~10mhz? Has anyone tested this?

Might be a silly question, I haven't used the PJRC encoder module, or any Arduino encoder module, I usually work with stuff runnig on FPGAs..... The index pulse itself is typically useless outside of the MCU doing the counting since it's such a short pulse you can't reliably relay it. I see there is a counter which is one way to do it, but is there an "index-enable" type of setup as well? Typically CNC setups use the index-enable, index-is-enabled and index-reset as a 2-way handshake. So on the teensy, when the index is caught it latches index-is-enabled = true and that would get piped to an output so the external controller sees the it, then the controller can set the Teensy's "index-reset" true to reset index-is-enabled so it can catch the next one. This setup doesn't necessarily mean you have to catch every index, it means you will catch the next one after it's enabled.

I realize some of the above can be done as part of the program, I'd think the basics of that have to exist in the encoder module itself for speed. I looked but didn't notice this type of usage explained in the readme or examples
 
Sorry, now that I look at what I wrote it was probably worded poorly. I meant what speed can it reliably count at without missing counts, ~10mhz? Has anyone tested this?

Might be a silly question, I haven't used the PJRC encoder module, or any Arduino encoder module, I usually work with stuff runnig on FPGAs..... The index pulse itself is typically useless outside of the MCU doing the counting since it's such a short pulse you can't reliably relay it. I see there is a counter which is one way to do it, but is there an "index-enable" type of setup as well? Typically CNC setups use the index-enable, index-is-enabled and index-reset as a 2-way handshake. So on the teensy, when the index is caught it latches index-is-enabled = true and that would get piped to an output so the external controller sees the it, then the controller can set the Teensy's "index-reset" true to reset index-is-enabled so it can catch the next one. This setup doesn't necessarily mean you have to catch every index, it means you will catch the next one after it's enabled.

I realize some of the above can be done as part of the program, I'd think the basics of that have to exist in the encoder module itself for speed. I looked but didn't notice this type of usage explained in the readme or examples

Think if you look at the libraries ReadMe you might find some of your answers on what the library contains. For instance you can specify whether you what to use an Index or trigger Pin as well as its configuration settings.

As for speed tests think some were done but can't find a reference to them right now. You could check this post out and play with it a bit: https://forum.pjrc.com/threads/5847...ncoder-Library?p=222007&viewfull=1#post222007
 
Will give it a try I can't remember if it worked in both directions - sorry - too many projects and distractions

EDIT: Just checked and its working as it should be from what I can see. I am using KY-040 Rotary Encoders to test with as a reference.

Hi mjs512, I got it working. Stupid mistake on my part. I didn't realize a version of your library shipped with Teensyduino, so when I installed a fresh copy of yours in the ~/Arduino/libraries folder, it was still using the built-in one. Once I ensured it was pointing at your latest version, the encoder started working properly.

Thanks again for your help fixing up the Teensy MicroMOD support so quickly!
 
Think if you look at the libraries ReadMe you might find some of your answers on what the library contains. For instance you can specify whether you what to use an Index or trigger Pin as well as its configuration settings.

As for speed tests think some were done but can't find a reference to them right now. You could check this post out and play with it a bit: https://forum.pjrc.com/threads/5847...ncoder-Library?p=222007&viewfull=1#post222007

Doesn't appear that it contains the functionality I mentioned but it looks like it could probably be created in program based on if IndexCount > 0 = true. Resetting the indexcount would return it to 0, therefore false.

I checked out the encSim, doesn't look like I'd need that to test a hardware encoder but the repo points to firmware files to test the lib, those links to the firmware are broken though. I don't do much programming myself but if anyone has that firmware or something else that's ready to go, I've got a jig I made for testing encoders. On hand I have a 1000ppr differential encoder I can spin upto 5000rpm with a 1hp servo. The servo drive also has a simulated encoder output I can program to represent various divisions of the 16bit encoder on the servo. The PCB my Teensy is attached to has a differential interface so it should be pretty good for a real world test
 
I checked out the encSim, doesn't look like I'd need that to test a hardware encoder but the repo points to firmware files to test the lib, those links to the firmware are broken though.
If you refer to the EncSim binaries: here they are: https://github.com/luni64/EncSim/tree/master/examples/SerialControl/precompiled_binaries

Regarding your question about the max count rate:
The manual states that the counters can count up to F_BUS which is 150MHz if you use the default 600MHz clock setting. Please note that one can set digital filters on the inputs which might reduce that frequency. Don't know if mjs513 uses those filters in his lib.

Screenshot 2021-11-25 191814.png
 
Doesn't appear that it contains the functionality I mentioned but it looks like it could probably be created in program based on if IndexCount > 0 = true. Resetting the indexcount would return it to 0, therefore false.

Based on what you said I think you are mis-reading something. If you configure the encoder to an index pin, it will reset the position counter when the index pin triggers the interrupt. The manual:
Capture.PNG

And if you look at the QuadEncoder_Interrupt_pins example it illustrates how this is accomplished.
 
Based on what you said I think you are mis-reading something. If you configure the encoder to an index pin, it will reset the position counter when the index pin triggers the interrupt. The manual:
View attachment 26659

And if you look at the QuadEncoder_Interrupt_pins example it illustrates how this is accomplished.

Actually you're misunderstanding what I said, but there's some missing info so it may not have made sense anyway. There is an "indexCounter" Right?....
Code:
If indexTrigger = ENABLE and INDEXTriggerMode = DISABLE (default). The encoder count will continue increase with no reset while the indexCounter with increment when trigger by the index signal (needs to be negative trigger) and the Position HOLD revolution value will increment or decrement depending on direction.

According to that you can have the index not affect the position count but still count index pulses, right? I originally asked about a latching boolean type output, alot of CNC systems use this type of thing to signal when the last index has been caught. That doesn't exist in the encoder module......or are you saying it does?....cuz I don't see it. So I said if in program there is a function that can reset the indexCounter to 0, then based on if indexCounter > 0 you can crate the boolean type output. So where am I wrong?

The problem is I tried the QuadEncoder_Interrupt_pins example, I set my index pin to 2 and in the otherwise unmodified program It resets the position counter every 4000 counts which is correct because it's a 1000ppr encoder, but the indexCounter over the serial monitor does not increment. When I set the config just as I quoted above it still does not increment. Hold counter does increment. So if the index counter does work, and it can be reset what I said above is fine. For something I'm about to start working on with this I need to be able to reset the position count without the index. I've seen it mentioned that write....(0) was the means, I also saw something earlier in this thread that said something about initialPostion or something like that. I tried the write(0) method based on a button press, that set the position to 0 but it would no longer count, just stayed there. What's the method for resetting the counters (without the index) or where is it explained?
 
Lets take this one at a time because you are asking 2 questions index counter and position counter. The use of the position counter and zeroing is clearing shown how to do in the simple.ino example. Why write(0) isn't working and freezing I can't tell for that problem you need to show your sketch other wise I am just guessing.

Second issue:
The problem is I tried the QuadEncoder_Interrupt_pins example, I set my index pin to 2 and in the otherwise unmodified program It resets the position counter every 4000 counts which is correct because it's a 1000ppr encoder, but the indexCounter over the serial monitor does not increment.
Not sure how you are getting your index Counter, again now sketch. But to get the index count you have to use the:
Code:
Serial.printf("Index Counter: %d\r\n", myEnc1.indexCounter);
Counts up and down. Again no sketch can't tell what you are doing. In the readme it specifies:
myEnc.write(newPosition);
Set the accumulated position to a new number.
it works its been tested.

Try running the example sketches and or post the sketch that you are using.

You can read the RM for the 1060 if you want the gory details.
 
Lets take this one at a time because you are asking 2 questions index counter and position counter. The use of the position counter and zeroing is clearing shown how to do in the simple.ino example. Why write(0) isn't working and freezing I can't tell for that problem you need to show your sketch other wise I am just guessing.

I was messing around with a few things and didn't save the sketch, I'll get back to that when I get a chance.

Second issue:
Not sure how you are getting your index Counter, again now sketch. But to get the index count you have to use the:
Code:
Serial.printf("Index Counter: %d\r\n", myEnc1.indexCounter);
Counts up and down. Again no sketch can't tell what you are doing. In the readme it specifies:
it works its been tested.

Try running the example sketches and or post the sketch that you are using.

You can read the RM for the 1060 if you want the gory details.

OK, so as I said, it was literally the Quadencoder_Interrupt_pins example with only line 8 changed to "QuadEncoder myEnc1(1, 0, 1, 0, 2);" Which includes the code you mentioned. I'm not gonna post that sketch. I then changed the config just as I quoted, then multiple other ways. Posting 5 sketches that don't work.....yeah I dunno.

But after messing around with the hardware I did figure out what does work so I'll post that, But I need to know what this means....
Code:
f indexTrigger = ENABLE and INDEXTriggerMode = DISABLE (default). The encoder count will continue increase with no reset while the indexCounter with increment when trigger by the index signal[B] (needs to be negative trigger)[/B] and the Position HOLD revolution value will increment or decrement depending on direction.

Because it suggests that the Index pin must stay high and then pulled low for the index event and since most single ended encoders are NPN that's most likely what that means, but that does not work. Since I'm running a differential encoder through a differential receiver I can invert that behavior by swapping Z+ and Z-. This is what works....

Index_working.jpg

with this sketch
View attachment QuadEncoder_Interrupt_pins.ino

And that will increment the indexCounter but I don't know that I'd call that a "negative trigger". In the unmodified interrupt_pins example sketch the position counter reset on index regardless of if it were high>low or low>high, but in order to increment the indexCounter is had to be as shown, low>high. pullups enabled/disabled doesn't matter in my case since the driver strength overcomes the pullups
 
As a quick test of write(0) I ran the simple encoder example with only one KY-040 encoder attached. And write(0) seems to work for me:
Code:
Left = 39, Right = 0
Left = 40, Right = 0
Reset both knobs to zero
Left = 0, Right = 0
Reset both knobs to zero
Left = 1, Right = 0
Left = 2, Right = 0
Left = 3, Right = 0

As for the next issue, yes the example is only updating the Position HOLD revolution value which counts up and down when the I hit the switch on the KY-040:
Code:
Current position value1: 16
Position differential value1: 1
Position HOLD revolution value1: 1
Index Counter: 0

Current position value1: 0
Position differential value1: 0
Position HOLD revolution value1: 2
Index Counter: 0
Note the revolution counter goes increases and decreases based on direction

Adding the:
Code:
  myEnc1.EncConfig.IndexTrigger = ENABLE;
does increment the index counter, and when index interrupt it hit it zeros out the position counter.
Code:
Current position value1: 8
Position differential value1: 1
Position HOLD revolution value1: 1
Index Counter: 2

Current position value1: 0
Position differential value1: 0
Position HOLD revolution value1: 2
Index Counter: 3

Using your example the position counter continues to increases and does not zero out when the index pin is triggered:
Code:
Current position value1: 514
Position differential value1: 1
Position HOLD revolution value1: 7
Index Counter: 15

Current position value1: 515
Position differential value1: 1
Position HOLD revolution value1: 8
Index Counter: 16
as for the negative trigger yeah you are probably right think I need to change that wording as the trigger is based on the a rising or falling edge
Capture.PNG
 
as for the negative trigger yeah you are probably right think I need to change that wording as the trigger is based on the a rising or falling edge
View attachment 26770

Yeah, I'd just leave that part out since typical ABZ encoders are open collector and I think the index output is active the whole time the index is NOT triggered, meaning it's pulling the line down. When the index occurs it goes into high impedance and the thing reading the encoder (the Teensy) can pull the line high. If that's the case you can just hookup a 5v single ended encoder from amazon and not worry about it damaging the inputs on the Teensy.

It's not *just* based on rising and falling edges, both edges are still present even if the index is inverted, just a matter of that edge happening at the beginning or the end of the index, The position counter did reset when configured as in the example sketch with the inverted index so that may only care about the edges, but the index counter only worked when the transition was low-high-low which is typical. I believe most encoders keep the index in phase with the B phase so the NXP hardware module must be based on something like that because an inverted index would be out of phase. Quadrature counting doesn't care about that because the A and B are always 90 degrees out of phase with a 50% duty cycle so if the whole encoder were inverted it would still be the same thing I saw above.

I don't have the RM, you gotta sign up on NXP to get it so I don't know what it says about all of that. I'd think that most people that grab a 5v single ended encoder and stick the ABZ wires to the Teensy pins would just see everything working properly as it is, but some oddball encoder that does something slightly different with the index probably wouldn't just work, at least not for the index counter.
 
Hi everyone,
I am quite new to programming on the Teensy 4.1 platform and was very happy to find this library.
I have been successfully using it to control the motors on a telescope.
Today I noticed something in the code (also in the one from MCUXpresso) and I would like to get an opinion on this:
The read() method in Quadencoder.cpp gets the lower 16 bits from the LPOSH register but should that not be read from the LPOS register?

Code:
int32_t QuadEncoder::read()
{
    uint32_t ret32;

    ret32 = channel[_encoder_ch].ENC->UPOS; /* Get upper 16 bits and make a snapshot. */
    ret32 <<= 16U;
    ret32 |= channel[_encoder_ch].ENC->[COLOR="#FF0000"]LPOSH[/COLOR]; /* Get lower 16 bits from hold register. */

    return (int32_t)ret32;
}

Should the code not be like this:

Code:
int32_t QuadEncoder::read()
{
    uint32_t ret32;

    ret32 = channel[_encoder_ch].ENC->UPOS; /* Get upper 16 bits and make a snapshot. */
    ret32 <<= 16U;
    ret32 |= channel[_encoder_ch].ENC->[COLOR="#008000"]LPOS[/COLOR]; /* CHANGED. Get lower 16 bits from hold register. */

    return (int32_t)ret32;
}

In case the original code is correct I would very much appreciate an explanation for why LPOSH is used as opposed to LPOS.
Thanks a lot,
Matt
 
Hi everyone,
I am quite new to programming on the Teensy 4.1 platform and was very happy to find this library.
I have been successfully using it to control the motors on a telescope.
Today I noticed something in the code (also in the one from MCUXpresso) and I would like to get an opinion on this:
The read() method in Quadencoder.cpp gets the lower 16 bits from the LPOSH register but should that not be read from the LPOS register?

Code:
int32_t QuadEncoder::read()
{
    uint32_t ret32;

    ret32 = channel[_encoder_ch].ENC->UPOS; /* Get upper 16 bits and make a snapshot. */
    ret32 <<= 16U;
    ret32 |= channel[_encoder_ch].ENC->[COLOR="#FF0000"]LPOSH[/COLOR]; /* Get lower 16 bits from hold register. */

    return (int32_t)ret32;
}

Should the code not be like this:

.......

In case the original code is correct I would very much appreciate an explanation for why LPOSH is used as opposed to LPOS.
Thanks a lot,
Matt
Good Morning Matt welcome to your first post.

As to your question. If you look at section 56.2.3.3 of the 1160 Reference Manual for the 1160 you find:
Capture.PNG

Basically when you read the UPOS (upper 16-bits) register it immediately puts the corresponding LPOS in the LPOSH (Lower 16-bit Hold register) - frozen until the next read - basically this gives you the corresponding lower 16bits for the read upper 16 bits other wise you will end up with the out of sync values for upper 16 bits and lower 16bits if the encoder is still moving when you do the read.

Hope I did confuse you too much.
 
Basically when you read the UPOS (upper 16-bits) register it immediately puts the corresponding LPOS in the LPOSH (Lower 16-bit Hold register) - frozen until the next read - basically this gives you the corresponding lower 16bits for the read upper 16 bits other wise you will end up with the out of sync values for upper 16 bits and lower 16bits if the encoder is still moving when you do the read.

Hope I did confuse you too much.

Thank you mjs513 for the explanation;
that makes a lot of sense.
So, if I understand correctly, the hold registers remain in their initial states (after power on) until UPOS or LPOS are read for the first time?
 
Thank you mjs513 for the explanation;
that makes a lot of sense.
So, if I understand correctly, the hold registers remain in their initial states (after power on) until UPOS or LPOS are read for the first time?

That's my understanding as well. Sometimes you have to read that RM a few times.
 
Sometimes you have to read that RM a few times.

It gives me headaches. :)
In rev. 3 of the 1060 manual, section 56.3.4 describes a speed measurement method, which I could really make use of.
However, they mention register POSDPERH, which supposedly holds a time length but so far, I have failed to find any other reference to this register. My IDE (Visual studio 2019 + visual micro) doesn't know it either. Does it even exist on the MCU used in the Teensy 4.1? Might be that I completely misunderstand the description in the RM.
 
It gives me headaches. :)
In rev. 3 of the 1060 manual, section 56.3.4 describes a speed measurement method, which I could really make use of.
However, they mention register POSDPERH, which supposedly holds a time length but so far, I have failed to find any other reference to this register. My IDE (Visual studio 2019 + visual micro) doesn't know it either. Does it even exist on the MCU used in the Teensy 4.1? Might be that I completely misunderstand the description in the RM.

Ok thats a new one on me. Rev 2 of the reference manual makes no mention of it. And I can tell you its not currently in the core. Right now I can not even get to the Rev 3 of the RM. Lock out my reset password
 
I think it's a copy&paste mistake on nxp's part when they updated to rev 3. I just had a look at the RMs of the 1160 and 1170 where these registers are clearly mentioned and explained in the QDC section.

I wanted to look into measuring the time between quad encoder pulses to get a more accurate slow speed reading using the hardware. Do you think this would be possible with the 1060 using your library? I could do it in software but that puts more load on the cpu, doesn't it?
 
I think it's a copy&paste mistake on nxp's part when they updated to rev 3. I just had a look at the RMs of the 1160 and 1170 where these registers are clearly mentioned and explained in the QDC section.

I wanted to look into measuring the time between quad encoder pulses to get a more accurate slow speed reading using the hardware. Do you think this would be possible with the 1060 using your library? I could do it in software but that puts more load on the cpu, doesn't it?

I just downloaded the Rev 3 RM and agree with you think its a copy and paste mistake. When looking for the POSPERH register definition it isn't mentioned. Also if I look at the the SDK list of registers its not listed for the decoder.

According to the RM
Inputs can be connected to a general purpose timer to make low speed velocity measurements
but I never figured out how that works so no. You could do a simple read of the position between a set time and get a speed. Never tried it.
 
I wanted to look into measuring the time between quad encoder pulses to get a more accurate slow speed reading using the hardware. Do you think this would be possible with the 1060 using your library? I could do it in software but that puts more load on the cpu, doesn't it?

I looked at the 1170 manual, and I'm not sure that POSDPER is what you're looking for. I think it's just a fine time measurement of the time between reads of POSD, as opposed to the time between edges of the A or B input. The way that I do what you're asking about is to connect either the A or B quadrature signal to an additional QDC pin and configure that pin for period measurement. I have used FreqMeasureMulti for that period measurement, and it works well. You have a lot of different options for whether and how to use interrupts, depending on the input frequency.
 
Back
Top