This thread has been locked.
If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.
Hello! I am working on a code, the aim of which is to blink the 2 the LED with a timer based delay passed as a parameter to a function. Following is the code :
------------------------------------------------------------------------------------------------------------------------------------------------------
#include <msp430f5438a.h>
unsigned long flag0 = 0, flag1 = 0, count0 = 0, count1 = 0, delay0 = 0, delay1 = 0 ;
void configA0 ( unsigned long ) ;
void configA1 ( unsigned long ) ;
void blink0 ()
{
if ( flag0 ==1)
{ if ( (delay0%0xFFFF) )
{ flag0 = 0; configA0 ( delay0%0xFFFF ) ; }
else
P1OUT ^= BIT0;
}
else P1OUT ^= BIT0;
}
void blink1 ()
{
if ( flag1== 1 )
{ if ( (delay1 % 0xFFFF) )
{ flag1 = 0; configA1 ( delay1 % 0xFFFF) ; }
else
P1OUT ^= BIT6 ;
}
else P1OUT ^= BIT6;
}
void configA0 (unsigned long i)
{
delay0 = i;
if ( delay0 > 0xFFFF )
{ flag0 = 1;
count0 = delay0 / 0xFFFF;
TA0CCR0 = 0xFFFF ; // Count limit (16 bit)
TA0CCTL0 = 0x10; // Enable Timer A1 interrupts, bit 4=1
TA0CTL = TASSEL_1 + MC_1; // Timer A1 with ACLK, count UP
}
else {
TA0CCR0 = delay0 ; // Count limit (16 bit)
TA0CCTL0 = 0x10; // Enable Timer A1 interrupts, bit 4=1
TA0CTL = TASSEL_1 + MC_1; // Timer A1 with ACLK, count UP
}
}
void configA1 ( unsigned long i)
{
//if ( delay > 65535)
// configA1 ( delay - 65535) ;
//long temp = delay ;
delay1 = i ;
if ( delay1 > 0xFFFF )
{
flag1 = 1;
count1 = delay1/ 0xFFFF ;
TA1CCR0 = 0xFFFF ; // Count limit (16 bit)
TA1CCTL0 = 0x10; // Enable Timer A1 interrupts, bit 4=1
TA1CTL = TASSEL_1 + MC_1; // Timer A1 with ACLK, count UP
}
else {
TA1CCR0 = delay1 ; // Count limit (16 bit)
TA1CCTL0 = 0x10; // Enable Timer A1 interrupts, bit 4=1
TA1CTL = TASSEL_1 + MC_1; // Timer A1 with ACLK, count UP
}
}
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer
P1DIR |= BIT0; // Set P1.0 to output direction
P1OUT &= ~BIT0; // Set the red LED off
P1DIR |= BIT6; // Set P1.6 to output direction
P1OUT &= ~BIT6; // Set the green LED off
configA0 ( 327675 ) ;
configA1 ( 65535 ) ;
_BIS_SR(GIE); // LPM0 (low power mode) interrupts enabled
// eint () ;
}
#pragma vector=TIMER1_A0_VECTOR // Timer1 A0 interrupt service routine
__interrupt void Timer1_A0 (void)
{
if ( flag1 == 1 )
{
count1 -- ;
if ( count1== 0 )
blink1 ();
}
else blink1();
}
#pragma vector=TIMER0_A0_VECTOR // Timer0 A0 interrupt service routine
__interrupt void Timer0_A0 (void)
{
if( flag0 == 1 )
{
count0 -- ;
if ( count0 == 0 )
blink0() ;
}
else blink0 () ;
}
---------------------------------------------------------------------------------------------------------------------------------------------------------------------
Now, when I run this code, the LEDs blink erratically; and the blinks are separated by long time intervals , sometimes even going till seconds. I do not understand why there is such an error. Someone, please help me .
>BIS_SR(GIE); // LPM0 (low power mode)
Does not turn main routine off, just enables IRQ and then keeps going.
You can make it a 17bit counter by just checking the TAIFG bit (irq don't even have to be enable I think)
Going above 0xffff by using a LONG, complicates it as you have to find out how many full turns around 0xffff and the final pass has to use the reminder.
I would not use division or modulo, as this can be handled with plain & + -
And as it should be that 0x0000 (as in 0x10000) should be added to ccr0 (so just leave it alone),
timer_a0 isr: (pseudo code) if (!delay_long) xor led;delay_long=value; if (delay_long &0xffff0000) delay_long -=0x10000; else ccr0 += delay_long; delay_long=0; //may have to use cast to += a long to a word register(?)
See my post here to get idea of blink two led's using a state machine.
Hi, to blink a led 1mS is enough so try use timer to have some counter of elapsed time in mS to use set led on or off. 1mS give you some hundred instruction to test if timer is the value you need. Your code is crazy and when you try test delay I don't understand where is called then time has elapsed.
Again you are calling code from interrupt, this is a bad habit, set a flag then run on main loop if not very short, this case insert on interrupt service to avoid overhead.
... try simple thing this code is unreadable and crazy...
Just use interrupt to update 1mS counter, keep time from this or better write some sort of timer count down to zero then stop, you can use them to activate an action when time expire.
Tony Philipsson said:Time slice everything to 1mS will make it easier, but if the principal of this code is to get any value at 1uS precision using a long.
Tony, the code has a lot of troubles, in first IRQ has Jitter, yes this is just single so Jitter is limited but no uS precision can be served when instruction time is 1uS for single cycle. Cycles needed to execute interrupt then the code on service forever account on time so never can match...
TO have precise 1uS pulses you need use compare and hardware output mode setting a pin from CCR register, this case on overflow interrupt a decision can be taken of when to load CCR and value too.
If pulse is close to zero has to be loaded early, so two timer are required, one to determine when load hardware CCR another to set output then prepare next event from hardware timer interrupt...
It is not possible from software and intermittent non deterministic behaviour reported by poster is proving that.
Though could just enable outmode on the last turn around, so it toggle the port in hardware and issue a IRQ.
Yes, I do see the problem if reminder or value is to low that it will miss setting CCR0 in time.
ideas, 1: Restricting values to minimum.
2: If reminder (e.g the lower word of the long) is to small it will run the two last loops as 0xFFFF+reminder/2
instead of regular 0xFFFF for the second-to-last and then 0x08(example) for the last one.
Tony Philipsson said:ideas, 1: Restricting values to minimum.
2: If reminder (e.g the lower word of the long) is to small it will run the two last loops as 0xFFFF+reminder/2
instead of regular 0xFFFF for the second-to-last and then 0x08(example) for the last one.
Yes this is KISS rule so it is forever the best way but split on two otherwise rule fails.
**Attention** This is a public forum