Code Monkey home page Code Monkey logo

teensy-4.x-quad-encoder-library's Introduction

Hardware Quadrature Library for the Teensy 4.x

Library based on NXP Quad Encoder SDK driver for the Encoder module but modified to support the Teensy 4.x infrastructure.

There are 4 hardware quadrature encoder channels available the Teensy 4.x. The Teensy 4.x Encoders are supported on pins: 0, 1, 2, 3, 4, 5, 7, 8, 30, 31 and 33. On the T4.1 the following additional pins are supported: 36 and 37.

WARNING! Pins 0, 5 and 37 share the same internal crossbar connections and are as such exclusive...pick one or the other. Same thing applies to pins 1 / 36 and 5 / 37.

For Teensy 4.0: pins 0-8, 30, 31, 33 are supported. For Teensy 4.1: pins 0-8, 30, 31, 33 and pin 37 are supported. For Teensy Micromod: pins 0-8, 30, 31, 33, 36 and 37 are supported

The constuctor is designed to tell the library what encoder channel, PhaseA and PhaseB pins to use as well as whether to use pullups on those pins. Example:

QuadEncoder myEnc1(1, 0, 1, 0);  // Encoder on channel 1 of 4 available
                                 // Phase A (pin0), PhaseB(pin1), Pullups Req(0)
QuadEncoder myEnc2(2, 2, 3, 0);  // Encoder on channel 2 of 4 available
                                 //Phase A (pin2), PhaseB(pin3), Pullups Req(0)

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);

In setup the encoder is initialized as:

  myEnc1.setInitConfig();  //Loads default configuration for the encoder channel
  myEnc1.init();           //Initializers the encoder for the channel selected

To access counts in loop:

    mCurPosValue = myEnc1.read();
    Serial.printf("Current position value1: %ld\r\n", mCurPosValue);
    Serial.printf("Position differential value1: %d\r\n", (int16_t)myEnc1.getHoldDifference());

all you have to call is getPosition() while myEnc1.getHoldDifference() shows direction.

Another example is the ability to change initial parameters once they are loaded:

  myEnc2.setInitConfig();  //
  myEnc2.EncConfig.positionInitialValue =100;
  myEnc2.init();

In this case myEnc2.EncConfig.positionInitialValue changes the starting value for the position counts.

Current available parameters:

		/* Basic counter. */
		bool enableReverseDirection;
		bool decoderWorkMode; // 0 = Normal mode, 1 = PHASEA input generates a count signal while PHASEB input control the direction. 

		/* Signal detection. */
		uint8_t HOMETriggerMode;   //0 - disable, 1 - rising, 2 - falling
		uint8_t INDEXTriggerMode; //0 - disabled, 1 - Use positive going edge-to-trigger initialization of position counters!, 2 - use falling
		bool clearCounter;  
		bool clearHoldCounter; 

		/* Filter for PHASEA, PHASEB, INDEX and HOME. */
		/* Input Filter Sample Count. This value should be chosen to reduce the probability of noisy samples causing an incorrect transition to be recognized. The value represent the number of consecutive samples that must agree prior to the input filter accepting an  input transition. A value of 0x0 represents 3 samples. A value of 0x7 represents 10 samples. The Available range is 0 - 7. */
		uint16_t filterCount; 

		/* Input Filter Sample Period. This value should be set such that the sampling period is larger than the period of the expected noise. This value represents the sampling period (in IPBus clock cycles) of the decoder input signals.	The available range is 0 - 255. */
		uint16_t filterSamplePeriod; 

		/* Position compare. */
		/* 0 - POSMATCH pulses when a match occurs between the	position counters (POS) and the compare value (COMP). 1 - POSMATCH pulses when any position counter register is read. */
		bool positionMatchMode;
		
		/* Position Compare Enabled. */
		bool positionCompareMode;   **<< NEW examples updated **
		/*!< Position compare value. The available value is a 32-bit number.*/
		uint32_t positionCompareValue;   

		/* Modulus counting. */
		/*0 - Use INDEX pulse to increment/decrement revolution counter. 1 - Use modulus counting roll-over/under to increment/decrement revolution counter. */ 
		bool revolutionCountCondition; 	
								
		bool enableModuloCountMode;     //Enable Modulo Counting. */
		
		/*Position modulus value. This value would be available only when	"enableModuloCountMode" = true. The available value is a 32-bit number. */
		uint32_t positionModulusValue;  
		
		//Position initial value. The available value is a 32-bit number. */
		uint32_t positionInitialValue;  

A couple of things to note when using the INDEX or the HOME triggers are used:

  1. If one of the two trigger pins are used while INDEXTriggerMode is DISABLED in the configuration structure the position counts will continue to increment while the "Position HOLD revolution value" will increment when the index pulse is seen on the pin.
  2. If INDEXTriggerMode is set to RISING_EDGE or FALLING_EDGE`` the associated interrupt will fire and increment the indexCounter``` but the position counts will be reset to zero.
  3. This applies to the HOME trigger as well.
  4. 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.
  5. If indexTrigger = ENABLE and INDEXTriggerMode = ENABLE. The encoder count will continue reset and 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.
  6. If indexTrigger = DISABLE (default) and INDEXTriggerMode = ENABLE. The encoder count will continue reset and the indexCounter will not increment with index signal (needs to be negative trigger) and the Position HOLD revolution value will increment or decrement depending on direction.
  7. items 4, 5, and 6 apply for the home trigger signal (needs to be positive) as well

Basic Usage for the Teensy 4.x

Basic usage for the T4 is similar to the current Teensy Encoder library.

Encoder myEnc(enc, pin1, pin2); 
   enc - encoder object (specify 1, 2, 3 or 4).
   pin1 - phase A
   pin2 - phase b
myEnc.read();
   Returns the accumulated position. This number can be positive or negative. 
myEnc.write(newPosition);
   Set the accumulated position to a new number. 

Example Program

(similar to example on https://www.pjrc.com/teensy/td_libs_Encoder.html. See SimpleEncoder.ino in the examples folder.

* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/

#include "Quadencoder.h"

// Change these pin numbers to the pins connected to your encoder.
// Allowable encoder pins:
// 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33
// Encoder on channel 1 of 4 available
// Phase A (pin0), PhaseB(pin1), 
QuadEncoder knobLeft(1, 0, 1);
// Encoder on channel 2 of 4 available
//Phase A (pin2), PhaseB(pin3), Pullups Req(0)
QuadEncoder knobRight(2, 2, 3);
//   avoid using pins with LEDs attached

void setup() {
 Serial.begin(9600);
 Serial.println("TwoKnobs Encoder Test:");
 /* Initialize Encoder/knobLeft. */
 knobLeft.setInitConfig();
 //Optional filter setup
 //knobLeft.EncConfig.filterCount = 5;
 //knobLeft.EncConfig.filterSamplePeriod = 255;
 knobLeft.init();
 /* Initialize Encoder/knobRight. */
 knobRight.setInitConfig();
 //knobRight.EncConfig.filterCount = 5;
 //knobRight.EncConfig.filterSamplePeriod = 255;
 knobRight.init();
}

long positionLeft  = -999;
long positionRight = -999;

void loop() {
 long newLeft, newRight;
 newLeft = knobLeft.read();
 newRight = knobRight.read();
 if (newLeft != positionLeft || newRight != positionRight) {
   Serial.print("Left = ");
   Serial.print(newLeft);
   Serial.print(", Right = ");
   Serial.print(newRight);
   Serial.println();
   positionLeft = newLeft;
   positionRight = newRight;
 }
 // if a character is sent from the serial monitor,
 // reset both back to zero.
 if (Serial.available()) {
   Serial.read();
   Serial.println("Reset both knobs to zero");
   knobLeft.write(0);
   knobRight.write(0);
 }
}

teensy-4.x-quad-encoder-library's People

Contributors

blackaddr avatar drf5n avatar mjs513 avatar paulstoffregen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

teensy-4.x-quad-encoder-library's Issues

Question: Index Interrupt

Is it possible to link index trigger to interrupt routine?

I would like to digitalWrite when index is seen...

Range issue in step/dir counter mode

Thank you for your library, it works like a charm.
I noticed however that, when the Quad Encoders are configured as STEP/DIR counters by EncConfig.decoderWorkMode=True, that the range of position value returned by read() is bound to 0: 2^32 and not to -2^31 : 2^31 as in quadrature mode.

Is this expected behavior?

pin0 incompatibility with multiple encoders

I am using 3 of the quad encoders, and using pin0 causes the first one to malfunction.
Example:
This works:

//The Teensy 4.0 Encoders are supported on pins: 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33
QuadEncoder encoder1(1, 1, 2, 0);  // Encoder on channel 1 of 4 available; Phase A (pin1), PhaseB(pin2), Pullups Req(0)
QuadEncoder encoder2(2, 3, 4, 0);  // Encoder on channel 2 of 4 available; Phase A (pin3), PhaseB(pin4), Pullups Req(0)
QuadEncoder encoder3(3, 5, 7, 0);  // Encoder on channel 3 of 4 available; Phase A (pin5), PhaseB(pin7), Pullups Req(0)

But this does not:

//The Teensy 4.0 Encoders are supported on pins: 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33
QuadEncoder encoder1(1, 0, 1, 0);  // Encoder on channel 1 of 4 available; Phase A (pin0), PhaseB(pin1), Pullups Req(0)
QuadEncoder encoder2(2, 2, 3, 0);  // Encoder on channel 2 of 4 available; Phase A (pin2), PhaseB(pin3), Pullups Req(0)
QuadEncoder encoder3(3, 4, 5, 0);  // Encoder on channel 3 of 4 available; Phase A (pin4), PhaseB(pin5), Pullups Req(0)

flipping wires so that encoders are connected does nothing - encoder on channel 1 counts very erratically.
commenting out the encoder2 and encoder3 makes channel 1 with no hardware changes:

//The Teensy 4.0 Encoders are supported on pins: 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33
QuadEncoder encoder1(1, 0, 1, 0);  // Encoder on channel 1 of 4 available; Phase A (pin0), PhaseB(pin1), Pullups Req(0)
// QuadEncoder encoder2(2, 2, 3, 0);  // Encoder on channel 2 of 4 available; Phase A (pin2), PhaseB(pin3), Pullups Req(0)
// QuadEncoder encoder3(3, 4, 5, 0);  // Encoder on channel 3 of 4 available; Phase A (pin4), PhaseB(pin5), Pullups Req(0)

Question: How well does this library handle bounce?

I've used Paul Stoffregen's Encoder library for a long time, and it has always worked really well. I see that this library uses the hardware encoder channels on the Teensy 4.0, but I don't see how it handles bounce issue (like setting sensitivity for the pulse count), other than maybe changing the filterSamplePeriod. Do you have any information/experience with this?

Calculation of velocity/count rate

it does not look as though there is a count rate or speed/velocity calculated. Is this something available from the hardware counter or would it need to be calculated by positional change over a timed interval?

Possible bug/definition in modulo counting mode

Hello,

First of all , thanks very much for making this library.

I am using a 512CPT Maxon MR Encoder (datasheet). Setting up the following test configuration:

-Maxon connected to Teensy via MAX14775 on pin 0 (ENCA), pin1 (ENCB), pin 2(ENCI)
-QuadEncoder configured as QuadEncoder enc(1, ENCA, ENCB)
-positionModulusValue set to 2048
-Attaching an interrupt to ENCI
-In the interrupt, the current position is measured and compared with the position of the previous interrupt.
-This gives 2048 when disabling modulo counting
-I would expect it to give 0 but instead it gave 1, and the actual count value when the interrupt occurs kept increasing.
-Switching positionModulusValue to 2047 gave a constant result

Could this be an issue in the library, or is this just the definition used in the decoder?

Question: Performance?

Hello. This is said to be hardware library, so how well does it perform with teensy 4.0 / 4.1? Can we see test results?
Specifically, I'm interested in how much RPM you can go with rotary encoder of specified lines per revolution amount (say. 1800 or 3600 lines).

Pins 1 and 36 on same xbar?

I think I found another crossbar limitation on pin arrangements. I'm connecting 4 AB encoders. My original intention was to use these pin assignments:

QuadEncoder e1(1, 1, 30)
QuadEncoder e2(2, 2, 31)
QuadEncoder e3(3, 3, 36)
QuadEncoder e4(4, 4, 37)

But there seemed to be weird behaviour on e1 and e3. Through trial and error I found that changing e3 to use pins 3 and 33 seemed to fix it. Looking at the diagram below it looks like pins 1 and 36 are both on xbar 16. Might need to update the readme? Happy to make a PR if my analysis is correct (and trawl through the rest of the pins to see if I can pick up any other conflicts); not that experienced so wanted to check first.

https://github.com/KurtE/TeensyDocuments/blob/master/Teensy4.1%20Pins.pdf

Very small bug in QuadEncoder constructor?

Lines 83-86 of constructor are shown below. Should the 2nd "if" statement be testing PhaseB_pin?

  if(PhaseA_pin != 255 )
	enc_xbara_mapping(PhaseA_pin, PHASEA, pin_pus);
  if(PhaseA_pin != 255 )
	enc_xbara_mapping(PhaseB_pin, PHASEB, pin_pus);

Reset Index counter when a max value is reached

Thank you very much for building this library for Teensy 4.0. It is really helpful!!!!
I am using it successfully with a 2000ppr quadrature encoder. However my encoder is connected with some gears with ratio 1:5 and I would like to count the ticks till the index number reaches 5 complete revolutions which translates to 10000 ticks. So the question is simple, is there anyway to configure the index counter once reaches the number 5 to reset back to zero?
One solution would be to modify the QuadEncoder::isr in QuadEncoder.cpp and manually set it to zero with some if statements.
Is there any clearer way?
Also I have read again and again the documentation you provide and the one found in the mcu site but I don't really get the difference between the index counter and the home counter. Could you please elaborate on this a bit?

Best regards!!!!

Initialisation of QuadEncoder * QuadEncoder::list[5];

I can't find any initialisation of the static variable QuadEncoder::list[5];. Should this not not happen in the constructor ?
e.g.

list[encoder_ch] = this ;

In the whole code there is only one access to list in checkAndProcessInterrupt

How can this work ?

Having some issues with getting valid data from a 3 Encoder Setup...

I'm running the following code
[CODE]
// http://www.pjrc.com/teensy/td_libs_Encoder.html
//
//This example code is in the public domain.
//

#include "QuadEncoder.h"
int pullup = 1; // Weather or not to use a pullup resistor

// Change these pin numbers to the pins connected to your encoder.
// Allowable encoder pins:
// 0, 1, 2, 3, 4, 5, 7, 30, 31 and 33
// Encoder on channel 1 of 4 available
// Phase A (pin0), PhaseB(pin1),
QuadEncoder knobA(1, 0, 1, pullup);
// Encoder on channel 2 of 4 available
//Phase A (pin2), PhaseB(pin3), Pullups Req(0)
QuadEncoder knobB(2, 2, 3, pullup);
//
QuadEncoder knobC(3, 4, 5, pullup);
// avoid using pins with LEDs attached

void setup() {
Serial.begin(9600);
Serial.println("TwoKnobs Encoder Test:");
/* Initialize Encoder/knobLeft. /
knobA.setInitConfig();
//Optional filter setup
knobA.EncConfig.filterCount = 5;
knobA.EncConfig.filterSamplePeriod = 255;
knobA.init();
/
Initialize Encoder/knobRight. */
knobB.setInitConfig();
knobB.EncConfig.filterCount = 5;
knobB.EncConfig.filterSamplePeriod = 255;
knobB.init();

knobC.setInitConfig();
knobC.EncConfig.filterCount = 5;
knobC.EncConfig.filterSamplePeriod = 255;
knobC.init();
}

long positionA = -999;
long positionB = -999;
long positionC = -999;

void loop() {
long newA, newB, newC;
newA = knobA.read();
newB = knobB.read();
newC = knobC.read();
if (newA != positionA || newB != positionB || newC != positionC) {
Serial.print(" A = ");
Serial.print(newA);
Serial.print(", B = ");
Serial.print(newB);
Serial.print(", C = ");
Serial.print(newC);
Serial.println();
positionA = newA;
positionB = newB;
positionC = newC;
}
}
[/CODE]

Which is generating the following output, which I find odd, as the 3'rd channel is generating output on A and C, while the other pins are generating output on their respective channel, but only 0 and 1 or 0 and -1... while that one output is increasing/decreasing the numbers.

A = 0, B = -1, C = 1720
A = 0, B = 0, C = 1720
A = 0, B = -1, C = 1720
A = 0, B = 0, C = 1720
A = 0, B = -1, C = 1720
A = 0, B = 0, C = 1720
A = 0, B = -1, C = 1720
A = 0, B = 0, C = 1720
A = 1, B = 0, C = 1719
A = 1, B = 0, C = 1720
A = 0, B = 0, C = 1720
A = 0, B = 0, C = 1719
A = 1, B = 0, C = 1719

Question: use of all 4 quad encoders at the same time / pin assignments

I am using all 4 quad encoders at the same time.
3 quad encoders need a home signal and the 4th one an index.

The challenge is that (on a Teensy 4.1) pins 0, 5 and 37 all use XBAR1_IN17 to rout the signal to the peripheral meaning that only 11 signals can be routed at the same time.
Can this be fixed or am I hitting a hardware limit of the RT1060 chip?
I've been looking at the processor reference manual but I have not found a good overview of all possible XBAR connections

Rob

TEENSY40 index 8 typo

QuadEncoder.cpp at line 23 :
{6, 7, &CORE_XIO_PIN7, 1, 15, 1}, {8, 8, &CORE_XIO_PIN8, 1, 14, 1},

probebly need to be
{6, 7, &CORE_XIO_PIN7, 1, 15, 1}, {7, 8, &CORE_XIO_PIN8, 1, 14, 1},

and the readme line
"For Teensy 4.0: pins 0-8, 30, 31, 33 are supported. For Teensy 4.1: pins 0-8"
is wong, it's not 0-8, pin 6 is not avalible

Multi channel index counter issue

Hi,

thanks a lot for this library, it really works great!

I am using it with two steppers, and corresponding encoders, both with an index pin.
Pins are 0, 1, 2 and 3, 4, 7, respectively
One issue I found is that the index counter (and looking at the source, I think similarly the home counter) seem to not count per channel, but for all connected decoders summed.
I.e. "quadEncoderCh1.indexCounter" always posesses the same value as "quadEncoderCh2.indexCounter".
I'm not sure this is desired, though it is easily worked around for my project.

Maybe you can hint on whether that is intended or if I might be docing something wrong.
Thanks again!
Cheers
Philipp

Permitted pin combinations

Hi,

I want to use three incremental encoders with a Teensy 4.1. I understand that only certain pins can be used as clearly stated in the documentation. What I want to confirm is whether there's any restrictions on which pairs of pins from that selection can be used together. Specifically, I want to use [0, 1], [2, 3] and [4, 7] for my three encoders. Am I ok?

Thanks,

Luke

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.