Arduino Forum

Products => Arduino Due => Topic started by: bg94 on Nov 03, 2012, 12:02 am

Title: Timer Interrupts on Due
Post by: bg94 on Nov 03, 2012, 12:02 am
I've been searching through the library code as well as thoroughly searched Google and haven't come across any working timer interrupt code for the Due. I could do this on the Uno in my sleep, but have yet to figure it out on the Due. Any pointers (http://xkcd.com/138/) or example code would be greatly appreciated. Basically I want to get a function to run once every X microseconds. Thanks.
Title: Re: Timer Interrupts on Due
Post by: mantoui on Nov 03, 2012, 12:23 pm
Yeah, I was hoping to get timer interrupt hints on my thread for Tone.cpp code.  I've done timers on Uno and Maple, but Maple IO architecture is quite different from DUE.  There is PWM timer code in
hardware/arduino/sam/cores/arduino/wiring_analog.c
but no interrupt code.  The Timer/Counter support routines (no interrupt routines) are in
hardware/arduino/sam/system/libsam/source/tc.c
with the #define's in
hardware/arduino/sam/system/CMSIS/Device/ATMEL/sam3sd8/include/component/component_tc.h
The ISR handler's are named TCx_Handler(), e.g.  TC0_Handler()

I'm guessing (don't have a DUE yet) that interrupt enable would be something like
tc->TC_CHANNEL[chan].TC_IER = TC_IER_CPCS;
but there is also an interrupt mask register TC_IMR?

not much help, but hopeful ...
Title: Re: Timer Interrupts on Due
Post by: stimmer on Nov 04, 2012, 04:17 am
I think I'm getting somewhere with this... try this:
Code: [Select]

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.
Title: Re: Timer Interrupts on Due
Post by: DuaneB on Nov 04, 2012, 06:21 am
Hi,
   Whats the best resource you have found for describing the timer registers ?

Thanks

Duane B

rcarduino.blogspot.com (http://rcarduino.blogspot.com)
Title: Re: Timer Interrupts on Due
Post by: seavik on Nov 04, 2012, 10:55 am
Not what you're looking for, but on a similar topic:
I wanted to use the TC* timers to create a software servo library but I couldn't find out how to use the timers so I ended up using the PWM clock to generate the output.

While testing the PWM pulse I used attachInterrupt on the same pin to measure the pulse timing, effectively creating software interrupts. It's a hack, but if you're interested the code is here: http://arduino.cc/forum/index.php/topic,130631.0.html (http://arduino.cc/forum/index.php/topic,130631.0.html)
It doesn't use any registers, so I can't tell you about those - just add attachInterrupt()
Title: Re: Timer Interrupts on Due
Post by: mantoui on Nov 04, 2012, 01:06 pm
timer/counter registers are detailed in chapter 37 of datasheet
Title: Re: Timer Interrupts on Due
Post by: bg94 on Nov 04, 2012, 04:14 pm

I think I'm getting somewhere with this... try this:
Code: [Select]

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.


I'll give this a shot thanks. I am curious though why you didn't do a digitalWrite() inside the handler? Arduino's digitalWrite() function is pretty clock-cycle heavy, but the following code works just fine for writing a digital output and only takes a couple of clock cycles if that was the primary concern.

Code: [Select]
static inline void pinOutput(int pin, int val)
{
if (val)
g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
else
g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
}


On another note, Maple uses a different processor, but gives as good of an explanation / example of how timers work as I've found so far:
http://leaflabs.com/docs/timers.html
http://leaflabs.com/docs/lang/api/hardwaretimer.html
http://leaflabs.com/docs/libmaple/api/timer.html

I haven't tried to implement any of their code yet, but thought I'd share the links.
Title: Re: Timer Interrupts on Due
Post by: stimmer on Nov 04, 2012, 09:20 pm
I recognize that code fragment 8)

As for digitalWrite not being in the handler, actually it was there originally, but you have to understand that I'd been struggling for hours with interrupt code that wouldn't fire, then it only fired once, then it got hammered with constant interrupts, and I didn't know what was going on. So I did what is pretty much standard debugging practice and changed the interrupt handler to do the absolute bare minimum just to be sure that digitalWrite wasn't causing a side effect (there's some architectures where you can't write certain registers in an interrupt). But the important thing turned out to be the dummy read of TC_SR0. By then it was late so I just posted what I'd done.

Since then I have tried putting digitalWrite and direct port writes back in and they don't seem to cause any odd side effects.

The Maple hardware is completely different unfortunately and the registers are incompatible.
Title: Re: Timer Interrupts on Due
Post by: bg94 on Nov 04, 2012, 10:00 pm
I understand. Thanks :)
Title: Re: Timer Interrupts on Due
Post by: seavik on Nov 05, 2012, 09:48 pm
Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

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

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12
Title: Re: Timer Interrupts on Due
Post by: mantoui on Nov 05, 2012, 11:40 pm
Sebastian:

  Well done!  thanks
Title: Re: Timer Interrupts on Due
Post by: mnpumar on Nov 19, 2012, 06:32 pm

Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
       TC_GetStatus(TC1, 0);
       digitalWrite(13, l = !l);
}

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

void setup(){
       pinMode(13,OUTPUT);
       startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12



Noob question here, could someone please explain the inputs to the startTimer function? What is channel, and how do we use the frequency input?  Also, what are the pins in the table for?
Title: Re: Timer Interrupts on Due
Post by: Selachii on Nov 23, 2012, 02:52 pm
Same question; please explain the inputs to the startTimer function.
Title: Re: Timer Interrupts on Due
Post by: Selachii on Nov 23, 2012, 11:31 pm
Are there any ready-to-use-libs (like http://www.arduino.cc/playground/Code/Timer1 (http://www.arduino.cc/playground/Code/Timer1)) for using Hardware Timer on Due?

Or is there a beginner-friendly How-To (like  http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/ (http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/)) for the Due?
Title: Re: Timer Interrupts on Due
Post by: cmaglie on Nov 24, 2012, 10:04 am

Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12



A brief explanation:
The SAM3X8E CPU has 3 Timer Counters (TC) they are called TC0, TC1, TC2.
Every Timer Counter contains 3 Channels numbered 0, 1 and 2 (this give us a total of 9 Channels).
Every Channel has its own counters and interrupt handler that are independent from other Channels.

In other words each Channel can be considered as a separate "Timer", and is like having 9 separate timers.

To initialize a Channel you need the following parameters:

TC0/TC1/TC2 - The Timer Counter instance
0 / 1 / 2 - The Channel number inside Timer Counter

If you want to use interrupts you must enable the NVIC (Nested Vector Interrupt Controller) for that channel with:
Code: [Select]

NVIC_EnableIRQ(TCx_IRQn);

where TCx_IRQn is the ID of the interrupt to enable. These id are listed in the following table together with the ISR handler function name:












TC        Chan   NVIC "irq"   IRQ handler function   PMC id
TC00TC0_IRQnTC0_HandlerID_TC0
TC01TC1_IRQnTC1_HandlerID_TC1
TC02TC2_IRQnTC2_HandlerID_TC2
TC10TC3_IRQnTC3_HandlerID_TC3
TC11TC4_IRQnTC4_HandlerID_TC4
TC12TC5_IRQnTC5_HandlerID_TC5
TC20TC6_IRQnTC6_HandlerID_TC6
TC21TC7_IRQnTC7_HandlerID_TC7
TC22TC8_IRQnTC8_HandlerID_TC8


(note that TC2_IRQn is the irq id for TC0-channel-2 not for TC2...)

but this is still not enough! Every peripheral in the SAM3X is off by default (to save power) and should be turned on. To turn on you need to run the following command:

Code: [Select]
pmc_enable_periph_clk(id);

where id is found on the last column of the above table (ID_TCx). It happened that ID_TCx constant equals TCx_IRQn, so Sebastian Vik has simplified a bit the function using TCx_IRQn as input for pmc_enable_periph_clk:

Code: [Select]
pmc_enable_periph_clk((uint32_t)irq);

Hope this helps to decode whats happening with timers inside SAM3X.


Are there any ready-to-use-libs (like http://www.arduino.cc/playground/Code/Timer1 (http://www.arduino.cc/playground/Code/Timer1)) for using Hardware Timer on Due?

Or is there a beginner-friendly How-To (like  http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/ (http://www.engblaze.com/microcontroller-tutorial-avr-and-arduino-timer-interrupts/)) for the Due?


Nope, there are no libs neither tutorials.

I've planned a SAM3Timer library (to simplify implementation of Arduino Core and some libraries) but I didn't started it yet.

Volunteers? :)
Title: Re: Timer Interrupts on Due
Post by: DuaneB on Nov 24, 2012, 10:29 am
Send me a Due and I will write some libraries for it.

Duane B

rcarduino.blogspot.com (http://rcarduino.blogspot.com)
Title: Re: Timer Interrupts on Due
Post by: Selachii on Nov 24, 2012, 01:20 pm
Quote
Quote from: Sebastian Vik on November 05, 2012, 08:48:40 PM
Here is the table of parameters:
ISR/IRQ   TC           Channel   Due pins
TC0   TC0   0   2, 13
TC1   TC0   1   60, 61
TC2   TC0   2   58
TC3   TC1   0   none  <- this line in the example above
TC4   TC1   1   none
TC5   TC1   2   none
TC6   TC2   0   4, 5
TC7   TC2   1   3, 10
TC8   TC2   2   11, 12

A brief explanation:
The SAM3X8E CPU has 3 Timer Counters (TC) they are called TC0, TC1, TC2.
Every Timer Counter contains 3 Channels numbered 0, 1 and 2 (this give us a total of 9 Channels).
Every Channel has its own counters and interrupt handler that are independent from other Channels.

In other words each Channel can be considered as a separate "Timer", and is like having 9 separate timers.

To initialize a Channel you need the following parameters:

TC0/TC1/TC2 - The Timer Counter instance
0 / 1 / 2 - The Channel number inside Timer Counter

If you want to use interrupts you must enable the NVIC (Nested Vector Interrupt Controller) for that channel with:
Code:

NVIC_EnableIRQ(TCx_IRQn);

where TCx_IRQn is the ID of the interrupt to enable. These id are listed in the following table together with the ISR handler function name:

TC           Chan      NVIC "irq"      IRQ handler function      PMC id
TC0   0   TC0_IRQn   TC0_Handler   ID_TC0
TC0   1   TC1_IRQn   TC1_Handler   ID_TC1
TC0   2   TC2_IRQn   TC2_Handler   ID_TC2
TC1   0   TC3_IRQn   TC3_Handler   ID_TC3
TC1   1   TC4_IRQn   TC4_Handler   ID_TC4
TC1   2   TC5_IRQn   TC5_Handler   ID_TC5
TC2   0   TC6_IRQn   TC6_Handler   ID_TC6
TC2   1   TC7_IRQn   TC7_Handler   ID_TC7
TC2   2   TC8_IRQn   TC8_Handler   ID_TC8

(note that TC2_IRQn is the irq id for TC0-channel-2 not for TC2...)

but this is still not enough! Every peripheral in the SAM3X is off by default (to save power) and should be turned on. To turn on you need to run the following command:

Code:

pmc_enable_periph_clk(id);


where id is found on the last column of the above table (ID_TCx). It happened that ID_TCx constant equals TCx_IRQn, so Sebastian Vik has simplified a bit the function using TCx_IRQn as input for pmc_enable_periph_clk:

Code:

pmc_enable_periph_clk((uint32_t)irq);


Hope this helps to decode whats happening with timers inside SAM3X.


Thank you for your detailed answer.
Can somebody explain the following code?
I want to use it to execute a function after every XY CPU counts:

        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;
Title: Re: Timer Interrupts on Due
Post by: seavik on Nov 25, 2012, 03:09 pm
Also, what are the pins in the table for?

Good question! If I understood everything correctly, the pins in the table are where you could output the clock of that timer/counter if you wanted to use it for something else than internal software interrupts.
Basically you can set up the hardware counter to output a clock signal. For example, TC0 channel 0 could be used to output a clock on the Arduino pin 2 or 13. So if you use TC0 channel 0 for your timer, you would not be able to output a clock on those pins (except using the frequency you set up the channel for).
That is why it would be better to use TC1 channels 0, 1 or 2 primarily for this kind of interrupt, as their output is not mapped to any of the Arduino pins and therefore does not limit any of your physically mapped outputs.
Title: Re: Timer Interrupts on Due
Post by: ForcisConnect on Nov 28, 2012, 09:18 am
Quote
Thank you for your detailed answer.
Can somebody explain the following code?
I want to use it to execute a function after every XY CPU counts:

        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;


I have the same question. I'm trying to create an Interrupt every 62.5 microseconds but I'm incapable! Do you know if it is possible and if it is how should I proceed? As I have understand I should modify the variable RC and reading through the net I came with a possible answer being (VARIAN_MCK/8)/SPEED of transmission (I need the interruption to modify the VirtualWire library for the DUE, which I have almost done  ;)) but it doesn't work!
Title: Re: Timer Interrupts on Due
Post by: cmaglie on Nov 29, 2012, 10:44 am
You should use the code Sebastian Vik already posted, I've slightly rewrite it with some comments

Code: [Select]


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

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

  // Start timer. Parameters are:

  // TC1 : timer counter. Can be TC0, TC1 or TC2
  // 0   : channel. Can be 0, 1 or 2
  // TC3_IRQn: irq number. See table.
  // 40  : frequency (in Hz)
  // The interrupt service routine is TC3_Handler. See table.

  startTimer(TC1, 0, TC3_IRQn, 40);

  // Paramters table:
  // TC0, 0, TC0_IRQn  =>  TC0_Handler()
  // TC0, 1, TC1_IRQn  =>  TC1_Handler()
  // TC0, 2, TC2_IRQn  =>  TC2_Handler()
  // TC1, 0, TC3_IRQn  =>  TC3_Handler()
  // TC1, 1, TC4_IRQn  =>  TC4_Handler()
  // TC1, 2, TC5_IRQn  =>  TC5_Handler()
  // TC2, 0, TC6_IRQn  =>  TC6_Handler()
  // TC2, 1, TC7_IRQn  =>  TC7_Handler()
  // TC2, 2, TC8_IRQn  =>  TC8_Handler()
}

void loop(){
}

volatile boolean l;

// This function is called every 1/40 sec.
void TC3_Handler()
{
  // You must do TC_GetStatus to "accept" interrupt
  // As parameters use the first two parameters used in startTimer (TC1, 0 in this case)
  TC_GetStatus(TC1, 0);

  digitalWrite(13, l = !l);
}



I have the same question. I'm trying to create an Interrupt every 62.5 microseconds but I'm incapable! Do you know if it is possible and if it is how should I proceed? As I have understand I should modify the variable RC and reading through the net I came with a possible answer being (VARIAN_MCK/8)/SPEED of transmission (I need the interruption to modify the VirtualWire library for the DUE, which I have almost done  ;)) but it doesn't work!


62.5 uS is 1000000/62.5 = 16000 Hz, use that value as last parameter of startTimer.
Title: Re: Timer Interrupts on Due
Post by: ForcisConnect on Nov 29, 2012, 02:34 pm
Well this last explanation was perfect! I have now managed to translate the VirtualWire library to the Arduino DUE. It is to be knowledge that it is a primary version and that I have tested it only with the standard speed of transmission (2000 bps) and it may have errors changing it (because the time of interrupt is not more dependent of the speed).
Title: Re: Timer Interrupts on Due
Post by: DuaneB on Nov 30, 2012, 03:36 pm
Hi,
   Is this or something similar going to be included in the Due API ?

EDIT - I have used this approach to get a timer interrupt running at 44.1Khz.

What is a good source of documentation on ARM Development ? I have the datasheet, I have found the API documentation, I have even read the .h and .c source files, but without the head start from Mr Vik I would not have had a hope in hell of getting this working.

As a quick example where is it documented that TC_GetStatus has to be called to re-enable the interrupt ?

   Duane B

rcarduino.blogspot.com (http://rcarduino.blogspot.com)
Title: Re: Timer Interrupts on Due
Post by: cmaglie on Dec 02, 2012, 12:57 am
DuaneB, I see your point, unfortunately I guess the only document close to what you're searching is the datasheet. Indeed having a reference implementation to look at helps a lot.


As a quick example where is it documented that TC_GetStatus has to be called to re-enable the interrupt ?


I discovered it by trial and error. I don't know if there is any book that explain it in this level of detail...

Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 05, 2013, 06:14 am
Thanks for posting the timer code. We need a 10Khz signal but using 10,000 as the value in the last parameter (as suggested by cmaglie) seems to - in our case at least - deliver half the required frequency (i.e. 5Khz) - according to our scope at least. However, when we use the value of 20,000 - and look at the value on the scope - we get a 100us square wave.

Are we misinterpreting something? This is the code we use to get our 10Khz signal - could someone please verify our findings for us?

Also, we need to synchronise the start of these pulses with some other Due's so that they all output synchronised pulses. Can anyone help us with that? Do we simply re-start the timer and, if so, how?

Thanks all,
Dev team

Quote

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

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

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 20000); //TC1 channel 0, the IRQ for that channel and the desired frequency
        // 20,000 seems to give 100uS/div signal, which is equivalent to 10,000Hz or 10Khz
}

void loop(){
}

Title: Re: Timer Interrupts on Due
Post by: selfonlypath on Jan 05, 2013, 06:50 am
it seems to me you're subject to different waveform coding, with arduino mega look at fast PWM versus phase correct PWM but also frequency & phase correct PWM. The last 2 cases will divide by 2 the actual timer frequency generation.

I've quicked look on SAM3X... datasheet for the equivalent story, same except they use WAVSEL to choose whatever mode. Later on the datasheet, they also speak of center align or left align.

So there is no bug, just program correctly the registers...
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 05, 2013, 08:15 am
@SelfOnlyPath - thanks for the clarification. Certainly the left / centre align is something we'll need to look into and the halving of the clock in certain modes makes perfect sense in the context of our experience. It must be time for us to hit the docco's hard wethinks. Thanks again.
Title: Re: Timer Interrupts on Due
Post by: jgmdavies on Jan 05, 2013, 10:13 am
@WomensFashionArt

Just tried your sketch here unmodified and I get a nice 10 KHz (100 us cycle) square wave output on pin 13, as measured on our Rigol scope.

But on further investigation I see that the timer interrupt is in fact at 20 KHz (50 us), but you are toggling the output state in the handler, so each cycle you see is twice 50 us = 100 us.

Try this instead and you'll see a 2 us pulse at 20 KHz:

Code: [Select]

void TC3_Handler()
{
        TC_GetStatus(TC1, 0);

        digitalWrite(13, 1);    // ON

        for (int i = 0; i < 10; i++)
          int j = i;

        digitalWrite(13, 0);    // OFF
}


HTH
Jim
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 05, 2013, 10:20 am
@ Jim; thanks for verifying that mate, much obliged.
Just as a "caution" for anyone using this routine, the setting TC_SetRA doesn't appear to be doing what the routine claims it does; We've varied its value and the pulse ratio seems "stuck" (or remains) at around 50%. We're investigating at present and will post updated code that - hopefully - takes a PWM percentage as well as a Frequency as part of its calling parameters. Much easier for us that way, and for anyone who wants to use it that way.
Title: Re: Timer Interrupts on Due
Post by: jgmdavies on Jan 05, 2013, 10:25 am
@WomensFashioArt

Thanks.

Just EDITED previous post, please review!

Jim
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 05, 2013, 10:53 am
@Jim; fantastic. Thanks. The code is a copy of some other code posted in this forum and - frankly - we didn't quite understand it all, but it's much clearer now (relatively old hands at Arduino, but new to the Due)...

So to make sure we understand it correctly, the frequency corresponds with the calling frequency of the routine (uint32_t frequency) delivering a 20Khz timed interrupt, but the digitalWrite(13, I = !I) flips the pin 13 logic value causing a 50us high, followed by a 50us low - creating a 10Khz square wave. That makes perfect sense.
Title: Re: Timer Interrupts on Due
Post by: jgmdavies on Jan 05, 2013, 11:05 am
@WomensFashionArt

Yep, your understanding is correct.  The software delay I inserted (the 'for' loop) is irrelevant, as the 'digitalWrite' is causing the 2 us odd delay I wanted to get a reasonable pulse out.

I know how easy it is easy to miss something when you're head-scratching, like the toggle 'I = !I'  :D

The Due Timer code contributed by others in this thread will be very useful.

Re. your other query:
Quote
Also, we need to synchronise the start of these pulses with some other Due's so that they all output synchronised pulses. Can anyone help us with that? Do we simply re-start the timer and, if so, how?


I would output a pulse each cycle from a digital pin on the 'master' Due, and connect it to an unused digital input on each 'slave' Due. You then need to use a hardware interrupt, i.e. an ISR, on each slave Due to reset each slave timer.  I'm afraid I haven't got suitable code for the Due handy, but maybe someone else has?

Jim
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 05, 2013, 11:16 am
@Jim; thanks so much for your pro-active engagement. No can do with the sync I'm afraid, there's 20m of cables between them and all sync is being done over this cable. I'm pretty sure that we'll end up using an interrupt of some sort so that all of them are able to reset at exactly the same time. This is our progress so far. It's reduced the PWM frequency to 2Khz for now (the Due can't handle the logic at the requisite 1,000,000 interrupts / second, but we'll work on that). This seems to work just fine and the comments should show the way.

It's late and we're off for the day, but hope that this is of use to somebody.

We'll update it as we go along so that others may benefit from the discussion.

Thanks again Jim, your help is very much appreciated.

Rgs,
WFA_Dev
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 05, 2013, 11:20 am
@Jim; the code would be rather useful here, wouldn't it... 8)

[FOLLOW-UP EDIT - 6 JAN 2013] Updated the code to approximate our 10Khz signal with 0...100% duty cycle.
Note: the frequency generation algorithm (uint32_t rc = VARIANT_MCK/3000/frequency; ) does not provide an accurate frequency. We've tested between 5Khz and 10Khz, for 5Khz we get approx. 5.1Khz, and for 10Khz we get 9.26Khz - as close as we can get it to 10Khz. In between the 5Khz and 10Khz, results vary wildly... please check your own numbers before relying too much on this routine.

Quote

volatile char On;
volatile char Total;
volatile char Max;

int PWM_Percent;
int PWM_Freq;

//TC1 ch 0
void TC3_Handler()
{
  
  // reset interrupt 
  TC_GetStatus(TC1, 0);

  // process percentage-based PWM waveforms
  
  // If count is at leading edge, raise pulse
  if (Total == 0) {
    digitalWrite(13,1);
  }
  // If count is at trailing edge, drop pulse
  else if (Total == On) {
    digitalWrite(13,0);
  }
      
  Total += 1;
  
  // If count is at 100%, reset to zero and start all over again
  if (Total > Max) {
    Total = 0; 
  }
}

// End TC3_Handler()

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_CLOCK3);
  uint32_t rc = VARIANT_MCK/3000/frequency; 
  TC_SetRA(tc, channel, rc/2);
  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);
}

void setup(){
  
  // Use the LED for now
  pinMode(13,OUTPUT);
  
  // Set the total to zero
  Total = 0;
  
  // Set pulse width to 50%
  PWM_Percent = 50;
  
  // Set interrupt frequency
  PWM_Freq = 10000; //

  // -------------------------------
  // calculate cycles
  On = PWM_Percent; //
  
  // set maximum percentage at full 100%
  Max = 100; //

  // -------------------------------
  
  // Start the timer
  startTimer(TC1, 0, TC3_IRQn, PWM_Freq); //TC1 channel 0, the IRQ for that channel and the desired frequency

}

void loop(){
}


Title: Re: Timer Interrupts on Due
Post by: selfonlypath on Jan 06, 2013, 05:50 am
I really don't understand why you guys are not fully using the the complete potential of timer possibilities, of course requires fine register initialization but you could get very precise high frequency PWM even beyond 500 KHz or 1 MHz.

For the moment, i've doing so for years with arduino mega on my power electronics project (plasma drivers, full H-bridge, MWO inverters...) many of them, see old post then specific update code even though now is even more refined http://arduino.cc/forum/index.php/topic,8162.msg65115.html#msg65115 (http://arduino.cc/forum/index.php/topic,8162.msg65115.html#msg65115) )

I do have an arduino DUE but as explained on other threads recently, I cannot download my actual MEGA projects using advanced arduino mega timer management because USB link of DUE is full of bugs.

Again I insist, just program the proper WAVESEL value and other registers, there is NO need to make interrupts slowing down and skewing the PWM jitter precision if using a timer, in particular with DUE being much more sophisticated timer possibilities than MEGA !

Just my 2 cents
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 06, 2013, 06:07 am
@Selfonlypath:

Thanks for your contribution. I don't necessarily disagree with your position, but the documentation (even the complete data sheet) isn't entirely clear on what / how these registers are programmed. Further, there is a serious shortage of programming examples in Atmel's documentation for these chips (well, in our opinion anyway).

All references to the Sam3A4C registers include stuff like setting timers as peripherals, using nested interrupts, programming the timers and cascades; all without examples and/or any guiding principles.

Consequently it is difficult (if not near-on impossible) for those of us without experience with this chip to even begin to explore its potential. Even using the Arduino IDE - which is still in Beta stage - we are still experiencing issues - it's early days yet.

For now, we are getting a relatively clean 9Khz signal over which we have full control - because it is software generated. We can modify the waveform - if and as we please. We can change its duty cycle - even by fractions of a percent if needed, and - because the waveform is generated in software - we are able to synchronise it accurately across multiple Arduino Due's.

So, in conclusion, yes - all things being equal your point is entirely valid.

However, until there is more clarity for us on how to accurately program the registers, and until we are able to identify some examples out there that we can piggy-back on, this does the job for us.

It's not an ideal world out there; we simply get the job done for now.

J.

Title: Re: Timer Interrupts on Due
Post by: selfonlypath on Jan 06, 2013, 07:22 am
I do agree that the Sam... datasheet register are not very detailed, maybe a mix of Atmel releasing too early beta datasheet or whatever.

You might want see this video where I'm using the four 16-bits MEGA timers, each being specifically delayed 90°, 180°, 270° with less than 62.5 ns

http://www.youtube.com/watch?v=sTSF23NCw8E (http://www.youtube.com/watch?v=sTSF23NCw8E)

P.S. In fact, there really SIX 16-bit timers, two of them are being emulated by my specific protoshield using some 74HCxy chips

Just hoping the arduino team will soon fix the USB serial issue via a new IDE release, at least on my side I cannot afford to migrate my actual project MEGA software using very advanced timer register tricks since i'm shuttling more than 5000 VAR's with my igbt's drivers, blue smoking and $$$ gone !

Once DUE serial USB will be OK, I'll look deeper on the DUE timers which i feel from datasheet are very very interesting with fascinating new features.
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 06, 2013, 07:39 am
@ SelfOnlyPath:

We're out on the yoga bit...  :smiley-mr-green: - informative video.
There is broad agreement that chip-generated PWM / waveforms will end up being superior to our (temporary) solution.

However, let's not forget that this is software; not hardware. We work with what we know and can realistically deliver at the highest possible quality in an acceptable timeframe. Once we understand the timers a bit better, we'll simply replace that bit of code.

Eliminates wasteful research, achieves the objective, and saves standing still altogether waiting for the right solution to arrive - :)

Title: Re: Timer Interrupts on Due
Post by: selfonlypath on Jan 06, 2013, 07:45 am
I really hope to have access to a new IDE so I can start using DUE on ALL my projects, more particularly its timers and interrupt routines.

You'll notice some of my boards hosting the MEGA as piggy board are in fact fully space compatible with DUE, the board were designed more than 1 year ago betting DUE will come up.

In fact, my special loose-coupled ferro-resonant project is bit stuck due to lack of more advanced timer low level inside MEGA.

As you said, world is not perfect but keeps moving.


Title: Re: Timer Interrupts on Due
Post by: selfonlypath on Jan 06, 2013, 09:26 am
P.S. You might notice from time 7min 0s in the video that actually I live update by ISR (Interrupt Software Routines) all the FOUR internal 16-bit timers register so you'll se a global frequency sweeping up. Due to the special topology of my circuit, this is equivalent to have arduino MEGA-generate phase locked 8 independent PWM rails aka 8 channel frequency generator.

http://www.youtube.com/watch?v=sTSF23NCw8E (http://www.youtube.com/watch?v=sTSF23NCw8E)

Once DUE will become more mature and guess as you said, the Atmel datasheet, such project will be easier with more timers and software possibilities with incredible few ns precision jitter.
Title: Re: Timer Interrupts on Due
Post by: jgmdavies on Jan 06, 2013, 11:09 am
@selfonlypath:  Very impressive - well done!

@WomensFashionArt:

No can do with the sync I'm afraid, there's 20m of cables between them and all sync is being done over this cable. I'm pretty sure that we'll end up using an interrupt of some sort so that all of them are able to reset at exactly the same time.

... the Due can't handle the logic at the requisite 1,000,000 interrupts / second


Couple of queries:



Best,
Jim
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 06, 2013, 11:31 am
Hi Jim,

Thanks for the questions.

1) "How well synchronised do the different Dues have to be" 

We'd like to get it below 20us. However, there are some obstacles to this. Firstly, total capacitance, line driver & logic gate delays will add some delays. We have not yet calculated those, but they are - presently - thought to be within our limits. Our second problem is that - for a new design - we'd like to go radio (probably some variant of 802.11 for its broad availability). That puts the cat among the pigeons because now that very fast response time is becoming increasingly difficult to achieve. Again, we haven't done the maths, but we are pretty sure that there are going to be complications. Our middle name... LOL.


2) "How did you get the 1 Mhz figure"? 

Well, 1,000,000 interrupts for 10 Khz leaves 100 interrupts for each cycle. In other words, 10 Khz @ between 0% and 100% duty cycle in 1% increments.

However, as these units will - initially - only see service inside our studios, we are fine with 5 Khz (which corresponds to exactly 5 pulses of light for a 1/1000 shutter speed on our cameras) - something which, thanks to the Due's fast clock - we have already achieved.

==============================

Unfortunately we only have a small hobby scope at our disposal and its resolution is inadequate for testing the Sync. However, there is a solution (we think) in that we are considering using an 8 input AND gate which will allow us to test the synchronicity of up to 8 Due's by the following methodologies:

* Assume pulses are initially out-of-phase by - say - 50%. That gives a net duty cycle of 25% on a 50% PWM (the AND gate is shut for the rest of the time because not all inputs are high).
* Issue a SYNC pulse to the Due's
* Verify that the AND gate output pulses now show a 50% duty cycle.

Whilst the above is inadequate to verify whether or not we were able to keep our response time sub 20 us, it will show us that our SYNC system is working, and that all the PWM signals are now lining up nicely.

The reason "jitter" isn't that much of an issue for us is, that at lower shutter speeds (and @ 10 Khz), each exposure is likely to be subjected to - say - 80 light pulses (1/125 sec). Even if we missed an entire pulse (not overly desirable, but not catastrophic either), we'd only experience a variance of just over one percent; not distinguishable by the naked eye.

Hope that answers some of your questions (as well as some you haven't asked, but are directly related).

Rgds, J.
Title: Software timer interrupt code for Duemilanove
Post by: WomensFashionArt on Jan 07, 2013, 07:17 am
Hi all,
We were wondering, with so much confusion about timers, PWM etc. whether one of our standard code blocks might come in handy.
This one trades resolution for frequency (as you do). Hope it is useful to somebody; nothing lost if it's not.

Quote


// Software PWM for the Arduino Atmel 328p @ 16MHz
//
// Women's Fashion Art Dev team
// 7 January 2013
// 
// Default settings: 
// volatile byte Maximum_Resolution_In_Percent = 50;
// byte Duty_Cycle_In_Percent = 50;
//
// Measured performance
// Freq: 3.27kHz
// Duty: 49.9%
// Vrms: 2.44V
// Vpp: 5.02V
// Vmin: 80.0 mV
// Vmax: 5.12V
// Vavg: 2.60V
// Target: Arduino Duemilanove - genuine
//
// Version 1.0 - 18 December 2012
//

#include <io.h>

// Variables
volatile byte Count;

// User variables - change these to suit
// volatiles
//
volatile byte Pin = 9;
volatile byte HighCount = 0;
volatile byte Maximum_Resolution_In_Percent = 50; // do not exceed 100% here...

// non volatiles
//
byte Duty_Cycle_In_Percent = 50; // do not exceed 100% here either...

// Setup routine
//
void setup(){

  // Set user's preferred pin to output
  //
  pinMode(Pin, OUTPUT);

  // Set up the high count
  HighCount = DoCalcs(Maximum_Resolution_In_Percent, Duty_Cycle_In_Percent);
  
  // Clear interrupts
  //
  cli();

  // Configure timer registers
  //
  TCCR2A = 0;//
  TCCR2B = 0;//
  TCNT2  = 0;//
  
  // set compare match register
  // OCR2A = 99; // 200 Hz at 100% or 400 Hz at 50%
  // OCR2A = 49; // 400 Hz at 100% or 800 Hz at 50%
  // OCR2A = 24; // 800 Hz at 100% or 1.6 Khz at 50%
   OCR2A = 11; // 1.6 kHz at 100% or 3.2 kHz at 50%   

  // CTC mode
  //
  TCCR2A |= (1 << WGM21);
  //CS11 bit for 8 prescaler
  //
  TCCR2B |= (1 << CS11);   
  // timer compare interrupt
  //
  TIMSK2 |= (1 << OCIE2A);

  // Re-enable interrupts
  //
  sei();
  
  // Create a dependable PWM sequence
  //
  digitalWrite(Pin, HIGH); // Start off with a high pulse
}

// Interrupt Service Vector (IDE preset)
//
ISR(TIMER2_COMPA_vect){

  // PWM High / Low Routine
  // Pull pin low once HighCount is achieved
  //
  if (Count == HighCount) {
    digitalWrite(Pin, LOW);
  }
  // Pull pin high once at the end of our resolution count
  //
  else if (Count == Maximum_Resolution_In_Percent) {
    digitalWrite(Pin, HIGH);
    Count = 0;
  }
    // Bump count by 1
    //
    Count += 1;
}

// Subroutines
//
int DoCalcs (byte Resolution, byte DutyCycle)
{
    // Set up the high count
  return (Duty_Cycle_In_Percent / (100 / Maximum_Resolution_In_Percent));
}

// Main loop
// This does nothing at present, but can add other stuff to this
// depending on how hard the timer is being driven....
//
void loop()
{
  while (1);
  {
    // do other stuff here
  }
}




Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 07, 2013, 08:09 am
@SelfOnlyPath:
Yes we know. However, sometimes it is desirable - for example for PCB layout purposes - to be able to use a user-assigned pin. In some cases that will allow you to use a single-sided board instead of double, or a double-sided board in place of 4 layers. We take a rather holistic approach to such things and this is only one of several libraries - each with a specific purpose. We chose to list this one because it is the most flexible for users not familiar with the timers on these chips.
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 07, 2013, 08:37 am
@SelfOnlyPath:
Points taken. Frankly, if we needed jitter-free PWM we'd either use a dedicated chip (i.e. the uM-PWM) or drive an interrupt with a high precision crystal at the MCU's highest priority level. Personally I'd never rely on a software timer inside an MCU for highly time-critical PWM - no matter what anyone suggests. A nice 10Mhz crystal running through a /10 would give you a nice clean and (if temperature controlled) highly predictable reference signal that is ns accurate with a small correction lookup table (if needed).

If you want high precision, jitter free, you have to - in my humble view - look outside the MCU software counters at any rate. As noted hereinbefore, jitter is the least of our problems; we have up to 1.5% tolerance - well within the MCU's software capabilities for our timeframes (down to 1/125th of a second).
Title: Re: Timer Interrupts on Due
Post by: WomensFashionArt on Jan 07, 2013, 08:50 am
@SelfOnlyPath:
Thanks for your expert help. All the best.
Title: Only fires once, when not in test code
Post by: MarkEMarkEMark on Jan 23, 2013, 09:19 pm
Hi all. I've implemented Sebastian Vik & cmaglie's timer code. I've got it working as is, with the LED. And I also tried a Serial.println and that works fine too.

However after transplanting the code to something more meaty (RGB Pixel light string) - the TC3_Handler only executes once.

The LEDs driver is using the hardware SPI channel - could it be anything to do with that? To rule out a clash of interrupts with the LED driver, I tried TC4/5 then TC0, but I still only get the first frame.

Any ideas? I'll post a video of the lights, if I get it working. (The code works otherwise - if I base the timer on time, it works fine)

I'll post the code, but you'd need the lights to see it:

https://github.com/MarkEMarkEMark/WS2801MEO

(note the previous version of the code works without the timer)
Title: Re: Timer Interrupts on Due
Post by: gst0098 on Jan 24, 2013, 05:34 pm
Hi to all, I'm new to the arduino environment, I own an arduino due, I made some experiments with interrupts, apparently I cannot get the frequency higher than 250kHz, is this a known limit of the hardware ? I'm missing something, I read the datasheet and it states that TC_CMR_TCCLKS_TIMER_CLOCK1 is 84MHz / 2 = 41MHz so I was hoping that setting appropriately RA and RC (in my case 20 and 41 respectively) I would be able to acquire timer interrupts at 1MHz frequency.

Where am I wrong ?

Thanks in advance,
Giuseppe
Title: Re: Timer Interrupts on Due
Post by: gst0098 on Jan 25, 2013, 12:08 pm
I answer myself, I was wrong, with correct values the timer interrupt can be triggered at 1MHz.
The problem was that the analogWrite is too slow to go to that frequency, so I digged into the arduino/sam7core sources and found how to use the SAM library directly, the code (much fast) that I wrote is:

// This function to configure a Timer was given some replies above, I changed only the used CLOCK.
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_CLOCK1);
  uint32_t rc = VARIANT_MCK/2/frequency; //2 because we selected TIMER_CLOCK1 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);
}

volatile boolean l;

void TC3_Handler()
{
  TC_GetStatus(TC1, 0);
  dacc_write_conversion_data(DAC0, (l = !l)*4095);
}

void setup() {
  Serial.begin(115200);
  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, 0);
  dacc_set_timing(DACC_INTERFACE, 0x0, 1, 0x0);

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

  // Start timer. Parameters are:

  // TC1 : timer counter. Can be TC0, TC1 or TC2
  // 0   : channel. Can be 0, 1 or 2
  // TC3_IRQn: irq number. See table.
  // 40  : frequency (in Hz)
  // The interrupt service routine is TC3_Handler. See table.

  startTimer(TC1, 0, TC3_IRQn, 1000000);
}


Thanks to all,
Giuseppe Stanghellini
Title: Re: Timer Interrupts on Due
Post by: DuaneB on Jan 27, 2013, 08:15 am
what does this compile to ?

Code: [Select]
dacc_write_conversion_data(DAC0, (l = !l)*4095);

why not l = ~l;

with l initialised to 4095 -it should be a lot faster.

Duane B

rcarduino.blogspot.com (http://rcarduino.blogspot.com)
Title: Re: Timer Interrupts on Due
Post by: gst0098 on Jan 30, 2013, 04:19 pm

what does this compile to ?

Code: [Select]
dacc_write_conversion_data(DAC0, (l = !l)*4095);

why not l = ~l;

with l initialised to 4095 -it should be a lot faster.

Duane B

rcarduino.blogspot.com (http://rcarduino.blogspot.com)


Good point! Nevertheless the code was timing correctly at 1MHz. Checked with a picoscope,

Giuseppe
Title: Re: Timer Interrupts on Due
Post by: mickeu on Feb 17, 2013, 08:45 pm
Quote
// Set pulse width to 50%
  PWM_Percent = 50;


How to change it to micro seconds?

Thanks in advance
Title: Re: Timer Interrupts on Due
Post by: SomeRandomGuy on Feb 19, 2013, 06:45 am
My classmate and I have written a timer library that encapsulates cmaglie's "Black Magic" code and allows the user to pass their own function that they want to be executed by the timer as a function pointer. I have included an example program that shows how this is used. It also cleanly allows the user to start multiple timers for multiple functions in the same sketch. I would appreciate any suggestions, criticism, comments, etc.

Thanks!
Title: Re: Timer Interrupts on Due
Post by: MarkEMarkEMark on Feb 23, 2013, 06:30 pm
Hi SomeRandomGuy.

That looks pretty good to me! I've already implemented two timers in my own code - one for lights and the other to debounce/read some buttons. I think that your library will make things much neater. I'll try it next weekend.
Title: Re: Timer Interrupts on Due
Post by: MarkEMarkEMark on Feb 24, 2013, 05:41 pm
I had a chance to use your timer, SomeRandomGuy. It works perfectly, and has tidied up my code somewhat.
Title: Re: Timer Interrupts on Due
Post by: SomeRandomGuy on Feb 24, 2013, 09:40 pm
Thanks for the feedback! Good to know that it is working well. If anyone thinks of some useful additions or improvements, I would be happy to add those in.

Thanks for taking a look at it.
Title: Re: Timer Interrupts on Due
Post by: CakeBoss on Feb 28, 2013, 12:39 am
Thanks alot for all the activity on this post. This is the first time I used timers and all I could find were explainations on how to do it on the atmega328. I read the datasheet but couldnt make up how to do it on the due, so this helped alot!
Title: Re: Timer Interrupts on Due
Post by: BKM on Feb 28, 2013, 10:33 pm
Nice library - thank you for sharing it.

One idea: it would be nice if startTimer() picked the clock source with the least error, given the desired frequency (credit for this idea goes to RCArduino - see comments in http://rcarduino.blogspot.com/2012/12/arduino-due-dds-part-1-sinewaves-and.html).

I hacked together some code to demonstrate it.   Caveat:  I'm an arduino newb.


Code: [Select]

/*
* pick clock that provides the least error for specified frequency.
*/
uint8_t pickClock(uint32_t frequency, uint32_t& retRC)
{
/*
Timer Definition
TIMER_CLOCK1 MCK/2
TIMER_CLOCK2 MCK/8
TIMER_CLOCK3 MCK/32
TIMER_CLOCK4 MCK/128
*/

struct {
uint8_t flag;
uint8_t divisor;
} clockConfig[] = {
{ TC_CMR_TCCLKS_TIMER_CLOCK1, 2 },
{ TC_CMR_TCCLKS_TIMER_CLOCK2, 8 },
{ TC_CMR_TCCLKS_TIMER_CLOCK3, 32 },
{ TC_CMR_TCCLKS_TIMER_CLOCK4, 128 }
};

int clkId = 3;
int bestClock = 3;
float bestError = 1.0;

do {
float ticks = (float) VARIANT_MCK / (float) frequency / (float) clockConfig[clkId].divisor;
float error = abs(ticks - round(ticks));
if (abs(error) < bestError) {
bestClock = clkId;
bestError = error;
}
} while (clkId-- > 0);

float ticks = (float) VARIANT_MCK / (float) frequency / (float) clockConfig[bestClock].divisor;
retRC = (uint32_t) round(ticks);
return clockConfig[bestClock].flag;
}

void startTimer(Tc *tc, uint32_t channel, IRQn_Type irq, uint32_t frequency, volatile void (*function)())
{
pmc_set_writeprotect(false);
pmc_enable_periph_clk((uint32_t)irq);

uint32_t rc = 0;
uint8_t clock = pickClock(frequency, rc);
TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | clock);

... remainder of startTimer() unchanged ...

}
Title: Re: Timer Interrupts on Due
Post by: SomeRandomGuy on Mar 01, 2013, 04:27 am
Thanks for the idea BKM! I have added it to the library along with several other major improvements that should completely remove any IRQ references from the sketches and make it much cleaner and more user friendly. I will attach a link to my github repo tomorrow night once I get to test it a little bit.
Title: Re: Timer Interrupts on Due
Post by: SomeRandomGuy on Mar 02, 2013, 05:51 am
Here is a link to the new library version: https://github.com/SomeRandomGuy/DueTimer (https://github.com/SomeRandomGuy/DueTimer)

When you download this, remove the "-master" part of the folder name so that it will show up correctly in the Arduino IDE and drag it into your libraries folder.

This has several new improvements. I would love some more testing/feedback if any of you get a chance.

Hope this is helpful!

SRG
Title: Re: Timer Interrupts on Due
Post by: SimonCino on Mar 03, 2013, 06:15 pm
Great library, Thank you very much for sharing it!

I noted that the function startTimer accepts as parameter the frequency at which the ISR is executed so I figure out that the maximum time between two consecutive calls of the ISR is 1 second. If I would like to executed some code at intervals of more than one second this should be managed inside the function corresponding to the ISR?

Thanks again,

Simon
Title: Re: Timer Interrupts on Due
Post by: OptimusPrime on Mar 06, 2013, 08:05 pm
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? :)
Thanks a lot!
Title: Re: Timer Interrupts on Due
Post by: dayta_eng on Mar 08, 2013, 04:55 pm

Here is a link to the new library version: https://github.com/SomeRandomGuy/DueTimer (https://github.com/SomeRandomGuy/DueTimer)


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?
Title: Re: Timer Interrupts on Due
Post by: yuyu900726 on Mar 11, 2013, 09:54 pm
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.  =( =( =( =( =(   


Title: Re: Timer Interrupts on Due
Post by: BKM on Mar 12, 2013, 12:00 am
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


Title: Re: Timer Interrupts on Due
Post by: robertspark on Mar 12, 2013, 01:22 am
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
Title: Re: Timer Interrupts on Due
Post by: yuyu900726 on Mar 12, 2013, 11:11 am

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?
Title: Re: Timer Interrupts on Due
Post by: BKM on Mar 12, 2013, 04:42 pm
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
 
Title: Re: Timer Interrupts on Due
Post by: yuyu900726 on Mar 13, 2013, 06:17 am
Thank you very much!  Seems like I have a lot of homework to do.

Best,
Tian
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Mar 24, 2013, 05:23 pm
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! :(

Any solution that can help me please?

Thanks!
Title: NEW DueTimer LIBRARY
Post by: ivanseidel on Mar 30, 2013, 11:09 pm
Hi!
As i like libraries, i have done one to the Arduino DUE.

You can check it out here: https://github.com/ivanseidel/DueTimer

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

Thanks for the tips on the topic! I will put your names there
Title: Re: Timer Interrupts on Due
Post by: cmaglie on Apr 03, 2013, 01:38 am
ivanseidel,

nice library!

Why don't you add also TC2 to the set of TImers? this will makes available other 3 timers.
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 03, 2013, 02:07 am
Good idea... will do it now =]
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 03, 2013, 03:05 am
Done!  :)
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 03, 2013, 09:32 pm
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);
}





Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 03, 2013, 11:34 pm
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.


Code: [Select]


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   

}
       
       
}
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 11, 2013, 12:26 am

I think I'm getting somewhere with this... try this:
Code: [Select]

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.
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 12, 2013, 02:08 am
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: https://github.com/ivanseidel/DueTimer

Hope it helps! (Library is commented, so it might help...)
Title: Re: Timer Interrupts on Due
Post by: rgbp on Apr 12, 2013, 03:20 am
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

Code: [Select]
//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(){

}

Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 12, 2013, 04:26 am

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

Code: [Select]
//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)
=]
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 12, 2013, 05:13 am

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: https://github.com/ivanseidel/DueTimer

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.


Code: [Select]




/*
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...
}

}

Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 12, 2013, 07:50 am
Hi,
Apparently you have only included the header file... no implementation is made to the class DueTimer.
Why did you added the header to the code, instead of including the library? Did it compiled? Did you installed the library correcly, and examples are on the examples menu of arduino IDE?
Ivan
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 12, 2013, 05:07 pm

Hi,
Apparently you have only included the header file... no implementation is made to the class DueTimer.
Why did you added the header to the code, instead of including the library? Did it compiled? Did you installed the library correcly, and examples are on the examples menu of arduino IDE?
Ivan


Dear Ivan,


Let me explain you what exactly I do. I go to the Simple Timer and copy and paste it in a new Arduino page and save on my desktop. (It has the header #include <DueTimer.h>)

Thereafter, I go to the header file and save it on the desktop as well beside the Simple Timer.

But when I run it has the following error:

fatal error: DueTimer.h: No such file or directory compilation terminated.


Can you please kindly advise me about this?

Thanks.
Title: Re: Timer Interrupts on Due
Post by: TheKitty on Apr 12, 2013, 06:23 pm
Henrimontreal, you are only getting the header - you need all the code which is packaged up as a library and placed within the Arduino IDE Library folder prior to writing your program.  See http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use on libraries and how they are used.  Then you can get the timer library, install it like in the tutorial, then your code will not give such error(s).  Putting the .h file on your desktop is not enough.
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 14, 2013, 06:03 pm

Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

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

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12





As you said:

TC6   TC2   0   4, 5


but when I change TC  to TC2 and choose channel 0 and choose either 4 or 5 pin it does not blink!

Do I need to change the clock as well?  Actually we do not have clock 6!!!

Can you please explain me how can I get frequency from the other channels and timers please?

Thanks!
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 14, 2013, 06:05 pm

Henrimontreal, you are only getting the header - you need all the code which is packaged up as a library and placed within the Arduino IDE Library folder prior to writing your program.  See http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use on libraries and how they are used.  Then you can get the timer library, install it like in the tutorial, then your code will not give such error(s).  Putting the .h file on your desktop is not enough.


Well, this is so strange! Even though, I copy them into the Arduino's Library as well as the same folder on my desktop. I still have the same error!  :smiley-eek:  I am so frustrated!  :smiley-yell:
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 14, 2013, 07:41 pm


Henrimontreal, you are only getting the header - you need all the code which is packaged up as a library and placed within the Arduino IDE Library folder prior to writing your program.  See http://learn.adafruit.com/adafruit-all-about-arduino-libraries-install-use on libraries and how they are used.  Then you can get the timer library, install it like in the tutorial, then your code will not give such error(s).  Putting the .h file on your desktop is not enough.


Well, this is so strange! Even though, I copy them into the Arduino's Library as well as the same folder on my desktop. I still have the same error!  :smiley-eek:  I am so frustrated!  :smiley-yell:


Hi,
I have sent a new commit to GitHub, with a new organization to facilitate installation.
Please, download egain (https://github.com/ivanseidel/DueTimer/archive/master.zip) the files, and install as explained on Arduino site.

Thanks,
Ivan Seidel
Title: Re: Timer Interrupts on Due
Post by: MarXoft on Apr 15, 2013, 05:52 pm
Thanks guys for this mission. I got 1 MHz working on the DUE, but I found that digitalWrite is slow. So it messes up my tc_handler. Doesn't leave it anymore. And I need to write in the ISR, maximum control every microsecond. You have a fast alternative for digitalWrite ?
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 15, 2013, 06:10 pm

Thanks guys for this mission. I got 1 MHz working on the DUE, but I found that digitalWrite is slow. So it messes up my tc_handler. Doesn't leave it anymore. And I need to write in the ISR, maximum control every microsecond. You have a fast alternative for digitalWrite ?


after configuring the pin, you can easily do as it follows:

Output HIGH on PIN 0 of port D:
REG_PIOD_SODR = 0x01; ( equivalent to: 0b0000000000000001);

Output low on PIN 0 of port D:
REG_PIOD_CODR = 0x01; ( equivalent to: 0b0000000000000001);

And, to configure PIN 0 of port D as output pin:
REG_PIOD_OER = 0x01; ( equivalent to: 0b0000000000000001);

Notice, that even digital pins are buffered, so, trying to read this register, will return NULL or some random value...

Also, writing more than one pin on the register will cause NO problem.

Also, to know wich port the pin relates with, read the arduino description, right on top, there is an link to check this...

There is one other easy way of doing this, but i'm without a computer right now...
Title: Re: Timer Interrupts on Due
Post by: stimmer on Apr 15, 2013, 07:18 pm

Thanks guys for this mission. I got 1 MHz working on the DUE, but I found that digitalWrite is slow. So it messes up my tc_handler. Doesn't leave it anymore. And I need to write in the ISR, maximum control every microsecond. You have a fast alternative for digitalWrite ?


digitalWriteDirect() will work faster than 1MHz, although it may be a challenge to get it that fast in an interrupt due to overhead. Try it anyway.

Code: [Select]
inline void digitalWriteDirect(int pin, boolean val){
  if(val) g_APinDescription[pin].pPort -> PIO_SODR = g_APinDescription[pin].ulPin;
  else    g_APinDescription[pin].pPort -> PIO_CODR = g_APinDescription[pin].ulPin;
}

inline int digitalReadDirect(int pin){
  return !!(g_APinDescription[pin].pPort -> PIO_PDSR & g_APinDescription[pin].ulPin);
}
Title: Re: Timer Interrupts on Due
Post by: MarXoft on Apr 16, 2013, 06:30 pm
Thanks for the fast reply. When I have the time I'll try.

-= Keep the good work goin' =-
Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 20, 2013, 10:08 pm


Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
       TC_GetStatus(TC1, 0);
       digitalWrite(13, l = !l);
}

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

void setup(){
       pinMode(13,OUTPUT);
       startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12



Noob question here, could someone please explain the inputs to the startTimer function? What is channel, and how do we use the frequency input?  Also, what are the pins in the table for?



Can anyone kindly answer to the following question please?
How can we disable the Timer by turning off the PWM? (Outside of Timer Function)

Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Apr 20, 2013, 10:12 pm



Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
       TC_GetStatus(TC1, 0);
       digitalWrite(13, l = !l);
}

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

void setup(){
       pinMode(13,OUTPUT);
       startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12



Noob question here, could someone please explain the inputs to the startTimer function? What is channel, and how do we use the frequency input?  Also, what are the pins in the table for?



Can anyone kindly answer to the following question please?
How can we disable the Timer by turning off the PWM? (Outside of Timer Function)




Hi,

If it's really needed to understand the code, i suggest you looking at the Datasheet, that is the best place to get those explanations since every uController is different.

But, if you just want to use timers on arduino Due, install the DueTimer library: github.com/ivanseidel/DueTimer

Regards,
Ivan
Title: Re: Timer Interrupts on Due
Post by: ant900 on Apr 20, 2013, 10:29 pm

Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

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

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12




I'm a bit confused about the code for the startTimer function.

-What is the purpose of TC3_Handler() and how does it interact with startTimer()?
-Once startTimer() is called, how do I stop the timer(how do I disable PWM)?
-There's a few lines that I don't understand in startTimer():


Code: [Select]


        TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4); <--- How does TC_Configure() work? Where can I find reference about this?
        uint32_t rc = VARIANT_MCK/128/frequency; <---------- is VARIANT_MCK the frequency of arduino DUE(84MHz)? What does rc do?
        TC_SetRA(tc, channel, rc/2); //50% high, 50% low<----sets the duty cycle?
        TC_SetRC(tc, channel, rc);<---------- what is this line for?
        TC_Start(tc, channel);<---------------enables PWM? How does it work?
        tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;<----------What does this line do?
        tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;<--------What does this line do?
        NVIC_EnableIRQ(irq); <-----enables interrupt?

Title: Re: Timer Interrupts on Due
Post by: raalst on Apr 21, 2013, 11:14 pm
  StartTimer starts the timer. this function needs to be called once.
  after Starttimer is finished, the (hardware) timer keeps running on it's own, without any need for code.
  the timer counts up to a certain value, then generates an interrupt, starts with 0 and continues counting.

  TC3_handler is called each time the interrupt of Timer/Counter TC3 (=timer 1 channel 0) is generated by the timer.
  "TC3_handler"  is a pre-determined functionname just like "setup" and "loop"
  because TC3_handler is called for each interrupt, it is called as often as the timer hits that "certain value".
  The lower that value the more often the TC3_handler is executed.

  TC_Configure(tc, channel, TC_CMR_WAVE | TC_CMR_WAVSEL_UP_RC | TC_CMR_TCCLKS_TIMER_CLOCK4);
Read the datasheet paragraph 37.7.11, fields WAVE, WAVSEL, TCCLKS. TC_configure just sets bits in the TC_CMR register that belongs to TC3 (= Timer 1 channel 0 )
 
       uint32_t rc = VARIANT_MCK/128/frequency; <---------- is VARIANT_MCK the frequency of arduino DUE(84MHz)? What does rc do?
Serial.Println(VARIANT_MCK,DEC) will enlighten. spoiler : yes
rc is the value the timer counts towards. it is that "certain value" I mentioned above.

       TC_SetRA(tc, channel, rc/2); //50% high, 50% low<----sets the duty cycle?
yes, see datasheet 37.6.11.1, for instance.

       TC_SetRC(tc, channel, rc);<---------- what is this line for?
it sets the value the timer counts towards. so it defines the frequency of the interrupts generated by the timer

       TC_Start(tc, channel);<---------------enables PWM? How does it work?
no, it starts the timer. the timer begins incrementing now.

       tc->TC_CHANNEL[channel].TC_IER=TC_IER_CPCS;<----------What does this line do?
I'm not sure but I think it sets the flag that specifies an interrupt is desired when timer = rc. IER = interrupt Enable Register

       tc->TC_CHANNEL[channel].TC_IDR=~TC_IER_CPCS;<--------What does this line do?
IDR = interrupt disable register, all other interrupt-types supported by  TC3 are disabled and will not occur.  

       NVIC_EnableIRQ(irq); <-----enables interrupt?
yes. it is the overall enabler, allowing interrupts to be generated by TC3.

Title: Re: Timer Interrupts on Due
Post by: henrimontreal on Apr 24, 2013, 10:26 pm


Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
       TC_GetStatus(TC1, 0);
       digitalWrite(13, l = !l);
}

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

void setup(){
       pinMode(13,OUTPUT);
       startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12



Noob question here, could someone please explain the inputs to the startTimer function? What is channel, and how do we use the frequency input?  Also, what are the pins in the table for?



Guys! can anyone kindly explain me why this code does not work for the frequencies upper than 3 KHZ?

I have tested 1Hz to 3000Hz for the frequency but seems further frequencies it has problem.

What's the acceptable range of frequency?

We did a loop as follows.



void loop() {
 
  startTimer(TC1, 0, TC3_IRQn, 1);
  Serial.println("1Hz");
 delay(5000);

  startTimer(TC1, 0, TC3_IRQn, 4000);     //  LIne 6
   Serial.println("4KHz");
 delay(3000);


 
 
 
 
}

This frequency is used to control the speed of motor.

When we set the second frequency (Line 6 ) to 4000HZ it won't return to the 1HZ as it is supposed to.

We tried 1 to 3KHZ and it works but more than 4KHZ it goes weird!

Any solution please?
Title: Re: Timer Interrupts on Due
Post by: ant900 on May 06, 2013, 09:17 pm
I got frequency between 1-21KHz to work, but I found another problem. I can't get 2 timers to run simultaneously. I ran the startTimer function twice with different handlers, but they refuse to work. Anyone know how to fix this problem?
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on May 07, 2013, 08:28 pm
Try using my Library: https://github.com/ivanseidel/DueTimer
It has everything implemented, revised, and checked... (It's not PERFECT, but if you find any bugs, fell free to notify me!)
Title: Re: Timer Interrupts on Due
Post by: Touf2638 on May 15, 2013, 02:04 pm
Hi,
I tried to use your librairie and it works until 4 us. Under it don't works. On scope I have 2.6us for 2 asked. For 4us I have 4us so it's ok.
It's not possible to put 2 ?
Thanks
Title: Re: Timer Interrupts on Due
Post by: Touf2638 on May 15, 2013, 02:42 pm
Sorry,
I use digitalwrite for my tests instead use port directly and digitalwrite take time  :smiley-roll-blue:
So it works thanks.
Title: Re: Timer Interrupts on Due
Post by: cdan on May 26, 2013, 07:27 pm
Hello everybody.
I am trying to generate a square wave using timer counters but I do not want to use an interrupt, rather I would like to output to go directly to TIOA0. I have the following configuration of the registers
http://paste.ubuntu.com/5703102/

but I get no output on pin 2 of Arduino Due.
What am I missing?

Best regards,
Dan.
Title: Re: Timer Interrupts on Due
Post by: cdan on May 27, 2013, 10:12 pm
Found the bug:
Code: [Select]

  TC_Configure(chTC, chNo,
       TC_CMR_TCCLKS_TIMER_CLOCK4 |
       TC_CMR_WAVE |         // Waveform mode
       TC_CMR_WAVSEL_UP_RC | // Counter running up and reset when equals to RC
       TC_CMR_ACPA_SET |     // RA compare sets TIOA
       TC_CMR_ACPC_CLEAR );  // RC compare clears TIOA


I have to set TC_CMR_ACPA_SET and TC_CMR_ACPC_CLEAR to instruct the counter to change the level on PIOA0 when the counter's value has reached RA/RC
Title: Re: Timer Interrupts on Due
Post by: AndiJay on May 28, 2013, 02:01 am
Where exactly is a function like TC_Configure() or TC_GetStatus() actually defined? Right now, I'm just trying to figure out how to write to specific registers in the Arduino IDE. I may need to do this to change the frequency of a PWM.
Title: Re: Timer Interrupts on Due
Post by: cdan on May 28, 2013, 09:49 am
If you include #include <Arduino.h> you should have access to them.
The source code can be found in:
arduino-1.5.2\hardware\arduino\sam\system\libsam\include\tc.h
arduino-1.5.2\hardware\arduino\sam\system\libsam\source\tc.c
Title: Re: Timer Interrupts on Due
Post by: AndiJay on May 28, 2013, 07:42 pm
I see I see,

Where all all the structs defined? Like tc->xxxx?

Thanks
Title: Re: Timer Interrupts on Due
Post by: cdan on May 29, 2013, 09:33 am
Everything is there. Just do a grep (or file search if not on a *nix os).
The source files even have some comments. You should also have the SAM3X8E datasheet at hand too.
Title: Re: Timer Interrupts on Due
Post by: AFlorencio on May 29, 2013, 03:41 pm

Try using my Library: https://github.com/ivanseidel/DueTimer
It has everything implemented, revised, and checked... (It's not PERFECT, but if you find any bugs, fell free to notify me!)




i try to use your library together whit Servo library  but is dosent  work.

Any idea of how to solve the compatibility issue.
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on May 30, 2013, 03:47 am


Try using my Library: https://github.com/ivanseidel/DueTimer
It has everything implemented, revised, and checked... (It's not PERFECT, but if you find any bugs, fell free to notify me!)




i try to use your library together whit Servo library  but is dosent  work.

Any idea of how to solve the compatibility issue.


I'm investigating...
Title: Re: Timer Interrupts on Due
Post by: exedor on May 31, 2013, 01:00 am
I'm doing this which isn't necessarily making sense to me.

Code: [Select]
void setup() {
  // put your setup code here, to run once:

  startTimer(TC1, 0, TC4_IRQn, 2400); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop() {
  // put your main code here, to run repeatedly:
 
}


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


// Interrupt routine for timer to send data
void TC4_Handler()
{
  int i;

  if (SerialUSB) {
    TC_GetStatus(TC1, 0);
    // ....
  }
}


I would have thought that to use irq4 and TC4_Handler it should be TC1 and channel 1 not channel 0.

Title: Re: Timer Interrupts on Due
Post by: sun152 on Jun 12, 2013, 06:14 pm
Hi,

I have some question about timer interrupt. Please see this post. Thank you.  :)

http://forum.arduino.cc/index.php?topic=171581.0
Title: Re: Timer Interrupts on Due
Post by: elevine on Jul 30, 2013, 09:38 pm

what does this compile to ?

Code: [Select]
dacc_write_conversion_data(DAC0, (l = !l)*4095);

why not l = ~l;

with l initialised to 4095 -it should be a lot faster.

Duane B

rcarduino.blogspot.com (http://rcarduino.blogspot.com)


Does that code even compile for you? I get an error trying to compile:
Invalid conversion from 'uint8_t' to 'Dacc*'
sketch_jul30a.ino: In function 'void TC3_Handler()':
sketch_jul30a:23: error: invalid conversion from 'uint8_t' to 'Dacc*'
sketch_jul30a:23: error: initializing argument 1 of 'void dacc_write_conversion_data(Dacc*, uint32_t)'
Title: Re: Timer Interrupts on Due
Post by: titous on Aug 27, 2013, 09:16 pm
this is a great thread, lots of good info here.  one related question, is it possible to use these timers to simply get elapsed time since program start?  i mean, is there a hardware implementation of micros()?
Title: Re: Timer Interrupts on Due
Post by: garygid on Sep 15, 2013, 08:40 pm
I will try using this DueTimer library today.
Thanks for your work and help.
Title: Re: Timer Interrupts on Due
Post by: garygid on Sep 15, 2013, 10:43 pm
Setting Timer, as in the Simple Example, and using micros() to
measure the time between interrupts.  I get strange results.

Setting 500000 usec, I get 499000 microseconds between
interrupts.  N*1000 (down to around N=3) always gives
me (N-1) *1000 micro seconds.

Are you setting some counter to N, and counting with a millisecond
interrupt?

If I set to 3030 usec, I typically get 2030 usec between interrupts.

Do I need to go back to the first page or two of this thread
and try the direct-to-hardware solution suggested there?

Thanks, Gary
Title: Re: Timer Interrupts on Due
Post by: MarXoft on Oct 08, 2013, 07:32 pm
Dear colleagues,
I'm trying to create a double pulse-generator for testing IGBT's. Writing a pin every uSecond.
I'll show you the code:
Code: [Select]

/**************************************************************************************/
/*                                                                                    */
/*             Bongo II, pulse output on PortA, pin 23                                */
/*                                                                                    */
/*             Port A0, pin 69 Output Pulse                                           */
/*             Port A1, pin 68 Enable Top                                             */
/*             Port A2, pin 61 Enable Bot                                             */
/*             Port A3, pin 60 Enable Pulse                                           */
/*                                                                                    */
/*                                                                                    */
/*                                                                                    */
/*                                                                                    */
/*                                                                                    */
/*                                                                                    */
/**************************************************************************************/

volatile int FTime     = 1000000; // In uSeconds !!
volatile int Freq      = 1;
volatile int PulseFreq;
volatile int Cnt_I     = 0;       

volatile int Pulse1    = 200000;    // uSeconds
volatile int Pause1    = 200000;
volatile int Pulse2    = 200000;

volatile int P1,
             P2,
             P3;
volatile boolean LED;

void setup()
{
  pinMode( 69, OUTPUT );
  pinMode( 68, OUTPUT );
  pinMode( 61, OUTPUT );
  pinMode( 60, OUTPUT );
 
  pinMode( 13, OUTPUT );

  PulseFreq = FTime / Freq ;
 
  P1 = Pulse1 ;
  P2 = Pulse1 + Pause1;
  P3 = Pulse1 + Pause1 + Pulse2;
 
  REG_PIOA_OWER = 0x0000000F;
  REG_PIOA_OWDR = 0xFFFFFFF0;

  REG_PIOD_OWER = 0x00000001;
  REG_PIOD_OWDR = 0xFFFFFFFE;


  startTimer(TC1, 0, TC3_IRQn, 1000000 ); // Start 1 MHz interrupt timer
 

}

void loop()
{
  digitalWrite( 13, LED = !LED );
  REG_PIOD_ODSR = 0x0001;
  delay( 1000 );
 
  REG_PIOD_ODSR = 0x0000;
  delay( 1000 );
}


//----------------------------------------------------------------------------------------------
//
//   Initialize the interrupt for every uSecond
//
//----------------------------------------------------------------------------------------------

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_CLOCK3);
  uint32_t rc = VARIANT_MCK/32/frequency; // 32 because we selected TIMER_CLOCK3 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);
}

//----------------------------------------------------------------------------------------------
//
//      The actual InterruptRoutine. Just count and write
//
//----------------------------------------------------------------------------------------------

void TC3_Handler()
{
  if( Cnt_I > PulseFreq )
    Cnt_I = 0;

  if( Cnt_I < P1 )
    REG_PIOA_ODSR = 0x0001;                // First puls on
  else
    if( Cnt_I < P2 )
      REG_PIOA_ODSR = 0x0000;              // Pause
    else
      if( Cnt_I < P3 )
        REG_PIOA_ODSR = 0x0001;            // Second puls on
      else
        REG_PIOA_ODSR = 0x0000;            // Interbellum....

  Cnt_I++;
}


Now the thing is, I got a beautiful double-puls on my output, but for the rest: Nothing.
The Loop-thing is totally avoided.

Someone got ideas....
Title: Re: Timer Interrupts on Due
Post by: Tejas_Kulkarni on Nov 30, 2013, 05:33 pm
Hi guys.. I'm new to Arduino Due and was wondering if there is any way to output a clock signal directly on one of the pins without using any interrupts.
My code uses timer interrupts already so I cannot use timer interrupts to output a clock signal.
Is there any way?
Thanks in advance.
Title: Re: Timer Interrupts on Due
Post by: cdan on Dec 01, 2013, 02:59 pm

Hi guys.. I'm new to Arduino Due and was wondering if there is any way to output a clock signal directly on one of the pins without using any interrupts.


Yes, it is possible through using the timer counter channels.
"Each channel can be independently pro-
grammed, through its two operating modes, to perform a wide range of functions
including frequency measurement, event counting, interval measurement, pulse gen-
eration
, delay timing, pulse width modulation and interrupt generation."

Please have a look at
http://www.atmel.com/Images/doc2682.pdf
Title: Re: Timer Interrupts on Due
Post by: kalo86 on Dec 04, 2013, 11:42 am
Hello people,
I would like to calculate the duration of an event on my Arduino DUE board.
I'm using a Hall Effect Sensor to read the RPM (revolutions per minute) of a crankshaft.
I want to calculate the RPM in this way:

T1 ---> this is the right time (it may be zero) when the hall sensor sees the magnet; a timer needs to be started since now;
T2 ---> this is the duration between two transitions of the magnet (duration for 1 revolution);
duration = T2 - T1;
RPM = 360 / duration;

I'd like to manage the output of the Hall sensor with interrupts:

Code: [Select]


void loop() {
attachInterrupt(hall_pin, start_timer, FALLING);
}

void start_timer {
execute_code_to_start_the_timer;
//here I get the value of T1 or I can simply reset the timer to impose T1 = 0
detachInterrupt(hall_pin);
attachInterrupt(hall_pin, stop_timer, FALLING);
}

void stop_timer() {
execute_code_to_stop_the_timer;
//here I get the duration between two consecutive pulses
detachInterrupt(hall_pin);
loop();
}


Can someone help me with this algorithm? Thanks in advance,

kalo86
Title: Re: Timer Interrupts on Due
Post by: garygid on Dec 04, 2013, 05:25 pm
Put the attach hall-interrupt in the setup routine, not the loop.
and, measure the milliseconds T1 before the attachment

In the loop, display the RPM.

In the interrupt, measure the milliseconds T2
do not enable or disable the interrupt, just leave it going.
If T2 >  T1 then Calculate RPM = 60000 / (T2 - T1)
then, set T1 = T2
to wait for the next interrupt
Title: Re: Timer Interrupts on Due
Post by: kalo86 on Dec 04, 2013, 05:46 pm

Put the attach hall-interrupt in the setup routine, not the loop.
and, measure the milliseconds T1 before the attachment

In the loop, display the RPM.

In the interrupt, measure the milliseconds T2
do not enable or disable the interrupt, just leave it going.
If T2 >  T1 then Calculate RPM = 60000 / (T2 - T1)
then, set T1 = T2
to wait for the next interrupt


Thank you very much, your help is much appreciated.
Can be "good" this sketch example?

Code: [Select]

void setup() {
T1 = micros();
attachInterrupt(hall_pin, duration, FALLING);
}

void loop() {
RPM = 60e6 / (T2 - T1);
code here for LCD ; // display RPM on LCD
T1 = T2;
}

void duration() {
T2 = micros();
}



Title: Re: Timer Interrupts on Due
Post by: jstampfl on Dec 06, 2013, 07:38 am
I have done a few modifications to the Due_Timers library, but I can't contact Ivan.  I want to help with this library.
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Dec 08, 2013, 03:40 pm

I have done a few modifications to the Due_Timers library, but I can't contact Ivan.  I want to help with this library.


Hi!

Sorry for the delay (if you sent me an email, I haven't got time to answer it yet...)

About the changes, I will be happy to review it and commit to the master branch of the repository. Could you kindly submit a new commit and a merge request?

Thanks!
Title: Re: Timer Interrupts on Due
Post by: ivanseidel on Mar 25, 2014, 01:44 pm
Hello,

Because there are some people with this problem, I made a modification on DueTimer that will allow you to put to work both Servo and DueTimer together.

I didn't have time to test, but I'm pretty sure everything will work just fine.

Here is the documentation on how to make it work: https://github.com/ivanseidel/DueTimer#compatibility-with-servoh (https://github.com/ivanseidel/DueTimer#compatibility-with-servoh)
Title: Re: Timer Interrupts on Due
Post by: astrodan on May 26, 2014, 04:59 pm
Hey just wanted to say thanks to all on this thread. I just finished building a theremin like instrument with an Arduino Due
http://2manyprojects.net/theremin-1 (http://2manyprojects.net/theremin-1) .

I would never have completed this project without all the info I got here. It uses two different timer interrupts, one at 44.1 kHz, and one every 20 mS. The 44.1 kHz is for actually playing the tone using granular synthesis ( only one grain ), I got started with the "RCArduino Quick And Dirty Synth for Arduino Due"
http://rcarduino.blogspot.com/2012/11/quick-and-dirty-synth-for-arduino-due.html (http://rcarduino.blogspot.com/2012/11/quick-and-dirty-synth-for-arduino-due.html).

The 20 mS interrupt is used to control a servo, this is done to demonstrate how to play a song. ( it will make sense if watch the video here http://2manyprojects.net/rtttl (http://2manyprojects.net/rtttl) ). 

I also wrote up a tutorial on making a LED flash SOS using timer interrupts.
http://2manyprojects.net/timer-interrupts (http://2manyprojects.net/timer-interrupts) .

Thanks Again
Danny
Title: Re: Timer Interrupts on Due
Post by: cdan on Aug 01, 2014, 11:17 pm

Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

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

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:











ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12



Is there any interference between Timer interrupts and arduino's Serial library? Using this function (see above) to set any timer except TC1 CH0 will cause Serial.available() to stop functioning. Is this a known problem?

Best regards,
Dan.
Title: Re: Timer Interrupts on Due
Post by: WesBrooks on Aug 05, 2014, 11:53 am
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!

Title: Re: Timer Interrupts on Due
Post by: stan_w_gifford on Aug 23, 2014, 03:41 am
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...
   }
   
}
Title: Re: Timer Interrupts on Due
Post by: stan_w_gifford on Aug 24, 2014, 01:45 am
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);
}
Title: Re: Timer Interrupts on Due
Post by: stan_w_gifford on Aug 25, 2014, 01:07 pm
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(){
}
Title: Re: Timer Interrupts on Due
Post by: stan_w_gifford on Aug 28, 2014, 04:21 am
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
Title: Re: Timer Interrupts on Due
Post by: interrupt on Aug 29, 2014, 03:38 pm
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?) :smiley-eek:


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
}

Title: Re: Timer Interrupts on Due
Post by: interrupt on Sep 02, 2014, 08:40 pm
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

Code: [Select]

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?:
Code: [Select]
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 - ????



Title: Re: Timer Interrupts on Due
Post by: stan_w_gifford on Sep 09, 2014, 07:28 am
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
   
Title: Re: Timer Interrupts on Due
Post by: otobus on Sep 16, 2014, 12:13 pm
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.
Title: Re: Timer Interrupts on Due
Post by: eniba on Nov 30, 2014, 10:36 pm
Hallo,

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

Thanks.

Title: Re: Timer Interrupts on Due
Post by: TheRevva on May 18, 2015, 01:33 am
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:
Code: [Select]

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:
Code: [Select]

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).
Title: Re: Timer Interrupts on Due
Post by: ss13 on Jun 11, 2015, 11:05 pm
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
Title: Re: Timer Interrupts on Due
Post by: youthreewire on Jun 21, 2015, 12:32 pm
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.
'
Code: [Select]
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);
}
Title: Re: Timer Interrupts on Due
Post by: sayrol on Jul 05, 2015, 12:59 pm
Using this code, you can set a timer for any of the ISRs TC0_Handler through TC8_Handler, see table of parameters below. It is possible to use the timers without a physically mapped pin, such as TC1 channel 0 (TC3_Handler) shown here:

Code: [Select]

volatile boolean l;

//TC1 ch 0
void TC3_Handler()
{
        TC_GetStatus(TC1, 0);
        digitalWrite(13, l = !l);
}

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

void setup(){
        pinMode(13,OUTPUT);
        startTimer(TC1, 0, TC3_IRQn, 4); //TC1 channel 0, the IRQ for that channel and the desired frequency
}

void loop(){
}


Here is the table of parameters:
ISR/IRQTC        ChannelDue pins
TC0TC002, 13
TC1TC0160, 61
TC2TC0258
TC3TC10none  <- this line in the example above
TC4TC11none
TC5TC12none
TC6TC204, 5
TC7TC213, 10
TC8TC2211, 12

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.
Title: Re: Timer Interrupts on Due
Post by: Wurstnase on Jul 08, 2015, 01:58 pm
Quote
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.
Title: Re: Timer Interrupts on Due
Post by: RustyBody on Oct 20, 2015, 05:51 pm
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
Title: Re: Timer Interrupts on Due
Post by: steadyState on Mar 18, 2017, 10:29 am

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
Title: Re: Timer Interrupts on Due
Post by: ard_newbie on Mar 19, 2017, 06:43 am

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 )
Title: Re: Timer Interrupts on Due
Post by: steadyState on Mar 19, 2017, 09:46 am
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... ;-)

Thank you very much, that makes it clear.
Title: Re: Timer Interrupts on Due
Post by: terryz on Nov 03, 2017, 09:00 pm
Here is another resource on using Due timers.


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