PID+PWM+Encoder+Interrupt

Hi,
I am working on three omniwheel robot, and I need to control 3 Dc motors with PID controller at 15 Khz PWM frequency.

For 15 Khz PWM frequency, someone helped me in this link.

To use my PID I need encoder Data, on Pin :

Motor 1 : PIN ( pwm 9, dir 2) encoder (phase A 22, Phase B 23)
Motor 2 : PIN ( pwm 10, dir 3) encoder (phase A 24, Phase B 25)
Motor 3 : PIN ( pwm 5, dir 4) encoder (phase A 26, Phase B 27)

or :
Motor 1 : PIN ( pwm 9, dir 2) encoder (phase A 22, Phase B 23)
Motor 2 : PIN ( pwm 10, dir 3) encoder (phase A 44, Phase B 55)
Motor 3 : PIN ( pwm 5, dir 4) encoder (phase A 42, Phase B 43)

Can someone help to use three encoders with interruption in Arduino Due on that'pins ? ( i saw that arduino Due got 2 encoder quadrature Pin but used from my PWM).

Thanks by advance

Hi @hyakoubi

One way to make the TC timer code more efficient, is to only call the timers' interrupts when you need to make a change to their respective duty-cycles. This should free up more CPU time to deal with the encoders:

// Set up the Arduino Due's digital pins D5 and D10 for 15kHz PWM with RC compare interrupts
volatile uint32_t dutycycleTC6 = 0, dutycycleTC7 = 0;

void setup() 
{
  PMC->PMC_PCER1 |= PMC_PCER1_PID34 | PMC_PCER1_PID33;    // Enable peripheral TC6 (TC2 Channel 0) and TC7 (TC2 Channel 1)
  PIOC->PIO_ABSR |= PIO_ABSR_P29 | PIO_ABSR_P25;          // Switch the multiplexer to peripheral B for TIOA6 (D5) and TIOB7 (D10)
  PIOC->PIO_PDR |= PIO_PDR_P29 | PIO_PDR_P25;             // Disable the GPIO on the corresponding pins

  TC2->TC_CHANNEL[0].TC_CMR = TC_CMR_ACPC_SET |           // Set TIOA on counter match with RC0                           
                              TC_CMR_ACPA_CLEAR |         // Clear TIOA on counter match with RA0
                              TC_CMR_WAVE |               // Enable wave mode
                              TC_CMR_WAVSEL_UP_RC |       // Count up with automatic trigger on RC compare
                              TC_CMR_EEVT_XC0 |           // Set event selection to XC0 to make TIOB an output
                              TC_CMR_TCCLKS_TIMER_CLOCK1; // Set the timer clock to TCLK1 (MCK/2 = 84MHz/2 = 42MHz)

  TC2->TC_CHANNEL[1].TC_CMR = TC_CMR_BCPC_SET |           // Set TIOB on counter match with RC0                              
                              TC_CMR_BCPB_CLEAR |         // Clear TIOB on counter match with RB0                             
                              TC_CMR_WAVE |               // Enable wave mode
                              TC_CMR_WAVSEL_UP_RC |       // Count up with automatic trigger on RC compare
                              TC_CMR_EEVT_XC0 |           // Set event selection to XC0 to make TIOB an output
                              TC_CMR_TCCLKS_TIMER_CLOCK1; // Set the timer clock to TCLK1 (MCK/2 = 84MHz/2 = 42MHz)

  TC2->TC_CHANNEL[0].TC_RC = 2800;                        // Set the PWM frequency to 15kHz: 42MHz / 15kHz = 2800 
  TC2->TC_CHANNEL[1].TC_RC = 2800;                        // Set the PWM frequency to 15kHz: 42MHz / 15kHz = 2800

  NVIC_SetPriority(TC6_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC6 to 0 (highest) 
  NVIC_EnableIRQ(TC6_IRQn);         // Connect TC6 to Nested Vector Interrupt Controller (NVIC)

  TC2->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;                // Enable RC compare interrupt for TC6 (TC2 Channel 0)

  NVIC_SetPriority(TC7_IRQn, 0);    // Set the Nested Vector Interrupt Controller (NVIC) priority for TC7 to 0 (highest) 
  NVIC_EnableIRQ(TC7_IRQn);         // Connect TC7 to Nested Vector Interrupt Controller (NVIC)

  TC2->TC_CHANNEL[1].TC_IER = TC_IER_CPCS;                // Enable RC compare interrupt for TC7 (TC2 Channel 1)

  TC2->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Enable the timer TC6 (TC2 Channel 0)
  TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Enable the timer TC7 (TC2 Channel 1)
}

bool ChangeTC6PWMFreq(uint32_t dutycycle)
{
  if (!(TC2->TC_CHANNEL[0].TC_IMR & TC_IMR_CPCS))         // Check if the RC compare interrupt for TC6 has been disabled
  {
    dutycycleTC6 = dutycycle;
    TC2->TC_CHANNEL[0].TC_IER = TC_IER_CPCS;              // Enable RC compare interrupt for TC6 (TC2 Channel 0)
  }
}

bool ChangeTC7PWMFreq(uint32_t dutycycle)
{
  if (!(TC2->TC_CHANNEL[1].TC_IMR & TC_IMR_CPCS))         // Check if the RC compare interrupt for TC7 has been disabled
  {
    dutycycleTC7 = dutycycle;
    TC2->TC_CHANNEL[1].TC_IER = TC_IER_CPCS;              // Enable RC compare interrupt for TC7 (TC2 Channel 1)
  }
}

void loop() 
{
  ChangeTC6PWMFreq(700);                                  // Set the duty-cycle to 25% on D5 on next timer cycle
  ChangeTC7PWMFreq(700);                                  // Set the duty-cycle to 25% on D10 on next timer cycle
  delay(2000);                                            // Wait for 2 seconds
  ChangeTC6PWMFreq(2100);                                 // Set the duty-cycle to 75% on D5 on next timer cycle
  ChangeTC7PWMFreq(2100);                                 // Set the duty-cycle to 75% on D10 on next timer cycle
  delay(2000);                                            // Wait for 2 seconds
}

void TC6_Handler()                                        // ISR TC6 (TC2 Channel 0)
{
  if (TC2->TC_CHANNEL[0].TC_SR & TC_SR_CPCS)              // Check for RC compare condition
  {
    TC2->TC_CHANNEL[0].TC_RA = dutycycleTC6;              // Set the duty-cycle to on D5
    TC2->TC_CHANNEL[0].TC_IDR = TC_IDR_CPCS;              // Disable RC compare interrupt for TC6 (TC2 Channel 0)
  }
}

void TC7_Handler()                                        // ISR TC7 (TC2 Channel 1)
{ 
  if (TC2->TC_CHANNEL[1].TC_SR & TC_SR_CPCS)              // Check for RC compare condition
  {
    TC2->TC_CHANNEL[1].TC_RB = dutycycleTC7;              // Set the duty-cycle on 10
    TC2->TC_CHANNEL[1].TC_IDR = TC_IDR_CPCS;              // Disable RC compare interrupt for TC7 (TC2 Channel 1)
  }
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.