Writing a delay with timer

Go To Last Post
5 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello,

 

I want to write a basic delay method to get a display working. Therefor I set up a timer which fires an interrupt every 1ms. The routine changes a global variable _ticks. The method called _delay_ms(uint32_t ms) sets the _ticks, starts the timer and waits for _ticks to 0. Than the timer is stopped. In theory this should work, but the method seems to ignore when _ticks becomes < 0.

 

Some code:

 

#include <avr32/io.h>
#include <interrupt/interrupt_avr32.h>

volatile int32_t _ticks;

__attribute__((__interrupt__)) static void delay_loop()
{
	AVR32_TC.channel[1].sr;
	_ticks--;
}

void _delay_ms(uint32_t ms)
{
	AVR32_TC.channel[1].CCR.clken = 1;	// (1 << AVR32_TC_CCR0_CLKEN) | (1 << AVR32_TC_CCR0_SWTRG);
	AVR32_TC.channel[1].CCR.swtrg = 1;
	_ticks = ms;
	while (_ticks > 0)
	{
		;
	}
	AVR32_TC.channel[1].CCR.clkdis = 1;     // Disable Clock
}

void main (void)
{

    Disable_global_interrupt();
    INTC_register_interrupt(&delay_loop, AVR32_TC_IRQ1, 1);    // Timer-Routine Registrieren
    AVR32_TC.channel[1].IER.cpcs = 1;                          // AVR32_TC.channel[0].ier =(1 << AVR32_TC_IER0_CPCS);
    AVR32_TC.channel[1].CMR.waveform.wave = 1;                 // (1 << AVR32_TC_CMR0_WAVE)    | (2 << AVR32_TC_CMR0_WAVSEL) | (4 << AVR32_TC_CMR0_TCCLKS);
    AVR32_TC.channel[1].CMR.waveform.wavsel = 2;
    AVR32_TC.channel[1].CMR.waveform.tcclks = 4;
    AVR32_TC.channel[1].RC.rc = 469;                           // Register RC 1000Hz
    Enable_global_interrupt();

    while (1)
    {
	_delay_ms(10);
	AVR32_GPIO.port[0].ovrt = (1 << 31);    // Toggle LED
    }
}

 

Last Edited: Thu. Aug 17, 2017 - 02:36 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your method seems sound, but why is ticks signed? 

ticks should also be accessed atomically....

 

Jim

 

Last Edited: Thu. Aug 17, 2017 - 02:58 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

when unsigned it changes to a very large number after subtracting when 0. But with a signed integer, it can be negative and so stop the loop -> -1 = boolean false-

 

Unsigned works as well.

 

But of course, it is somehow pointless because it is just an other form of polling.

 

void _delay_ms(uint32_t ms)
{
	_ticks = ms;
	AVR32_TC.channel[1].IER.cpcs = 1;
	while (_ticks)
	{

	}
	AVR32_TC.channel[1].IDR.cpcs = 1;
} 

[SOLVED]

Last Edited: Thu. Aug 17, 2017 - 05:30 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It is still broken until you access _ticks atomically outside of the ISR (typically by disabling ints - or at least the timer int -, accessing _ticks, and then re-enabling.

EDIT: Sorry, I was thinking in terms of 8-bit accesses.  I assume all _ticks accesses are atomic with the UC3, but confirm.

Last Edited: Mon. Sep 11, 2017 - 10:46 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Jacky_88 wrote:

when unsigned it changes to a very large number after subtracting when 0. But with a signed integer, it can be negative and so stop the loop -> -1 = boolean false-

 

Using signed is actually more robust, as you point out, especially if you are not sitting in a tight loop looking at the value, but rather just checking the value on occasion in between other tasks.  However, by not counting down to zero, but simply advancing a tick counter and comparing against various deadlines, you can use the same tick for multiple independent timing purposes.  Here's a little tutorial I wrote on the subject (beginning at "A CYCLIC EXECUTIVE FRAMEWORK"):

https://www.embeddedrelated.com/...