Encoder

Status
Not open for further replies.
Hi to all, I'm new... :)
I want to ask if anyone have connected a Teensy 3.5 to and Encoder and calculate the max frequency teensy 3.5 is able to read.

Use the encoder.h library is the best performance choice?
Use the arduino-compiler is the best performance choice?

What's the relationship between clock frequency processor and encoder frequency max count?
 
No, Encoder is not the fastest. Teensy 3.5 has two hardware decoders that can reliably do several MHz. There is some discussion in this thread:
https://forum.pjrc.com/threads/3774...sing-counts-overclock-possible-upgrade-to-3-5

The latest Teensyduino beta has new and much faster pin interrupt dispatching, which does improve performance of Encoder. Putting a number on how fast it can count is tricky, since it will start loosing counts if there is a library that disables interrupts for too long. Under ideal circumstances, the limit is probably around 300'000 counts per second. If there is a library that disables interrupts, that limit can be far lower.

I have a DMA-based encoder library that can do more than 1MHz, which I plan to release soon.

Teensyduino uses GCC. Although the version is a bit old at this point, don't expect better performance from a different compiler.
 
Thanks so much for answering.
I need to read just 170 kHz...I just realizing a step-dir --> Analog -10/+10V servo controller with pid.
So if limit is so high for my application (300 kHz) I think encoder library is enough fast and I have enough time for pid control...of course I think is better to don't use serial interface during pid and encoder reading
:)

Use an interrupt to read (while encoder are in use) the step can alterate encoder count?
 
Last edited:
Reading the encoder count in an ISR is fine.

At 170kHz, you want to increase the pin interrupt priority, so that you don't loose encoder steps. By default, most Teensy interrupt priorities are 128. Interrupts at the same priority level can't interrupt each other.

There isn't really a pin interrupt, interrupts are for a complete IO port. A pin to IO port map is here (the native column):
https://forum.pjrc.com/threads/34808-K66-Beta-Test?p=106291&viewfull=1#post106291

The priority of the port interrupt can be set with (use IRQ_PORTA, IRQ_PORTB, IRQ_PORTC, IRQ_PORTD, IRQ_PORTE depending on the port(s)):
Code:
NVIC_SET_PRIORITY(IRQ_PORTA, 32);
 
The Teensy Serial port 1 uses a hardware FIFO so you can handle short (16 byte?) serial messages without interrupts causing to much trouble and just wait till the number of bytes is enough to pull out and parse.
 
170 kHz shouldn't be a big issue. I'm using a T3.1 system which easily does the following tasks in parallel:

  • Reading 3 encoders at about 200kHz
  • Managing a web socket connection and send out encoder data over the connection to a display (web browser on a tablet)
  • Running a web server to serve the html for the display

I'm using the system more or less daily on my lathe and did never observe any lost steps so far. (If somebody is interested: https://www.youtube.com/watch?v=WNYi6aPL8Rg and here a test of the hardware counters running at about 800kHz: https://www.youtube.com/watch?v=ZLVXQfjfS6Q)
 
Hi luni, would you be willing to share your code or which libraries you used for the encoders in your project?
Thanks.
 
Rod,

here my code. Opposed to the standard encoder library I don't use port interrupts for counting the quadrature signals but a fixed sampling frequency.

Reason:
My main application is to read out high resolution encoders on my lathe. If the machine stops "near an encoder edge" vibrations can generate a high frequency up/down counting signal which would lead to a very high number of interrupts. Using a fixed sampling frequency is said to be more robust in these situations. Algorithm and discussion (german) can be found here https://www.mikrocontroller.net/articles/Drehgeber

In case you want to try it, I extracted my encoder code into a library and did a small example with 6 encoders (attached). Just out of curiosity I tested the performance with a T3.6 @240Mhz. I connected an encoder (Heidenhain ROD426-1000) and tried to rotate it by hand to get about 10kHz pulse frequency which roughly corresponds to your 130rpm / 4096 counts/rev. Sampling frequency was 33kHz.

The pictures show the A/B signal (trace 2/3) and the time spent in the interrupt (trace 1).

encoder1.PNG


encoder2.PNG

Result:
  • reading out 6 encoders requires a total time of about 0.8µs. At 30 kHz sampling rate this corresponds to a processor load of 2.4%.
  • 6 encoders with a required count rate of 200kHz would need a sampling frequency of at least 400kHz. This would lead to a processor load of about 30%

Would be interesting to compare to performance data of the standard encoder lib.

Usage:

Code:
#include "AltEncoder.h"

using namespace AltEncoder;

// Define a list of as much encoders you need
// Parameters are pin numbers for 
// phase A and phase B

Encoder* encoderList[] =
{//            A  B
  new Encoder( 3, 4),
  new Encoder( 5, 6),
  new Encoder( 7, 8),
  new Encoder( 9,10),
  new Encoder(11,12),
  new Encoder(14,15),
  nullptr
};

void setup() 
{
  Serial.begin(0);
  Controller::begin(encoderList, 30/*µs*/);   // choose a sampling period which is at least a factor of two smaller than the shortest time between two encoder signal edges. 
}                                            
void loop() 
{
  for(int i = 0; i< 6; i++) 
  {
    Serial.println(encoderList[i]->counter);
  }
  Serial.println();

  delay(100);
}
 

Attachments

  • AltEncoder.zip
    832 bytes · Views: 251
  • encoder.ino
    762 bytes · Views: 209
Last edited:
I appreciate you sharing your code and looking into my problem, I'll have the teensy on wednesday and will update my thread with the results with both libraries as soon as possible.

I was wondering: how did you measure or estimate the 0.8µs time required to sample the encoder signals?
 
I just set a pin to HIGH when I enter the ISR and back to LOW when I leave it. For the actual measurement I use a cheap logic analyzer (traces shown in the post). This of course does not measure the time required for e.g. pushing/popping registers and it does not take into account that the optimizer might shuffle the execution order (pin might be set HIGH some time after the code enters the ISR). But for that kind of performance estimations it should be accurate enough.
 
Your code worked perfectly to take all of the encoders in and was easy to understand, Thank you.
 
Status
Not open for further replies.
Back
Top