Go Down

Topic: Serial usage on due messes up timers ??? (Read 117 times) previous topic - next topic

educa

Hi,

I'm trying to make a nice stepper motor controller + laser controller for a cnc laser cutter.

To do that, I need to generate very strict stepper motor and laser shooting timings.
In the code below, I do this (working perfectly fine) with Timer2 channel 0 , Timer2 channel 1 and Timer2 channel 2.

Now I want to make the next logical step and that is to enable communication between my pc and the due to send in the needed.

The code in my loop() is very small/little. If I run the code without the line while (Serial.available() < 14) { } , then everything runs fine and the code generates perfectly 1000 pulses on X, synchronised with 500 pulses on Y and 250 on the laser shoot pin.

The X step signal is held high for 10µS by timer2 channel 0, Y step signal is kept high for 10µS by Timer2 channel 1 and the laser shoot signal is kept high for 3mS by Timer2 channel2 . Everything works really perfectly, until......

When I enable the line in my loop which checks on serial and waits until 14 characters are available in buffer, then the signals are not generated correctly anymore.

Off course, with that line enabled, I also send at least 14 characters from my pc to the due or else it would be a very logical fail ;)

I am 100% sure that the code goes over the waiting code line, because I measure the signals with my logic analyzer and the code really starts generating the signals I want.... but after around 20mS or so (after a few generated pulses) the code seems to do extremely strange things and pulse generation is halted and everything goes in I-don't-know-what-happens-mode.

I also trye to read the 14 characters from serial directly after cheching the buffer, just to be sure that the buffer is empty during the step generation for the motors, but that doesn't change anything to the behaviour.


This makes me think: Is serial on the due maybe using something of Timer 2 channel 0,1 or 2 ?

It is quite clear that enabling that 1 single line (Serial.available) messes up my other code which heavily uses timer2 channel 0,1 and 2 and which works 100% perfect if that 1 line is commented out.

Does anybody have a clue what could be going wrong here ? Is serial using resources I use elsewhere and mess up? Did I maybe init something wrong ?

Kind regards,
Bart


I will post code in next post because forum says my message exceeds 9000 characters

educa

Code: [Select]

/*Connections to the machine
  Digital 5 : X step pulse
  Digital 3 : Y step pulse
  Digital 11 : laser shoot pulsed
  Digital 8: X direction signal
  Digital 9: Y direction signal
  Digital 34: PWM Laser power signal
*/

//Global vars
int32_t Cont, dx, dy, dz, Adx, Ady, Adz, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2, xxx, yyy, zzz, Xold, Yold, Zold, Xnew, Ynew, Znew;
const int xDir = 8; //1=+ , 0=-
const int yDir = 9; //1=+ , 0=-

void setup() {
  //Prepare timers that will help generate the pulses for xStep, yStep and laser shoot.
  pmc_set_writeprotect(false);  //Turn off write protection on Power Management Controller
  pmc_enable_periph_clk(TC6_IRQn);  // Enable the  peripheral clock by IRQ for Timer 2 channel 0 : X step pulse
  pmc_enable_periph_clk(TC7_IRQn);  // Enable the  peripheral clock by IRQ for Timer 2 channel 1 : Y step pulse
  pmc_enable_periph_clk(TC8_IRQn);  // Enable the  peripheral clock by IRQ for Timer 2 channel 2 : Laser shoot pulse

  //Specific preparation for Timer 2 channel 0 (X step pulse)
  TC_Configure(TC2, 0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | 64); // Configure the timer on its specified channel. Timer is stopped after config and must be started in code.
  TC_SetRA(TC2, 0, 1); // Set the counter value where the output of  TIOA goes high in register RA (datasheet p.867)
  TC_SetRC(TC2, 0, 420); //Set the counter value (3ms) where the output of TIOA goes low and the counter is reset in register RC (datasheet p.867)
  REG_PIOC_ABSR |= PIO_ABSR_P25;     // Switch the multiplexer to peripheral B for TIOA6 (pin 5 on due)
  REG_PIOC_PDR |= PIO_ABSR_P25;     // Disable PIO for TIOA6 pin 5 on due

  //Specific preparation for Timer 2 channel 1 (Y step pulse)
  TC_Configure(TC2, 1, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | 64); // Configure the timer on its specified channel. Timer is stopped after config and must be started in code.
  TC_SetRA(TC2, 1, 1); // Set the counter value where the output of  TIOA goes high in register RA (datasheet p.867)
  TC_SetRC(TC2, 1, 420); //Set the counter value (6ms) where the output of TIOA goes low and the counter is reset in register RC (datasheet p.867)
  REG_PIOC_ABSR |= PIO_ABSR_P28;     // Switch the multiplexer to peripheral B for TIOA7 (pin 3 on due)
  REG_PIOC_PDR |= PIO_ABSR_P28;     // Disable PIO for TIOA7 pin 3 on due

  //Specific preparation for Timer 2 channel 2 (Laser shoot pulse)
  TC_Configure(TC2, 2, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1 | TC_CMR_ACPA_SET | TC_CMR_ACPC_CLEAR | 64); // Configure the timer on its specified channel. Timer is stopped after config and must be started in code.
  TC_SetRA(TC2, 2, 1); // Set the counter value where the output of  TIOA goes high in register RA (datasheet p.867)
  TC_SetRC(TC2, 2, 125925); //Set the counter value (9ms) where the output of TIOA goes low and the counter is reset in register RC (datasheet p.867)
  REG_PIOD_ABSR |= PIO_ABSR_P7;     // Switch the multiplexer to peripheral B for TIOA8 (pin 11 on due)
  REG_PIOD_PDR |= PIO_ABSR_P7;     // Disable PIO for TIOA8 pin 11 on due

  //Specific preparation to enable a 20kHz PWM signal on digital pin 34
  pmc_enable_periph_clk (PWM_INTERFACE_ID) ;  // turn on clocking to PWM unit
  PWMC_ConfigureChannel (PWM, 0, 1, 0, 0) ; // PWM channel 0, clock = MCLK/2 = 42MHz
  PWMC_SetPeriod (PWM, 0, 2100) ;  // Channel 0 period = 2100 pwm clocks (20kHz)
  PWMC_SetDutyCycle (PWM, 0, 80 * 2100 / 100) ; // Channel 0 duty set to 80%
  PWMC_EnableChannel (PWM, 0) ;   // enable channel 0
  PIOC->PIO_PDR = 1 << 2 ; // disable PIO control on PC2 (pin34) by setting bit 2 of the PIO_PDR register for PIO controller PIOC
  PIOC->PIO_IDR = 1 << 2 ; // disable PIO interrupts on PC2 (pin34) by setting bit 2 of the PIO_IDR register for PIO controller PIOC
  PIOC->PIO_ABSR |= 1 << 2 ; // switch PC2 (pin34) to B peripheral, which carries PWM channel 0 ?

  //Prepare the Xdir and Ydir pins for startup and make sure they are low
  pinMode(xDir, OUTPUT);
  g_APinDescription[xDir].pPort -> PIO_CODR = g_APinDescription[xDir].ulPin; //xDir low
  pinMode(yDir, OUTPUT);
  g_APinDescription[yDir].pPort -> PIO_CODR = g_APinDescription[yDir].ulPin; //yDir low

  //Serial init
  Serial.begin(250000); // opens serial port, sets data rate to 250000 bps
  pinMode(10, OUTPUT); //I only use this pin to get some signal for the logic analyzer ;)
}

void drawLine(int32_t x, int32_t y, int32_t z) {

  Xnew = x;
  Ynew = y;
  Znew = z;

  xxx = Xold;
  yyy = Yold;
  zzz = Zold;

  dx = Xnew - Xold;
  dy = Ynew - Yold;
  dz = Znew - Zold;

  //Bereken de richting van de X as
  if (dx < 0)
  {
    x_inc = -1;
    g_APinDescription[xDir].pPort -> PIO_CODR = g_APinDescription[xDir].ulPin; //xDir low
  }
  else
  {
    x_inc = 1;
    g_APinDescription[xDir].pPort -> PIO_SODR = g_APinDescription[xDir].ulPin; //xDir high
  }

  //Bereken de richting van de Y as
  if (dy < 0)
  {
    y_inc = -1;
    g_APinDescription[yDir].pPort -> PIO_CODR = g_APinDescription[yDir].ulPin; //yDir low
  }
  else
  {
    y_inc = 1;
    g_APinDescription[yDir].pPort -> PIO_SODR = g_APinDescription[yDir].ulPin; //yDir high
  }

  Adx = abs(dx);
  Ady = abs(dy);
  Adz = abs(dz);

  dx2 = Adx * 2;
  dy2 = Ady * 2;
  dz2 = Adz * 2;

  if ((Adx >= Ady) && (Adx >= Adz))
  {
    err_1 = dy2 - Adx;
    err_2 = dz2 - Adx;
    for (Cont = 0; Cont < Adx; Cont++)
    {
      if (err_1 > 0)
      {
        yyy += y_inc;
        err_1 -= dx2;
        TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let Y step with a timer regulated signal.
      }
      if (err_2 > 0)
      {
        zzz += z_inc;
        err_2 -= dx2;
        TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let laser shoot with a timer regulated signal
      }
      TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let X step automatically every iteration using a timer regulated signal.
      err_1 += dy2;
      err_2 += dz2;
      xxx += x_inc;
      delayMicroseconds(10000); //put 10 milliseconds pause between stepper steps for testing
    }
  }

  else if ((Ady >= Adx) && (Ady >= Adz))
  {
    err_1 = dx2 - Ady;
    err_2 = dz2 - Ady;
    for (Cont = 0; Cont < Ady; Cont++)
    {
      if (err_1 > 0)
      {
        xxx += x_inc;
        err_1 -= dy2;
        TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let X step with a timer regulated signal.
      }
      if (err_2 > 0)
      {
        zzz += z_inc;
        err_2 -= dy2;
        TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let laser shoot with a timer regulated signal.
      }
      TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let Y step automatically every iteration using a timer regulated signal.
      err_1 += dx2;
      err_2 += dz2;
      yyy += y_inc;
      delayMicroseconds(10000); //put 10 milliseconds pause between stepper steps for testing
    }
  }

  else if ((Adz >= Adx) && (Adz >= Ady))
  {
    err_1 = dy2 - Adz;
    err_2 = dx2 - Adz;
    for (Cont = 0; Cont < Adz; Cont++)
    {
      if (err_1 > 0)
      {
        yyy += y_inc;
        err_1 -= dz2;
        TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let Y step with a timer regulated signal.
      }
      if (err_2 > 0)
      {
        xxx += x_inc;
        err_2 -= dz2;
        TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // let X step with a timer regulated signal.
      }
      TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; // laser shoots automatically every iteration using a timer regulated signal.
      err_1 += dy2;
      err_2 += dx2;
      zzz += z_inc;
      delayMicroseconds(10000);
    }
  }
}

void loop() {
  g_APinDescription[10].pPort -> PIO_SODR = g_APinDescription[10].ulPin; //pin 10 high
  while (Serial.available() < 14) { }
  g_APinDescription[10].pPort -> PIO_CODR = g_APinDescription[10].ulPin; //pin 10 low

  drawLine (1000, 500, 250);

  g_APinDescription[10].pPort -> PIO_SODR = g_APinDescription[10].ulPin; //pin 10 high
  delay(1000);
  g_APinDescription[10].pPort -> PIO_CODR = g_APinDescription[10].ulPin; //pin 10 low
}

Go Up
 


Please enter a valid email to subscribe

Confirm your email address

We need to confirm your email address.
To complete the subscription, please click the link in the email we just sent you.

Thank you for subscribing!

Arduino
via Egeo 16
Torino, 10131
Italy