programming on MSP430 in CCS
Using Timer_A, ACLK and his interrupt to blink LED(just blinking now- same long time torned off- same time turned on).
This code blink led with 2 sec delay. There is problem that register TA1CCR0 can be max 0xFFFF= 65535 (2 sec for ACLK). And for my application(blinking LED is only exapmle) I will need scale from 1 sec to 999 sec. (row 6-7 in code). How can I do that? Is it possible?
#include <msp430.h>
#include <msp430f6736.h>
void CfgTA(unsigned long delayCycles)
{
int t2=2; // must be variable from 1 to 999
t2=delayCycles*t2;
TA1CCTL0 |= CCIE; //Enable Interrupts on Timer
TA1CCR0 = t2-1; //Number of cycles in the timer
TA1CTL |= TASSEL_1 | MC_1; //ACLK , UP mode
}
void ledblink()
{
//LED config
P4DIR |= BIT6;
P4OUT &= ~BIT6;
CfgTA(32768); //Timer configuration to blink every 1 sec
while (1)
{
_bis_SR_register(LPM3_bits + GIE); //Enter Low Power Mode 3 with interrupts
}
}
#pragma vector=TIMER1_A0_VECTOR
__interrupt void Timer_A0(void)
{
P4OUT ^= BIT6; // Swapping on/off LED
}
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
ledblink();
return 0;
}
how to count seconds on a 1 second interrupt.
1) initialize interrupt to occur once each second and reload its' timer/counter register
2) set global variable to number of seconds to delay:
int delaySeconds = 10;
3) inside the interrupt function
static int count =0;
count++;
if( count >= delaySeconds )
{
count = 0;
P4OUT ^= BIT6; // Swapping on/off LED
}
I think the interrupt function, before exiting, also needs to clear the time1 interrupt pending flag
On your MSP430, you can slow down ACLK with the DIVA field in the UCSCTL5 register, and you can further divide down the timer's clock input with the ID and IDEX fields in the TAxCTL and TAxEX0 registers.
With the timer input divided down to 16 Hz, you would be able to count for up to 4096 seconds.
Related
unsigned long slptime=0;
unsigned long wdttime_count = 0;
void timer1_init()
{
//TCNT1=0xFF4E;//16ms
TCNT1=0xFFF5;//1ms
// TCNT1=0xFF9B; //10ms
TIMSK1=0x01;
TCCR1A &= ~(1<<WGM10); // RV09_H, Date: 05-May-2022, set Normal mode operation
TCCR1A &= ~(1<<WGM11);
TCCR1B &= ~(1<<WGM13);
TCCR1B &= ~(1<<WGM12);
TCCR1B |= (1<<CS12) | (1<<CS10); //1024 prescalar; fosc=11059200hz; freq=fosc/1024 = 10800hz; t=0.092ms;
}
void timer1_stop()
{
TCCR1B = 0x00;
TIMSK1 = 0x00;
}
ISR(TIMER1_OVF_vect)
{
//TCNT1=0xFF4E;//16ms
TCNT1=0xFFF5;
//TCNT1=0xFF9B;
wdttime_count=wdttime_count+1;
}
void main()
{
timer1_init();
_delay_ms(250);
timer1_stop();
sendtimediff((wdttime_count*1000)/1080);
}
The timer1 is configured for 1080Hz by counting upto 10 at 10800hz. I was just checking the timer accuracy but the above code return 227ms instead of 250ms.
What I am missing in it? Or _delay_ms() is causing the error?
When you set timer value to 0xFFF5 it increments 11 times before the overflow.
11059200 / 1024 / 11 = 981,8 Hz == 1,0185 ms.
It counts 245 times.
245 * 1000 / 1080 = 227
You probably want to set value to 0xFFF6
There is no need to set the timer in each interrupt. Instead, you can use CTC mode, forcing the timer to count from zero to a value in OCR1A (Mode 4) or ICR1 (Mode 12). E.g.:
void timer1_init()
{
TCNT1=0;
OCR1A = 9; // from 0 to 9 == 10 timer (prescaled) clock cycles
TIMSK1 = (1 << OCIE1A); // Use Output Compare interrupt
TCCR1A &= ~(1<<WGM10); // Set Mode 4 (CTC)
TCCR1A &= ~(1<<WGM11);
TCCR1B &= ~(1<<WGM13);
TCCR1B |= (1<<WGM12);
TCCR1B |= (1<<CS12) | (1<<CS10); //1024 prescalar; fosc=11059200hz; freq=fosc/1024 = 10800hz; t=0.092ms;
}
ISR(TIMER1_COMPA_vect) // use Output Compare A vector, instead of Overflow
{
// No need to reset the timer
wdttime_count=wdttime_count+1;
}
...
Keep in mind that _delay_ms macro just counts CPU cycles, therefore if there are interrupts happened during the delay, the delay can take longer time. _delay_ms and _delay_us macros are generating plain CPU loop, which counts with accuracy up to single CPU clock cycle, but only when the loop itself is not interrupted.
There is no point to compare _delay_ms to timer clocked from the same main clock, as the CPU itself. The comparison result will be always the same, no matter what actual CPU speed is.
Classic bug for free running timers, TCNT1=interval; in the ISR won't work. It needs to be something like:
volatile uint16_t next_TCNT1 = TCNT1;
next_TCNT1 += interval;
TCNT1 = next_TCNT1;
The reason for this is: you have set the interrupt to trigger when the timer compare hits a certain value. That's the point when the timer flag is set, but from the point where that happens until you reach the actual code inside the ISR, a lot of time has passed, interrupt latency. This was particularly nasty on the various old, crap architecture 8-bitters.
So by the time you update the timer counter, it isn't sitting at "interval", but rather at "interval plus interrupt latency plus execution overhead" which means the next interrupt will come much sooner than expected.
By reading the current value inside the ISR and adding the timer interval to it, you compensate for interrupt latency. Now the only real-time delay you have is those few lines inside the ISR, which are likely negligible.
There is Attiny85, with an internal clock source at 8 MHz.
I am trying to implement a microsecond timer based on the hardware timer timer0.
What is my logic:
Since the clock frequency is 8 MHz and the prescaler is off, the time of one clock cycle will be about 0.1us (1/8000000).
Initially, the timer overflows and causes interruptions when passing 0 ... 255, it takes more than 0.1us and is inconvenient for calculating 1μs.
To solve this, I thought about the option to change the initial value of the timer instead of 0 to 245. It turns out that in order to get to the interruption, you need to go through 10 clock cycles, which takes about 1us in time.
I load this code, but the Attiny LED obviously does not switch for about 5 seconds, although the code indicates 1 second (1000000us).
Code:
#include <avr/io.h>
#undef F_CPU
#define F_CPU 8000000UL
#include <avr/interrupt.h>
// Timer0 init
void timer0_Init() {
cli();
//SREG &= ~(1 << 7);
// Enable interrupt for timer0 overflow
TIMSK |= (1 << 1);
// Enabled timer0 (not prescaler) - CS02..CS00 = 001
TCCR0B = 0;
TCCR0B |= (1 << 0);
// Clear timer0 counter
TCNT0 = 245;
sei();
//SREG |= (1 << 7);
}
// timer0 overflow interrupt
// 1us interval logic:
// MCU frequency = 8mHz (8000000Hz), not prescaler
// 1 tick = 1/8000000 = 100ns = 0.1us, counter up++ after 1 tick (0.1us)
// 1us timer = 10 tick's => 245..255
static unsigned long microsecondsTimer;
ISR(TIMER0_OVF_vect) {
microsecondsTimer++;
TCNT0 = 245;
}
// Millis
/*unsigned long timerMillis() {
return microsecondsTimer / 1000;
}*/
void ledBlink() {
static unsigned long blinkTimer;
static int ledState;
// 10000us = 0.01s
// 1000000us = 1s
if(microsecondsTimer - blinkTimer >= 1000000) {
if(!ledState) {
PORTB |= (1 << 3); // HIGH
} else {
PORTB &= ~(1 << 3); // LOW
}
ledState = !ledState;
blinkTimer = microsecondsTimer;
}
}
int main(void)
{
// Set LED pin to OUTPUT mode
DDRB |= (1 << 3);
timer0_Init();
while (1)
{
ledBlink();
}
}
Attiny85 Datasheet
What could be the mistake? I have not yet learned how to work with fuses, so I initially loaded the fuses at 8 MHz through the Arduino IDE, and after that I already downloaded the main code (without changing the fuses) through AVRDUDE and Atmel Studio.
And another question, should I check the maximum value when updating my microsecond counter? I know that in Arduino, the micro and millis counters are reset when they reach the maximum value. For example, if I do not clear the TimerMicrosecond variables variable and it exceeds the size of the unsigned long, will it crash?
As pointed out by #ReAI, your ISR does not have enough time to run. Your ISR will take more than 1 microsecond to execute and return, so you always are missing interrupts.
There are other problems here too. For example, your microsecondsTimer variable is accessed in both the ISR and the foreground and is a long. long variables are 4 bytes wide and so are not updated atomically. It is possible, for example, that your foreground could start reading the value for microsecondsTimer and then in the middle of the read, the ISR could update some of the unread bytes, and then when the foreground starts again it will end up with a mangled value. Also, you should avoid messing with the count register since updating it can miss ticks unless you are very careful.
So how could you implement a working uSec timer? Firstly you'd like to call the ISR as infrequently as possible, so maybe pick the largest prescaller you can get get the resolution that you want and only ISR on overflow. In the case of the ATTINY85 Timer0, you can pick /8 prescaller which gets you one tick of the timer per microsecond with an 8Mhz system clock. Now your ISR only runs once every 256 microseconds and when it runs, it need only increment a "microseconds * 256" counter in each call.
Now to read the current microseconds in the foreground, you can get the number of microseconds mod 256 by directly reading the count register, and then read the "microseconds * 256" counter and multiply this by 256 and add that the counter and you'll have the full count. Note that you will need take special precautions to make sure your reads are atomic. You can do this either by carefully turning off the interrupts, quickly reading the values, and then turning the interrupts back on (save all the math for when interrupts are back on), or looping on the read values to make sure you get two full reads in a row that are the same (time means that have not updated while you were reading them).
Note that you can check out the source code to Arduino timer ISR for some insights, but note that theirs is more complicated because it can handle a wide range of tick speeds whereas you are able to keep things simple by specifically picking a 1us period.
why you didn't use pre-scaler ?!
your code need a relly relly big delay intervall(1 sec it's huge time according to cpu speed) .... so it's not wisdom choose to interrupt microcontroller every 1 us !!.. so it will be great if we could slow down your microcontroller clock and make interrupt for example every 1 ms
calculation
the microcontroller clock speed is 8 mega Hz so if we chose the preScaller to 64 then the timer clock will be 8MHz/64=125 KHz so that mean each tik (timer clock) time will be 1/125KHZ=8 us
so if we like to have inturrpt every 1ms then we need 125 tik
modify code
try this code it's more clear to understand
#undef F_CPU
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
volatile int millSec;
void timer0_Init();
void toggleLed();
int main(void)
{
// Set LED pin to OUTPUT mode
DDRB |= (1 << 3);
timer0_Init();
millSec = 0; // init the millsecond
sei(); // set Global Interrupt Enable
while (1)
{
if(millSec >= 1000){
// this block of code will run every 1 sec
millSec =0; // start count for the new sec
toggleLed(); // just toggle the led state
}
// Do other backGround jobs
}
}
//#####Helper functions###########
void timer0_Init() {
// Clear timer0 counter
TCNT0 = 130; //255-125=130
// Enable interrupt for timer0 overflow
TIMSK = (1 << 1);
// set prescaler to 64 and start the timer
TCCR0B = (1<<CS00)|(1<<CS01);
}
void toggleLed(){
PORTB ^= (1 << 3); // toggle led output
}
ISR(TIMER0_OVF_vect) {
// this interrupt will happen every 1 ms
millSec++;
// Clear timer0 counter
TCNT0 = 130;
}
Sorry, i am late but i have got some suggestions. If you calculate the Timer0 with prescaler 1, the timer is counting up every 125ns. It is not possible to reach 1 us without a small divergence. But if you use prescaler 8 you reach exactly 1 us. I actually do not have your hardware but give this a try:
#ifndef F_CPU
#define F_CPU 8000000UL
#else
#error "F_CPU already defined"
#endif
#include <avr/io.h>
#include <avr/interrupt.h>
volatile unsigned int microsecondsTimer;
// Interrupt for Timer0 Compare Match A
ISR(TIMER0_COMPA_vect)
{
microsecondsTimer++;
}
// Timer0 init
void timer0_Init()
{
// Timer0:
// - Mode: CTC
// - Prescaler: /8
TCCR0A = (1<<WGM01);
TCCR0B = (1<<CS01);
OCR0A = 1;
TIMSK = (1<<OCIE0A)
sei();
}
void ledBlink() {
static unsigned int blinkTimer;
if(microsecondsTimer >= 1000)
{
microsecondsTimer = 0;
blinkTimer++;
}
if(blinkTimer >= 1000)
{
PORTB ^= (1<<PINB3);
blinkTimer = 0;
}
}
int main(void)
{
// Set LED pin to OUTPUT mode
DDRB |= (1 << PINB3);
timer0_Init();
while (1)
{
ledBlink();
}
}
If you are using internal clock of attiny it may be divied by 8. To disable the clock division you have to disable the prescaler within 4 clock cycles (atomic operation):
int main(void)
{
// Reset clock prescaling
CLKPR = (1<<CLKPR);
CLKPR = 0x00;
// ...
Please try this solution an give feedback if it is working. Maybe you can verify it with an oscilloscope...
Notice that operations with unsigned long needs more than 1 clock cycle to handle on an 8 bit microcontroller. Maybe it would be better to use unsigned int or unsigned char. The main loop also should not contain lots if instructions. Otherwise error correction of microsecond timer has to be implemented.
Basic description of what I have to do :
The "reaction timer" is an embedded system that measures the user's reaction time to a signal and displays it in a scale of three LEDs. When the user presses the "ready" pushbutton on the system, the "reaction timer" turns off all LEDs in the system and waits for a random amount of time between 1 and 10 seconds. Upon the expiration of this waiting time, the "reaction timer" turns on a blue LED and signals to the user. The user then presses the "react" pushbutton on the system as quickly as possible to react to the signal. The "reaction timer" then turns off the blue LED used to signal and measures the time elapsed between the signal and the user's reaction to the signal. If the user's reaction time to signal is less than one second, greater than one second but less than two seconds or greater than two seconds, the "reaction timer" turns on a green, orange or a red LED, respectively to display the user's performance.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdlib.h> //library includes srand(), rand() methods
#include <time.h> //library include time()
#define F_CPU 4000000UL; //Define F_CPU as 4MHz
int volatile randomnum; //Declare volatile variable for random number generation
int volatile speed; //Declare volatile variable to get the reaction speed
int main(void)
{
DDRB = DDRB | 0b00100111; //Configure PB5,PB0,PB1,PB2 as outputs
DDRD = DDRD & 0b11110011; //Configure PD2(INT0), PD3(INT3) as inputs
PORTD = PORTD | 0b00001100; //Pull-up PD2, PD3
EICRA = (EICRA & 0b11111010) | 0b00001010; //Set external interrupt on falling edge of INT0,INT1
EIMSK = EIMSK | 0b00000011; //Enable external interrupt on INT0,INT1
sei(); //Enable interrupts globally
TCCR1B = (TCCR1B & 0b11111101) | 0b00000101; //Set clock source as F_CPU/1024
TCNT1 = 0; //Default TCNT value as 0
while (1)
{
}
return 0;
}
ISR(INT0_vect){
time_t t; //Declare time variable
PORTB = 0; //Switch off all LEDs
srand( (unsigned) time(&t) ); //Seed the random number using time
randomnum = rand() % 10 + 1; //Generate a random number between 1-10
TCNT1 = ( 65535 - (randomnum * 3906.25) ) + 1; //Assign the value for TCNT to get the delay of random number seconds
TIMSK1 = TIMSK1 | 0b00000001; //Enable timer overflow interrupt
}
ISR(TIMER1_OVF_vect){ //ISR for timer overflow interrupt
PORTB=PORTB|0b00100000; //Switch ON LED connected to PB5
}
ISR(INT1_vect){
speed = TCNT1 / 3906.25; //Calculate the time taken to react
if(speed > 2) //If reaction time greater than 2s
{
PORTB = PORTB | 0b00000100; //Switch ON LED connected to PB2
}
else if ( (speed<2) && (speed>1) ) //If reaction time greater than 1s but less than 2s
{
PORTB = PORTB | 0b00000010; //Switch ON LED connected to PB1
}
else if(speed < 1) //If reaction time less than 1s
{
PORTB = PORTB | 0b00000001; //Switch ON LED connected to PB0
}
}
I have tried to find references on C programs to code embedded system as above. But failed as all those were in arduino.
The above program seems to work only if random number generates as 1. I couldn't find where is the error. Can you please refer my code and point me where the error is?
I think you should clear the overflow flag BEFORE enabling the related interrupt.
Otherwise, if the flag is already set (i.e. about 17 seconds have passed since starting up the program) the interrupt will fire right away.
Please try this, just before enabling the overflow interrupt:
TIFR1 = 0b00000001; // Clear timer overflow flag
I´m quite new in this kind of programming.
I need to create a real time count on MSP430F6736A (with millisecond accuracy). I'm creating an app that neeeds to do something in short intervals
(for example: every 2 seconds turn on LED for 50 milliseconds).
Using Code composer 6.1.1
I was thinking about use of Timer and interrupts but I don´t know if it is possible to count millisec like this. I just read that can be applied on seconds, hours .... If it is possible which clock should I choose?
The other way I thought about was some delay or sleep. Can i sleep uC for a 50 millisec (real time) preciselly?
EDIT
Here´s code. / [Code ][1]/ Using Timer_A, ACLK and his interrupt to blink LED(just blinking now- same long time torned off- same time turned on).
This code blink led with 2 sec delay.
There is problem that register TA1CCR0 can be max 0xFFFF= 65535 (2 sec for ACLK)
And for my application i will need scale from 1 sec to 999 sec. (row 6-7 in code). How can I do that? Is it possible?
#include <msp430.h>
#include <msp430f6736.h>
void CfgTA(unsigned long delayCycles)
{
int t2=2; // must be variable from 1 to 999
t2=delayCycles*t2;
TA1CCTL0 |= CCIE; //Enable Interrupts on Timer
TA1CCR0 = t2-1; //Number of cycles in the timer
TA1CTL |= TASSEL_1 | MC_1; //ACLK , UP mode
}
void ledblink()
{
//LED config
P4DIR |= BIT6;
P4OUT &= ~BIT6;
CfgTA(32768); //Timer configuration to blink every 1 sec
while (1)
{
_bis_SR_register(LPM3_bits + GIE); //Enter Low Power Mode 3 with interrupts
}
}
#pragma vector=TIMER1_A0_VECTOR
__interrupt void Timer_A0(void)
{
P4OUT ^= BIT6; // Swapping on/off LED
}
int main(void) {
WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer
ledblink();
return 0;
}
I have an atmega168a chip. I use Counter 0 to toggle PORTC by using ISR(TIMER0_COMPA_vect) and ISR(TIMERB_COMPA_vect) interrupt sub-routines. I would like to activate the 16-bit timer when if condition is true. So, I use TIMSK1 = (1<<OCIE1A), but this line calls ISR(TIMER1_COMPA_vect) interrupt instantly where I want 16 bit timer to be interrupted only when the counter reaches to OCR1A value. How can I activate the 16-bit timer on the run-time without causing an instant interrupt?
here is my code:
#define F_CPU 8000000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdint.h>
volatile uint8_t counter;
int main (void){
DDRC = 0xFF; //sets PORTC as output
PORTC = 0xFF; //initial output value
/*COUNTER0 settings*/
TIMSK0 = ((1<<OCIE0A) | (1<<OCIE0B)); // Enable Interrupt TimerCounter0 Compare Match A & B
TCCR0A = (1<<WGM01); // Mode = CTC
TCCR0B = (1<<CS01) | (1<<CS00); // Clock/64, 1/(8000000/64)= 0.000008 seconds per tick
OCR0A = 200; // 0.000008 *230 = 1.6 ms
OCR0B = 100; // 0.8 ms
/*16bit timer - counter1 settings*/
TIMSK1 &= ~(1<<OCIE1A); // Disable Interrupt Counter 1, output compare A (TIMER1_CMPA_vect)
TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12)); // Clock/1024, 1/(8000000/1024) = 0.000128 seconds per tick, Mode=CTC
OCR1A = 40; // 0.000128*40 ~= 5.12 milliseconds
sei(); //interrupts are globally switched on
counter =0;
while(1){
if(counter >= 4){
TCNT1 = 0; // clear the counter 1
TIMSK1 = (1<<OCIE1A);// Enables the interrupt for Counter 1,(TIMER1_CMPA_vect)
TIMSK0 &= ~((1<<OCIE0A) | (1<<OCIE0B)); //disables the Counter 0's interrupts
counter = 0;
}
}
return 0;
}
ISR(TIMER0_COMPA_vect){ //1.6ms
PORTC = 0xFF;
counter++;
}
ISR(TIMER0_COMPB_vect){ //0.8 ms
PORTC = ~PORTC;
}
ISR(TIMER1_COMPA_vect){ // 5.2 milisecond interrupt
PORTC = 0x00;
TCNT0 = 0; //clear the counter of counter0
// TIMSK0 = ((1<<OCIE0A) | (1<<OCIE0B)); //Enable the Counter 0 interrupts
// TIMSK1 &= ~(1<<OCIE1A);// Disable Interrupt Counter 1, output compare A (TIMER1_CMPA_vect)
}
here is an oscilloscope output that shows why I don't want the interrupt to be set instantly, because it set the signal 0 instantly.
I think the problem might be that in CTC mode, interrupt is generated when OCF1A flag is set (in TIFR). Since your timer is always running, just not generating interrupts, it sets OCF1A flag, which never gets cleared. On page 142 in the datasheet it says:
OCF1B is automatically cleared when the Output Compare Match B
Interrupt Vector is executed. Alternatively, OCF1B can be cleared by
writing a logic one to its bit location.
This means that when you set up timer 1, you also need to clear OCF1A:
TIFR1 &= ~(1<<OCF1A)
However, I think you can do better. You could just stop the timer when not needed, and start it when you do, instead of twiddling the TIMSK and having timer 1 run always. If you set TCCR1B to zero, that clears CS12, CS11, and CS10, which, according to the datasheet means "Timer stopped." Then, when your counter reaches 4 you can turn on timer1 as you have it above:
TCCR1B = ((1<<CS12) | (1<<CS10) | (1<<WGM12));
If you do this, you shouldn't need to turn timer 1 interrupts on and off: just leave them on, and only turn the counting on when you need it.
Also I am wondering if it is actually necessary to fire off two interrupts to toggle pins on PORTC? Are you not using PWM for that because it doesn't give you the pulse lengths precisely enough?