Timer Interrupts on Due

Hi!
I read trough this thread and find it very very helpful!
At the moment i am trying to measure times between signal-flanks. Therefore i need to stop the time between two (external)interrupts. I'd like to do this with a timer - but don't need the timer interrupt.
As far as i can see the actual time is hold in the TC_CV register. How do i get this value?
I saw you make a lot of use of functions like pmc_set_write_protect and others. Where do you get the documentation of these functions from? And why do you know they even exist? :slight_smile:
Thanks a lot!

SomeRandomGuy:
Here is a link to the new library version: GitHub - SomeRandomGuy/DueTimer: Timer Library for the Arduino Due

Could someone offer some more explanation on this library I am trying to get my head around it.
I would like to set up a 500Khz clock output to a ATA6870. Is this possible using this library?
Does setting up these timers on certain pins have any affects on other parts of the system like the SPI Bus as I am using this to communicate with the ATA6870 which will use a SCK of half the CLK input I provide as recommended in the ATA6870 datasheet?

I am new to ARM processor and I am struggling making the timer work as well. The content in this post have been very helpful. But I have a very very dumb question.

Where did you guys find the reference manual for those functions used in these code? Like(NVIC_EnableIRQ, TC_Configure, TC_SetRA, etc). From the files in IDE it seems to be a library from Atmel. I probably used wrong keyword; I tried to search those on google for hours and got nothing. =( =( =( =( =(

I used:

  1. ATMEL data sheet: http://www.atmel.com/Images/doc11057.pdf
  2. API ref: http://asf.atmel.com/docs/latest/api.html
  3. the code (in the arduino dist)

You have to do some homework as none of the above is a tutorial. Most of the functions/defines were not obvious until I read the code. Had to do the same thing for the DAC interface (e.g., to enable flexible & word mode updates).

Best,
Bruce

This may be off topic, but is it possible to modify the library to be able to measure pulse duration on a pin using the timer interrupts?

Many thanks for your time in advance

Kind regards Rob

BKM:
I used:

  1. ATMEL data sheet: http://www.atmel.com/Images/doc11057.pdf
  2. API ref: http://asf.atmel.com/docs/latest/api.html
  3. the code (in the arduino dist)

You have to do some homework as none of the above is a tutorial. Most of the functions/defines were not obvious until I read the code. Had to do the same thing for the DAC interface (e.g., to enable flexible & word mode updates).

Best,
Bruce

Thank you very much for your reply, that is the sort of stuff I want.

I have one more question though. I cannot find some functions, for instance "TC_Configure()" in this API. I choose Timer Counter as catalog and SAM3X as devices. There is a function called "void tc_init (Tc *p_tc, uint32_t ul_channel, uint32_t ul_mode)" with same signature but the name is different and it cannot be compiled. Can you please tell me where do I find the information for those functions that compile-able by the arduino compiler?

I found the source for TC_Configure() in the arduino dist (.../hardware/arduino/sam/system/libsam/{include/tc.h,source/tc.c}).

In this case, it appears that the ATMEL documentation and the code in the arduino dist do not match. The documentation for tc_init() appears to match the source code for TC_Configure (caveat: I just took a quick look, but it appears to be essentially the same function). My guess is that they renamed the function at some point, and that the docs and code diverged.

The source for TC_Configure is pretty clear if you also look at the SAM3X data sheet for the behavior of the TC registers.

Best,
Bruce

Thank you very much! Seems like I have a lot of homework to do.

Best,
Tian

Guys!

Your solution is awesome and now I can use pin 13 and pin 2 to make two different LEDs blink independently with different frequencies.
But what if I use the "Serial monitor" to manipulate the frequency?

For example, I know that in the following code if I change

uint32_t rc = VARIANT_MCK/1300/frequency;

to

uint32_t rc = VARIANT_MCK/128/frequency;

it flashes slower....

but I want to make a serial loop in a way that it asks the user to change this number by putting a new number and read to serial monitor.

The problem is that I cannot put serial monitor in
Void Timer section! :frowning:

Any solution that can help me please?

Thanks!

sketch_mar23a.ino (2.09 KB)

Hi!
As i like libraries, i have done one to the Arduino DUE.

You can check it out here: GitHub - ivanseidel/DueTimer: ⏳ Timer Library fully implemented for Arduino DUE

All 6 timers are fully implemented, and ready to play with...

Thanks for the tips on the topic! I will put your names there

ivanseidel,

nice library!

Why don't you add also TC2 to the set of TImers? this will makes available other 3 timers.

Good idea... will do it now =]

Done! :slight_smile:

Can anyone kindly let me know how I can have an exact frequency of 1HZ or period of 1sec out of the following code please?

I have changed the TC_RC to
REG_TC0_RC0 =.25*0x5f5e100;

But I am not sure if this is 1sec or not?

Thanks all.

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 =.25*0x5f5e100; // counter period ---- POW (base, exponent) .5 ==> almost 1sec 10^8 = 0x5F5E100
//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);
}

Thanks to "stimmer" I got the right frequency of 1HZ or Period of 1sec, luckily. My next step is to use the
"Serial Monitor" to change the frequency.

When I use the following approach. And put something in the command line it starts to blink but it is not the exact frequency.
Afterwards, when I put another amount in the command line, the frequency does not change.

What do you suggest to read from the Serial monitor to change the frequency?

Thank you.

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(){
  Serial.begin(9600);
  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_CMR0=0b00000000000010011100010000000000; // set channel mode register (see datasheet)
  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);

          if (Serial.available() > 0) {

int x = Serial.read();

REG_TC0_RC0 = x*pow(10,6);  // counter period      ----  POW (base, exponent)     .5 ==> almost 1sec   10^8 = 0x5F5E100   

}
       
       
}

stimmer:
I think I'm getting somewhere with this... try this:

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);
}



The timer controls the output of pin 2 and the interrupt toggles a flag which is output on pin 13.

Could you please somebody kindly explain me the Handler part and "!l" please?

I cannot find such section on the data sheet.

Thanks.

A "Handler" is a default callback function, in this case, called when the timer is triggered.
In order to "reset" the timer, and let's say, "tell the uController that you handled the callback", you must reset a flag (the one in the first line), otherwise, it would get into a infinite loop, as the flag is not erased.

If you wish, you can use my library, where all timers are fully implemented: GitHub - ivanseidel/DueTimer: ⏳ Timer Library fully implemented for Arduino DUE

Hope it helps! (Library is commented, so it might help...)

Hey guys,

I am trying to get the timer interrupt works. I used your library, also I tried using without library, but
if I set the frequency for 200kHz, I always get a waveform on oscilloscope with the half frequency, so 100kHz.
Is that right? I couldn't get 1MHz as someone said in a post before, the maximum was 585kHz, when I set the frequency for 2MHz.

Someone can help me?

Thanks

//Chirp wave output

//#include <DueTimer.h>

#define TAM 4095

int frequency = 1000000;
volatile int i = 0;

void waveGenerate(){
  dacc_write_conversion_data(DACC_INTERFACE, (i=!i)*4095);
  //dacc_write_conversion_data(DACC_INTERFACE, sinWave[i++]);
  //if(i==4096)
  //  i=0;
}

void setup(){
  Serial.begin(9600);
  pinMode(DAC0, OUTPUT);
  analogWriteResolution(12);
  pmc_enable_periph_clk(DACC_INTERFACE_ID);
  dacc_reset(DACC_INTERFACE);
  dacc_set_transfer_mode(DACC_INTERFACE, 0); 
  dacc_set_power_save(DACC_INTERFACE, 0, 1); //Sleep mode = 0 (Normal Mode), Fast Wake Up = 1 (Enabled)
  dacc_set_timing(DACC_INTERFACE, 0x0, 1, 0x0); //REFRESH 0x0, MAXS = 1 (Max Speed Mode Enabled), STARTUP = 0 (0 periods of DACClock)
  
  dacc_set_writeprotect(DACC_INTERFACE, 0); //Disable 
  dacc_set_analog_control(DACC_INTERFACE, DACC_ACR_IBCTLCH0(0x02) |
                   DACC_ACR_IBCTLCH1(0x02) |
                   DACC_ACR_IBCTLDACCORE(0x01));
  dacc_disable_trigger(DACC_INTERFACE);
  dacc_set_channel_selection(DACC_INTERFACE, 0);
  dacc_enable_channel(DACC_INTERFACE, 0);
  

  Timer4.attachInterrupt(waveGenerate).setFrequency(frequency).start();
}

void loop(){

}

rgbp:
Hey guys,

I am trying to get the timer interrupt works. I used your library, also I tried using without library, but
if I set the frequency for 200kHz, I always get a waveform on oscilloscope with the half frequency, so 100kHz.
Is that right? I couldn't get 1MHz as someone said in a post before, the maximum was 585kHz, when I set the frequency for 2MHz.

Someone can help me?

Thanks

//Chirp wave output

//#include <DueTimer.h>

#define TAM 4095

int frequency = 1000000;
volatile int i = 0;

void waveGenerate(){
 dacc_write_conversion_data(DACC_INTERFACE, (i=!i)*4095);
 //dacc_write_conversion_data(DACC_INTERFACE, sinWave[i++]);
 //if(i==4096)
 //  i=0;
}

void setup(){
 Serial.begin(9600);
 pinMode(DAC0, OUTPUT);
 analogWriteResolution(12);
 pmc_enable_periph_clk(DACC_INTERFACE_ID);
 dacc_reset(DACC_INTERFACE);
 dacc_set_transfer_mode(DACC_INTERFACE, 0);
 dacc_set_power_save(DACC_INTERFACE, 0, 1); //Sleep mode = 0 (Normal Mode), Fast Wake Up = 1 (Enabled)
 dacc_set_timing(DACC_INTERFACE, 0x0, 1, 0x0); //REFRESH 0x0, MAXS = 1 (Max Speed Mode Enabled), STARTUP = 0 (0 periods of DACClock)
 
 dacc_set_writeprotect(DACC_INTERFACE, 0); //Disable
 dacc_set_analog_control(DACC_INTERFACE, DACC_ACR_IBCTLCH0(0x02) |
                  DACC_ACR_IBCTLCH1(0x02) |
                  DACC_ACR_IBCTLDACCORE(0x01));
 dacc_disable_trigger(DACC_INTERFACE);
 dacc_set_channel_selection(DACC_INTERFACE, 0);
 dacc_enable_channel(DACC_INTERFACE, 0);

Timer4.attachInterrupt(waveGenerate).setFrequency(frequency).start();
}

void loop(){

}

Notice that:
Setting timer interrupt for 1hz (for example), would generate 1seccond of HIGH and 1 seccond of LOW, read as 0.5hz (1/2 of the interrupt frequency)
If you set it to 200khz, than you would be setting High 100.000 times per seccond, and low 100.000times per seccond. witch is 100.000hz (100khz, or, half of 200khz)
=]

ivanseidel:
A "Handler" is a default callback function, in this case, called when the timer is triggered.
In order to "reset" the timer, and let's say, "tell the uController that you handled the callback", you must reset a flag (the one in the first line), otherwise, it would get into a infinite loop, as the flag is not erased.

If you wish, you can use my library, where all timers are fully implemented: GitHub - ivanseidel/DueTimer: ⏳ Timer Library fully implemented for Arduino DUE

Hope it helps! (Library is commented, so it might help...)

Thanks for your response.

Actually I have used your header file + Simple timer but I dunno why pin 13 does not blink. Should I change it somewhere?

I merge two files as I couldn't use them separately as follows.

/*
DueTimer.h - DueTimer header file, definition of methods and attributes...
For instructions, go to https://github.com/ivanseidel/DueTimer

Created by Ivan Seidel Gomes, March, 2013.
Released into the public domain.
*/

#ifdef __arm__

#ifndef DueTimer_h
#define DueTimer_h

#include "Arduino.h"

#include <inttypes.h>

class DueTimer
{
protected:
int timer; // Stores the object timer id (to access Timer struct array)
static int _frequency[9]; // Stores the object timer frequency (to access know current timer period, frequency...)

static uint8_t bestClock(uint32_t frequency, uint32_t& retRC); // Picks the best clock to lower the error

public:
struct Timer
{
Tc *tc;
uint32_t channel;
IRQn_Type irq;
};

static DueTimer getAvaliable();

static const Timer Timers[9]; // Store timer configuration (static, as it's fix for every object)
static void (*callbacks[9])(); // Needs to be public, because the handlers are outside class

DueTimer(int _timer);
DueTimer attachInterrupt(void (*isr)());
DueTimer detachInterrupt();
DueTimer start(long microseconds = -1);
DueTimer stop();
DueTimer setFrequency(long frequency);
DueTimer setPeriod(long microseconds);


long getFrequency();
long getPeriod();
};

extern DueTimer Timer; // Just to call Timer.getAvaliable instead of Timer::getAvaliable()

extern DueTimer Timer0;
extern DueTimer Timer1;
extern DueTimer Timer2;
extern DueTimer Timer3;
extern DueTimer Timer4;
extern DueTimer Timer5;
extern DueTimer Timer6;
extern DueTimer Timer7;
extern DueTimer Timer8;

#endif

#else
#pragma message("Ops! Trying to include DueTimer on another device?")
#endif








/////////


int myLed = 13;

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

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

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

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

void loop(){

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

}