Timer Interrupts on Due

I'm doing this which isn't necessarily making sense to me.

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.

Hi,

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

http://forum.arduino.cc/index.php?topic=171581.0

DuaneB:
what does this compile to ?

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

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

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()?

I will try using this DueTimer library today.
Thanks for your work and help.

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

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:

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

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.

Tejas_Kulkarni:
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

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:

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

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

garygid:
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?

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

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

jstampfl:
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!

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: GitHub - ivanseidel/DueTimer: ⏳ Timer Library fully implemented for Arduino DUE

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 .

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"
RCArduino: Quick And Dirty Synth For Arduino Due.

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

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

Thanks Again
Danny

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.

Very useful thread, thanks all.

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

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

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

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

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

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

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

(master clock freq) / (clock divider)

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

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

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

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

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

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

So the minimum time between of interupts is:

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

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

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

EDIT: 32 bits is 4294967295, not 65535!

1 Like

Hi - have just about run out of ideas.

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

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

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

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

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

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

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

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

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

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

Modified example:

#include <DueTimer.h>

int myLed = 13;

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

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

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

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

void loop(){

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

}

Getting closer.

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

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

#ifndef DUE_SERVO_H
#define DUE_SERVO_H

#include <Arduino.h>

#define PWM_DUTY_MIN 1
#define PWM_DUTY_MAX 2400

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

#endif

#define PWM_CLOCK 48000000
#define PWM_PERIOD 20

static bool PWMEnabled = false;

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

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

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

if(channel == NOT_ON_PWM)
return;

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

PWMC_SetDutyCycle(PWM_INTERFACE, channel, dutyCycle);
}

#define SERVO_PIN 6
bool high = false;

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

void loop() {

delay(500);
}