Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
keepcool
PostPosted: Sep 27, 2011 - 07:11 AM
Hangaround


Joined: Oct 07, 2009
Posts: 248


Good night dear Freaks, here I'm again asking the help of the smarter ones.
As usual here is the story:
As you might already read I'm designing a small robot for a contest, and I'm still in the motor control stage.
After some searching around google and here I found some nice code to read my encoders at 2x because 1x resolution was a bit on the short side, my problem is that the encoder that is connected to external INT0 works flawlessy, but the one connected to INT1 only counts down, which seems strange, I have already checked everything and swapped the motors and the problem only happens with the INT0 pin..
Here is what I think that is the relevant code if someone as some time to read it and maybe help me Embarassed

Code:

void motorInit(void){

   serialInit();

   DIRDDR |= ((1<<DIR1A)|(1<<DIR1B)|(1<<DIR2A)|(1<<DIR2B));   //sets direction control pins as outputs
   ENCADDR &= ~((1<<ENC1A)|(1<<ENC2A));            //Sets encoder pins as inputs
   ENCBDDR &= ~((1<<ENC1B)|(1<<ENC2B));            //sets the rest of the encoder pins as inputs
   PWMDDR |= ((1<<PWMMPIN1)|(1<<PWMMPIN2));         //Sets pwm pins as outputs
   LEDDDR |= ((1<<LEDERR)|(1<<LEDOK));            //Set status leds as outputs

   MOTORDIRDDR = ((1<<MOTOR1A)|(1<<MOTOR1B)|(1<<MOTOR2A)|(1<<MOTOR2B));   //Sets H bridge dir select pins as outputs

   EICRA |= ((1<<ISC10)|(1<<ISC00));            //Ext int 0 and 1 respond to any edges in the respective pins
   EIMSK |= ((1<<INT1)|(1<<INT0));               //Enable external int 0 and 1 in the interrupt mask, dont forget the sei() in main

   MOTORPORT |= ((1<<MOTOR1A)|(1<<MOTOR1B)|(1<<MOTOR2A)|(1<<MOTOR2B));   //Stop the motors in the init

   //Pwm init and config
   TCCR0A = ((1<<COM0A1)|(1<<COM0B1)|(1<<WGM00));         //Enable pwm in both timer 0 pins with phase correct pwm
   TCCR0B = (1<<CS00);                  //No prescaled clock, feed 16Mhz to the timer
   PWMMOTOR1 = 0;                     //Fpwm = (Fio/(N*510)), with N=1, Fpwm = 31Khz
   PWMMOTOR2 = 0;                     //This is to avoid stupid noises from the motors, and init the values to 0

   //Timer 1 init and config
   TCCR1B = ((1<<WGM12)|(1<<CS10));            //Timer in CTC mode, no prescaling of Fclock
   OCR1A = 15999;                     //Magic number to get 1ms with an 16Mhz clock
   TIMSK1 = (1<<OCIE1A);                  //Enable compare interrupt

   //TImer 2 init and config
   //Used to calculate the motor speed
   //So, its very essential
   TCCR2A = (1<<WGM21);            //Timer in CTC mode
   TCCR2B = ((1<<CS22)|(1<<CS21));         //prescaler is 256
   OCR2A = 250;               //Target count to have 250Hz interrupt   
   TIMSK2 = (1<<OCIE2A);            //Enable timer compare match interrupt
   
}


Code:
#define DIRDDR      DDRC   //Motor control port
#define DIR1A      PC0   //Pins to choose motor direction
#define DIR1B      PC1   //Pins to choose motor direction
#define DIR2A      PC4   //Pins to choose motor direction
#define DIR2B      PC5   //Pins to choose motor direction

#define ENCADDR      DDRD   //Port where external In for encoders are located
#define ENCAPIN      PIND
#define ENC1A      PD2   //External Int 0 pin, encoder 1 pin A
#define ENC2A      PD3   //External Int 1 pin, encoder 2 pin A
#define ENCBDDR      DDRB   //Port where pin B of encoders are located
#define ENCBPIN      PINB   //Used to read encoder pins
#define ENC1B      PB0   //Encoder 1, pin B
#define ENC2B      PB1   //Encoder 2, pin B

#define PWMDDR      DDRD   //Port where the pwm pins are located
#define PWMMPIN1   PD6   //Pwm pin for motor 1
#define PWMMPIN2   PD5   //Pwm pin for motor 2
#define PWMMOTOR1   OCR0A   //To write speed values for the motor 1
#define PWMMOTOR2   OCR0B   //To write speed values for the motor 2

#define MOTORDIRDDR   DDRC   //Port where the H bridge dir pins are connected
#define MOTORPORT   PORTC
#define MOTOR1A      PC0
#define MOTOR1B      PC1
#define MOTOR2A      PC2
#define MOTOR2B      PC3


Code:

ISR(INT0_vect){

   if(!(ENCAPIN & (1<<ENC1A))){      //This means a falling edge

      if((ENCBPIN & (1<<ENC1B)) == 0){
         encoderA++;
         }
      else {
         encoderA--;
         }
   }
   else{
      
      if((ENCBPIN & (1<<ENC1B)) == 1){
         encoderA++;
         }
      else {
         encoderA--;
         }
      }

}

ISR(INT1_vect){

   if(!(ENCAPIN & (1<<ENC2A))){      //This means a falling edge

      if((ENCBPIN & (1<<ENC2B)) == 0){
         encoderB++;
         }
      else {
         encoderB--;
         }
   }
   else{
      
      if((ENCBPIN & (1<<ENC2B)) == 1){
         encoderB++;
         }
      else {
         encoderB--;
         }
      }

}


PS.: I'm sorry but the code in gVim is perfectly indented, but then here and in Avr Studio it gets all messed up :/
 
 View user's profile Send private message  
Reply with quote Back to top
mschoeldgen
PostPosted: Sep 27, 2011 - 07:31 AM
Hangaround


Joined: Sep 22, 2011
Posts: 240
Location: Berlin

It looks as if theres a little typo in INT1 . Change the first line from
Code:
if(!(ENCAPIN & (1<<ENC2A))){      //This means a falling edge
to
Code:
if(!(ENCBPIN & (1<<ENC2B))){      //This means a falling edge


Hope that helps
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
meslomp
PostPosted: Sep 27, 2011 - 07:33 AM
Raving lunatic


Joined: May 02, 2007
Posts: 3167
Location: Nieuwegein, Netherlands

a couple of things you can check:
what happens if you only use 1 encoder at a time. so first only write code for INT0, then only for INT1. INT0 you have already working you state, so that should be easy and fast to do. Use the same encoder for writing both versions of the code. Then swap the encoder to make sure that the second encoder also works on both INT1 and 0. this to rule out a defective encoder.

if the 2 loose parts work, then combine them and only use 1 encoder to see if that works, then only use the other and finally use them both.

I assume you did not forget the sei() in main, as per comment in your code.

regards

_________________
1)Datasheet and application notes checked?
2)tutorial forum
3)Newbie start here
 
 View user's profile Send private message  
Reply with quote Back to top
Asle
PostPosted: Sep 27, 2011 - 07:39 AM
Wannabe


Joined: Aug 11, 2010
Posts: 85
Location: Porsgrunn, Norway

Hi

May be you have selected device, but the Xmega series has inbuild Quadrature Decoders.
This works nice. I have tested it on full speed on my Dremel (20000 rpm).
 
 View user's profile Send private message  
Reply with quote Back to top
keepcool
PostPosted: Sep 27, 2011 - 06:25 PM
Hangaround


Joined: Oct 07, 2009
Posts: 248


I have been doing all my testing with only one encoder, using INT0, I have already swapped the motors and they both work fine when connected to INT0 pin.

My nomenclature got a bit weird, ENCA means that its channel A of the encoder and encoder 1 and 2 means the pair of encoder channel A and B of each motor, so ENCA is the A channel that is connected respectively to PD2 and PD3 that have the INT0 and INT1 capability and ENCB are the channel B that are connected to PB0 and 1 as the channel B from each encoder, yes I have sei() in my code, because I have a timer generating interrupts at 1ms rate to do soft timing in my code and also timer 2 is being used as a time base to calculate rpm/wheel speed at regular intervals to feed the pid loop to maintain steady speed.

I will look more into the code to see if I can discover the mistake, but this is really bugging me.

EDIT

One thing that I found that is confusing me is that the generated code for the two ISR's is not equal, in the INT1 the first encoder B++ is missing!
So, is this a compiler bug?

Code:
ISR(INT0_vect){
 164:   1f 92          push   r1
 166:   0f 92          push   r0
 168:   0f b6          in   r0, 0x3f   ; 63
 16a:   0f 92          push   r0
 16c:   11 24          eor   r1, r1
 16e:   8f 93          push   r24
 170:   9f 93          push   r25
 172:   af 93          push   r26
 174:   bf 93          push   r27

   if(!(ENCAPIN & (1<<ENC1A))){      //This means a falling edge
 176:   4a 99          sbic   0x09, 2   ; 9
 178:   0e c0          rjmp   .+28        ; 0x196 <__vector_1+0x32>

      if((ENCBPIN & (1<<ENC1B)) == 0){
 17a:   19 99          sbic   0x03, 1   ; 3
 17c:   0d c0          rjmp   .+26        ; 0x198 <__vector_1+0x34>
         encoderA++;
 17e:   80 91 4c 01    lds   r24, 0x014C
 182:   90 91 4d 01    lds   r25, 0x014D
 186:   a0 91 4e 01    lds   r26, 0x014E
 18a:   b0 91 4f 01    lds   r27, 0x014F
 18e:   01 96          adiw   r24, 0x01   ; 1
 190:   a1 1d          adc   r26, r1
 192:   b1 1d          adc   r27, r1
 194:   0c c0          rjmp   .+24        ; 0x1ae <__vector_1+0x4a>
         encoderA--;
         }
   }
   else{
      
      if((ENCBPIN & (1<<ENC1B)) == 1){
 196:   83 b1          in   r24, 0x03   ; 3
         encoderA++;
         }
      else {
         encoderA--;
 198:   80 91 4c 01    lds   r24, 0x014C
 19c:   90 91 4d 01    lds   r25, 0x014D
 1a0:   a0 91 4e 01    lds   r26, 0x014E
 1a4:   b0 91 4f 01    lds   r27, 0x014F
 1a8:   01 97          sbiw   r24, 0x01   ; 1
 1aa:   a1 09          sbc   r26, r1
 1ac:   b1 09          sbc   r27, r1
 1ae:   80 93 4c 01    sts   0x014C, r24
 1b2:   90 93 4d 01    sts   0x014D, r25
 1b6:   a0 93 4e 01    sts   0x014E, r26
 1ba:   b0 93 4f 01    sts   0x014F, r27
         }
      }

}
 1be:   bf 91          pop   r27
 1c0:   af 91          pop   r26
 1c2:   9f 91          pop   r25
 1c4:   8f 91          pop   r24
 1c6:   0f 90          pop   r0
 1c8:   0f be          out   0x3f, r0   ; 63
 1ca:   0f 90          pop   r0
 1cc:   1f 90          pop   r1
 1ce:   18 95          reti

000001d0 <__vector_2>:

ISR(INT1_vect){
 1d0:   1f 92          push   r1
 1d2:   0f 92          push   r0
 1d4:   0f b6          in   r0, 0x3f   ; 63
 1d6:   0f 92          push   r0
 1d8:   11 24          eor   r1, r1
 1da:   8f 93          push   r24
 1dc:   9f 93          push   r25
 1de:   af 93          push   r26
 1e0:   bf 93          push   r27

   if(!(ENCAPIN & (1<<ENC2A))){      //This means a falling edge
 1e2:   4b 99          sbic   0x09, 3   ; 9
 1e4:   03 c0          rjmp   .+6         ; 0x1ec <__vector_2+0x1c>

      if((ENCBPIN & (1<<ENC2B)) == 0){
 1e6:   18 99          sbic   0x03, 0   ; 3
 1e8:   0f c0          rjmp   .+30        ; 0x208 <__vector_2+0x38>
 1ea:   02 c0          rjmp   .+4         ; 0x1f0 <__vector_2+0x20>
         encoderB--;
         }
   }
   else{
      
      if((ENCBPIN & (1<<ENC2B)) == 1){
 1ec:   18 9b          sbis   0x03, 0   ; 3
 1ee:   0c c0          rjmp   .+24        ; 0x208 <__vector_2+0x38>
         encoderB++;
 1f0:   80 91 50 01    lds   r24, 0x0150
 1f4:   90 91 51 01    lds   r25, 0x0151
 1f8:   a0 91 52 01    lds   r26, 0x0152
 1fc:   b0 91 53 01    lds   r27, 0x0153
 200:   01 96          adiw   r24, 0x01   ; 1
 202:   a1 1d          adc   r26, r1
 204:   b1 1d          adc   r27, r1
 206:   0b c0          rjmp   .+22        ; 0x21e <__vector_2+0x4e>
         }
      else {
         encoderB--;
 208:   80 91 50 01    lds   r24, 0x0150
 20c:   90 91 51 01    lds   r25, 0x0151
 210:   a0 91 52 01    lds   r26, 0x0152
 214:   b0 91 53 01    lds   r27, 0x0153
 218:   01 97          sbiw   r24, 0x01   ; 1
 21a:   a1 09          sbc   r26, r1
 21c:   b1 09          sbc   r27, r1
 21e:   80 93 50 01    sts   0x0150, r24
 222:   90 93 51 01    sts   0x0151, r25
 226:   a0 93 52 01    sts   0x0152, r26
 22a:   b0 93 53 01    sts   0x0153, r27
         }
      }

}
 22e:   bf 91          pop   r27
 230:   af 91          pop   r26
 232:   9f 91          pop   r25
 234:   8f 91          pop   r24
 236:   0f 90          pop   r0
 238:   0f be          out   0x3f, r0   ; 63
 23a:   0f 90          pop   r0
 23c:   1f 90          pop   r1
 23e:   18 95          reti


EDIT2:

Looks like a compiler problem, just commented out the INT0 ISR code and now the INT1 ISR is working perfectly counting up and down, I'm stumbled Surprised
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 27, 2011 - 06:57 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62954
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

Looks like a compiler problem, just commented out the INT0 ISR code and now the INT1 ISR is working perfectly counting up and down, I'm stumbled

Or a programmer problem perhaps? Have you timed how long the ISRs take? How often do they occur. If INT0 (which has a higher priority than INT1) prevents INT1 from occuring it's likely because it's absorbing almost all the CPU time.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
keepcool
PostPosted: Sep 27, 2011 - 07:11 PM
Hangaround


Joined: Oct 07, 2009
Posts: 248


You are righ Clawson, but right now I'm rotating the motors by hand, and one at a time, so when I rotate the motor that is using INT1 the motor that is using INT0 is totally stopped.
Now I uncommented the INT0 ISR and its the INT0 that only down counts, this is starting to seem very strange!

I think that I'm not overloading the micro, because each motor "only" outputs 116 pulses per revolution.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 27, 2011 - 07:14 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62954
Location: (using avr-gcc in) Finchingfield, Essex, England

OK so tell us more about this "compiler problem". What evidence do you have that the compiler has generated code that does not match what the source has asked for?

I see threads here where there are "bugs in the silicon" - with the exception of Xmega, there aren't any of those either(*).

(*) OK there are rare faults like the AVcc-Vcc internal connection in some old chips - but they are very rare!

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
keepcool
PostPosted: Sep 27, 2011 - 07:21 PM
Hangaround


Joined: Oct 07, 2009
Posts: 248


I'm not blamming the compiler and I should have said this first I'm almost sure that this is my problem, but here is the actual state:

The encoder connected to INT0 pin works 100%, perfect in fact, I can swap the motors and both work perfectly, but when I try to connect one of the motors to INT1 it only down-counts, this means that if I rotate it in one direction it keeps the count at 0, but in the other direction the values start to go negative, again rotate to the other side and it doesn't increment the count.

If I comment the ISR(INT0_vect) code ou the INT1 start working perfectly like INT0 does, if I uncomment it, it stops working again and only downcounts.
I dont understand almost nothing about assembler but it seems that the code generated for both INT0 and INT1 are different when the source is exactly the same.
 
 View user's profile Send private message  
Reply with quote Back to top
kscharf
PostPosted: Sep 27, 2011 - 07:33 PM
Posting Freak


Joined: Aug 04, 2004
Posts: 1822
Location: Davie, FL

Try leaving both interrupt routines in the code but only enable interrupt 1, then try only enabling interrupt 0. This way the code for both will be present but only one interrupt can actually happen since only one will be enabled.

BTW another way of handling this is to use a timer interrupt to schedule a polling of the encoders. Figure out the highest speed that the encoders will be switching (rev per sec * pulses per rotation) and set your timer to interrupt faster than that (now you will know if the micro is fast enough!). On each timer interrupt poll both encoders and note the state changes to figure out forward, backward, or stable (write a state machine, there are 4 possible encoder states). You can always expand this method to handle more than two encoders (if you have enough IO and the processor is fast enough).
 
 View user's profile Send private message  
Reply with quote Back to top
kscharf
PostPosted: Sep 27, 2011 - 07:39 PM
Posting Freak


Joined: Aug 04, 2004
Posts: 1822
Location: Davie, FL

Quote:
Now you mention it the two RJMP at 0x1e8 and 0x1ea do, on the surface of things, look a bit odd? The second looks to be unreachable?

I think the second jump might be a trampoline.

[just to note that I deleted by post (quoted above) when I realised what an idiot I was. The two rjmps are preceded by SBIC so of course it's valid to have two consecutive RJMPs - I'll now return to sleep - BTW he is right that seemingly identical ISRs do seem to generate different code though - Cliff]
 
 View user's profile Send private message  
Reply with quote Back to top
sparrow2
PostPosted: Sep 27, 2011 - 07:42 PM
Raving lunatic


Joined: Oct 07, 2002
Posts: 2059
Location: Denmark

And you are 100% that all varibles used between ISR and main are decleared volatile !
 
 View user's profile Send private message  
Reply with quote Back to top
keepcool
PostPosted: Sep 27, 2011 - 08:34 PM
Hangaround


Joined: Oct 07, 2009
Posts: 248


Yes, everything used in the ISR's is volatile, if someone wants to look at the project I will attach everything in a .zip.
 
 View user's profile Send private message  
Reply with quote Back to top
keepcool
PostPosted: Sep 30, 2011 - 01:11 AM
Hangaround


Joined: Oct 07, 2009
Posts: 248


I have "temporarily" fixed this using a simpler method to read the encoders at the expense of reduced resolution, still I have a 5 degree resolution which seems enough for a small robot, here is the now working code:
Code:

ISR(INT0_vect){

   if((ENCBPIN & (1<<ENC1B)) == 0){
      encoderA++;
      }
   else {
      encoderA--;
      }
}

ISR(INT1_vect){

   if((ENCBPIN & (1<<ENC2B)) == 0){
      encoderB++;
      }
   else {
      encoderB--;
      }
}


If someone as the time/willingness to do it, I would like to see my original code compiled in a different avr-gcc version to see if it is a compiler problem or my problem.
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Sep 30, 2011 - 09:08 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62954
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

I would like to see my original code compiled in a different avr-gcc version

To know what's "different" I think first you are going to have to tell us which one you used.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
keepcool
PostPosted: Sep 30, 2011 - 08:37 PM
Hangaround


Joined: Oct 07, 2009
Posts: 248


I'm using WinAVR-20100110 maybe its a bit outdated...
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits