Jump to content
43oh

Cannot wake up from LPM upon ADC conversion end - please help! :)


Recommended Posts

Guys,

I've spent literally 5 hours trying to figure out why my code doesn't work on F5529. It seems that even though I start the ADC12 conversion the ISR isn't triggered and the CPU won't wake up from the LPM. Code snippets are below:

[here set the timer to 0 and call the get_adc_data(), ADC reading to be done on A0, P6.0, ref to AVcc, single samples in the software loop]

int get_adc_data()
{
	int adcVal[AS_NUM_OF_ADC_READS];
	int i, adcValAvgPrev, adcValAvg;

	P6SEL |= BIT0;
	ADC12CTL0 = ADC12ON + ADC12SHT02;
	ADC12IE = 0x01;
	ADC12CTL1 = ADC12CONSEQ_0;
	ADC12CTL2 |= ADC12RES_1;					// 10-bit resolution
	ADC12MCTL0 |= ADC12INCH_0 + ADC12SREF_0;			// V(R+) = AVCC and V(R-) = AVSS
	ADC12CTL0 |= ADC12ENC;

	for (i = 0; i < AS_NUM_OF_ADC_READS; i++)
	{
		uart_puts("ADC before LPM\n\r");
		ADC12CTL0 |= ADC12SC;

		__bis_status_register(LPM0_bits + GIE);

		uart_puts("ADC after LPM\n\r");

		adcVal[i] = ADC12MEM0;

		adcValAvgPrev = !i ? adcVal[i] : adcValAvg;	// if it's the first iteration then adcValAvgPrev = adcVal[0]

		adcValAvg = adcValAvgPrev + ((adcVal[i] - adcValAvgPrev) / i);
	}
	ADC12CTL0 &= ~ADC12ENC;

	return adcValAvg;
}
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
{
       __bic_status_register_on_exit(CPUOFF);
}

#pragma vector = TIMER0_A0_VECTOR
__interrupt void Timer0_A0(void)
{
      if (!(++timer_ms % 5000))
      {
            am_probe_finished_flag = 1;
            __bic_status_register_on_exit(CPUOFF);
       }
}
Ok, so the TIMER0_A0_VECTOR wakes up the CPU every 5 seconds and it indeed does. But before this time I expect the ADC12_ISR to wake up the CPU. In fact what I see is "ADC before LPM" then 5 seconds of break and finally "ADC after LPM". It should do 10 readings one after another within milliseconds.
The code was ported from G2553 where it worked perfectly, although I can see that ADC12 is way different than ADC10.

 

I know that multiple readings can be done better with ADC12MEMx, but this is not a problem here, I will fix it once I have ISR being triggered. Can you please take a short look to see what may be wrong? I have no idea...

 

Best Regards,

tml

Link to post
Share on other sites

I'm not familiar with ADC12, but am a bit suspicious of that ADC ISR. It never clears ADC12IFG0 and leaves GIE set on exit. I think that means it's possible for the ISR to trigger repeatedly, blocking execution from reaching the line that reads ADC12MEM0 (and clears ADC12IFG0 as a side effect).

 

EDIT: Looking back at the 2-series ADC10 docs, ADC10IFG gets cleared automatically on entry to the ISR as it's a single-source interrupt vector. That fits in with your observation that the equivalent code worked on msp430g2553.

 

That said, I'm not sure why the Timer ISR would unblock execution after 5s if this is what's happening.

Link to post
Share on other sites

I'm not familiar with ADC12, but am a bit suspicious of that ADC ISR. It never clears ADC12IFG0 and leaves GIE set on exit. I think that means it's possible for the ISR to trigger repeatedly, blocking execution from reaching the line that reads ADC12MEM0 (and clears ADC12IFG0 as a side effect).

 

EDIT: Looking back at the 2-series ADC10 docs, ADC10IFG gets cleared automatically on entry to the ISR as it's a single-source interrupt vector. That fits in with your observation that the equivalent code worked on msp430g2553.

 

That said, I'm not sure why the Timer ISR would unblock execution after 5s if this is what's happening.

 

It seems the program does not go into ADC12_ISR at all, I guess it's not about leaving interrupts enabled. It's like the conversion either never starts or never ends (in fact I have the P6.0 pin not connected to any signal, but still I'd expect it to be probed). 

I tried enabling all ADC12 interrupts by having ADC12IE = 0xFFFF, that doesn't help either, I have no idea what is wrong.

 

The code is very simple and almost identical to the example. In the evening I will try running the MSP430F55xx_adc_01.c example to see whether it works for me. Also will try polling the ADC12CTL1's ADC12BUSY bit to see the activity of the ADC12. In the meantime if anybody had any idea I will be grateful for help.

 

F5529 is surprisingly different to G2553 in all aspects, This is the last item to be ported in my code. I thought it would be just a simple port remapping, while it

Link to post
Share on other sites

What behaviour are you seeing that tells you the program never gets into the ADC ISR? Have you tried setting a breakpoint inside the ISR?

I have assumed basing on the observation with the uart_puts() added to Timer0 and ADC12 ISRs. For Timer0 one it works, for ADC12's doesn't.

Additionally if it would go into ADC12_ISR then it would wake up the CPU just like it does when entering Timer0_ISR.

 

Best Regards,

tml

Link to post
Share on other sites

I have assumed basing on the observation with the uart_puts() added to Timer0 and ADC12 ISRs. For Timer0 one it works, for ADC12's doesn't.

 

Ok, it's most likely not getting into the ADC12 ISR then (unless something weird's going on with the uart_puts call from inside ADC12 ISR).

 

Looking at whether the example code works correctly is probably the best thing to try next.

 

Additionally if it would go into ADC12_ISR then it would wake up the CPU just like it does when entering Timer0_ISR.

 

It would wake the CPU up, but if the ADC12IFG0 flag is never cleared and GIE is set execution would be stuck in an infinite loop. As soon as the return from the ISR executes it would immediately retrigger. The code after __bis_status_register(LPM0_bits + GIE) in get_adc_data() wouldn't get chance to run, so it would appear as if the CPU was still asleep.

Link to post
Share on other sites

Hi,

Thank you tripwire for your hints, they finally got me on the root cause. OK, so the code works now (I started with successfully running MSP430F55xx_adc_01.c demo, experimenting with it and comparing to my code).

 

The key to the success is:

 

28.2.10.1 ADC12IV, Interrupt Vector Generator of SLAU208M:
"ADC12IFGx bits are reset automatically by accessing their associated ADC12MEMx register or may be reset with software." - I somehow missed this important info when reading about ADC12.
 
And this is what I missed. To fix it we can either:
- disable the interrupts on ISR exit in the ADC12 ISR (__bic_status_register_on_exit(CPUOFF + GIE)) while not accessing ADC12MEMx inside ISR
or
- access the ADC12MEMx inside the ISR which will clear the ADC12IFGx flag and will not cause the program to go into ISR again.
 
I guess you were right to say that the CPU stuck in the ISR. Why the TimerA0 ISR caused the program to continue just before uart_puts("ADC after LPM\n\r") I don't know (yet).
 
It seems that the MSP430F5529 is full of pitfalls for a newbie like me ;-) G2553 was way easier to comprehend...
 
Best Regards,
tml
Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...