Hi all,
This is my first post on this helpful forum. I'm currently carrying out my graduating placement as embedded system engineer. Therefore I'm not very experienced with micro-programming and totally new to MSP430. Also I am french so excuse me in advance if sometimes my English sounds weird!
I'm using MSP430F2132 with IAR EW 4.20.1 and I am facing some issues with interrupts.
What I'm trying to do is to drive an IR LED. My output signal is modulated at about 10KHz with a PWM ratio of approximately 10% (high level for 10us and low for 90us). To do this I'm using Timer A in up/down mode. I have no problem for this.
The second point is that I want to emit like this: 20 pulses and then nothing, this periodically every 100ms. I do this with Timer B in up mode and again it works fine.
Last point is the critical point, I want to control this emitting with a knob. When the knob is pushed on: start emitting, when it's released: stop emitting. My main() doesn't do anything except turning the MSP into LPM0. For the time being I only use interrupts. What I do is that I detect first a falling edge on my knob (internal pull-up resistor on Port1 is used) then turn on Timers and toggle the interrupt edge. Then I detect rising edge and stop all timers.
The prob is that sometimes I miss the releasing event. I assume it happens because the MSP is processing Timers ISR and Timers interrupts priorities are higher than I/O Ports ones, so my "knob interrupt" is missed. I would like to know if it's possible to modify interrupts priorities or bypass by any way this problem?
Here is part of my code:
void main( void )
{
WDTCTL = WDTPW + WDTHOLD; //stop watchdog
BCSCTL1 = CALBC1_1MHZ; //Set DCO to 1MHz
DCOCTL = CALDCO_1MHZ; //Set DCO to 1MHz
__bis_SR_register(GIE); //Enable interrupts
P1DIR |= (BIT0); //P1.0 output -> IR emitting diode
P1OUT &= ~(BIT0); //P1.0 = 0
P1DIR &= ~(BIT1); //P1.1 input -> child locker knob
P1REN |= (BIT1); //P1.1 pull-up enabled -> SW to GND
P1IE |= (BIT1); //P1.1 interrupt enabled
P1IES |= (BIT1); //P1.1 interrupt edge: high-to-low
P1IFG = 0; //Clear port 1 interrupt flag
ADC10CTL0 = ADC10SHT_2 + ADC10ON + ADC10IE;
//Sample time 16CLK, ADC ON, Interrupt Enable
ADC10AE0 = 0x01; //P2.0 ADC10 option select
while(1)
{
__bis_SR_register(LPM0_bits); //LP mode 0 = turns CPU OFF
}
}
////////////////////////////////////////////////////////////////////////////////
// Interrupts
////////////////////////////////////////////////////////////////////////////////
//Timer A0 interrupt service routine (TACCR0)
#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer_A_TACCR0 (void)
{
if (IR_pulse++ < 20) //IR emitted for 20periods
{
P1OUT |= (BIT0); //set P1.0
ADC10CTL0 |= ENC + ADC10SC; //Sampling and conversion start
}
else //20pulses have been done
{
IR_pulse = 0;
IR_Process_TimerA_clear(); //Stops TimerA at 8Mhz
IR_Process_TimerB_init(); //Runs TimerB at 1MHz
}
//Timer A1 interrupt service routine (TAIV)
#pragma vector = TIMER0_A1_VECTOR
__interrupt void Timer_A_TAIV (void)
{
switch (__even_in_range(TAIV, 10)) //Efficient switch-implementation
{
case 2: break; //TACCR1 not used
case 4: //TACCR2
P1OUT &= ~(BIT0); //Clear P1.0
case 10: break; //Overflow not used
default: break; //Others cases ignored
}
}
//Timer B0 interrupt service routine (TACCR0)
#pragma vector = TIMER1_A0_VECTOR
__interrupt void Timer_B_TACCR0 (void)
{
IR_Process_TimerB_clear();
IR_Process_TimerA_init();
}
//Port 1 interrupt service routine
#pragma vector = PORT1_VECTOR
__interrupt void Child_locker_ISR (void)
{
__bic_SR_register(GIE);
if (P1IFG & BIT1)
{
if (P1IN & BIT1) //Interrupt triggered on low-to-high
{
IR_Process_TimerA_clear();
IR_Process_TimerB_clear();
}
else //Interrupt triggered on high-to-low
{
IR_Process_TimerA_init();
__bic_SR_register_on_exit(LPM0_bits); //Disable LP mode 0 = CPU is active
}
}
P1IES ^= (BIT1); //Toggle P1.1 interrupt edge
P1IFG = 0; //Clear Port 1 interrupt flag
__bis_SR_register(GIE);
}
//ADC10 interrupt service routine
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
__bic_SR_register_on_exit(LPM0_bits); //Disable LP mode 0 = CPU is active
}
////////////////////////////////////////////////////////////////////////////////
// Timers Registers settings functions
////////////////////////////////////////////////////////////////////////////////
void IR_Process_TimerA_init (void)
{
BCSCTL1 = CALBC1_8MHZ; //Switch DCO to 8MHz
DCOCTL = CALDCO_8MHZ; ////////////////////
TACCTL0 = CCIE; //TACCR0 Interrupt enabled
TACCTL2 = CCIE; //TACCR2 Interrupt enabled
TACCR0 = TACCR_0; //Count value of TACCR0
TACCR2 = TACCR_2; //Count value of TACCR2
TACTL = TASSEL_2 + MC_3; //SMCLK + Up-down mode
}
void IR_Process_TimerB_init (void)
{
TA1CCTL0 = CCIE; //TA1CCR0 Interrupt enabled
TA1CCR0 = TA1CCR_0; //Count value of TA1CCR0
TA1CTL = TASSEL_2 + ID_3 + MC_1; //SMCLK + CLK/8 + Up mode
}
void IR_Process_TimerA_clear (void)
{
BCSCTL1 = CALBC1_1MHZ; //Switch Back DCO to 1MHz
DCOCTL = CALDCO_1MHZ; /////////////////////////
TACCTL0 &= ~(CCIE); //TACCR0 Interrupt disabled
TACCTL2 &= ~(CCIE); //TACCR2 Interrupt disabled
TACTL &= ~(TASSEL_2 + MC_3); //Clear SMCLK + Up-down mode
TACCR0 = 0x0000; //Clear count value
TACCR2 = 0x0000; //Clear count value
}
void IR_Process_TimerB_clear (void)
{
TA1CCTL0 &= ~(CCIE); //TACCR0 Interrupt disabled
TA1CTL &= ~(TASSEL_2 + MC_1); //Clear SMCLK + Up mode
TA1CCR0 = 0x0000; //Clear count value
}
I hope everything is understandable. Any help or advice is deeply welcomed!
Thank you in advance.
Kind Regards,
Antoine