Teensy 4.x H/W Quadrature Encoder Library

I am using this library, and it works well.

In my application, I am reading a quad encoder feedback from an electric motor. Since the encoder is naturally a differential measurement, it starts at zero on power up. However, I need it to start at some non zero quantity on startup.

Here is my setup:

const int c_Steering_Angle_Rev_Count = 42000;

//Encoder Setup
myEnc1.setInitConfig(); //
myEnc1.EncConfig.revolutionCountCondition = ENABLE;
myEnc1.EncConfig.enableModuloCountMode = ENABLE;
myEnc1.EncConfig.positionModulusValue = c_Steering_Angle_Rev_Count;
// with above settings count rev every 20 ticks
// if myEnc1.EncConfig.revolutionCountCondition = ENABLE;
// is not defined or set to DISABLE, the position is zeroed every
// 20 counts, if enabled revolution counter is incremented when
// phaseA ahead of phaseB, and decrements from 65535 when reversed.
myEnc1.EncConfig.positionInitialValue = 0;
myEnc1.EncConfig.filterCount = 0;
myEnc1.EncConfig.filterSamplePeriod = 6;
myEnc1.init();



I have an external Analog rotary potentiometer to use as an absolute position reference. So, I would like to read the Analog position - convert it to a number of revolutions and position counts, then set the appropriate registers.

So, I can set the positionInitialValue to the converted position counts,
myEnc1.EncConfig.positionInitialValue = reset_value;

But, how can I set the revolution counter to a value? I can't seem to find a function to do this. But, I'm also dumb. So there's that.
 
In my application, I am reading a quad encoder feedback from an electric motor. Since the encoder is naturally a differential measurement, it starts at zero on power up. However, I need it to start at some non zero quantity on startup.
Setting the myEnc1.EncConfig.positionInitialValue sets the starting value for the counter so instead of 0 it will be set to your reset_value.

how can I set the revolution counter to a value
The actual revolution counter can not be set by the user. That is an internal counter used the by IMXRT1062 itself. By calling:
Code:
  myEnc2.EncConfig.positionMatchMode = ENABLE;
  myEnc2.EncConfig.positionCompareValue = 200;
automatically resets when the internal counter hits 200.

Code:
 mCurPosValue = myEnc1.read();
and the subsequent print of mCurPosValue will give you the counts.

So I am not entirely sure what you want to do with setting revolution counter?
 
I have a motor with 42,000 counts per revolution. Lock to lock position on the motor is 5 turns, or 5 x 42,000 counts = 210,000 total counts. I need to know the absolute position when initially powered on - it can theoretically be located anywhere in the range of the 5 turns on powerup. So, I have an external analog rotary potentiometer input that I can use as an absolute position reference. So I was thinking of reading the absolute position reference, converting it to absolute counts, then setting the revolution counter accordingly. Sounds like that can't happen.

I could turn off the modulo counter, but then I would run out of resolution on the counter as it is only valid to 65,536, which is only slightly more than one revolution? Is there a way to cast the counter to a long? Or some easier way to accomplish an absolute position counter up to 210,000 counts?
 
I have a motor with 42,000 counts per revolution. Lock to lock position on the motor is 5 turns, or 5 x 42,000 counts = 210,000 total counts. I need to know the absolute position when initially powered on - it can theoretically be located anywhere in the range of the 5 turns on powerup. So, I have an external analog rotary potentiometer input that I can use as an absolute position reference. So I was thinking of reading the absolute position reference, converting it to absolute counts, then setting the revolution counter accordingly. Sounds like that can't happen.

I could turn off the modulo counter, but then I would run out of resolution on the counter as it is only valid to 65,536, which is only slightly more than one revolution? Is there a way to cast the counter to a long? Or some easier way to accomplish an absolute position counter up to 210,000 counts?

pretty sure this is a 32 bit hw encoder? but you use the analog to know the position, counts are not for absolute positioning.... they're good for PID and moving the motor at specific velocity or acceleration.... you can convert it to move X distance but from what reference point will always be unknown unless you "home" the motor to a known location using a trigger.. switch or IR sensor, it's unreliable even if you could because you assume that the motor wasn't manually moved when the system was off. if you already have the analog position with a Potentiometer, you do not need counts to know the position, you already know it. you map the potentiometer values to degrees.... 0 being center, + 180 all the way left, -180 all the way right right. 0 could be 2.5v, 0v +180, 5v -180... however you want to do it.....
 
Hello everyone, I'm new here.
I'm just now testing your QuadEncoder library with SimpleEncoder example,
but compilinig it gives me this error:
C:\Users\...\Teensy-4.x-Quad-Encoder-Library\QuadEncoder.cpp:39:76: error: invalid application of 'sizeof' to incomplete type 'const QuadEncoder::ENC_Hardware_t []'
const uint8_t QuadEncoder::_hardware_count = (sizeof(QuadEncoder::hardware)/sizeof(QuadEncoder::hardware[0]));

Any guess? Thank you
 
Hello everyone, I'm new here.
I'm just now testing your QuadEncoder library with SimpleEncoder example,
but compilinig it gives me this error:
C:\Users\...\Teensy-4.x-Quad-Encoder-Library\QuadEncoder.cpp:39:76: error: invalid application of 'sizeof' to incomplete type 'const QuadEncoder::ENC_Hardware_t []'
const uint8_t QuadEncoder::_hardware_count = (sizeof(QuadEncoder::hardware)/sizeof(QuadEncoder::hardware[0]));

Any guess? Thank you

I just compiled the SimpleEncoder sketch on the T4.0 and the T4.1 and didn't receive any error messages from the library.

Right now I am using Arduino 1.8.13 with the Teensyduino 1.53- beta5. So really need a bit more info on your config and processor you are using.
 
I just compiled the SimpleEncoder sketch on the T4.0 and the T4.1 and didn't receive any error messages from the library.

Right now I am using Arduino 1.8.13 with the Teensyduino 1.53- beta5. So really need a bit more info on your config and processor you are using.

Arduino 1.8.10 and Teensyduino 1.48, are there any significant differences?
 
Maybe not with Arduino 1.8.10 but definitely between Teensyduino versions. I just tested the sketch with 1.8.10 with TD 1.50 and didn't receive a compile error. So would recommend updating - besides a lot of things have been fixed and improved on since 1.48
 
I had also to update Arduino to 1.8.13 because Teensyduino 1.53 does not support 1.8.10,
now it works with no compiling errors!
Also the manual update of imxrt.h is not needed anymore.
Thank you
 
I had also to update Arduino to 1.8.13 because Teensyduino 1.53 does not support 1.8.10,
now it works with no compiling errors!
Also the manual update of imxrt.h is not needed anymore.
Thank you

Great that is working and yep no more manual updates :)
 
Hello, and thank you for the great library. Not sure if it si proper conduct to post on an older thread, but it looks like it has happened twice before and fairly recently.

I am implementing a design with three DC motors with encoders running a pretty fast PID loop. The encoders are on the following pins:
#define XENC_CHANNEL 1 //Encoder Channel
#define XENC_A 0 //Encoder Phase A
#define XENC_B 1 //Encoder Phase B
#define YENC_CHANNEL 2 //Encoder Channel
#define YENC_A 30 //Encoder Phase A
#define YENC_B 31 //Encoder Phase B
#define ZENC_CHANNEL 3 //Encoder Channel
#define ZENC_A 4 //Encoder Phase A
#define ZENC_B 36 //Encoder Phase B

And the encoders are starting with the following code:
_motor_encoder(enc_channel, enc_a, enc_b, 0)

_motor_encoder.setInitConfig(); //Loads default configuration for the encoder channel
_motor_encoder.EncConfig.positionInitialValue = 00;
_motor_encoder.init(); //Initializers the encoder for the channel selected

We read them every millisecond.

We currently have two problems:
1. The encoder for Y always works, but it seems that only the X or Z can function at the same time. I saw the warning about not using pin 0, 5 and/or 37 at the same time, but it appears we have stumbled upon another combination.

2. The encoders when they are working appear to be loosing counts. Each motor has a gearhead and when we back drive it, the counts climb then stop. Also, if the PID loop is not tuned properly and there is an oscillation, the motor slowly drifts to one side as it jitters back and forth even as the encoder doesn't indicate net motion.

Any ideas?

I would really like to use the hardware encoders because of the speed, but have really hit an impasse. Thanks in advance,
Tim




excited about using the
 
Real late for me but the reason for certain pins not working together is because they share the same IO enconder connection. So basically:

Pins 1 and 36 can not be used together so you can use only one in your sketch if you are using multiple channels. So in your sketch you can use Pin 1 or 36.
Pins 0, 5, and 37 are mutually exclusive so you can use only one in your sketch if you are using multiple channels. So in your sketch you can use Pin 0 or 5 or 37.

Looks like I left out pin 1 and 36 on that list in the read me. Thanks for pointing this out.

As to your second problem, not seeing your whole sketch you need to initialize the 3 encoders in setup once, not keep intializializing them as you need them. To zero an encoder out _motor_enc.write(0);

Look at the simple_encoder sketch in the examples folder and you will see what I mean.

The encoder will only change if it sees a interrupt signal from the encoder on the motor - if the motor is just jittering it may not hit an indent. But then the jitter may cause some problems in counts - never tested that way.

Again with seeing your code or hardware hard to say.
 
Thanks a lot, and I am massively impressed with the speed of the reply.

I am a happy to have a clear cut answer on pins 1 and 36, if a little disappointed. That helps keep me from chasing gremlins.

I have the encoders within a custom written library with the PID and a bunch of other functions that together form an Axis. I need to do some more digging on the speed/jitter and will post a follow up with some scope traces and a cleaner outline of the code. I am not continually initializing them, only in the constructor so that is not it. Based on some previous posts about the pulse rate, my suspicion is that it is on my end. Thank you, and more info to come.
 
I need to multiplex (with a Teensy 4.1) 24 encoders.

Which is better?
A. multiplex 6 encoders per each of the 4 hardware encoder ports
B multiplex 24 encoders using i/o pins and software

thanks

Richard
 
I need to multiplex (with a Teensy 4.1) 24 encoders.

Which is better?
A. multiplex 6 encoders per each of the 4 hardware encoder ports
B multiplex 24 encoders using i/o pins and software

thanks

Richard

Hai Richard

I think it is a mistake to say that the tinsy has 4 harware encoders ports. I can not find that kind of ports I think it is a software limitation.
Perhaps this limitation is due too build into the software library. I think that is because timing considerations, that is the most likely explanation.
In case you try to do the job using 24 I?O pins you will encounter the same problem. Perhaps it is possible to define two or more encoder
objects in your application and reassign the ports. A other option is to look into the software and try to modify it for the use of more encoders.
I think you need some advice of the developer of the board. An important question is the speed you need of the decoders

John
 
Hai Richard

I think it is a mistake to say that the tinsy has 4 harware encoders ports. I can not find that kind of ports I think it is a software limitation.
Perhaps this limitation is due too build into the software library. I think that is because timing considerations, that is the most likely explanation.
In case you try to do the job using 24 I?O pins you will encounter the same problem. Perhaps it is possible to define two or more encoder
objects in your application and reassign the ports. A other option is to look into the software and try to modify it for the use of more encoders.
I think you need some advice of the developer of the board. An important question is the speed you need of the decoders

John

The T4.1, which is based on the nxp 1162 supports has 4 H/W Quadrature encoders. There is a library as this thread mentions that provides the access you need to use those 4 H/W Quadrature encoders. The library setups up the pin configurations that are needed to get access to the builtin Quad encoders. So while technically the cards don't show "ports" the pins can be reconfigured.
 
Sorry for the confusion. I replied to the wrong thread.

I have a library based on NXP Quad Encoder SDK driver for the Encoder module but modified to support the Teensy 4.x infrastructure.

NOTE: you will need to incorporate the Update imxrt.h for encoder structure #402 to make use of the library.

There are 4 hardware quadrature encoders available the Teensy 4.0. These are currently supported on FlexIO pins: 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33. The library is available in my GitHub repository: https://github.com/mjs513/Teensy-4.x...ncoder-Library.

thanks,

Richard
 
I noticed the library does not support pin 36 for the Teensy MICROMOD, only for T4.1. I can understand why T4.0 doesn't support (no logical pin 36), but why doesn't the MICROMOD support the hardware encoder on it's logical pin 36? Is it not the same CPU ball as pin36 on the T4.1?

With some schematic checking I may have answered my own question. On the MICROMOD, logical pin 36 is B0_01, on Teensy 4.1, logical pin 36 is B1_02.

I'm guessing B1_02 supports the hardware encoder but B0_01 does not?
 
In the RT1062 programming guide, it looks MICROMOD pin 36 (B0_01) is connected to XBAR1_INOUT05, ALT3. I tried modifying the QuadEncoder.* files but can't seem to get it to work. Can someone explain why logical Pin 36 on the MICROMOD cannot support the hardware encoder?
 
In the RT1062 programming guide, it looks MICROMOD pin 36 (B0_01) is connected to XBAR1_INOUT05, ALT3. I tried modifying the QuadEncoder.* files but can't seem to get it to work. Can someone explain why logical Pin 36 on the MICROMOD cannot support the hardware encoder?

Actually pins 36 and 37 are supported but for the Teensy 4.1. Looks like I put the ifdef in the wrong spot - its against the Teensy 4 and not the Teens4.1.

Just pushed the change to the library to: https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library. If you want to give it a try.
 
Hi @mjs513, I tried your lastest change and unfortunately it does not work. However, there are still a couple issues that I can see I am pretty sure need to be resolved to support MicroMOD properly.

- QuadEncoder.h only defines the CORE_XIO_PIN36 for Teensy41, not MicroMOD, and this definition must be different for T4.1 vs MicroMOD because pins 36/37 are on different CPU balls, thus the XBAR1 I/O is different as well.

- QuadEncoder.cpp needs to have separate Hardware_t structures for each of the supported hardware platforms because out of the three (T4.0, T4.1, and MicroMOD) none are completely identical.

I've created a pull request here to demonstrate some of what I think the solution is, but I am not sure how to set all the values correctly in Hardware_t for MicroMOD. You help is greatly appreciated! I am using 4 encoders on my project and designed it to put all four on H/W encoder pins.

Here is the PR on Github (again, it doesn't work, but it illustrates what I'm doing. We can merge once we get it working).
https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library/pull/8

Here is the config for the four encoders. Three of them work fine. The one using pins 31/316 does not. If I replace it with the software based Encoder class, it works fine so hardware should be good.
Code:
QuadEncoder enc0(1, 33, 2); //  ENC0
QuadEncoder enc1(2, 31, 36); //  ENC1
QuadEncoder enc2(3, 5, 4); //  ENC2
QuadEncoder enc3(4, 3, 30); //  ENC3

void setup() {
  Serial.begin(9600);
  Serial.println("Encoder Test:");
  /* Initialize Encoder/knobLeft. */
  enc0.setInitConfig();
  enc0.init();
  enc1.setInitConfig();
  enc1.init();
  enc2.setInitConfig();
  enc2.init();
  enc3.setInitConfig();
  enc3.init();
}
 
Hi @mjs513, I tried your lastest change and unfortunately it does not work. However, there are still a couple issues that I can see I am pretty sure need to be resolved to support MicroMOD properly.

- QuadEncoder.h only defines the CORE_XIO_PIN36 for Teensy41, not MicroMOD, and this definition must be different for T4.1 vs MicroMOD because pins 36/37 are on different CPU balls, thus the XBAR1 I/O is different as well.

- QuadEncoder.cpp needs to have separate Hardware_t structures for each of the supported hardware platforms because out of the three (T4.0, T4.1, and MicroMOD) none are completely identical.

I've created a pull request here to demonstrate some of what I think the solution is, but I am not sure how to set all the values correctly in Hardware_t for MicroMOD. You help is greatly appreciated! I am using 4 encoders on my project and designed it to put all four on H/W encoder pins.

Here is the PR on Github (again, it doesn't work, but it illustrates what I'm doing. We can merge once we get it working).
https://github.com/mjs513/Teensy-4.x-Quad-Encoder-Library/pull/8

Here is the config for the four encoders. Three of them work fine. The one using pins 31/316 does not. If I replace it with the software based Encoder class, it works fine so hardware should be good.
Code:
QuadEncoder enc0(1, 33, 2); //  ENC0
QuadEncoder enc1(2, 31, 36); //  ENC1
QuadEncoder enc2(3, 5, 4); //  ENC2
QuadEncoder enc3(4, 3, 30); //  ENC3

void setup() {
  Serial.begin(9600);
  Serial.println("Encoder Test:");
  /* Initialize Encoder/knobLeft. */
  enc0.setInitConfig();
  enc0.init();
  enc1.setInitConfig();
  enc1.init();
  enc2.setInitConfig();
  enc2.init();
  enc3.setInitConfig();
  enc3.init();
}

I understand exactly what you are saying. Will take a closer look later today. Right now in the middle of some other testing that I want to finish up.
 
@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:
Capture.jpg

Thanks for taking the changes and doing the leg work. Let me know if its working for you.
 
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
 
Back
Top