Timer Interrupts on Due

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

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.

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

AFlorencio:

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

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