Tool/software:
Hi everybody,
I got a problem with activating a timer in a interrupt, which occurs while the microcontroller is in LPM4.
In my main function, I enable the low power mode to save energy until the user is pressing a button. After that I get into the ISR of the button and want to activate a timer for a standby function. Unfortunately I cannot activate the timer because the microcontroller is still in low-power mode.
I tried the function __bic_SR_register in the ISR to instantly deactivate the low power mode, but this did not work as the program is jumping again in LPM4 after finishing with the ISR.
I also tried the __bic_SR_register_on_exit function. This does properly deactivate the LPM but just when the ISR is finished and I want to activate the timer in the ISR, so the timer does not get activated this way.
I did put my code below and the section where I want to activate and deactivate the LPM4 are commented with "deepsleep"
Does anybody of you can help me out with my problem?
Thanks a lot.
Yours sincerely,
Timo Kurz
#include <msp430.h> #include <stdint.h> #include "asciizeichen.h" #include <stdio.h> #include <string.h> // Definitions for Nokia 5110 display #define LCD_RST BIT2 #define LCD_DC BIT4 #define LCD_DIN BIT5 #define LCD_CLK BIT6 #define LCD_CE BIT1 #define LCD_LED BIT7 #define SW BIT3 // ToDo: change to correct activation bit - VORSICHT!!!! AKTUELL NOCH PORT1 STATT PORT2 #define OUT BIT0 // ToDo: change to correct output bit #define SENSOR_PIN (BIT1 | BIT2) #define STANDBY_TIMEOUT 32768 // Timer for standby modus #define DEBOUNCE_DELAY 5000 // debounce Timer #define CHARGING 1000000 // Value for recognizing if device is plugged in #define MAX_TEMP 120 // Value for safety overheat shutdown #define MIN_VOLTAGE 0 // Value for safety shutdown if battery is empty volatile uint16_t adc_result[3] = {0}; // Variable to store ADC results volatile uint16_t current = 0; // Variable for actual charging current volatile uint16_t voltage = 0; // Variable for actual battery voltage volatile uint16_t temperature = 0; // Variable for actual temperature static int started = 0; void delay(unsigned int t); void LCD_write_byte(unsigned char data, unsigned char mode); void LCD_init(); void LCD_clear(); void LCD_string(char *characters); void LCD_char(char character); void ausgabe_string(char *str1, double kommazahl); void main(void) { double zahl = 0.0; int zaehler = 0, i = 0; WDTCTL = WDTPW | WDTHOLD; // Stop watchdog timer P1DIR |= OUT; // Set Output pin -> Output P1DIR &= ~SW; // Set SW pin -> Input P1REN |= SW; // Enable Resistor for SW pin P1OUT |= SW; // Select Pull Up for SW pin P1OUT &= ~OUT; // Disable Output at start P1IES |= SW; // Select Interrupt on Falling Edge P1IE |= SW; // Enable Interrupt on SW pin // configure ADC ADC10CTL1 = INCH_2 + CONSEQ_3; // Channel select A2 + sequence of channels ADC10CTL0 = SREF_0 + ADC10SHT_2 + ADC10ON + ADC10IE; // REF = VCC & VSS + ADC SampleAndHoldTime 16 x ADC10CLKs + + // ADC10AE0 |= SENSOR_PIN; // These bits enable the PIN 1.1 & P1.2 for analog input P1SEL |= SENSOR_PIN; // ADC input select mode P1.1 & P1.2 // Timer0 to interrupt after 10 seconds TA0CCR0 = STANDBY_TIMEOUT / 8; // 32.768 kHz crystal oscillator, divided by 8 TA0CTL = TASSEL_1 + MC_0 + ID_3; // ACLK (32.768 kHz), Stop mode, Divider 8 TA0CCTL0 |= CCIE; // Timer1 for debouncing TA1CCTL0 |= CCIE; // Enable Timer1 interrupt TA1CCR0 = DEBOUNCE_DELAY; // Set debounce delay TA1CTL = TASSEL_2 + MC_0 + TACLR; // SMCLK, Stop mode, clear timer __bis_SR_register(GIE); // Enable global interrupts while(1) { if(started) { LCD_init(); P1OUT |= OUT; // Toggle Output Pin 1.0 P1OUT |= LCD_LED; // Backlight on LCD_clear(); while (started) { char str1[20] = "Zahl: "; ausgabe_string(str1, zahl); LCD_string(" "); LCD_string("Funktioniert "); for (i = 0; i <= zaehler; i++) { LCD_char(128); } zaehler += 1; if (zaehler >= 5) { zaehler = 0; } zahl += 0.1; if (zahl >= 10.0) { zahl = 0.0; } start_ADC_conversion(); // Start the ADC conversion __delay_cycles(1000000); // one sec delay } } // ToDo: value if device is currently charging else if(current > CHARGING) // State if device Timeout and device is currently charging { P1OUT &= ~LCD_LED; // Backlight off LCD_clear(); } else { P1OUT &= ~LCD_LED; // Backlight off LCD_clear(); P1OUT &= ~OUT; // Turn off Output // __bis_SR_register(LPM4_bits + GIE); // ToDo: deepsleep } } } void start_ADC_conversion() { ADC10CTL1 = INCH_10 + ADC10DIV_3; // Select channel A10 for temperature, divide by 4 ADC10CTL0 = SREF_1 + ADC10SHT_2 + ADC10ON + ADC10IE + REFON + REF2_5V; // Internal reference, 2.5V, ADC on, enable interrupt __delay_cycles(1000); // Wait for reference to settle ADC10CTL0 |= ADC10SC + ENC; // Start conversion while (ADC10CTL1 & ADC10BUSY); // Wait for conversion to finish adc_result[0] = ADC10MEM; temperature = ((adc_result[0] - 673) * 423) / 1024; // Convert ADC value to temperature in Celsius if(temperature > MAX_TEMP) // overheat protection { P1OUT &= ~OUT; // Turn off Output // ToDo: Response, for overheating } ADC10CTL0 &= ~ENC; // Disable conversion ADC10CTL0 &= ~REFON; // Turn off reference to save power ADC10CTL1 = INCH_2; // select channel A2 as input ADC10CTL0 |= ADC10SC + ENC; while (ADC10CTL1 & ADC10BUSY); adc_result[1] = ADC10MEM; voltage = adc_result[1]; // ToDo: conversion to actual value // ToDo: safety shutdown if battery is empty // if(voltage < MIN_VOLTAGE) // { // P1OUT &= ~OUT; // Turn off Output // // ToDo: Response, for empty battery // } ADC10CTL0 &= ~ENC; ADC10CTL1 = INCH_1; // select channel A1 for ADC + Conversion sequence mode select == Sequence-of-channels + ACLK - clock (no input div) ADC10CTL0 |= ADC10SC + ENC; // ADC10SC == 0 >> no sample start conversation + ENC == EnableConversation while (ADC10CTL1 & ADC10BUSY); adc_result[2] = ADC10MEM; current = adc_result[2]; // ToDo: conversion to actual current ADC10CTL0 &= ~ENC; // disable conversation } #pragma vector=ADC10_VECTOR __interrupt void ADC10_ISR(void) { ADC10CTL0 &= ~ADC10IFG; // Clear interrupt flag } #pragma vector=PORT1_VECTOR __interrupt void Port_1(void) { P1IE &= ~SW; // Disable button interrupt P1IFG &= ~SW; // Clear SW interrupt flag started = 1; // __bic_SR_register(LPM4_bits); // ToDo: Wakeup from deepsleep TA0CTL |= MC_1; // Start Timer0 in up mode TA1CTL |= TASSEL_2 + MC_1; // Start Timer1 for debouncing } #pragma vector=TIMER0_A0_VECTOR __interrupt void Timer_A0_ISR(void) { TA0CTL &= ~MC_1; // Stop Timer0 started = 0; TA0CCTL0 &= ~CCIFG; } #pragma vector=TIMER1_A0_VECTOR __interrupt void Timer_A1_ISR(void) { TA1CTL &= ~MC_1; // Stop Timer1 P1IE |= SW; // Re-enable button interrupt TA1CTL |= TACLR; // Clear Timer1 TA1CCTL0 &= ~CCIFG; // Clear Timer1 interrupt flag }