Timer 1 configuration

Hi,
Again, problems with the timers ...

My code is a bit special. I have to use the 9 available timers.

Everything works fine except for timer 1.
I cannot find if there is a special feature for this timer.

I do frequency measurements with TIOA0, TIOA1, TIOA2, TIOA7 and TIOA8. Everything works except TIOA1.

Thank you for your help.
 //*************  Timer 0 : Counter 0 Channel 0 - capture sur TIOA0 PB25   ************
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                        // TC0 instance ID 
  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2    // capture mode, MCK/2, horloge sur front montant
                              | TC_CMR_ABETRG               // TIOA0 utilisé en déclencheur
                              | TC_CMR_LDRA_RISING          // Chargement RA sur front montant
                              | TC_CMR_LDRB_FALLING;        // Chargement RB sur front descendant
  TC0->TC_CHANNEL[0].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // interruption sur chargement de RA ou RB
  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;  // Déclenchement logiciel et clock enable (start)
  NVIC_EnableIRQ(TC0_IRQn);                                 // autorisation interruption

  
  //*************  Timer 1 : Counter 0 Channel 1 - capture sur TIOA1 PA2  ************  
  PMC->PMC_PCER0 |= PMC_PCER0_PID28;                        // TC2 instance ID 
  TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2    // capture mode, MCK/2, horloge sur front montant
                              | TC_CMR_ABETRG               // TIOA1 utilisé en déclencheur
                              | TC_CMR_LDRA_FALLING         // Chargement RA sur front montant
                              | TC_CMR_LDRB_RISING;         // Chargement RB sur front descendant
  TC0->TC_CHANNEL[1].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // interruption sur chargement de RA ou RB
  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;  // Déclenchement logiciel et clock enable (start)
  NVIC_EnableIRQ(TC1_IRQn);                                 // autorisation interruption

  
  //*************  Timer 2 : Counter 0 Channel 2 - capture sur TIOA2 PA5  ************  
  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                        // TC2 instance ID 
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2    // capture mode, MCK/2, horloge sur front montant
                              | TC_CMR_ABETRG               // TIOA1 utilisé en déclencheur
                              | TC_CMR_LDRA_FALLING         // Chargement RA sur front montant
                              | TC_CMR_LDRB_RISING;         // Chargement RB sur front descendant
  TC0->TC_CHANNEL[2].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // interruption sur chargement de RA ou RB
  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;  // Déclenchement logiciel et clock enable (start)
  NVIC_EnableIRQ(TC2_IRQn);                                 // autorisation interruption
 
  
  //*************  Timer 7 : Counter 2 Channel 1 - capture sur TIOA7 PC28  ************  
  PMC->PMC_PCER1 |= PMC_PCER1_PID34;                        // TC7 instance ID 
  TC2->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2    // capture mode, MCK/2, horloge sur front montant
                              | TC_CMR_ABETRG               // TIOA7 utilisé en déclencheur
                              | TC_CMR_LDRA_FALLING         // Chargement RA sur front descendant
                              | TC_CMR_LDRB_RISING;         // Chargement RB sur front montant
  TC2->TC_CHANNEL[1].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // interruption sur chargement de RA ou RB
  TC2->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;  // Déclenchement logiciel et clock enable (start)
  NVIC_EnableIRQ(TC7_IRQn);                                 // autorisation interruption

  
  //*************  Timer 8 : Counter 2 Channel 2 - capture sur TIOA8 PD7  ************  
  PMC->PMC_PCER1 |= PMC_PCER1_PID35;                        // TC8 instance ID 
  TC2->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK2    // capture mode, MCK/2, horloge sur front montant
                              | TC_CMR_ABETRG               // TIOA8 utilisé en déclencheur
                              | TC_CMR_LDRA_FALLING         // Chargement RA sur front descendant
                              | TC_CMR_LDRB_RISING;         // Chargement RB sur front montant
  TC2->TC_CHANNEL[2].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // interruption sur chargement de RA ou RB
  TC2->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;  // Déclenchement logiciel et clock enable (start)
  NVIC_EnableIRQ(TC8_IRQn);

There is an uncorrect comment for TC0->TC_CHANNEL[2]. Timer Counter 0 channel 2 is TC2. TC2 inputs can be TIOA2 or TIOB2. TIOA2 is PA5 (Not broken out on a DUE !), but TIOB2 is PA6 (broken out on a DUE at pin A4). Select TIOB2 to be used as an external trigger.

Plus other uncorrect comments, e.g.:

| TC_CMR_LDRA_FALLING // Chargement RA sur front montant descendant
| TC_CMR_LDRB_RISING; // Chargement RB sur front descendant montant

Note: there are typos for LDRB: RB Loading Edge Selection page 882 of Sam3x datasheet

Hi,
Thanks for reply.
I'm not using a DUE, it's my own PCB with a SAM3X8E, so I can use TIOA2 and others.
Everything works fine except timer 1 (TCO CH1), I don't understand why...

I can't see anything wrong with Timer Counter 0 channel 1 in your code (except comments...). Maybe there is something wrong in the code you didn't post, e.g. timer Counter interrupt handlers.

Write a minimal code with ONLY Timer Counter 0 channel 1 input capture, post this minimal code AND describe precisely the issue your are having.

It works fine now.

Input PA2 (TIOA1) was defined like the others.
eg :
int LEDV = PIO_PC25;
int LEDO = PIO_PC27;
int LEDR = PIO_PC26;
int IN1 = PIO_PA2;
etc...
But this don't works just for PA2, all the others definitions works...
So, if I write instead the digital name :
int IN1 = 61;

this works.
I have no explanations because it works for the other TIOA0 - TIOA7 - TIOA8 …

I did a simple sketch with Timer Counter 0 channel 1 in input capture with TIOA1 and Timer Counter 0 channel 0 in waveform mode to generate a 1 KHz pulse thru TIOA0, and it works nicely on a DUE.

Maybe you screwed-up something in your pin definitions for your custom Sam3x PCB.

The example sketch written for a DUE (should work too on your custom PCB):

/*************************************************************************************************/
/*  a jumper needs to be installed between pin 2 (TIOA0) and pin A7 (TC0 channel 1 TIOA1 pin)    */
/*************************************************************************************************/
//#define Serial SerialUSB
volatile uint32_t CaptureCountA, CaptureCountB, Period, Duty;
volatile boolean CaptureFlag;

void setup() {
  Serial.begin(250000);

  /*************  Timer Counter 0 Channel 0 to generate PWM pulses thru TIOA0  ************/
  PMC->PMC_PCER0 |= PMC_PCER0_PID27;                      // Timer Counter 0 channel 0 IS TC0
  PIOB->PIO_PDR |= PIO_PDR_P25 | PIO_PDR_P27;
  PIOB->PIO_ABSR |= PIO_ABSR_P25 | PIO_ABSR_P27;

  TC0->TC_CHANNEL[0].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1   // MCK/2, clk on rising edge
                              | TC_CMR_WAVE                // Waveform mode
                              | TC_CMR_WAVSEL_UP_RC        // UP mode with automatic trigger on RC Compare
                              | TC_CMR_ACPA_CLEAR          // Clear TIOA0 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA0 on RC compare match


  TC0->TC_CHANNEL[0].TC_RC = 42000;                          // Frequency of PWM pulses = MCK/2/TC_RC
  TC0->TC_CHANNEL[0].TC_RA = 21000;                          // Duty cycle of PWM pulses = (TC_RA/TC_RC) * 100 %

  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN; // Software trigger and enable

  /*************  Timer Counter 0 Channel 1 to capture PWM pulses thru TIOA1  ************/
  PMC->PMC_PCER0 |= PMC_PCER0_PID28;                       // Timer Counter 0 channel 1 IS TC1

  TC0->TC_CHANNEL[1].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK1   // capture mode, MCK/2, clk on rising edge
                              | TC_CMR_ABETRG              // TIOA1 is used as the external trigger
                              | TC_CMR_LDRA_RISING         // load RA on rising edge of trigger input
                              | TC_CMR_LDRB_FALLING;       // load RB on falling edge of trigger input

  TC0->TC_CHANNEL[1].TC_IER |= TC_IER_LDRAS | TC_IER_LDRBS; // Trigger interruption on Load RA and load RB
  TC0->TC_CHANNEL[1].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;  // Software trigger and enable

  NVIC_DisableIRQ(TC1_IRQn);
  NVIC_ClearPendingIRQ(TC1_IRQn);
  NVIC_SetPriority(TC1_IRQn, 0);                      // Give TC1 interrupt the highest urgency
  NVIC_SetPriority(SysTick_IRQn, 15);                 // SysTick interrupt will not interrupt TC1 interrupt
  NVIC_SetPriority(UART_IRQn, 14);                    // UART interrupt will not interrupt TC1 interrupt
  
  NVIC_EnableIRQ(TC1_IRQn);                           // Enable TC1 interrupts

}

void loop() {
  const uint32_t _F_CPU = F_CPU / 2;
  static uint32_t counter;
  float Frequency;
  float _Duty;

  if (counter++ > 100000) { 

    if ( CaptureFlag == true) {

      Frequency = _F_CPU / Period  ; //  (Mck/2 is TC1 clock) F in Hz
      _Duty = (Duty * 100.00) / Period;

      //Serial.print(" F = "); Serial.print((uint32_t)Frequency); Serial.print(" Hz ");
      //Serial.print (" ,  Duty = "); Serial.print((uint32_t)_Duty); Serial.println(" %");
      printf(" F = %d  Hz , Duty = %d per cent\n", (uint32_t)Frequency, (uint32_t)_Duty);
      counter = 0;
      CaptureFlag = false;

    }
  }
}

void TC1_Handler() {

  static uint32_t _CaptureCountA;

  uint32_t status = TC0->TC_CHANNEL[1].TC_SR;       // Read and Clear status register


  //if (status & TC_SR_LOVRS) abort();  // We are loosing some edges

  if (status & TC_SR_LDRAS) {  // If ISR is triggered by LDRAS then ....
    CaptureCountA = (uint32_t) TC0->TC_CHANNEL[1].TC_RA;        // get data from capture register A for TC0 channel 1
    Period = CaptureCountA - _CaptureCountA;
    _CaptureCountA = CaptureCountA;
  }
  else { /*if ((status & TC_SR_LDRBS) == TC_SR_LDRBS)*/  // If ISR is triggered by LDRBS then ....
    CaptureCountB = (uint32_t) TC0->TC_CHANNEL[1].TC_RB;         // get data from caputre register B for TC0 channel 1
    Duty = CaptureCountB - _CaptureCountA;
    CaptureFlag = true;                      // set flag indicating a new capture value is present
  }

}

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