My Infrared-Receiver sends me digital data on Port P1.1. I already have my Timer configured that if theres a falling or rising edge a interrupt gets triggered. I wanna know how i get the actual time difference between the edges. Afterwards i wanna save them in an array.
Main:
// Stop watchdog timer
WDTCTL = WDTPW + WDTHOLD;
//1mhz = 0.000001
BCSCTL1 = CALBC1_1MHZ; // load calibrated data
DCOCTL = CALDCO_1MHZ;
//Define Outputs
P1DIR = green_led+red_led+IR_Send;
P2DIR = LED1+LED2+LED3;
//Define Inputs
P1DIR &= ~IR_Recv;
//Set IR_Recv as input for Timer (TA0.CCI0A)
P1SEL |= BIT1;
//Timer_A using SMCLK/8 = 0.000008s and Continuous mode
TACTL = TASSEL_2 | MC_2 | ID_3;
// falling edge and rising edge capture mode, CCI0A, enable IE
CCTL0 = CM_3 | CCIS_0 | CAP | CCIE;
//Enter LPM and enable Global Interrupts
__bis_SR_register(CPUOFF + GIE);
Interrupt Routine:
//gets called when falling or rising edge is detected on IR_Recv
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A (void)
{
if(edgeCount < 10){
rxData[edgeCount] = TACCR0;
TACCR0 = 0;
}
edgeCount++;
P2OUT ^= LED2;
//Clear interrupt Flag
TACCTL0 &= ~CCIFG;
//go back to LPM
__bic_SR_register_on_exit ( CPUOFF );
}
To get the time difference, in ticks, between two captured events, just let the timer keep running without resetting it, and subtract the captured time stamps:
uint16_t difference = rxData[1] - rxData[0];
This computation is correct even when the timer counter happens to overflow.
Related
I'm using and MSP430F5529 dev board, a created PCB and CCS to program. My code is as follows:
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW | WDTHOLD; //stop watchdog timer
P1SEL |= BIT2; //configure P1.2 as TA0.2
P1DIR |= BIT2; //P1.2 is output (compare mode)
P1SEL |= BIT3; //configure P1.3 as TA0.3
P1DIR |= BIT3; //P1.3 is output (compare mode)
P1SEL |= BIT4; //configure P1.4 as TA0.4
P1DIR |= BIT4; //P1.4 is output (compare mode)
TA0CCR0 = 999; //CCR0 is used to generate the desired period
TA0CCR2 = 599; //CCR2 is used to generate 0.60 duty cycle
TA0CCR3 = 299; //CCR3 is used to generate 0.30 duty cycle
TA0CCR4 = 99; //CCR4 is used to generate 0.10 duty cycle
TA0CCTL2 = OUTMOD_7; //PWM 2
TA0CCTL3 = OUTMOD_7; //PWM 3
TA0CCTL4 = OUTMOD_7; //PWM 4
TA0CTL = MC_1 + TASSEL_2 + TACLR|ID_2;
_BIS_SR(LPM0_bits+GIE);
}
Not a single LED turns on using this code and I am unsure of how to fix it.
You return from main() in a bare metal MCU program, so it will crash & burn before it gets a chance to do anything meaningful.
The most common way to write main() in freestanding programs is:
void main (void)
{
...
for(;;)
{
// kick watchdog here
...
}
}
Notable, this never returns from main() but stay in the "for-ever" loop.
void main (void) is an implementation-defined form supported by every embedded systems compiler out there. (To use this form on gcc, you have to compile with -ffreestanding.)
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;
}
}
The While(busy); loop is instantly skipped. But the only place where busy can be set to 0 is in the Timer1 ISR. But Timer 1 is stopped and only ever starts when in the Pin Change ISR.
From the UART output I can tell that Timer 1 ISR happens, while Pin Change ISR never does. which should not be possible, right?
What am I missing?
In my main function:
...
uint32_t temp = 0;
busy = 1;
mode = 1;
// Timer Interrupt Init
TCCR1B &= ~((1<<2) | (1<<1) | (1<<0)); // Makeing sure timer is not running
TIMSK1 |= (1 << TOIE1); // Timer 1 overflow interrupt enable
TCNT1 = 0; // Makeing sure Timer is on 0
// Pin Change Interrupt Init
PCICR |= (1<<2); // Activating PCMSK2
PCMSK2 |= (1<<6); // PCMSK2 -> PCINT23.. 16 seem to correspond to physical pins D 0-7
UartSendstring("1");
// Scanning (see ISR)
sei();
TCCR1B &= ~((1<<2) | (1<<1) | (1<<0));
while(busy);
cli();
...
Timer 1 ISR:
ISR(TIMER1_OVF_vect)
{
UartSendstring("3");
busy = 0;
}
Pin Change ISR:
ISR(PCINT2_vect)
{
UartSendstring("2");
//todo make first values not empty
TCCR1B &= ~((1<<2) | (1<<1) | (1<<0));// CS12 - CS10 are set to 0 to stop the timer
data[addr] |= TCNT1L;
data[addr] |= (TCNT1H << 8); // High and low byte are saved to data
TCNT1 = 0; // Timer is reset
TCCR1B |= ((1<<1) | (1<<0)); // CS12 is set to 1 to restart the timer with prescaler 64 -> tick time = 4us
// Signal period duration is 1s / 38 000 = 26us
// -> at least on timer tick in one signal period
addr++; // Prepares to write to the next address with next edge
}
Uart output is:
13
edit
I tried moving the TIMSK1 |= (1 << TOIE1); to the Pin Change ISR. Now it goes in there at least once like I want it but as soon as I enable the Interrupt it triggers the ISR again and ends.
As the Arduino core starts all timers by default (because of PWM), there is possibility that interrupt flags are already set and they fires as soon as you enable the corresponding interrupts. So you have to clear them before reenabling interrupts. But there is a tiny little obstacle: interrupt flags are cleared by writing logic one into corresponding bit. Therefore you have to use something like this TIFR1 = _BV(ICF1) | _BV(OCF1B) | _BV(OCF1A) | _BV(TOV1); (however as you don't use any other Timer1 interrupt, you can clear TOV1 flag only).
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.
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?