Part Number: MSP430FR2311
Hello,
Sorry for the horrible title of this thread, but it is hard to describe the problem. I've seen some strange behavior. Sometimes when I run my code the debugger always seems to stop on one of the "__bis_SR_register(LPM0_bits + GIE);" in one of the ADC reading calls. If it hit play it will just loop through the code once more and stop again. I have no breakpoints set. The strange part is if I remove one of the adc reading calls it goes away (e.g adc0_sample()). I dug into this further and started toggling P2.3 when the CPU is awake and notice when it does this strange behavior that GPIO P2.3 will be high all time time which somewhat implies the CPU never goes back to sleep. I even detach the debugger and see the same behavior. Like I said before if I remove one of the adc reading calls, it goes away. So then I added more code in each of the adc_sample() calls that sets the P2.3 low before it goes to sleep waiting for the ADC conversion to finish. After the conversion is finished I set P2.3 high again. Once I did this the problem went away again. I see what I would expect. P2.3 high for short time and then sleep. It does this three times and then stays high for a longer interval to process everything else and then finally goes back to sleep for a longer interval until the next RTC interrupt kicks off the next cycle through the while(1).
So I'm really confused if I have a race condition of some sort or if I have an implementation bug. Below I've attached the general idea of my code. It is worth noting I'm running the highest level of optimization for size in the compiler.
#include "driverlib.h" #include <msp430.h> /* * main.c */ int main(void) { //Stop WDT WDT_A_hold(WDT_A_BASE); initClockTo16MHz(); initUART(); /* Initialize peripherals */ initGPIO(); initRTC(); __delay_cycles(10000); EUSCI_A_UART_enable(EUSCI_A0_BASE); while(1){ //woken by RTC interrrupt P2OUT |= BIT3; //check CPU usage adc1Sample(); adc1_reading = ADC_Conversion_Result; adc0Sample(); adc0_reading = ADC_Conversion_Result; tempSample(); temperature_reading = ADC_Conversion_Result; do_other_processing(); P2OUT &= ~BIT3; // check cpu usage __bis_SR_register(LPM0_bits + GIE); // change to LPM0 } } void enable_ADC10(uint8_t adc_channel){ //Initialize the ADC Module /* * Base Address for the ADC Module * Use internal ADC bit as sample/hold signal to start conversion * USE MODOSC 5MHZ Digital Oscillator as clock source * Use default clock divider of 1 */ ADC_init(ADC_BASE, ADC_SAMPLEHOLDSOURCE_SC, ADC_CLOCKSOURCE_ADCOSC, ADC_CLOCKDIVIDER_1); ADC_enable(ADC_BASE); ADC_setupSamplingTimer(ADC_BASE, ADC_CYCLEHOLD_1024_CYCLES, ADC_MULTIPLESAMPLESDISABLE); if(adc_channel == ADCINCH_12) { ADC_configureMemory(ADC_BASE, adc_channel, ADC_VREFPOS_INT, ADC_VREFNEG_AVSS); } else { ADC_configureMemory(ADC_BASE, adc_channel, ADC_VREFPOS_AVCC, ADC_VREFNEG_AVSS); } ADC_clearInterrupt(ADC_BASE, ADC_COMPLETED_INTERRUPT); //Enable the Memory Buffer Interrupt ADC_enableInterrupt(ADC_BASE, ADC_COMPLETED_INTERRUPT); } void disable_ADC10(void){ ADC_disableConversions(ADC_BASE,0); ADC_disable(ADC_BASE); } void adc1Sample(void) { enable_ADC10(ADCINCH_1); __delay_cycles(15); //Enable and Start the conversion //in Single-Channel, Single Conversion Mode ADC_startConversion(ADC_BASE, ADC_SINGLECHANNEL); //LPM0, ADC conversion complete will force exit __bis_SR_register(LPM0_bits + GIE); disable_ADC10(); } void adc0Sample(void) { enable_ADC10(ADCINCH_0); // should be 0 __delay_cycles(15); //Enable and Start the conversion //in Single-Channel, Single Conversion Mode ADC_startConversion(ADC_BASE, ADC_SINGLECHANNEL); //LPM0, ADC conversion complete will force exit __bis_SR_register(LPM0_bits + GIE); disable_ADC10(); } void tempSample(void) { enable_ADC10(ADCINCH_12); __delay_cycles(15); //Enable and Start the conversion //in Single-Channel, Single Conversion Mode ADC_startConversion(ADC_BASE, ADC_SINGLECHANNEL); //LPM0, ADC conversion complete will force exit __bis_SR_register(LPM0_bits + GIE); disable_ADC10(); } void initGPIO(void){ P1DIR |= 0b01000000; P2DIR |= 0b00001111; // P0-P3 all outputs P2OUT = 0x00; PMM_enableTempSensor(); // enable temperature sensor PMM_enableInternalReference(); P1SEL1 |= GPIO_PIN6; // PWM mode P1SEL1 &= ~(BIT7); // USCI_A0 UART operation TX only P1SEL0 |= BIT7; // I2C pins P1SEL0 |= BIT2 | BIT3; P1SEL1 &= ~(BIT2 | BIT3); //ADC Pins P1SEL0 |= BIT0 | BIT1; P1SEL1 |= BIT0 | BIT1; /* * Disable the GPIO power-on default high-impedance mode to activate * previously configured port settings */ PMM_unlockLPM5(); } // ADC interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=ADC_VECTOR __interrupt void ADC_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(ADC_VECTOR))) ADC_ISR (void) #else #error Compiler not supported! #endif { ADC_Conversion_Result = ADCMEM0; // AP __bic_SR_register_on_exit(LPM0_bits); // Exits LPM0 } void initClockTo16MHz() { // Configure one FRAM waitstate as required by the device datasheet for MCLK // operation beyond 8MHz _before_ configuring the clock system. FRCTL0 = FRCTLPW | NWAITS_1; __bis_SR_register(SCG0); // disable FLL CSCTL8 |= MODOSCREQEN; CSCTL3 |= SELREF__REFOCLK; // Set REFO as FLL reference source CSCTL0 = 0; // clear DCO and MOD registers CSCTL1 &= ~(DCORSEL_7); // Clear DCO frequency select bits first CSCTL1 |= DCORSEL_5; // Set DCO = 16MHz CSCTL2 = FLLD_0 + 487; // set to fDCOCLKDIV = (FLLN + 1)*(fFLLREFCLK/n) // = (487 + 1)*(32.768 kHz/1) // = 16 MHz __delay_cycles(3); __bic_SR_register(SCG0); // enable FLL while(CSCTL7 & (FLLUNLOCK0 | FLLUNLOCK1)); // FLL locked CSCTL4 = SELMS__DCOCLKDIV | SELA__REFOCLK; } // RTC interrupt service routine #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector=RTC_VECTOR __interrupt void RTC_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(RTC_VECTOR))) RTC_ISR (void) #else #error Compiler not supported! #endif { __bic_SR_register_on_exit(LPM0_bits); // Sleep Timer Exits LPM0 switch(__even_in_range(RTCIV,RTCIV_RTCIF)) { case RTCIV_NONE: break; // No interrupt case RTCIV_RTCIF: // RTC Overflow break; default: break; } } void initRTC() { RTCMOD = 16-1; // setup for 256Hz SYSCFG2 |= RTCCKSEL; // Select ACLK as RTC clock RTCCTL = RTCSS_1 | RTCSR | RTCPS__16 | RTCIE; }