Timer Interrupts on Due

TheKitty: 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! :astonished: I am so frustrated! :stuck_out_tongue_closed_eyes:

henrimontreal:

TheKitty: 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! :astonished: I am so frustrated! :stuck_out_tongue_closed_eyes:

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

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 ?

MarXoft: 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...

MarXoft: 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.

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

Thanks for the fast reply. When I have the time I'll try.

-= Keep the good work goin' =-

mnpumar: [quote author=Sebastian Vik link=topic=130423.msg984328#msg984328 date=1352148520] 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:

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

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? [/quote]

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

henrimontreal:

mnpumar: [quote author=Sebastian Vik link=topic=130423.msg984328#msg984328 date=1352148520] 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:

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


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)

[/quote]

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

[quote author=Sebastian Vik link=topic=130423.msg984328#msg984328 date=1352148520] 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:

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

[/quote]

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

        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?

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.

mnpumar: [quote author=Sebastian Vik link=topic=130423.msg984328#msg984328 date=1352148520] 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:

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

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? [/quote]

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?

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?

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

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

Sorry, I use digitalwrite for my tests instead use port directly and digitalwrite take time :roll_eyes: So it works thanks.

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.

Found the bug:

  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

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.

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

I see I see,

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

Thanks