programming a 1ms delay using RTC clock - c

I am currently working with S32k142 microcontroller.
I would like to configure a 1ms delay using the RTC clock. I have an external RTC clock(32.768KHz) which has been configured to drive the RTC module of the microcontroller.
I have programmed the following:
void wait_1ms_RTC(void)
{
UINT32 tpr = (UINT32)RTC->TPR; // RTC Time Prescaler Register: increments at a freq of 32.768KHz
UINT32 tsr = (UINT32)RTC->TSR; // RTC Time Seconds Register: increments every second
tpr = tpr + (UINT32)32; // 32->1ms(32*30.51us=976.32us)
if (tpr <= 32767)
{
while (((UINT32)RTC->TPR <= tpr)&& ((UINT32)RTC->TSR <= tsr));
}
else
{
while (((UINT32)RTC->TPR <= (tpr - 32768))&& ((UINT32)RTC->TSR <= tsr+1));
}
}
This code simply reads the TPR and TSR register, and waits till the TPR register and TSR register reached certain value that corresponds to 1ms.
This works most of the time except in few occasions where it does not create a delay of 1ms ,I am assuming it is happening during the roll over, but still cannot figure out where exactly is the issue in the code.
Any ideas on how this can be solved?

You have over complicated it; you only need the TPR. By shifting the TPR value left by 1 bit, and assigning it to uint16_t, the natural modulo 216 arithmetic deals with the roll-over for you:
#define RTC_TPR_MILLISEC ((32768<<1)/1000)
void wait_1ms_RTC(void)
{
// RTC Time Prescaler Register: 0 to 2^15,
// shift-left 1 but to make it 2^16 so uint16_t modulo arithmetic works
uint16_t start = RTC->TPR << 1 ;
while( (RTC->TPR << 1) - start < RTC_TPR_MILLISEC )
{
// spin
}
}
It fact it is probably even simpler than that. The user manual shows that TPR is a 16 bit register and that TSR is incremented when TPR:14 transitions from 1 to 0. It does not imply that TPR is a 15 bit value and that the counter is reset to zero after 32767. I am not familiar with the part, but if in fact it is a full 16 bit counter as the documentation suggests then the shifting is unnecessary:
#define RTC_TPR_MILLISEC (32768/1000)
void wait_1ms_RTC(void)
{
// RTC Time Prescaler Register: 0 to 2^16
uint16_t start = RTC->TPR ;
while( RTC->TPR - start < RTC_TPR_MILLISEC )
{
// spin
}
}
If you are not sure why that works, see How to deal with a wrapping counter in embedded C (the example there is a 32 bit counter, but the same applies for 16 bit).

Related

Using Timers for Blink & Count

I'm creating part of a program right now for a personal project. This is my first year ACTUALLY coding and have been studying for hours to understand many concepts so please be nice and try not to be rude as others have...
The project of mine is an AVRDUDE using a chip called ATMEGA328P in a program called Microchip studios.
[This project is having 3 LED count every time a switch is pressed, I should have them count continuously and change to the next number every second using a TIMER 1.
**counting in binary from 0-8 then rolling over **
I need some help on one aspect of it which is using interrupts after I have already created a blinking LED to use a TIMER0 instead of delays.
I have made my fourth LED flash at 5Hz which is the blinking part of my code include below at the end of this question.
Now the problem I am running into is trying to create interrupts for the 3 LEDS count every time a switch is pressed, I should instead have them continually count, changing to the next number approximately every second, using TIMER1.]
This is my code for the project
Again please be nice and at least lead me in some type of direction...
#include <avr/io.h>
#include <avr/interrupt.h>
#define F_CPU 1000000UL
int global = 0 ;
volatile uint8_t overflow0; // Variable for counting overflows for first timer
volatile uint8_t overflow1; // Variable for counting overflows for second timer
void FirstTimer() // Initialize Timer 1
{
TCCR0B |= (1<<CS02) | (1<<CS00); // Prescaler of 1024
TCNT0 = 0;
}
void SecondTimer() //Initialize Timer 2
{
TCCR1B |= (1<<CS11) | (1<<CS10);
TCNT1 = 0;
}
int main(void)
{
DDRB |= (1 << DDB0);
FirstTimer(); // Calling timer 1 and 2 initialization
SecondTimer();
while (1)
{
{
if (TCNT0 >= 195) // Amount of ticks needed
{
PORTB ^= (1 << PORTB0); //LED on
TCNT0 = 0; //Reset counter
}
}
{
if (TCNT1 >= 15625) // Ticks needed
{
TCNT1 = 0; // Timer reset
}
}
}
}
An approach you could use is keeping a count variable (unsigned char - assuming 8 bit register width) and in your Timer ISR simply increment the count and write that value to the output register. Once count > 8 set to zero.
Configure the Timer mode to trigger on overflow w/ reset to zero.
Then you do some basic math using the clock speed and timer ceiling (overflow value) to calculate the frequency you want the overflow ISR to occur (increment the LED count values).
Note that for this to work the LEDs need to be on the first 3 pins.
i.e.
P1.0 = LED1
P1.1 = LED2
P1.2 = LED3
...
If not connected like this then you can still make it work with additional bit manipulation (shifts and masks).

AVR 8 bit timer - what to do when compare value doesn't fit in register?

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

Translating 8051 microcontroller C code

void extrint (void) interrupt 0 // external Interrupt to detect the heart pulse
{
bt = tick; // number of ticks are picked
tick = 0; // reset for next counting
}
void timer0 (void) interrupt 1 using 1 // Timer 0 for one second time
{
TH0 = 0xdc; // The value is taken for Ssc/100 at crystal 11.0592MHz
sec100++; // It is incremented every Ssc/100 at crystal 11.0592MHz
tick++; // This variable counts the time period of incoming pulse in Sec/100
if (tick >= 3500)
{tick = 0;} // tick are limited to less than 255 for valid calculation
if (sec100 >= 100) // 1 sec = sec100 * 100
{
sec++;
sec100=0;
}
}
Can somebody explain me what the above code means and does. It was written for a 8051 microcontroller.
i got it from here
http://www.zembedded.com/heart-rate-beats-meter-with-microcontroller-at89c51-based-heartbeat-monitor/
Very hard to tell without context. I guess following:
The timer0 interrupt routine is called every 100th of a second. There it increments the tick counter which is reset to 0 as soon as it gets bigger than 3500. The sec counter seems to be a second counter as it is incremented every 100th call to timer0 (which is called 100 times per second).
The extrint seems to be called upon some external event. It just copies the actual value of tick into bt (presumably for some further processing) and resets tick to 0.

AVR timer programming

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.

Understanding timer and period of interrupts

I am having a hard time understanding some code I found for using a timer and interrupts on an ARM board I have. The timer basically toggles an LED every interrupt between on and off to make it flash.
void main(void) {
/* Pin direction */
led_init();
/* timer setup */
/* CTRL */
#define COUNT_MODE 1 /* Use rising edge of primary source */
#define PRIME_SRC 0xf /* Peripheral clock with 128 prescale (for 24 MHz = 187500 Hz)*/
#define SEC_SRC 0 /* Don't need this */
#define ONCE 0 /* Keep counting */
#define LEN 1 /* Count until compare then reload with value in LOAD */
#define DIR 0 /* Count up */
#define CO_INIT 0 /* Other counters cannot force a re-initialization of this counter */
#define OUT_MODE 0 /* OFLAG is asserted while counter is active */
*TMR_ENBL = 0; /* TMRS reset to enabled */
*TMR0_SCTRL = 0;
*TMR0_CSCTRL = 0x0040;
*TMR0_LOAD = 0; /* Reload to zero */
*TMR0_COMP_UP = 18750; /* Trigger a reload at the end */
*TMR0_CMPLD1 = 18750; /* Compare one triggered reload level, 10 Hz maybe? */
*TMR0_CNTR = 0; /* Reset count register */
*TMR0_CTRL = (COUNT_MODE<<13) |
(PRIME_SRC<<9) |
(SEC_SRC<<7) |
(ONCE<<6) |
(LEN<<5) |
(DIR<<4) |
(CO_INIT<<3) |
(OUT_MODE);
*TMR_ENBL = 0xf; /* Enable all the timers --- why not? */
led_on();
enable_irq(TMR);
while(1) {
/* Sit here and let the interrupts do the work */
continue;
};
}
Right now, the LED flashes at a rate that I cannot determine per second. I'd like it to flash once per second. However, I do not understand the whole comparison and reloading.
Could somebody better explain this code?
As timers are a vendor- and part-specific feature (not a part of the ARM architecture), I can only give general guidance unless you mention which CPU or microcontroller you are dealing with.
Timers have several features:
A size, for instance 16 bits, which means they can count up or down to/from 65535.
A clock input, given as a clock frequency (perhaps from the CPU clock or an external crystal), and a prescaler which divides this clock frequency to another value (or divide by 1).
An interrupt on overflow - when the timer wraps back to 0, there is usually an option to trigger an interrupt.
A compare interrupt - when the timer meets a set value it will issue an interrupt.
In your case, I can see that you are using the compare feature of your timer. By determining your timer clock input, and calculating new values for the prescalers and compare register, you should be able to achieve a 1 Hz rate.
Before trying to understand the code you found, please do understand how a Timer Peripheral Unit works, then understand how you can configure it's registers to get the desired output.
How a Timer Peripheral Unit works?
This is hardware module which is embedded into micro controller along with CPU and other peripherals. Every peripheral modules inside micro controller are synchronized with common clock source. With reference to the code, Timer peripheral clock is 24 MHz which is then pre-scaled by 128 which means it will work at 187500 Hz. Now this frequency will depend upon clock configuration and oscillator.
Now Timer unit has a counter register which can count up to it's bit-size which could be 8,16 or 32 generally. Once you enable counting, this counter starts up-counting or down-counting the rising or falling or on both edges. Now you have choices whether you want to up-count (from 0 towards 255, for 8-bit) or down count (from 255 towards 0) and you want to count on which clock edge.
Now, at 187500 Hz, 1 cycle = 5.333333 us, if you are counting once in 1 cycle either at rising or at falling edge and e.g, if counter value = 100 (Up counting), total time elapsed is 5.33333*100=533us. Now you have to set a compare value value for the counter to set this period which will depend upon your flash rate. This compare value will be compared against your counter value in by comparator of Timer and Once it matches it will send an interrupt signal if you have enabled interrupt generation on compare match, where you can toggle you LED.
I hope you have understood How a Timer works.
In your sample code, Timer is configured to obtain a compare match event at the rate of 10Hz. so compare value is 187500/10 = 18750., for 1sec you can keep it 187500/1.
you have Timer Control Register TMR0_CTRL, where you can configure whether you want to count up or down, count on falling/rising/both edges, count only once/continuous, count upto compare value and then reset or keep counting till it's limit. Refer to micro controller manual for details of each bit fields.

Resources