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
Jonathan87
PostPosted: Jul 05, 2012 - 02:59 PM
Newbie


Joined: Jun 21, 2012
Posts: 1


I am writing a triple axis motor control program and have run into some programming issues. In an attempt to clean up my code, I moved my incremental encoder coder to its own .h and .c file. When I call the function to read the encoder position it will only return an int, but not a long int. I am using quad counting for the encoder and need to use a long int since int will overflow. Any ideas on why this would occur? I am using Atmel Studio 6 to code and compile. I am using the ATMEGA328P.


I call the function using this:

Code:
long POS_X=Encoder_Read(1);


My library code is below:

Code:
/* encoder.h*/

#ifndef encoder_h
#define encoder_h

   #include <stdint.h>

   long Encoder_Read(int);
   long Encoder_Reset(int);

#endif



Code:
/*encoder.c  these are the functions for encoder.h*/

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "encoder.h"

volatile uint8_t oldPosition=0;  // Initialize the old position as A=0, B=0.
volatile long IncPos_X=0;
volatile long IncPos_Y=0;
volatile long IncPos_Z=0;

 long Encoder_Read(int axis)
{   
        switch(axis)
   {
      case 1:
         return IncPos_X;
         break;
      case 2:
         return IncPos_Y;
         break;
      case 3:
         return IncPos_Z;
         break;
      default:
         break;
   }
}

 long Encoder_Reset(int axis)
{
   IncPos_X=0;
   return IncPos_X;
   switch(axis)
   {
      case 1:
         IncPos_X=0;
         return IncPos_X;
         break;
      case 2:
         IncPos_Y=0;
         return IncPos_Y;
         break;
      case 3:
         IncPos_Z=0;
         return IncPos_Z;
         break;
      default:
         break;
   }
}

ISR(INT0_vect)
{
   PORTB ^= (1 << 5);
   uint8_t A = PIND & (1<<2);      // Read PD2 and set A equal to it
   uint8_t B = PIND & (1<<3);      // Read PD3 and set B equal to it
   uint8_t newPosition=A|B;      // Or A & B together to obtain the current values on the two interrupt pins
   
   switch(oldPosition)      // Based on the old position, determine if a step was made and if so, what direction
   {
      case 0b00000000:                  // A=0, B=0
      switch(newPosition)
      {
         case 0b00000000:            // No Change
         break;
         case 0b00001000:            // A=0, B=1 --> 1 tick CW (negative)
         IncPos_X++;
         break;
         case 0b00000100:            // A=1, B=0 --> 1 tick CCW (positive)
         IncPos_X++;//--;
         break;
         
         default:
         break;
      }
      break;
      
      case 0b00000100:
      switch(newPosition)
      {
         case 0b00000100:            // No Change
         break;
         case 0b00000000:            // A=0, B=0 --> 1 tick CW (negative)
         IncPos_X++;
         break;
         case 0b00001100:            // A=1, B=1 --> 1 tick CCW (positive)
         IncPos_X++;//--;
         break;
         default:                  // Default: Do not change the position
         break;
      }
      break;
      
      case 0b00001000:
      switch(newPosition)
      {
         case 0b00001000:            // No Change
         IncPos_X=IncPos_X;
         break;
         case 0b00001100:            // A=1, B=1 --> 1 tick CW (negative)
         IncPos_X++;
         break;
         case 0b00000000:            // A=0, B=0 --> 1 tick CCW (positive)
         IncPos_X++;//--;
         break;
         default:                  // Default: Do not change the position
         break;
      }
      break;
      
      case 0b00001100:
      switch(newPosition)
      {
         case 0b00001100:            // No Change
         break;
         case 0b00000100:            // A=1, B=0 --> 1 tick CW (negative)
         IncPos_X++;
         break;
         case 0b00001000:            // A=0, B=1 --> 1 tick CCW (positive)
         IncPos_X++;//--;
         break;
         default:                  // Default: Do not change the position
         break;
      }
      break;
      
      default:                        // Default: Do not change the position
      break;
   }
   oldPosition=newPosition;               // Set the oldPosition equal to the new position
}


Regards,
Jonathan
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 05, 2012 - 03:09 PM
10k+ Postman


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

How do you know it's not returning long? IOW how are you observing this? I think it may be whatever tool you use to make the observation that's in error not the code itself. Also study the .lss, does it return 2 or 4 registers?

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Jul 05, 2012 - 03:15 PM
10k+ Postman


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

As a test I built this:
Code:
#include <avr/io.h>

volatile long IncPos_X=0;
volatile long IncPos_Y=0;
volatile long IncPos_Z=0;

__attribute__((noinline)) long Encoder_Read(int axis)
{
   switch(axis)
   {
      case 1:
      return IncPos_X;
      break;
      case 2:
      return IncPos_Y;
      break;
      case 3:
      return IncPos_Z;
      break;
      default:
      break;
   }
}

long POS;

int main(void)
{
   POS = Encoder_Read(1);
}

and got this:
Code:
00000092 <Encoder_Read>:
volatile long IncPos_Y=0;
volatile long IncPos_Z=0;

__attribute__((noinline)) long Encoder_Read(int axis)
{
   switch(axis)
  92:   82 30          cpi   r24, 0x02   ; 2
  94:   91 05          cpc   r25, r1
  96:   79 f0          breq   .+30        ; 0xb6 <Encoder_Read+0x24>
  98:   83 30          cpi   r24, 0x03   ; 3
  9a:   91 05          cpc   r25, r1
  9c:   a9 f0          breq   .+42        ; 0xc8 <Encoder_Read+0x36>
  9e:   81 30          cpi   r24, 0x01   ; 1
  a0:   91 05          cpc   r25, r1
  a2:   d9 f4          brne   .+54        ; 0xda <Encoder_Read+0x48>
   {
      case 1:
      return IncPos_X;
  a4:   40 91 68 00    lds   r20, 0x0068
  a8:   50 91 69 00    lds   r21, 0x0069
  ac:   60 91 6a 00    lds   r22, 0x006A
  b0:   70 91 6b 00    lds   r23, 0x006B
  b4:   13 c0          rjmp   .+38        ; 0xdc <Encoder_Read+0x4a>
      break;
      case 2:
      return IncPos_Y;
  b6:   40 91 64 00    lds   r20, 0x0064
  ba:   50 91 65 00    lds   r21, 0x0065
  be:   60 91 66 00    lds   r22, 0x0066
  c2:   70 91 67 00    lds   r23, 0x0067
  c6:   0a c0          rjmp   .+20        ; 0xdc <Encoder_Read+0x4a>
      break;
      case 3:
      return IncPos_Z;
  c8:   40 91 60 00    lds   r20, 0x0060
  cc:   50 91 61 00    lds   r21, 0x0061
  d0:   60 91 62 00    lds   r22, 0x0062
  d4:   70 91 63 00    lds   r23, 0x0063
  d8:   01 c0          rjmp   .+2         ; 0xdc <Encoder_Read+0x4a>
  da:   03 c0          rjmp   .+6         ; 0xe2 <Encoder_Read+0x50>
      break;
      default:
      break;
   }
}
  dc:   34 2f          mov   r19, r20
  de:   25 2f          mov   r18, r21
  e0:   cb 01          movw   r24, r22
  e2:   63 2f          mov   r22, r19
  e4:   72 2f          mov   r23, r18
  e6:   08 95          ret

As you can see in the three case:'s four registers are loaded then the routine ends with a bit of jiggery-pokery to arrange for the result to be in the ABI registers R25..R22.

That sure looks like returning a "long"!

This was built in AS6 with the default compiler (4.6.2)

BTW there does seem to be a missed optimisation here - why can the compiler not simply load direct to the ABI return registers?

_________________
 
 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