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.
I'm trying to enter in LPM4 inside a Comparator_D interruption but when the systems enters in LPM4_bits, never exits. This is my code:
#include <msp430.h>
unsigned int l=0;
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
PJDIR |= BIT0; // P1.0/LED output direction
// compare input
P1SEL0 |= BIT1; // P1.1/CD1
P1SEL1 |= BIT1;
// Setup ComparatorD
CDCTL0 |= CDIPEN + CDIPSEL_1; // Enable V+, input channel CD1
CDCTL2 |= CDRSEL; // VREF is applied to -terminal
CDCTL2 |= CDRS_3+CDREFL_1; // R-ladder off; bandgap ref voltage (1.2V)
// supplied ref amplifier to get Vcref=1.5V (CDREFL_2)
CDCTL3 |= BIT1; // Input Buffer Disable @P1.1/CD1
__delay_cycles(400); // delay for the reference to settle
CDINT &= ~(CDIFG + CDIIFG); // Clear any errant interrupts
CDINT |= CDIE; // Enable CompB Interrupt on rising edge of CDIFG (CDIES=0)
CDCTL1 |= CDON; // Turn On ComparatorD
__bis_SR_register(GIE);
__no_operation(); // For debug
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector=COMP_D_VECTOR
__interrupt void Comp_D_ISR (void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(COMP_D_VECTOR))) Comp_D_ISR (void)
#else
#error Compiler not supported!
#endif
{
l++;
CDCTL1 ^= CDIES; // Toggles interrupt edge
CDINT &= ~(CDIFG + CDIIFG);
if (l%2==0)
{
CDINT|=CDIE;
__bis_SR_register(LPM4_bits);
}
__bic_SR_register_on_exit(LPM4_bits);
PJOUT ^= 0x01; // Toggle P1.0
P3DIR |= BIT5;
P3SEL1 |= BIT5;
P3SEL0 |= BIT5;
//CDCTL1 ^= CDIES; // Toggles interrupt edge
CDINT &= ~CDIFG; // Clear Interrupt flag
}
Inside an interrupt handler, GIE is automatically cleared to prevent the function from being interrupted by another or the same interrupt.
When you go into LPM inside an interrupt handler, the cleared GIE prevents any interrupts that could get the CPU out of LPM from being executed.
When you want to go to sleep, you should do so after the interrupt handler has returned. This is what __bis_SR_register_on_exit() is for.
However, the typical pattern is that the main loop goes to sleep when it has nothing to do, and that interrupt handlers wake up the main loop with __bic_SR_register_on_exit() when they need to.
BTW: You forgot the main loop; execution falls out of the end of main().
Hi, thanks for your answer. What I'm trying to do is when the Vcomp is smaller than Vref0, system should go to sleep and when Vcomp is bigger than Vref1, system should exit from LPM4. I'm programming the interruption as follows just to test what you told me before, but I don't know why the system is kept inside the interruption routine, I mean, when the system exits from LPM4, instead of going to the main loop, it goes to line "l2++" and starts again executing all inside the interruption :
#pragma vector=COMP_D_VECTOR
__interrupt void COMP_D_ISR(void)
{
l2++;
//CDCTL1 ^= CDIES; // Toggles interrupt edge
m=__get_SR_register();
//CDINT &= ~(CDIFG + CDIIFG);
PJOUT ^= 0x01; // Toggle P1.0
P3DIR |= BIT5;
P3SEL1 |= BIT5;
P3SEL0 |= BIT5;
__bis_SR_register_on_exit(LPM4_bits);
}
Hi, thanks for your answer. What I'm trying to do is when the Vcomp is smaller than Vref0, system should go to sleep and when Vcomp is bigger than Vref1, system should exit from LPM4. I'm programming the interruption as follows just to test what you told me before, but I don't know why the system is kept inside the interruption routine, I mean, when the system exits from LPM4, instead of going to the main loop, it goes to line "l2++" and starts again executing all inside the interruption :
#pragma vector=COMP_D_VECTOR
__interrupt void COMP_D_ISR(void)
{
l2++;
//CDCTL1 ^= CDIES; // Toggles interrupt edge
m=__get_SR_register();
//CDINT &= ~(CDIFG + CDIIFG);
PJOUT ^= 0x01; // Toggle P1.0
P3DIR |= BIT5;
P3SEL1 |= BIT5;
P3SEL0 |= BIT5;
__bis_SR_register_on_exit(LPM4_bits);
}
Alberto,
You are not clearing the interrupt flag, so I think you are immediately re-entering the ISR because the flag is still set.
Does your code need to be:
Is that the code flow you are looking for?
This pseudocode shows the kind of code flow I am thinking of if that is the case:
main() { init code set comparator to interrupt if Vcomp < vref0 variable interrupt_edge = 0; //software flag, 0 = falling edge, 1 = rising edge enable interrupts while(1) { other code } } comp_ISR() { if(interrupt_edge == 0) //falling edge { //falling edge handling change CDIES to interrupt on rising edge next time interrupt_edge = 1; //software flag to indicate we are waiting for rising edge next time __bis_SR_register_on_exit(LPM4_bits + GIE); //after exiting ISR, go to LPM4 and wait for the next comp interrupt, rising edge } else { //rising edge handling change CDIES to interrupt on falling edge next time interrupt_edge = 0; //software flag to indicate we are waiting for falling edge next time __bic_SR_register_on_exit(LPM4_bits); //wake part up and go back to main when exiting ISR this time } clear comparator interrupt flag }
Please note - __bic_SR_register_on_exit clears the specified bits - it causes you to wake and return to normal code (if no pending interrupts) on ISR exit. Whereas __bis_SR_register_on_exit sets the specified bits - it causes you to go to sleep mode (if no pending interrupts) on ISR exit.
Does this help show what we are talking about?
Regards,
Katie
HI, Thanks for your answer.
Yes, what you wrote is what I want to implement. I followed your pseudocode but when the system enters in LPM4, never exits. I added my code:
#include <msp430.h>
unsigned int int_edge=0;
unsigned int l=0;
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
int_edge=0;
// compare input
P1SEL0 |= BIT1; // P1.1/CD1
P1SEL1 |= BIT1;
// Compare output
P3DIR |= BIT5;
P3SEL1 |= BIT5;
P3SEL0 |= BIT5;
// Setup Comparatord
CDCTL0 |= CDIPEN + CDIPSEL_1; // Enable V+, input channel CD0
CDCTL2 |= CDRSEL; // VRef is applied to -terminal
//CDCTL2 |= CDRS_1+CDREF13; // VREF1 is Vcc*1/4
//CDCTL2 |= CDREF04+CDREF03; // VREF0 is Vcc*3/4
CDCTL2 |= CDRS_3+CDREFL_1; // R-ladder off; bandgap ref voltage (1.5V)
/*CDCTL2|=CDRS_1;
CDCTL2 |= CDREF14+CDREF13; // VREF1 is Vcc*3/4
CDCTL2 |= CDREF03+CDREF02;; // VREF0 is Vcc*1/4*/
CDCTL3 |= BIT1; // Input Buffer Disable @P1.1/Cd1
CDCTL1|=CDIES;
__delay_cycles(400); // delay for the reference to settle
CDINT |= CDIE; // Enable CompB Interrupt on rising edge of CDIFG (CDIES=0)
CDINT &= ~(CDIFG + CDIIFG); // Clear any errant interrupts
CDCTL1 |= CDON; // Turn On Comparatord
__bis_SR_register(GIE);
while(1)
{
if (l==40)
l=0;
l++;
}
}
#pragma vector=COMP_D_VECTOR
__interrupt void COMP_D_ISR(void)
{
// Compare output
if (int_edge==0)
{
//falling edge handling
CDCTL1 ^= CDIES; // Toggles interrupt edge
int_edge=1;
__bis_SR_register_on_exit(LPM4_bits + GIE); //after exiting ISR, go to LPM4 and wait for the next comp interrupt, rising edge
}
else
{
//rising edge handling
CDCTL1 ^= CDIES; // Toggles interrupt edge.
int_edge=0;
__bic_SR_register_on_exit(LPM4_bits); //wake part up and go back to main when exiting ISR this time
}
CDINT &= ~(CDIE);
}
**Attention** This is a public forum