Timer Interrupts on Due

hi;
I'm working on something similar, if i have a success, be sure i'll post something relevant. If you suceed what you are doing, pls post over here.

Hallo,

how can i produce a
rectangle signal (250KHz) with arduino due.

Thanks.

Hi everybody...
I know that I am 'posting' to an old thread, but it just felt like the most appropriate place...

Going right back to 'the basics', I repeat below the code fragment suggested by 'stimmer' on the first page of this thread:

volatile boolean l;

void TC0_Handler()
{
    long dummy=REG_TC0_SR0; // vital - reading this clears some flag
                            // otherwise you get infinite interrupts
    l= !l;
}

void setup(){
  pinMode(13,OUTPUT);
  pinMode(2,OUTPUT);    // port B pin 25  
  analogWrite(2,255);   // sets up some other registers I haven't worked out yet
  REG_PIOB_PDR = 1<<25; // disable PIO, enable peripheral
  REG_PIOB_ABSR= 1<<25; // select peripheral B
  REG_TC0_WPMR=0x54494D00; // enable write to registers
  REG_TC0_CMR0=0b00000000000010011100010000000000; // set channel mode register (see datasheet)
  REG_TC0_RC0=100000000; // counter period
  REG_TC0_RA0=30000000;  // PWM value
  REG_TC0_CCR0=0b101;    // start counter
  REG_TC0_IER0=0b00010000; // enable interrupt on counter=rc
  REG_TC0_IDR0=0b11101111; // disable other interrupts

  NVIC_EnableIRQ(TC0_IRQn); // enable TC0 interrupts

}

void loop(){
      digitalWrite(13,l);
}

Well, it certainly seems to work just fine since I can see my LED toggling state VERY s-l-o-w-l-y and throwing a DMM on digital pin 2 shows that it is indeed 'toggling'. However, I have a small 'issue'.
As far as the Atmel datasheet is concerned, pretty much all of the peripherals on the chip are 'disabled' at reset and this INCLUDES all 9 channels of timers.
I've verified this by adding a few lines to print out the content of REG_PMC_PSR0 and REG_PMC_PSR1 in hex to the serial port both before AND after the code in stimmers fragment. In BOTH cases, it seems to be telling me that the PMC bits corresponding to the timer channel in use remain OFF. Therefore, my idiotic brain is telling me that there's no way the code can work, and yet there it is in front of me flashing an LED.
Have I 'missed' something, or am I seeing a contradiction between the silicon in front of me and the Atmel datasheet?

Here's my trivial edit to stimmers original setup() code fragment:

void setup(){
  Serial.begin (9600);
  Serial.print ("REG_PMC_PCSR0:[");
  Serial.print (REG_PMC_PCSR0, HEX);
  Serial.println ("]");
  Serial.print ("REG_PMC_PCSR1:[");
  Serial.print (REG_PMC_PCSR1, HEX);
  Serial.println ("]");

  pinMode(13,OUTPUT);
  pinMode(2,OUTPUT);    // port B pin 25  
  analogWrite(2,255);   // sets up some other registers I haven't worked out yet
  REG_PIOB_PDR = 1<<25; // disable PIO, enable peripheral
  REG_PIOB_ABSR= 1<<25; // select peripheral B
  REG_TC0_WPMR=0x54494D00; // enable write to registers
  REG_TC0_CMR0=0b00000000000010011100010000000000; // set channel mode register (see datasheet)
  REG_TC0_RC0=100000000; // counter period
  REG_TC0_RA0=30000000;  // PWM value
  REG_TC0_CCR0=0b101;    // start counter
  REG_TC0_IER0=0b00010000; // enable interrupt on counter=rc
  REG_TC0_IDR0=0b11101111; // disable other interrupts

  NVIC_EnableIRQ(TC0_IRQn); // enable TC0 interrupts

  Serial.print ("REG_PMC_PCSR0:[");
  Serial.print (REG_PMC_PCSR0, HEX);
  Serial.println ("]");
  Serial.print ("REG_PMC_PCSR1:[");
  Serial.print (REG_PMC_PCSR1, HEX);
  Serial.println ("]");
}

As far as I can tell, his call to analogWrite() turns on bit#31 of PMC_PCSR0 which corresponds to the second channel of the second timer/counter, but there's nothing in there that 'enables' the channel (TC0) that's actually used to flash the LED via the ISR? i.e. Bit#27 of REG_PMC_PCSR0 remains at 0.
(Edit: I'm guessing that the call to analogWrite() sets up TC4 as the source of the PWM clock which is why bit 31 of PMC_PCSR0 gets set).

hi
i want to design a timer with arduino mega 2560
this time must have a restore point and Measure every 10 millisecond and display this time on the lcd
i have a lot of problem
the first problem is for reset point
i cant active the reset point and show this on the lcd
please help me
this is my email
fziaee93@yahoo.com
please send your proposed about my project to my email
thanks alot

How to set an external clock signals for the interrupt? I am using a codec chip with the Due where the codec shield sends an external clock out.I need to sync the external clock from the codec with the due. I have the follow code for timer but I dont think it does that.
'

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency) {
        pmc_set_writeprotect(false);
        pmc_enable_periph_clk((uint32_t)irq);
        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
        uint32_t rc = VARIANT_MCK/128/frequency; //128 because we selected TIMER_CLOCK4 above
        TC_SetRA(tc, channel, rc/2); //50% high, 50% low
        TC_SetRC(tc, channel, rc);
        TC_Start(tc, channel);
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;
        NVIC_EnableIRQ(irq);
}

Someone can help me please. I wanna know where do you get these functions from : pmc_set_writeprotect(false);
TC_SetRA(tc, channel, rc/2); //50% high, 50% low
TC_SetRC(tc, channel, rc);
TC_GetStatus(TC1, 0);
Because I searched in datasheet ATMEL SAM3X (1459 pages), and i never found anything about that.

Someone can help me please. I wanna know where do you get these functions from : pmc_set_writeprotect(false);
TC_SetRA(tc, channel, rc/2); //50% high, 50% low
TC_SetRC(tc, channel, rc);
TC_GetStatus(TC1, 0);
Because I searched in datasheet ATMEL SAM3X (1459 pages), and i never found anything about that.

Because it's libsam and CMSIS.

Thanks for the great info but I would really be interested to know how to include the Atmel Studio project (solution) directory structure in an Arduino project, which includes CMSIS and more. It's to big to "flatten" and i really don't want to have to do what others have done in this thread - dig down to the binary register values. Since macros are still in use, I assume there is a file somewhere with the #define statements (pointing to register addresses) but where?

FYI, Atmel Studio is available for free from Atmel. It only runs in Windoze, however and you will need a JEDEC or some other interface in order to program Arduino's with Atmel code. The debugger is really handy, though. (I use a SAM-ICE hadware debugger/interface.)

Thanks,
Rusty

Hi,

If I understand correctly, I can trigger an interrupt through the TC_IER register on RA, RB and RC compare, then on counter overflow, and others. Is the ISR called always this TCn_Handler()?

Does anybody know about a way to call different ISRs upon different trigger cases?

Thanks,
steady

All enabled interrupts of TC counter TCx will trigger TCx_Handler().

Inside the call back Handler, you:
1/ Read and save the status register, which saves status bits and clears immediately bits so the interrupt can be triggered again

2/ you test in the saved status variable which bit is up (e.g. RA compare )

ard_newbie:
2/ you test in the saved status variable which bit is up (e.g. RA compare )

Then, when you read the answer, suddenly all is so obvious... :wink:

Thank you very much, that makes it clear.

Here is another resource on using Due timers.

http://2manyprojects.net/timer-interrupts

Steen Oluf Karlsen here! I would like to use timer interrupts on an Arduino Due to run a sampling function that is calling analogRead. The samples should be taken with the sampling time Ts between them. I try to deduct all your advice here. I see the last posting is from nov 2012 - so it's more than 7 years that have passed!

There are numerous example sketches provided in the DUE sub forum for ADC conversions triggered by a timer counter or a PWM Event Line.

Another one:

/**********************************************************************************************/
/*   ADC conversions of 1 analog input triggered at 3 KHz by TC0 channel 2 TIOA2 pulse        */
/**********************************************************************************************/

volatile boolean AnalogConversion;
volatile uint16_t Result;

void setup()
{

  pinMode(LED_BUILTIN, OUTPUT);
  adc_setup();
  tc_setup();
}

void loop()
{

  if (AnalogConversion)
  {
    //Do smething with Result
    AnalogConversion = false;
  }
}

/*************  Configure ADC function  *******************/
void adc_setup() {

  PMC->PMC_PCER1 |= PMC_PCER1_PID37;                    // ADC power on

  ADC->ADC_CR = ADC_CR_SWRST;                           // Reset ADC
  ADC->ADC_MR |=  ADC_MR_TRGEN_EN                       // Hardware trigger select
                  | ADC_MR_TRANSFER(2)
                  | ADC_MR_PRESCAL(1)
                  | ADC_MR_TRGSEL_ADC_TRIG3;            // Trigger by TIOA2

  //ADC->ADC_ACR = ADC_ACR_IBCTL(0b01);                   // For frequency > 500 KHz

  ADC->ADC_IER = ADC_IER_EOC7;            // Interrupt on End Of Conversions channel 7

  ADC->ADC_CHER = ADC_CHER_CH7;           // Enable Channels 7 = A0

  NVIC_EnableIRQ((IRQn_Type)ADC_IRQn);    // Enable ADC interrupt
}

void ADC_Handler () {

  static uint32_t Count;

  Result = ADC->ADC_CDR[7];
  AnalogConversion = true;

  if (Count++ == 3000)
  {
    PIOB->PIO_ODSR ^= PIO_ODSR_P27;
    Count = 0;
  }
}

/*************  Timer Counter 0 Channel 2 to generate PWM pulses thru TIOA2  ************/
void tc_setup() {

  PMC->PMC_PCER0 |= PMC_PCER0_PID29;                      // TC2 power ON : Timer Counter 0 channel 2 IS TC2
  TC0->TC_CHANNEL[2].TC_CMR = TC_CMR_TCCLKS_TIMER_CLOCK3  // MCK/32, 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 TIOA2 on RA compare match
                              | TC_CMR_ACPC_SET;           // Set TIOA2 on RC compare match

  TC0->TC_CHANNEL[2].TC_RC = 875;  //<*********************  Frequency = (Mck/32)/TC_RC  Hz = 3000 Hz
  TC0->TC_CHANNEL[2].TC_RA = 400;  //<********************   Any Duty cycle in between 1 and 874

  TC0->TC_CHANNEL[2].TC_CCR = TC_CCR_SWTRG | TC_CCR_CLKEN;// Software trigger TC2 counter and enable
}

Ok thanks, Ard_newbie. I will look into this. I have implemented an analogRead(0) inside a for-loop that runs SIGLEN times. I have used delay_microseconds(Ts - runtime); // Obtain SampleTime (Ts) as specified

It actually has worked quite well- but I got the feeling I could do much better if I used timed interrupts.
That the whole thing would work more precise.

I understand that calling the analogRead() function often takes too long time.
That if I can go directly to the relevant registers it will speed up things tremendously.

Ok so I can choose my own sampling frequency! I read here: 84MHz/(32*875) = 3 kHz

TC0->TC_CHANNEL[2].TC_RC = 875; //<********** Frequency = (Mck/32)/TC_RC Hz = 3000 Hz

I still need to understand the real time flow of the sampling, though. I see a parameter reset when
3000 samples is reached:

if (Count++ == 3000)
{
PIOB->PIO_ODSR ^= PIO_ODSR_P27;
Count = 0;
}

I will need to transfer each Result sample value to an input buffer of a given length, say 4096 samples.
I understand that with the timer interrupt the writing of the buffer will be continuous -
so the input buffer would be "circular" and at any given point in time it would be possible to read the latest 4096 samples. I am afraid I do not understand the use of the "bitwise XOR" "^=" statement !?
Thanks in advance!

The blinking LED is an "optionnal" feature, only for debugging (1 Hz blinking LED).

Search on your favorite search engine how works bitwise XOR.

I have your code running now, ard_newbie. I have a scope on D13. I see the 1Hz square wave.

I tried to change the count limit to 1050 and the sampling frequency to 4096 samples/s which I use in my project. As expected I get an up-time on D13 of 1050/4096 = 256ms.

I have another frequency band however where I would like to use f_sampl = 40960 samples/s.

This gives the clock divider calculation TC_RC =(84E+6)/(32*40960) = 64 (approx)
Now: This gives no activity on D13 at all. Is there maybe a lower limit to TC_RC ?

if (Count++ == 40960)
{
..........

Ok let me try to interpret what you write here- I guess that my caculation of the sampling rate is correct -
that the same calculation is used whether I want 4096 samples/s in freqband 1 or I want 40960 samples/s in freqband 0.

So if I let count continue to 40960 as you suggest, what would I expect? I would in theory end up with a 1 hz signal on D13 indicating 40960 samples/s - ok I will try it, but I have seen no activity at all on D13 when the sampling frequency gets over a certain point - I saw that point to be about 5000 samples/s. But I will try!