I have a 32 bit hardware timer that I'd like to extend to 64 bit effective length in software.
In my embedded system, I have available a 32-bit hardware "core timer" (CT) that ticks at ~ 40 MHz, so it rolls over in about 107 seconds.
That's great for precise timing of periods up to 107 seconds. But I'd like to do equally precise timing of longer periods.
It also has a 32-bit "period" register - when the CT value matches the period register, an interrupt is generated.
My ISR looks like this (simplified for clarity):
const UINT32 ONE_MILLISECOND = TICK_RATE/1000;
UINT64 SwRTC;
void CT_ISR(void) {
PeriodRegister += ONE_MILLISECOND;
SwRTC += ONE_MILLISECOND;
ClearCTInterrupt();
}
So, now I have a 64 bit "SwRTC" that can be used to measure longer periods, but only to a precision of 1 millisecond, plus the 32-bit hardware timer that is precise to 1/40 MHz (25 nanoseconds). Both use the same units (TICK_RATE).
How can I combine both to get a 64 bit timer that's equally precise, while still getting interrupts at 1000 Hz?
My first try looked like this:
UINT64 RTC(void){
UINT64 result;
DisableInterrupts(); // to allow atomic operations
result = (SwRTC & 0xFFFFFFFF00000000ull) + ReadCoreTimer();
EnableInterrupts();
return result;
}
But that's no good, because if the CT rolls over while interrupts are disabled then I'll get a result with a small number in the low-order 32 bits, but without the high-order bits having been incremented by the ISR.
Maybe something like this would work - read it twice and return the higher value:
UINT64 RTC(void){
UINT64 result1, result2;
DisableInterrupts(); // to allow atomic operations
result1 = (SwRTC & 0xFFFFFFFF00000000ull) + ReadCoreTimer();
EnableInterrupts();
DisableInterrupts(); // again
result2 = (SwRTC & 0xFFFFFFFF00000000ull) + ReadCoreTimer();
EnableInterrupts();
if (result1 > result2)
return result1;
else
return result2;
}
I'm not sure if that'll work or if there is a hidden problem there I've missed.
What is the best way to do this?
(Some may ask why I need to time such long periods so precisely in the first place. It's mainly for simplicity - I don't want to use 2 different timing methods depending on the period; I'd prefer to use the same method all the time.)
I think I've almost solved this myself:
UINT64 Rtc(void){
UINT64 softwareTimer = SwRTC;
UINT32 lowOrderBits = softwareTimer; // just take low-order 32 bits
UINT64 coreTimer = ReadCoreTimer();
if (lowOrderBits > coreTimer) // if CT has rolled over since SwRTC was updated
softwareTimer += 0x100000000; // then increment high-order 32 bits of software count
return (softwareTimer & 0xFFFFFFFF00000000ull) + coreTimer;
}
This first reads the 64-bit software timer, then the 32-bit hardware timer.
The hardware timer (updated every 25 nS) should always be >= the low-order 32-bits of the software timer (updated only every 1 mS).
If it's not, that indicates the hardware timer rolled over since the software timer was read.
So, in that case I increment the high-order word of the software timer.
Then just combine the high-order 32 bits from the software time with the low-order 32 bits from the hardware timer.
One nice side effect is there's no need to disable interrupts.
The only problem I can see is, what if compiler optimization re-orders the code so that the hardware timer gets read first? Then I could get an interrupt that increments the software timer before I have a chance to read it.
At first I thought I could fix that by disabling interrupts while reading both timers, but what if the compiler re-orders the code so the DisableInterrupts() comes too late?
If it is an upcounter for example I will typically
elapsed = ((nowtime-starttime)&MASK)+(rollovers<<SIZE);
so long as you sample often enough (many times per rollover) for an upcounter of nowtime (time I just sampled) is less than lasttime (lasttime is the prior nowtime) then it rolled over.
assuming it is counting out every value and not skipping from say 0xFF..FFF to 0x00...01.
Downcounter just do everything opposite starttime-nowtime. nowtime > lasttime.
Some timers have a rollover interrupt which you can sometimes just poll instead of interrupt if you want and again so long as you can guarantee you sample that once or more than once per rollover you can simply use that to flag a rollover count.
If at any time you miss a rollover, then naturally you will be off by the size of the timer 4 giga counts or whatever.
Some hardware may allow for you to use one timer to generate an output clock which you can then feedback as an input to another timer and cascade that way (sometimes they do that on chip).
Related
I am currently programming a Teensy micro-controller and want to setup a pause function for a game. I have been able to create a timer from ISR counter overflows, however I haven't been able to work out how to pause this counter. I have tried:
ISR(TIMER1_OVF_vect) {
if (paused == 0){
overflow_counter ++;
}
}
This seems to make no difference to the counter, the counter just keeps going no matter what instructions I put inside the function. I have tried a variety of if statements and they are ignored - the function just increases the counter for some reason (even if I put overflow_counter --)!
So I have tried to setup another variable that takes a snapshot of the time when the pause button is pressed, then when the game is un-paused it would take another snapshot and calculate the difference. This would then be taken away from the overall time.
double snapshot_time = 0;
double get_current_time(void){
double time = ( overflow_counter * 65536.0 + TCNT1 ) * PRESCALE / FREQ;
if (paused == 0 && switch_state[5] == 1){
snapshot_time = time;
}
return time;
}
I have tried setting snapshot_time as a global variable and making it equal to time thinking this may dynamically capture a static variable but unfortunately it doesn't. Can anyone offer a way to do this?
There are many aspects hidden in your question.
1. First of all, the counter variable should be marked volatile. The compiler is applying different optimizations to variables, so it may, say, load a variable into a register and continue to work with register, assuming it is only the place, where content of the variable is stored. If a variable is declared with the keyword volatile, then the compiler knows that it could be changed occasionally in any time, therefore the compiler will reload and/or rewrite the variable each time it is accessed. So, it may be declared like this
volatile uint16_t overflow_counter;
The same goes for the paused variable.
2. You should remember that, if interrupts are not disabled, then timer interrupt can occur between any two processor's instructions. Since processor is 8bit, it access the memory using 8-bit wide bus. That means, to read 16-bit data, it requires 2 instructions. Let's say we copy the counter value into a local variable:
uint16_t counter_snapshot = overflow_counter;
The local variable will allocate two registers and two memory read operations will be performed. Let's imagine the interrupt is happened after first of them, but before second. So, on output you'll have half of the number copied from it's previous value, while the second half from it's new. I.e. the value will be damaged. It will not be happened, if variable is 8-bit and copied by one instruction. But if it is wider, or if it is read-modified-written, then precautions should be taken:
uint8_t old_sreg = SREG; // SREG i/o register contains processor state flags, including "interrupt flag", which allows interrupt
cli(); // clear the "interrupt flag", preventing interrupts from happening
uint16_t counter_snapshot = overflow_counter; // safely taking the snapshot
SREG = old_sreg; // restoring the "interrupt flag" to it's previous state. Other flags also restored but we do not care about them.
3. As said above, interrupt can happen in any time. That means if you try to read overflow_counter and TCNT1 both, the interrupt can be happened in between, so, result will be not as expected. Especially if reading of those two values is separated by such a long operation as floating-point multiplication. So, workaround may be as follows:
uint8_t old_sreg = SREG; // saving state
cli(); // locking interrupts
// latching values we are interested in
uint16_t latch_overflow_counter = overflow_counter;
uint16_t latch_tcnt1 = TCNT1;
uint8_t latch_tifr1 = TIFR1;
SREG = old_sreg; // restoring interrupts
/* We are disabling interrupts, but it do not stop the timer from counting,
therefore TCNT1 value continue changing, and timer could overflow in any time
within that block above. But which moment exactly? Before we read TCNT1 or just after?
Let's assume if TCNT1 have high values then we got it's value just before the timer overflow;
otherwise, overflow happened before that */
if ((latch_tifr1 & (1 << TOV1)) && // we got the overflow flag set
(latch_tcnt < 32768) { // we are within the low values
latch_overflow_counter++; // increasing the latched value
}
double time = ( latch_overflow_counter * 65536.0 + latch_tcnt1 ) * PRESCALE / FREQ; // now using latched values to calculate...
By the way, throughput can be much improved, if avoid using floating point where it is not necessary.
Recently, I started programming the Atmega328P in pure c/c++, without all the arduino libraries and arduino IDE. I want to blink an LED at a rate of 1Hz (1 sec. on, 1 sec. off). Unfortunately, I can only use Timer0, an 8-bit timer. The mcu has a clock frequency of 16MHz and I chose a prescaler of 1024 to reduce to number of overflows as much as possible to reduce jitter, as an interrupt routine always has overhead (this makes more sense if you read the rest of my question). Using simple maths, I came to conclusion that after 1 second, Timer0 has overflowed 61 times and that the TCNT0 register equals 8.
Then, I came up with this solution:
#define F_CPU 16000000ul
#include <avr/io.h>
#include <avr/interrupt.h>
#define bit(b) (1 << (b))
void initBlinkTimer()
{
//Timer0 with CTC Mode
TCCR0A |= bit(WGM01) | bit(WGM00);
//Compare TCNT0 with 8
OCR0B = 8;
//Interrupt at OCR0B compare match aka: execute interrupt when TCNT0 equals 8
TIMSK0 |= bit(OCIE0B);
//Set PB5 as output
DDRB |= bit(PB5);
//Set the prescaler to 1024
TCCR0B |= bit(CS02) | bit(CS00);
//Enable global interrupts, so that the interrupt routine can be executed upon the OCR0B compare match
sei();
}
//Keeps track of the number of overflows
volatile unsigned char nOverflows = 0;
ISR(TIMER0_COMPB_vect)
{
if(nOverflows >= 61)
{
//Toggle PB5
PORTB ^= bit(PB5);
//Reset timer
nOverflows = 0;
TCNT0 = 0;
}
else
{
nOverflows++;
}
}
int main()
{
initBlinkTimer();
while(1){}
}
This code initializes an 8-bit CTC timer with a prescaler of 1024. An interrupt service routine (ISR) is executed when TCNT0 equals OCR0B, which I set to 8 in my code. In the ISR, the nOverflows variable is compared to 61. If nOverflows equals 61, one second has passed and the PB5 pin is to be toggled. It also performs a greater-than check, in case the mcu missed the 61th overflow (if that's somehow possible in this case). The timer and nOverflows variable are cleared after toggling the pin and the timer then starts again from zero.
My question is: Is this a good way to blink an LED at 1Hz, when only an 8-bit timer is available? Can/should a part of this be implemented in the hardware instead of in the software?
You don't need super high precision in your LED blinking; no one will be able to tell with their eyes if it is slightly off.
I'd say you should configure the timer to overflow about one to ten times per millisecond. Let's say it overflows every 251 microseconds (the exact number doesn't matter). Then every time it overflows, you add 251 to a uint16_t variable for counting microseconds. If the microsecond counter is greater than or equal to 1000, you subtract 1000 from it and increment your millisecond counter, which should probably be a uint32_t so you can use it to time long periods of time.
But what if the overflow period is not an exact number of microseconds? That's still fine, because it will probably be expressible in the form "N/M milliseconds", where N and M are whole numbers. So every time the overflow happens, you increment your counter by N. If the counter reaches M, you subtract M from the counter and add 1 to your millisecond counter. (In the preivous paragraph, we only considered the M=1000 case, and I think by starting with that case it is easier to see what I'm talking about.)
You can either use an ISR to update your millisecond counter or do it in your main-line code by frequently checking for an overflow flag. Either way would work.
So now you have a variable that counts up once per millisecond, like the Arduino millis() function, and you can use it for all sorts of millisecond-scale timing, including blinking LEDs.
The least-significant bit (bit 0) of the millisecond counter toggles once per millisecond, so its period is 2 ms. The next bit up from that (bit 1) has a period of 4 ms. Bit 10 has a period of 2048 ms.
So a simple way to blink your LED with a period of 2048 ms would be:
led_state = millisecond_counter >> 10 & 1;
(The code above uses bitwise operations to set led_state to be a copy of bit 10 from the millisecond counter. Assuming you run this code frequently and write led_state out to the LED using the I/O registers, your LED would then have a period of 2048 ms.)
If you really care that your LED is slow by 2.4%, you could do something more complicated like this:
static uint16_t last_toggle = 0;
if ((uint16_t)(millisecond_counter - last_toggle) >= 1000)
{
last_toggle += 1000;
toggle_the_led();
}
I'm trying to generate note for example Do , do's frequency is 523.
I wrote some codes but, i did not work
Systick 8 mhz
void note1(void){ // Note Do
for (int i = 0; i < 523; i++){
GPIOE->ODR = 0x4000;
delay_ms(1);
GPIOE->ODR = 0x0000;
delay_ms(1);
}
}
How can we solve this problem ?
EasyMx Pro v7
I'm calling the function like that
void button_handler(void)
{
note1();
// Clear pending bit depending on which one is pending
if (EXTI->PR & (1 << 0)){
EXTI->PR = (1 << 0);
}
else if (EXTI->PR & (1 << 1)){
EXTI->PR = (1 << 1);
}
}
523 times sending 1 and 0 and delay_ms 1 = 1 ms
1000 = 1 sec
On STM32 (as I can see you have it) you have timers which can be configured as PWM output.
So use timer, set period and prescaler values according to your needed frequency and set duty cycle on channel to 50%.
If you need 523Hz PWM output, then set your timer PWM to 523Hz using prescaler and period value:
timer_overflow_frequency = timer_input_clock /
(prescaler_value + 1) /
(period_value + 1) ;
Then, for your output channel set value half of timer period value.
For standard peripheral library, tutorial can be used from here:
https://stm32f4-discovery.net/2014/05/stm32f4-stm32f429-discovery-pwm-tutorial/
Link from unwind for Cube https://electronics.stackexchange.com/questions/179546/getting-pwm-to-work-on-stm32f4-using-sts-hal-libraries
You appear to have a fundamental misunderstanding. In your code note1(), the value 523 will affect only the duration of the note, nit its frequency. With 1ms high, 1ms low repeated 523 times you will generate a tone of approximately 500Hz for approximately 1.43 seconds. I say "approximately" because there will be some small overhead in the loop other then the time delays.
A time delay resolution 1ms is insufficient to generate an accurate tone in that manner. To do it in the manner you have, each delay would need to be 1/2f seconds, so for 523Hz approximately 956ms. The loop iteration count would need to be ft, so for say .25 seconds, 131 iterations.
However if button_handler() is as it appears to be an interrupt handler, you really should not be spending 1.46 seconds in an interrupt handler!
In any event this is an extraordinarily laborious, CPU intensive and inaccurate method of generating a specific frequency. The STM32 on your board is well endowed with hardware timers with direct GPIO output that will generate the frequency you need accurately with zero software over head. Even if none of the timers map to a suitable GPIO output that you need to use, ou can still get one to generate an interrupt at 1/2f and toggle the pin in the interrupt handler. Either way that will leave the processor free to do useful stuff while the tone is being output.
I was studying avr timers (Mazidi) in that book where a program was given in timer chapter it said whenever we need to calculate the value to enter inside TCNT0 ,we should calculate like this. for example 8Mhz, 256 prescalar , 1 s delay
8 Mhz = .125 usec
256 x 0.125 = 32 usec
for 1 ms delay
1sec / 32usec = 31250 clock cycles = 0x7A12
so the value for TCNT0 is
1+FFFF-7A12 = 0x8255 //what this step means
Also when polling we look for TIFRs 0th bit for 1. when it becomes 1 we stop the timer and stop the clock source, but why we do this
TIFR = 0x1 //clears TIFR??
in the book it was written it clears TIFR . How is this possible when that bit is already 1, writing 1 on it makes it clear?
1+FFFF-7A12 = 0x8255 //what this step means
This is not the usual way to use a timer, but it subtracts your number from 0 (which is equivalent to 0xFFFF + 1) so that it "counts down" and trips when the timer reaches 0.
It makes much more sense to us TOC (timer output compare) instead.
TIFR = 0x1 //clears TIFR??
Yes. This register is not a memory location. It is mapped to a memory location. Some registers do work this way.
I'm using C with the BoostC compiler. I'm worried how accurate my code is. The configuration below ticks at more or less 1Hz, (tested with an LED to the naked eye). (It uses an external watch crystal 32kHz for Timer1 on the 16f74).
I'm hoping someone can tell me...
Does my code below need any adjustments? What would be the easiest way of measuring the accuracy to the nearest CPU clock period? Will I need to get dirty with assembly to reliably ensure accuracy of the 1Hz signal?
I'm hoping the time taken to execute the timer handler (and others) doesn't even come into the picture, since the timer is always counting. So long as the handlers never take longer to execute than 1/32kHz seconds, will the 1Hz signal have essentially the accuracy of the 32kHz Crystal?
Thanks
#define T1H_DEFAULT 0x80
#define T1L_DEFAULT 0
volatile char T1H = T1H_DEFAULT;
volatile char T1L = T1L_DEFAULT;
void main(void){
// setup
tmr1h = T1H;
tmr1l = T1L;
t1con = 0b00001111; // — — T1CKPS1 T1CKPS0 T1OSCEN NOT_T1SYNC TMR1CS TMR1ON
// ...
// do nothing repeatedly while no interrupt
while(1){}
}
interrupt(void) {
// Handle Timer1
if (test_bit(pir1, TMR1IF) & test_bit(pie1, TMR1IE)){
// reset timer's 2x8 bit value
tmr1h = T1H;
tmr1l = T1L;
// do things triggered by this time tick
//reset T1 interrupt flag
clear_bit(pir1, TMR1IF);
} else
... handle other interrupts
}
I can see some improvements...
Your timer initiation inside interrupt isn't accurate.
When you set the timer counter in interrupt...
tmr1h = T1H;
tmr1l = T1L;
... then you override the current value what isn't good for accuracy.
... just use:
tmr1h = T1H; //tmr1h must be still 0!
Or even better, just set the 7th bit of tmr1h register.
The compiler must compile this order to single asm instruction like...
bsf tmr1h, 7
...to avoid losing data in tmr1 register. Because if this is made with more than one instructions the hardware can increment the counter value between execution of: read-modify-write.