Changing Motor Pins in 2.0

Post Reply
Spambot
Posts: 3
Joined: Sun May 13, 2012 11:56 am

Changing Motor Pins in 2.0

Post by Spambot »

Since I have problems with my PWM-Out Pin2 on my Mega-Board I had to switch the output pins and e.g. use pin7 instead of pin2. This has been easy in firmware 1.9 and earlier, but the new timer-controlled output code does overchallenge my ATmega and poor PWM knowledge.

I have so far tried to identify the code-lines that deal with the output to the motors(in output.h) and would like to
obtain some of your thoughts and if I'm on the right way so far.

IMO 'writeMotors()' is just responsible for the PWM-Generation, setting the Output Compare Registers to the corresponding values => no change needed

Here the relevant code-lines for a QuadX

Code: Select all

void writeMotors() { // [1000;2000] => [125;250]
  #if defined(MEGA)// [1000:2000] => [8000:16000] for timer 3 & 4 for mega
    #if (NUMBER_MOTOR > 0)
      #ifndef EXT_MOTOR_RANGE
        OCR3C = motor[0]<<3; //  pin 3
      #else
        OCR3C = ((motor[0]<<4) - 16000) + 128;
      #endif
    #endif
    #if (NUMBER_MOTOR > 1)
      #ifndef EXT_MOTOR_RANGE
        OCR3A = motor[1]<<3; //  pin 5
      #else
        OCR3A = ((motor[1]<<4) - 16000) + 128;
      #endif
    #endif
    #if (NUMBER_MOTOR > 2)
      #ifndef EXT_MOTOR_RANGE
        OCR4A = motor[2]<<3; //  pin 6
      #else
        OCR4A = ((motor[2]<<4) - 16000) + 128;
      #endif
    #endif
    #if (NUMBER_MOTOR > 3)
      #ifndef EXT_MOTOR_RANGE
        OCR3B = motor[3]<<3; //  pin 2
      #else
        OCR3B = ((motor[3]<<4) - 16000) + 128;
      #endif
    #endif
    #if (NUMBER_MOTOR > 4)
      #ifndef EXT_MOTOR_RANGE
        OCR4B = motor[4]<<3; //  pin 7
        OCR4C = motor[5]<<3; //  pin 8
      #else
        OCR4B = ((motor[4]<<4) - 16000) + 128;
        OCR4C = ((motor[5]<<4) - 16000) + 128;
      #endif
    #endif
    #if (NUMBER_MOTOR > 6)
      #ifndef EXT_MOTOR_RANGE
        OCR2B = motor[6]>>3; //  pin 9
        OCR2A = motor[7]>>3; //  pin 10
      #else
        OCR2B = ((motor[6]>>2) - 250) + 2);
        OCR2A = ((motor[7]>>2) - 250) + 2);
      #endif
    #endif
  #endif
  #if defined(PROMICRO)
    #if (NUMBER_MOTOR > 0) // Timer 1 A & B [1000:2000] => [8000:16000]
      OCR1A = motor[0]<<3; //  pin 9
    #endif
    #if (NUMBER_MOTOR > 1)
      OCR1B = motor[1]<<3; //  pin 10
    #endif
    #if (NUMBER_MOTOR > 2) // Timer 4 A & D [1000:2000] => [1000:2000]
      #if !defined(HWPWM6)
        // to write values > 255 to timer 4 A/B we need to split the bytes
        static uint8_t pwm4_HBA;
        static uint16_t pwm4_LBA; // high and low byte for timer 4 A
        pwm4_LBA = 2047-motor[2]; pwm4_HBA = 0; // channel A is inverted
        while(pwm4_LBA > 255){
          pwm4_HBA++;
          pwm4_LBA-=256;
        }     
        TC4H = pwm4_HBA; OCR4A = pwm4_LBA; //  pin 5
      #else
        OCR3A = motor[2]<<3; //  pin 5
      #endif
    #endif
    #if (NUMBER_MOTOR > 3)
      static uint8_t pwm4_HBD;
      static uint16_t pwm4_LBD; // high and low byte for timer 4 D
      pwm4_LBD = motor[3]; pwm4_HBD = 0;
      while(pwm4_LBD > 255){
        pwm4_HBD++;
        pwm4_LBD-=256;
      }   
    TC4H = pwm4_HBD; OCR4D = pwm4_LBD; //  pin 6
    #endif   


afterwards in 'initOutput()' the Timers are being initialized and the Waveform Generation Mode is set to PWM, Phase Correct(ATmega documentation).
But where there is commented "connect pinx to timer y channel A/B/C" i can't find out how this codeline:

Code: Select all

TCCR3A |= _BV(COM3B1); // connect pin 2 to timer 3 channel B 
that is setting the Compare Output Mode for Timer 3 does refer to pin2.. This is the point I need your help.

and for completeness the complete code-block from initOutput() for a QuadX:

Code: Select all

void initOutput() {
  for(uint8_t i=0;i<NUMBER_MOTOR;i++)
    pinMode(PWM_PIN[i],OUTPUT);
  #if defined(MEGA)
    #if (NUMBER_MOTOR > 0)
      // init 16bit timer 3
      TCCR3A |= (1<<WGM31); // phase correct mode
      TCCR3A &= ~(1<<WGM30);
      TCCR3B |= (1<<WGM33);
      TCCR3B &= ~(1<<CS31); // no prescaler
      ICR3   |= 0x3FFF; // TOP to = 16383;     
     
      TCCR3A |= _BV(COM3C1); // connect pin 3 to timer 3 channel C
    #endif
    #if (NUMBER_MOTOR > 1)
      TCCR3A |= _BV(COM3A1); // connect pin 5 to timer 3 channel A
    #endif
    #if (NUMBER_MOTOR > 2)
      // init 16bit timer 4
      TCCR4A |= (1<<WGM41); // phase correct mode
      TCCR4A &= ~(1<<WGM40);
      TCCR4B |= (1<<WGM43);
      TCCR4B &= ~(1<<CS41); // no prescaler
      ICR4   |= 0x3FFF; // TOP to = 16383;   
     
      TCCR4A |= _BV(COM4A1); // connect pin 6 to timer 4 channel A
    #endif
    #if (NUMBER_MOTOR > 3)
      TCCR3A |= _BV(COM3B1); // connect pin 2 to timer 3 channel B
    #endif

    #if (NUMBER_MOTOR > 4)
      TCCR4A |= _BV(COM4B1); // connect pin 7 to timer 4 channel B
      TCCR4A |= _BV(COM4C1); // connect pin 8 to timer 4 channel C
    #endif


I hope this is a detailed description of my problem and that someone can help me with this :)
so far,
Spambot
Last edited by Spambot on Sat May 19, 2012 8:44 am, edited 2 times in total.

Spambot
Posts: 3
Joined: Sun May 13, 2012 11:56 am

Re: Changing Motor Pins in 2.0

Post by Spambot »

anyone?

ronco
Posts: 317
Joined: Thu Aug 18, 2011 2:58 pm

Re: Changing Motor Pins in 2.0

Post by ronco »

Hi spambot,

sorry for the late replay .. somtimes i miss to look at general forum ;)

to change pin 2 to pin 7 on the mega and for a quad you need to change the the timer used for pin 2...

first change the PWM pin order to have pin 7 initialized with a 4 motor setting.
change: (in output.pde)

Code: Select all

#if defined(MEGA)
  uint8_t PWM_PIN[8] = {3,5,6,2,7,8,9,10};      //for a quad+: rear,right,left,front   //+ for y6: 7:under right  8:under left
#endif

to:

Code: Select all

#if defined(MEGA)
  uint8_t PWM_PIN[8] = {3,5,6,7,2,8,9,10};      //for a quad+: rear,right,left,front   //+ for y6: 7:under right  8:under left
#endif


then change the comperator(channel) for motor 4 from OCR3B to OCR4B
change:

Code: Select all

void writeMotors() { // [1000;2000] => [125;250]
...
    #if (NUMBER_MOTOR > 3)
      #ifndef EXT_MOTOR_RANGE
        OCR3B = motor[3]<<3; //  pin 2
      #else
        OCR3B = ((motor[3]<<4) - 16000) + 128;
      #endif
    #endif
...
}

to:

Code: Select all

void writeMotors() { // [1000;2000] => [125;250]
...
    #if (NUMBER_MOTOR > 3)
      #ifndef EXT_MOTOR_RANGE
        OCR4B = motor[3]<<3; //  pin 2 -> now pin 7
      #else
        OCR4B = ((motor[3]<<4) - 16000) + 128;
      #endif
    #endif
...
}


then the same for init output

change:

Code: Select all

void initOutput() {
...
    #if (NUMBER_MOTOR > 3)
      TCCR3A |= _BV(COM3B1); // connect pin 2 to timer 3 channel B
    #endif
...
}

to:

Code: Select all

void initOutput() {
...
    #if (NUMBER_MOTOR > 3)
      TCCR4A |= _BV(COM4B1); // connect pin 7 to timer 4 channel B
    #endif
...
}


then it should work.

regards felix

Spambot
Posts: 3
Joined: Sun May 13, 2012 11:56 am

Re: Changing Motor Pins in 2.0

Post by Spambot »

Hi Felix,
many thanks for your answer! I just didn't get the whole timer thing..
Gonna try it out soon and report if I got it to work, but looks very resonable now that you postet it :)
greetings, Benno


Edit:
Works perfectly, thank you

IamTheVector
Posts: 7
Joined: Mon May 25, 2015 5:53 pm

Re: Changing Motor Pins in 2.0

Post by IamTheVector »

MAN!! WTF you are my hero! I will copy this answer all over those crying souls all over the places and forums ! ( i relly think that this pin assignment problem should be improoved )

Post Reply