Timer Interrupts on Due

Very useful thread, thanks all.

What timers are used by the arduino in it's default state?

Were the problems caused to the servo library by the timer library shared due to both libraries changing the point at which a timer was reset?

Can the code that runs the triggering of the interupt can be considered to be running in parallel to the other code in the script?

So the interupt function itself doesn't run in parallel. If this is the case this gives you a specific time slot in which the interupt function would have to complete before the next interupt triggers. If an interupt function call extents beyond the end of the next interupt what happens?

As the called interupt function is running in series with the existing script then the size of the interupt function itself needs to be carefully consedered in order to avoid degrading the performance of the remaining script on the arduino. Is there a resource for estimating the number of clock cycles descrete segments of code take? I've read that multiplication can take place in one clock cycle the number required for a case statement, function call, and changing a global variables value would be a good starting point.

If someone could check if I've got the right end of the stick with the following right it would be helpful!

So the 'click' for each timer is coming in at the following frequencies:

(master clock freq) / (clock divider)

1 ~ Divider=2 ~ 42MHz
2 ~ Divider=8 ~ Master clock / 8 ~ 10MHz
3 ~ Divider=32 ~ Master clock / 32 ~ 2.6MHz
4 ~ Divider=128 ~ Master clock / 128 ~ 0.66MHz

As the timer is a 32 bit timer the maximum time between interupts is:

((clock divider) * 4294967295) / (master clock freq)

1 ~ 102 sec
2 ~ 409 sec
3 ~ 1640 sec
4 ~ 6540 sec

As RA is the number of 'clicks' until an interrupt is triggered, and RC is the number of steps until the timer is reset the frequency of interupts can be much higher. RA could be 1, and RC 2, meaning the click sequence would be:

Timer sequence: 0 - 1 - (reset to 0) - 1 - (reset to 0)
Interupt sequence: 0 - Interupt - 0 - Interupt

So the minimum time between of interupts is:

((clock divider) * 2) / (master clock freq)

1 ~ 47 ns ~ (21 MHz) ~ 4 Clock cycles
2 ~ 190 ns ~ (5.25 MHz) ~ 16 Clock cycles
3 ~ 762 ns ~ (1.31 MHz) ~ 64 Clock cycles
4 ~ 3050 ns ~ (0.328 MHz) ~ 256 Clock cycles

(I'm having another read through this thread to see what questions I can answer for myself - 9 pages is a fair bit to digest in one pass!)

EDIT: 32 bits is 4294967295, not 65535!

1 Like

Hi - have just about run out of ideas.

Problem: Trying to output a 8mhz signal on a pin - any pin does not matter.

Used some of the original code in this thread and go up to 667 via the irq - but believe I can get the actual timer/clock logic to do it for me.

Currently I have a probe on digital pin 5 which corresponds to TIOA6 which is TC2 channel 1.

Was not getting anywhere so decided to use a simple example to see if it worked - I downloaded Ivans Library and modified the simpleTimer example as follows (to use Timer6)

Zip on pin5 - the line goes high and that is it.

Q1. Ivan - will your library enable TIOA6 (pin 5) with a clock?

Q2. Does anyone have a simple example for the Due that outputs a signal without using an interrupt (getting the hardware to do it) - any example just to get me over the hump.

Q3. Using Ivans example, it uses an IRQ - does the use of an IRQ by any chance disable the internal CPU's toggling of the pin?

BTW - I have read the atmel specs, been googling but am not getting anywhere.

Also BTW - I have done a simple check on pin 5 with a variation of blink - the line goes high/low without a problem.

Modified example:

#include <DueTimer.h>

int myLed = 13;

bool ledOn = false;
void myHandler(){
ledOn = !ledOn;

digitalWrite(myLed, ledOn); // Led on, off, on, off...
}

void setup(){
pinMode(myLed, OUTPUT);

Timer6.attachInterrupt(myHandler);
Timer6.start(50000); // Calls every 50ms
}

void loop(){

while(1){
// I'm stuck in here! help me...
}

}

Getting closer.

Found the following sample which I have modified - now get 4mhz.

Note that the wave is pretty good - but now and again there is a little 'pause' - suspect CPU best busy updating another timer or something.

#ifndef DUE_SERVO_H
#define DUE_SERVO_H

#include <Arduino.h>

#define PWM_DUTY_MIN 1
#define PWM_DUTY_MAX 2400

void writeMicros(int pin, uint16_t dutyCycle);
void initServo(int pin, uint16_t dutyCycle);

#endif

#define PWM_CLOCK 48000000
#define PWM_PERIOD 20

static bool PWMEnabled = false;

void initServo(int pin, uint16_t dutyCycle) {
if(!PWMEnabled) {
pmc_enable_periph_clk(PWM_INTERFACE_ID);
PWMC_ConfigureClocks(PWM_CLOCK, 0, VARIANT_MCK);
PWMEnabled = true;
}
const PinDescription *config = &g_APinDescription[pin];
int channel = config->ulPWMChannel;
if(channel == NOT_ON_PWM)
return;

PIO_Configure(
config->pPort,
config->ulPinType,
config->ulPin,
config->ulPinConfiguration);
PWMC_ConfigureChannel(PWM_INTERFACE, channel, PWM_CMR_CPRE_CLKA, 0, 0);
PWMC_SetPeriod(PWM_INTERFACE, channel, PWM_PERIOD);
writeMicros(pin, dutyCycle);
PWMC_EnableChannel(PWM_INTERFACE, channel);
}

void writeMicros(int pin, uint16_t dutyCycle) {
int channel = g_APinDescription[pin].ulPWMChannel;

if(channel == NOT_ON_PWM)
return;

if(dutyCycle < PWM_DUTY_MIN)
dutyCycle = PWM_DUTY_MIN;
if(dutyCycle > PWM_DUTY_MAX)
dutyCycle = PWM_DUTY_MAX;

PWMC_SetDutyCycle(PWM_INTERFACE, channel, dutyCycle);
}

#define SERVO_PIN 6
bool high = false;

void setup() {
initServo(SERVO_PIN, 10);
}

void loop() {

delay(500);
}

OK getting somewhere - found out that the PIO_Configure was needed to attached the output (TIOA6 in my case)

The following scotch works - and outputs a lovely 3Mhz signal - I thing I am missing something however.

Using timer 1, RA increments every sysclk/2 ticks = 42,000,000

I toggle the output every ??? 2 TIMER1 ticks (when RA = RC) so I assume I should be getting a 21mhz wave - any ideas anyone?

Stan

void TC6_Handler()
{
TC_GetStatus(TC2, 0);

}

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq) {
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_CLOCK1|
TC_CMR_ACPA_TOGGLE ); // RC compare TOGGLES TIOA););

TC_SetRA(tc, channel, 1); //50% high, 50% low
TC_SetRC(tc, channel, 1);

PIO_Configure(PIOC,
PIO_PERIPH_B,
PIO_PC25B_TIOA6,
PIO_DEFAULT);

TC_Start(tc, channel);

}

void setup(){

startTimer(TC2, 0, TC6_IRQn);
}

void loop(){
}

FWIW - it appears that getting anying above a stable 3Mhz signal is a bit iffy at most.

Have spent best part of 2 weeks on this (hour or 2 at a time) but have now ordered an external clock generator (Adafruit).

Anyway, with minor mods, if anyone wants a 3Mhz signal, with minor mods (just to clean it up), the above code will do it (BTW it is a sketch not a scotch.....)

Stan

Hi!

Maybe somene can help me with my problem
How to correctly set up registers.

What I want to do.
I want to set up timer and to get it triggered not only when it reaches some redefined value OR on a external signal with for falling edge . What I did now and what I want to get rid of (I dont want to use attachinterrupt, I want to use TC handler, but for this I have to set up TIOB, PIO? and TC_CMR0?) :astonished:

setup code:
pmc_set_writeprotect(false);
pmc_enable_periph_clk(ID_TC0);
TC_Configure(TC0, 0, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK1);
attachInterrupt(22, inter_test, FALLING);
TC_Start(TC0, 0);

void inter_test()
{
Serial.println(TC_ReadCV(TC0, 0)); //read ticks
TC0->TC_BCR = TC_BCR_SYNC; //reset timer
}

Hi,

I have read manual and I tried to make setup code, it is not working yet.

In manual I see:
The channel can also be configured to have an external trigger. In Waveform Mode, an external event can be programmed on one of the following signals: TIOB, XC0, XC1 or XC2. This external event can then be programmed to perform a trigger by setting ENETRG in TC_CMR.
If an external trigger is used, the duration of the pulses must be longer than the master clock period in order to be detected.
In Waveform Mode, TIOA is always configured to be an output and TIOB is an output if it is not selected to be the external trigger

My problem was:

  • I want to use TC0, channel 0
  • I think I will use Waveform mode, without RC compare
  • I want to use interrupts - interrupt should be triggered on external event (signal from other device of FALLING edge, 50Hz)
  • I want to use interrupt handler
void setup()
{
  Serial.begin(115200); 
  pinMode(22, INPUT); //I dont know, do I have to set it up just like that, I want to use pin22 as external signal
 
  pmc_set_writeprotect(false); //For being able to set up TC registers (like TC_CMR, TC_CCR etc)
  pmc_enable_periph_clk(ID_TC0);
 
  TC_Configure(TC0, 0, 0b00000000000000001001001000000000); // From manual (explained below)
  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; //Start TC or use APIs TC_start function
 
  //TC0->TC_CHANNEL[0].TC_IER = 0b00000000000000000000000010000001; // IER = interrupt enable register
  TC0->TC_CHANNEL[0].TC_IER = TC_IER_ETRGS | TC_IER_COVFS; //Enable interupt
}
 
void loop()
{
  Serial.println(TC_ReadCV(TC0, 0));
}
 
void TC0_Handler() 
{
  Serial.println(TC_ReadCV(TC0, 0));
  TC0->TC_CHANNEL[0].TC_CCR = TC_CCR_CLKEN | TC_CCR_SWTRG; //Restart timer
}

So problem here is
This code is never handled in TC0_Handler, even, when counter gets full.

  1. Is interrupt handler set up correctly?
  2. How do I tell the system that I use pin22 (B.26) as an input for TIOB (Do I have to set up PIO registers, how)?
  3. Maybe TC_CMR mode is set up incorrectly?:
TC_Configure(TC0, 0, 0b00000000000000001001001000000000);

I got it like this:
TC_CMR register, using Waveform Mode. This mode is used in TC_Configure().
TCCLKS: 000 -> usage of MCK/2 ie 48Mhz
CLKI: 0 ehk counter is incremtented on rising edge of the clock - fine by me
BURST: 00 - the clock is not gated by an external signal - fine by me
CPCSTOP: 0 counter clock is not stopped when counter reaches RC? I think its correct, I dont use RC, in waveform mode 00.
CPCDIS: 0 - counter clock is not disabled when counter reaches RC - I think its OK like this.
EEVTEDG: 10 (2) - on falling egde of external event triggers - This is correct I suppose.
EEVT: 00 - TIOB, signal selected as external event - Must be like that, according to manual.
ENETRG: 1 - the external event restars the counter and starts the coutner clock - Yup.
WAVSEL: 00 - upmode without automatic trigger on RC compare - I think its OK, I cant use here RC compare. 00 is OK.
WAVE: 1 - waveform is enabled
ACPA: 00 - ra compare effect on TIOA - none - as I dont use RA compare
ACPC: 00 - rc compare effect on TIOA - none - as I dont use RC compare
AEEVT: 00 - external event effet on TIOA???? Hmmm, what's that?
ASWTRG: 00 stoftware trigger effect on TIOA - Hmmmm, what's that?
BCPS, BCPC, 00 00 - ???
BEEVT, BSWTRG: 00 00 - ????

Are you to able to explain the requirements a little more;

If for example you want a single shot, you may want to steer clear of timers and just put some code like what follows;

volatile fred int;

ISR() {
fred=2;
}
Loop()
{
long ct;
ct=millis();
fred=0;
** Now register ISR as a falling edge interrupt on a pin - exercise for the reader ***
while (fred==0)
{
if (millis() > (ct + 1000))
fred=1;
}

Disengage interupt code

*** Now do something

}

In theory, either a second will go by or via the ISR the volatile variable fred gets set to break out of the loop

SO this is a single shot and you can evaluate fred - if it has value 1, you know the timer expired - if 2 you know the interrupt fired.

I suspect however you want to do something more than just a single shot - in which case perhaps you could take the code in loop and put it into another routine - and call it each time you want to check for an interrupt in a period of time.

Stan

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