Go Down

Topic: Timer counter -1 PPS from GPS and interrupt every minute- (Read 395 times) previous topic - next topic

taxodium

Hello,
Sorry for my bad english, my native language is french.
Here is my question.
I usually work with arduino uno and i know the use of timer/counter.
It's more difficult for me with the DUE and the SAM3x.
I would just like to read the impulses of a GPS (1PPS) and cause an interrupt as soon as I get to 60 seconds (to activate an event every minute).
I would like to use the TC and certainly make a comparison (= 60).
I admit to being a little lost in reading the datasheet.
Would you have a simple example or simply list the important registers I need to work on?
Thank you.

ard_newbie

To capture 1 pulse per second, a simple attachInterrupt() will do the job. For much higher frequencies, a Timer counter input capture is necessary.

An example sketch to output a PWM pulse and capture its frequency and duty thru a TC input capture:

Code: [Select]

/*************************************************************************************************/
/*  a jumper needs to be installed between pin 2 (TIOA0) and pin A7 (TC0 channel 1 TIOA pin)     */
/*************************************************************************************************/

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 = 50;                          // Frequency of PWM pulses = MCK/2/TC_RC
  TC0->TC_CHANNEL[0].TC_RA = 25;                           // 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              // TIOA 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_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) { // Do not serial.print too often ....

    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(" %");
      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
  }

}




taxodium

Thank you @ard_newbie.
I tried your code but it does not work.

Is it not possible, in capture mode, to use my 1PPS as clock (XC0). Count continuously until the value is compared with Registrer C (interrupt CPCS)?

taxodium

I have read again the datasheet regarding TC and here are my notes ...

Code: [Select]

void setup() {
  Serial.begin(9600);
  REG_TC0_WPMR = 0x54494D00;
  REG_TC0_CMR0 = 0b00000000000011001100000000000101;
  REG_TC0_RC0 = 2;
  REG_TC0_IER0 = 0b00010000;
  REG_TC0_IDR0 = 0b11101111;
  NVIC_EnableIRQ(TC0_IRQn);
  REG_TC0_CCR0 = 0b00000100; 
}

void loop() {

}

void TC0_Handler() {
  TC_GetStatus(TC0, 0);
  Serial.println("OK");
}


I'm working in binary for a better reading of the registers in my datasheet.
This code does not work even if I think I'm on the right track.
I use the waveform function (mode 2), an external clock (XC0), and I make a toggle on comparison of the RC register (this one activates a CPCS interrupt).
XCO is connected to TCLK0 (pin 22 arduino DUE).
Is my reflection good?

taxodium

I found a functional code but I do not want to use output 2.
Also if i remove pinMode (2, OUTPUT); and analogWrite (2,255); nothing works anymore.
Why?

Code: [Select]

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

  pinMode(2, OUTPUT);   
  analogWrite(2, 255); 

  REG_TC0_WPMR=0x54494D00;
  REG_TC0_CMR0 = 0b00000000000011001100000000000101;
  REG_TC0_RC0 = 2;
  REG_TC0_CCR0 = 0b00000101; 
  REG_TC0_IER0 = 0b00010000;
  REG_TC0_IDR0 = 0b11101111;
  NVIC_EnableIRQ(TC0_IRQn);

}

void loop() {

}

void TC0_Handler() {
  TC_GetStatus(TC0, 0);
  Serial.println("OK");
}


"Thank you to me for this monologue"

Go Up