OK so I have been attempting to create some code using a MSP430FR5994 TI launch pad that utilizes Timer0 and 3 separate compare registers to trigger 3 separate isr's. I have successfully got one to work however as soon as I add another compare register the CCIFE flag sets and never competes the execution of the second isr. I have watched the code in the debugger on both CCstudio and IAR same thing happens in both, the set up registers are correct and the TA0R registers is counting and will trigger the first isr based on the TA0CCR0 but all other compare regs R1 2 3 etc will not trigger and execute successfully. The code is below, idea's on what I am doing wrong would be much appreciated.
#include "msp430.h"
#include <stdbool.h>
#define COUNT_1 12000
#define COUNT_2 800
int main( void )
{
// Stop watchdog timer to prevent time out reset
WDTCTL = WDTPW + WDTHOLD;
PM5CTL0 &= ~LOCKLPM5;
P1DIR |= BIT0 + BIT1;
P1OUT = BIT0 + BIT1;
//set up and enable timer A or TA0 for continous mode
TA0CCR0 = COUNT_1;
TA1CCR1 = COUNT_2;
TA0CTL = TASSEL__ACLK + MC_2; //set the max period for 16bit timer operation
TA1CTL = TASSEL__ACLK + MC_2;
TA0CCTL0 = CCIE; //enable compare reg 0
TA1CCTL1 = CCIE; //enable compare reg 1
//TA0CTL |= TAIE;
_BIS_SR( GIE); //ENABLE GLOBAL INTERRRUPTS
//set the max period for 16bit timer operation
while(true){}
}
#pragma vector= TIMER0_A0_VECTOR //compare interrupt 0 flahse red led
__interrupt void TIMER0_A0(void) {
P1OUT ^= BIT1 ;
}
#pragma vector = TIMER1_A1_VECTOR //compare interrupt 1 flashes green led
__interrupt void TIMER1_A1(void) {
P1OUT ^= BIT0;
}
The User's Guide says in section 25.2.6.1:
The TAxCCR0 CCIFG flag is automatically reset when the TAxCCR0 interrupt
request is serviced.
However, this does not happen for the other CCRx interrupts, because multiple ones use the same interrupt vector.
Section 25.2.5.2 says:
The highest-priority enabled interrupt generates a number in the TAxIV register (see register description). […]
Any access, read or write, of the TAxIV register automatically resets the highest-pending interrupt flag.
So you always have to read the TAxIV register (and with three or more CCRs, you need it to find out which CCR triggered the interrupt):
__interrupt void TIMER1_A1(void) {
switch (TA1IV) {
case TAIV__TACCR1:
P1OUT ^= BIT0;
break;
case TAIV__TACCR2:
...
break;
}
}
Related
I am trying to implement a 16-bit timer overflow interrupt on the ATMEGA168. The idea is to write a message to the UART I/O register when the timer overflows.
I've tested the UART separately and it works fine via RealTerm (baudrate of 9600 bits/s).
I created a base project from https://start.atmel.com/#dashboard where I had to set the input clock frequency to 16MHz to be compatible with the debugger (see page 5). So I would expect to see a 0x1 on my serial terminal every (16x106 / 1024)-1 x 216 = 4.194 seconds.
However, I'm not seeing anything on the terminal regardless of the prescaler I select. Can anyone please advise what could be going wrong?
I have attached the ISR and the main() below:
#include <atmel_start.h>
#include <stdio.h>
#include <usart_basic.h>
#include <atomic.h>
#include <avr/interrupt.h>
#include <avr/io.h>
// timer1 overflow
ISR(TIMER1_OVF_vect) {
// Send 0x1 over UART
UDR0 = 0x1;
}
int main(void) {
atmel_start_init();
// enable timer overflow interrupt for Timer1
TIMSK1 = (1<<TOIE1); // also tried |=
// start 16-bit counter with /1024 prescaler
TCCR1B = (1 << CS10) | (1 << CS12); // also tried |=
TCCR1A = 0x0;
// enable interrupts
sei();
while(true) {
// more code here...
}
}
I have tried to isolate the problem by not writing to UART in the ISR, but just incrementing a counter (declared with the volatile qualifier) and then printing its value to the screen via UART in the while(true) loop. But the counter doesn't increment either and remains stuck at 0.
You have no USART initialisation code. Specifically you don't enable the transmitter or set the baud rate. I accept that you have tried it with a counter, but that is not the code shown so we can come to no conclusion about its correctness or otherwise.
Without initialisation, the transmitter will not run, and the baud rate will be 1Mbps. Your need at least:
// Set baud rate 9600
uint16_t brr = (FOSC / 16 / 9600) - 1
UBRR0H = (uint8_t)(ubrr >> 8);
UBRR0L = (uint8_t)ubrr;
// Enable transmitter
UCSR0B = (1<<TXEN0);
// Note reset state frame is N,8,1
I am not convinced that it matters but your timer initialisation order is not idiomatic. You would normally enable the interrupt after setting the prescaler and any other configurations, and to ensure the first period is a complete period, reset the counter to zero immediately before enabling interrupts.
// set up timer with prescaler = 1024
TCCR1B = (1 << CS12) & (1 << CS11);
// initialise counter
TCNT1 = 0;
// enable overflow interrupt
TIMSK = (1 << TOIE1);
// enable global interrupts
sei();
As I said, I am not sure that will fix your problem but the elided part:
while(true) {
// more code here...
}
may well be the code that is breaking it. You would do well to discount that possibility by disabling or removing any code there temporarily.
With timers, I want to toggle an LED every one second. I'm using ATMega32 and the clock frequency is 1MHz. I can get to 0.1 second using the 8-bit counter, and for each 10 timer interrupts, I blink the led.
#define F_CPU 1000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
typedef unsigned char u8_t;
typedef unsigned short u16_t;
void func();
int main(void)
{
DDRC = 0x80;
TCCR0 |= (1 << WGM01); // CTC bit.
TCCR0 |= (1 << CS02) | (1 << CS00); // Prescalar = 1024.
OCR0 = 98; // 98 ticks correspond to roughly 0.1 second with 1024 prescaler
TIMSK |= (1 << OCIE0);
TCNT0 = 0;
sei();
while(1)
{
if (!(TIFR & (1 << OCF0))) {
func();
}
}
}
void func()
{
static u8_t extra_time = 0;
if (extra_time == 10)
{
extra_time = 0;
PORTC ^= 0x80;
}
else extra_time++;
TIFR |= (1 << OCF0);
}
In the preceding code, I do not define an ISR for the TIMER0_COMP_vect interrupt.
From the datasheet:
The OCF0 bit is set (one) when a compare match occurs between the Timer/Counter0 and the
data in OCR0 – Output Compare Register0. OCF0 is cleared by hardware when executing the
corresponding interrupt handling vector. Alternatively, OCF0 is cleared by writing a logic one to
the flag. When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and
OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed.
emphasis mine.
Therefore, by the emphasized sentence, I can check for the OCF0 bit for being a zero, and if so, I can "handle" the on-compare-match event.
However, the LED blinks much more frequently (not even a tenth second between each blink but I cannot measure of course).
This works fine if I just set an ISR on TIMER0_COMP_vect and check for nothing, but I want to know why is the OCF0 always(?) logic 0, hence "on", even though I set it to high on each func() call. And what's the problem with this method.
Keep reading the next line in the data sheet
When the I-bit in SREG, OCIE0 (Timer/Counter0 Compare Match Interrupt Enable), and OCF0 are set (one), the Timer/Counter0 Compare Match Interrupt is executed.
then take a look at your code
you have Enabled Compare Match Interrupt
TIMSK |= (1 << OCIE0);
you have Enabled the Global interrupt (I-bit in SREG)
sei();
so whenever output compare flag OCF0 is set then all the 3 conditions for interrupt have occurred and interrupt is automatically fired
when an interrupt has been fired the program flow of execution will jump to a specific memory location corresponding to this interrupt to execute the code and handle it,
but you did not provide any code for this interrupt (no ISR), so the microcontroller does not know what he can do because you did not tell him, so simply he will RESET
and so on, interrupt with no Handler keep fired makes the microcontroller keep
reset
finally, when you add an empty ISR you Provide a code which tell the microcontroller to do nothing if this interrupt is fired and the micro will not reset because he knows how to handle it
if you want to keep track OCF0 flag by yourself delete this line
TIMSK |= (1 << OCIE0);
Hello i have been coding with Tm4c123gh6pm lately and i have faced a part where i want to use the edge timing mode , now i haven't went for the tivaware api's i just went for traditional register level and following the datasheet and i faced this problem
i want to know which pin to use as the one where the timer is waiting for the rising edge to come so it moves the current timer value ?
i checked the data sheet all i can find is that timer 0 is somehow related to PB6 and PF0 now i tried PB6 and it didn't work but is that even the correct approach ?
are these the correct pins the microcontroller's timer waits for the rising edge to move the current timer value ?
here is a sample of my code and please note that this is just a testing code im trying its not a final code what i did was copy the initialization section in the datasheet for the timer mode i want and followed it step by step
this code will make the counter start running from 0xFF downwards but when i place a 'high' signal i.e 3.3 volts on PB6 nothing is moved to the GPTMTnR register.
i just wonder if there is something im doing wrong and im not noticing ?
#include "tm4c123gh6pm.h"
void Timer0Init(void);
int main(void)
{
int i=0;
Timer0Init();
while(1){
for(i=0;i<100000;i++){
}
}
return 0;
}
void Timer0Init(void)
{
//initialize PORT B
volatile unsigned long delay;
SYSCTL_RCGC2_R |= 0x00000002; // 1) B clock
delay = SYSCTL_RCGC2_R; // delay to allow clock to stabilize
GPIO_PORTB_AMSEL_R &= 0x00; // 2) disable analog function
GPIO_PORTB_PCTL_R &= 0x00000000; // 3) GPIO clear bit PCTL
GPIO_PORTB_DIR_R &= 0x00; // 4.2) PB all input
GPIO_PORTB_AFSEL_R &= 0x40; // 5) no alternate function
GPIO_PORTB_DEN_R |= 0xFF; // 7) enable digital pins PF4-PF1
GPIO_PORTB_PCTL_R = 7;
//timer clock
SYSCTL_RCGCTIMER_R |=0x01;
delay = SYSCTL_RCGCTIMER_R;
//1. Ensure the timer is disabled (the TnEN bit is cleared) before making any changes.
TIMER0_CTL_R &= 0xFE;
//2. Write the GPTM Configuration (GPTMCFG) register with a value of 0x0000.0004.
TIMER0_CFG_R= 0x00000004;
//3. In the GPTM Timer Mode (GPTMTnMR) register, write the TnCMR field to 0x1 and the TnMR field to 0x3.
TIMER0_TAMR_R= TIMER0_TAMR_R | 0x007;
//4. Configure the type of event that the timer captures by writing the TnEVENT field of the GPTM Control (GPTMCTL) register.
TIMER0_CTL_R = TIMER0_CTL_R & 0xFFFFFFF3;
//5. If a prescaler is to be used, write the prescale value to the GPTM Timer n Prescale Register (GPTMTnPR).
//no prescaler for now
//6. Load the timer start value into the GPTM Timer n Interval Load (GPTMTnILR) register.
TIMER0_TAILR_R = 0xFF;
//7. If interrupts are required, set the CnEIM bit in the GPTM Interrupt Mask (GPTMIMR) register.
//no interrupts required
//8. Set the TnEN bit in the GPTM Control (GPTMCTL) register to enable the timer and start counting.
TIMER0_CTL_R= TIMER0_CTL_R & 0x00000001;
TIMER0_CTL_R |= 0x01;
//9. Poll the CnERIS bit in the GPTMRIS register or wait for the interrupt to be generated (if enabled). In both cases,
//the status flags are cleared by writing a 1 to the CnECINT bit of the GPTM Interrupt Clear (GPTMICR) register.
//The time at which the event happened can be obtained by reading the GPTM Timer n (GPTMTnR) register.
/*In Input Edge Timing mode, the timer continues running after an edge event has been detected,
but the timer interval can be changed at any time by writing the GPTMTnILR register. The change
takes effect at the next cycle after the write.*/
}
there was a problem with my portb initialization i used tivaware for that part and it worked perfectly fine now on placing high on PB6 it passes the current timer value to the other register
also note that when counting up the timer counts up to the value initialized in the TAIL_R register also if u want to reset the timer you need to write the value u want the timer to begin with in the TAV_R register
Best Of Luck everyone
Hello good people of stack overflow. My problem is an interrupt service routine (ISR) that seemingly never executes! Here's some info on my set up:
I am flashing an avr attiny85. I have the bare bones of a project set up so far with simply a main.c and two modules: timer and hardwareInit. In the timer module, I have a timer0_init function that I am using to set up timer0 for CTC mode to overflow ever 1 ms. Here is the function:
void timer0_init( void )
{
cli();
TCCR0B |= 3; //clock select is divided by 64.
TCCR0A |= 2; //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= 2; //Enable overflow interrupt
sei(); //enable global interrupts
}
with the timer set up, I added an ISR to increment ticks every time the counter overflows, so I can keep track of how much time has elapsed, etc.
ISR(TIMER0_OVF_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
as you can see, I commented out the ticks++ because it wasn't working, and replaced it with PORTB |= ( 1 << PORTB0 ); which simply turns on an LED, so if the interrupt is ever executed, I will know by proof of the LED being on.
Unfortunately, I can't get it to turn on and can't see what I'm missing. (to prove that I 1. have the LED set up on the right pin, and 2. am manipulating the correct bit in the correct register, I put just this statement PORTB |= ( 1 << PORTB0 ); in my infinite loop and confirmed the LED came on)
For further explanation, here is my main.c:
/*================================= main.c =================================*/
#define F_CPU 8000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "timer.h"
#include "hardwareInit.h"
int main(){
//Initialize hardware HERE
DDRB |= ( 1 << PORTB0 ); //set this pin as an output for an LED
SetClockPrescale(1); //internal clock divided by 1 = 8 MHz, from hardwareInit
timer0_init(); //set up timer0 for 1 ms overflow
while(1)
{
/* if( getTicks() > 0 )
{
PORTB |= ( 1 << PORTB0 );
_delay_ms(1000);
PORTB &= ~( 1 << PORTB0 );
_delay_ms(1000);
} */
}
return 0;
}
So, what you see in the infinite loop is what I tried first, but after that didn't work, I tried something simpler, just having an empty loop (commented out previous stuff), and waiting for the interrupt to get triggered which would turn on the LED.
Any help you could give would be really appreciated. I'm quite puzzled why this hasn't been working.
You are using the wrong ISR as #andars has pointed out correctly. In CTC "Clear Timer on Compare" mode the timer will never overflow as it will be cleared on compare match.
So you enabled the wrong interrupt of the timer as well. Bit 1 of TIMSK register enables timer overflow interrupt on timer0. That won't be triggered because of the previous reason. Taken from datasheet.
As you are using OCR0A to set the compare value, you have to enable Bit 4 – OCIE0A: Timer/Counter0 Output Compare Match A Interrupt Enable.
Back to the ISR, you need the ISR(TIMER1_COMPA_vect) or ISR(TIMER1_COMPB_vect) depending on which bit you set in TIMSK. Note that the compare value should be written into the matching registers as well, OCR0A or OCR0B.
Note that, you can use the bit names in your code just like the register names, in my opinion it makes the code more transparent.
Your code should be changed as follows to enable the corresponding interrupt:
void timer0_init( void )
{
cli();
TCCR0B |= (1<<CS01) | (1<<CS00); //clock select is divided by 64.
TCCR0A |= (1<<WGM01); //sets mode to CTC
OCR0A = 0x7C; //sets TOP to 124 so the timer will overflow every 1 ms.
TIMSK |= (1<<OCIE0A); //Output Compare Match A Interrupt Enable
sei(); //enable global interrupts
}
The ISR:
ISR(TIMER0_COMPA_vect)
{
cli();
//ticks ++;
PORTB |= ( 1 << PORTB0 );
sei();
}
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?