Pages: 1 [2] 3 4   Go Down
Author Topic: Using the Hardware Quadrature Encoder Channel on the DUE  (Read 14791 times)
1 Member and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

As far as I understand the due has only one hardware encoder, but you can still use interrupt versions of software encoders to handle almost as many encoders as you wish.

in terms of speed you will then be limited by your interrupt handlers. If you programm cleverly you can get the time to handle the interrupts well below 1us (I can provide code if necessary), meaning that you can detect slopes at rates above 1MHz. If you use more than one encoder you just divide the 1MHz by the number of encoders you'd like to use.

I don't know exactly how fast the hardware encoder can go but since it uses the master clock (84MHz) as a reference I guess it can take at least more than 10MHz slope rate, probably even much faster.

For your application this would mean that you connect the encoder with the highest speed demands on the hardware encoder and you programm two interrupt based software encoders for the other 2. Those would then be able to detect slope rates of more than 500kHz.

Would that fit your "extremely fast" application?

for level shifting you can use chips like 74LVCC4245 and others. they're convenient to handle and super fast (10ns delay)


Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 38
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

the buffer is a better way but i am using my 5 volt encoders with a voltage divider on the output. just a 10k and 20k resistor in series. easier to stick in as an afterthought than wiring in the buffer.
Logged

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am using a 500 pulse/rev encoder from maxon motors (I think they are rebranded AvagoTech Encoders), rated for 5V and 3,3kOhm Pullups on the signal lines. I use it with 3.3V and 10k Pullups and it works just fine. Maybe just give it a try.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 37
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you all. Im going to buy the next Arduino Due ASAP. and replace my MEGA 1280. and get 3 buffers. its going to be interesting. next question how can i get a 5v pwm signal out?
Logged

St. Petersburg, FL
Offline Offline
Jr. Member
**
Karma: 1
Posts: 61
Retired physicist
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Use one of the same buffer chips but connect Vss to 5V. As long as your input signal crosses around the 50% point, the output will switch states. Use the B version of the chip as it's switching level is better defined. Check the data sheet on AllDataSheet.com.

http://pdf1.alldatasheet.com/datasheet-pdf/view/26876/TI/CD4050B.html


Logged

Offline Offline
Newbie
*
Karma: 1
Posts: 42
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you might actually run into troubles using the hardware quadrature encoder simultaneously with the standard PWM outputs.
The hardware encoder uses the timer counter TC0 and the standard PWM uses it partially too, as far as I know..

anyone with more insight on how the standard PWM would interfere with the settings on TC0 channel 0 and 1?

I circumvent this problem by not using the arduino defined PWM outputs (that use the timer counter channels) but by using the SAM3x8e internal PWM channels (labeled PWMHx and PWMLx in the due pinout diagramm http://arduino.cc/forum/index.php?PHPSESSID=cddf2a518756c532262dde0095dd89df&topic=132130.0). They actually exceed the functionality of the standard ones in terms of resolution and available PWM frequencies. The drawback is that you have to do a bit of reading in the datasheet and to programm some registers.
I will probably post some code examples when I have a bit more time..
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 2
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

just solved the problem.. the EDGPHA bit in the TC_BMR register controls whether the edges are detected on both PHA and PHB or just on PHA. I had this bit set to 0 before which according to the datasheet was the good choice.

("0: edges are detected on both PHA and PHB. 1: edges are detected on PHA only.")

BUT!! the description in the datasheet is WRONG!! its inverted!

so the code that works fine is the following:
Code:
const int quad_A = 2;
const int quad_B = 13;
const unsigned int mask_quad_A = digitalPinToBitMask(quad_A);
const unsigned int mask_quad_B = digitalPinToBitMask(quad_B); 

void setup() {
    Serial.begin(115200); 
    delay(100);
   
    // activate peripheral functions for quad pins
    REG_PIOB_PDR = mask_quad_A;     // activate peripheral function (disables all PIO functionality)
    REG_PIOB_ABSR |= mask_quad_A;   // choose peripheral option B   
    REG_PIOB_PDR = mask_quad_B;     // activate peripheral function (disables all PIO functionality)
    REG_PIOB_ABSR |= mask_quad_B;   // choose peripheral option B
   
    // activate clock for TC0
    REG_PMC_PCER0 = (1<<27);
    // select XC0 as clock source and set capture mode
    REG_TC0_CMR0 = 5;
    // activate quadrature encoder and position measure mode, no filters
    REG_TC0_BMR = (1<<9)|(1<<8)|(1<<12);
    // enable the clock (CLKEN=1) and reset the counter (SWTRG=1)
    // SWTRG = 1 necessary to start the clock!!
    REG_TC0_CCR0 = 5;   
   
void loop() {
  Serial.println(REG_TC0_CV0,DEC);
  delay(500);
}
I tested the proposed code at up to 60 kHz, works great! But the index is not work at A7. Does anyone understand? My knowledge there is no longer enough.
Logged

Germany
Offline Offline
Newbie
*
Karma: 0
Posts: 23
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

To enable the Index Signal you have to configure the input pin to the right peripheral function
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

After an hour studying the SAM3X manual, I am getting a vague idea of how the decoding works - but can an example of how to also count the index be added to the working code example?

I am trying with an interrupt for the index, but the counts are low and drop more when the encoder is spun faster (TS5303 - can handle 5000RPM, pulses dropped at perhaps 100RPM).

I'm using 4N35s - perhaps they aren't switching fast enough?

Last question : the count keeps increasing, does it eventually overflow? can it be reset (per rev)? how is this normally handled?

I would be very appreciative of help here
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 37
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

When using interup try to keep the statments as quick and short as you can. my interupt code ive only been able to run at 0.1-150RPM with 250Pulses/rev. (1000counts) and that is with an arduino mega 1280, with encoder A+B+Z channels on interupts@change.

my interrupts are simple:
Code:
X_EncoderA(){
 if (digitalRead(encoderXPinA)==HIGH) {
   if (digitalRead(encoderXPinB) == LOW)  encoderXPos++;         // CW
   if (digitalRead(encoderXPinB) == HIGH)  encoderXPos--;         // CCW
 } else {
   if (digitalRead(encoderXPinB) == HIGH)  encoderXPos++;        // CW
   if (digitalRead(encoderXPinB) == LOW)  encoderXPos--;         // CCW
 }
}
X_EncoderB(){
 if (digitalRead(encoderXPinB)==HIGH) {
   if (digitalRead(encoderXPinA) == LOW)  encoderXPos++;         // CW
   if (digitalRead(encoderXPinA) == HIGH)  encoderXPos--;         // CCW
 } else {
   if (digitalRead(encoderXPinA) == HIGH)  encoderXPos++;         // CW
   if (digitalRead(encoderXPinA) == LOW)  encoderXPos--;          // CCW
 }
}


if you keep spinning the encoder in one direction it will overflow. depending on what data type you are using to store them. i use "unsigned int" that gives me 0 to 4,294,967,295 (2^32 - 1). i use unsigned because when i zero it, it is at it's left most extreme location. (i used to use "int" because i zero'ed it in the middle and needed the negative numbers.)

Sorry i cant help with any SAM3X information, or buffers. i dont use them YET.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Ok, that would give me more than 24 hours before it overflowed (at 1800RPM) so not a problem

My interrupt is even simpler, just detects RISING and sets a flag

I'm using the flag in loop to display the number of pulses. So the serial comms should not be interfering, unless the previous print has not completed before the flag is being set again

And if I just count high flag state and only display the pulses after 100 revs, the count is still low and differening. I only get the expected count when rotating very slowly
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

schwingkopf da boss....

Now running up to 4000RPM with consistent pulsing (1440 state changes per rev, 96000 per second). Problem - bad breadboard connection somewhere  smiley-red

Ready to solder smiley

I'd like to get the Z (index) pin working instead of using an interrupt - as I sometimes get a count +1 or -1, I guess a race situation because both index and a pulse pin are changing more or less at the same time. Funny that an encoder does that in a way - if the Due hardware logic sorts it out, it really can't be much better
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 37
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

you guys have got to be jokeing!!! 
Quote
4000RPM with consistent pulsing (1440 state changes per rev, 96000 per second)

I cant wait to get my DUE. how are you getting feedback, serial?
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

const int quad_A = 2;
const int quad_B = 13;
const unsigned int mask_quad_A = digitalPinToBitMask(quad_A);
const unsigned int mask_quad_B = digitalPinToBitMask(quad_B); 
const int z = 10;
volatile int reg_at_z=0;
volatile int zcount=0;
volatile int  lag;
unsigned int prevmillis;
unsigned int thismillis;
int t;
int prevt=0;
float rpm=0.0;

volatile int firsttime=1;

void setup() {
    Serial.begin(115200); 
    delay(100);
   
    // activate peripheral functions for quad pins
    REG_PIOB_PDR = mask_quad_A;     // activate peripheral function (disables all PIO functionality)
    REG_PIOB_ABSR |= mask_quad_A;   // choose peripheral option B   
    REG_PIOB_PDR = mask_quad_B;     // activate peripheral function (disables all PIO functionality)
    REG_PIOB_ABSR |= mask_quad_B;   // choose peripheral option B
   
    // activate clock for TC0
    REG_PMC_PCER0 = (1<<27);
    // select XC0 as clock source and set capture mode
    REG_TC0_CMR0 = 5;
    // activate quadrature encoder and position measure mode, no filters
    REG_TC0_BMR = (1<<9)|(1<<smiley-cool|(1<<12);
    // enable the clock (CLKEN=1) and reset the counter (SWTRG=1)
    // SWTRG = 1 necessary to start the clock!!
    REG_TC0_CCR0 = 5;   
 
   pinMode(z, INPUT);       
   attachInterrupt(z, zrising, RISING); 

}   
void loop() {
  if (reg_at_z==1) {
    t=REG_TC0_CV0;   
    Serial.println((t-prevt),DEC);   
     thismillis=millis();
     rpm = 1.0/((thismillis-prevmillis)/60000.0);
    Serial.println(rpm,DEC);         
     reg_at_z=0;
     prevt=t;
     prevmillis=thismillis;
  }

}

void zrising() {
  reg_at_z=1;
}

Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 55
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

For what it's worth - I suggest some careful checking before trying this.



* encoder due test.png (415.54 KB, 1782x2040 - viewed 171 times.)
Logged

Pages: 1 [2] 3 4   Go Up
Jump to: