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.
Hi,
I'm trying to ADC sample at least two pins simultaneously, but I saw only one ADC10MEM register.
I also tried this code but it does not seem to be working. the values in memory address 0x0200 to 0x0206 does not make any sense.
One way to work around it might be use ADC10 and ADC12 at the same time?
#include <msp430.h>
int main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
ADC10CTL1 = INCH_3 + CONSEQ_1; // A3/A2/A1, single sequence
ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
ADC10DTC1 = 0x03; // 3 conversions
ADC10AE0 |= 0x0E; // P1.3,2,1 ADC10 option select
P1DIR |= 0x40; // Set P1.0 output
while(1)
{
ADC10CTL0 &= ~ENC;
while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
ADC10SA = 0x200; // Data buffer start
P1OUT |= 0x40; // P1.0 = 1
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
//__bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
P1OUT &= ~0x40; // P1.0 = 0
}
}
// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
//__bic_SR_register_on_exit(CPUOFF); // Clear CPUOFF bit from 0(SR)
}
Thanks!
Holly
A3 A2 A1 A0Holly Liang said:ADC10CTL1 = INCH_3 + CONSEQ_1; // A3/A2/A1, single sequence
Since you programmed the DTC for 3 values only, you'll get an ADC10 interrupt when the DTC is done, and one more after the ADC has done the last conversion of the sequence.
Sampling is done sequentially, by multiplexing the input pins. Each conversion result is presented in the same ADC10MEM register until the next conversion is complete. The DTC intercepts the conversion interrupt and performs a DMA transfer on each conversion, triggering an interrupt when done with the given number of conversions. If the DTC is inactive, each conversion triggers an interrupt.Holly Liang said:I'm trying to ADC sample at least two pins simultaneously, but I saw only one ADC10MEM register.
What do you get and what do you expect?Holly Liang said:the values in memory address 0x0200 to 0x0206 does not make any sense.
The values are (or should be) in the range 0 to 1023, where 0 is 0V and 1023 is VCC. At least with your configuration.
You have disabled the LPM in main. As a result, main doesn't wait for the conversions to be done, and resets and restarts the ADC endlessly before it has time for even one conversion. Entering LPM and letting the ADC10 ISR ending LPM will stop main until the DTC has done its job. Currently (without the synchronization by LPM or alternatively by checking whether the ADC is still busy), you might not get any result at all, as no conversion will ever complete.
Hi Jens,
What if I don't want to turn off CPU since I'm running a bunch of other things at the same time? Should I put _NOP after each loop? How many should I put?
The program is about sample two pins at the same time, and output two different PWM accordingly(for motor control). Now I can sample two channels, or I can output two PWM, but when I put them together, the motor stopped moving.
Thank you so much!
-Holly
No. The ADC tells you with its interrupt when it is done. In your ISR you can set a global flag telling main that the work is done.Holly Liang said:Should I put _NOP after each loop? How many should I put?
If you want to do something else in the meantime, then do something else and come back when the ADC has done its job. Don't waste time in waiting.
Holly Liang said:The program is about sample two pins at the same time
Not at the same time, but sequentially, one right after the other. Just to make sure you understand the difference.
Sorry about the delay of reply, but do you mean something like this:
int done;
main()
{
done =1;// ADC flag
while(1)
{
if(done)
{
done=0;
ADC10CTL0 &= ~ENC;
while (ADC10CTL1 & BUSY); // Wait if ADC10 core is active
ADC10SA = 0x200; // Data buffer start
P1OUT |= 0x40; // P1.0 = 1
ADC10CTL0 |= ENC + ADC10SC; // Sampling and conversion start
}
pwm1();
pwm2();
}
// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
p13= *(int *)0x0200;
p12= *(int *)(0x0202);
p11= *(int *)(0x0204);
done=1;
}
}
pwm1(){blah blah}
pwm2(){blah blah}
I set a breakpoint in the ADC isr, but the program never stopped, so I think the ISR never entered.. it never interrupted...
volatile int done; Else the compiler might just load done into a register and never see it changing (because in the visible program flow, it is never changed). Interrupts do magic: they may change the system state without any apparent (for the compiler) reason. So anything that doe snot behave like it should from the sequential program execution, must be flagged as 'volatile' to the compiler. Like all hardware registers. And all global variables that are used (changed, but also just read!) by an ISR.Holly Liang said:int done;
In your code, I don't see that youHolly Liang said:I set a breakpoint in the ADC isr, but the program never stopped,
Don't use absolute addresses this way. In your case, likely the linker placed 'done' at 0x200 (the start of ram), not knowing that you instructed the DTC to overwrite this location with your ADC results.Holly Liang said:ADC10SA = 0x200; // Data buffer start
Hi!
I configured ADC10IE in the main loop but forgot to include it in the last post:
WDTCTL = WDTPW + WDTHOLD; // Stop WDT
//ConfigClocks();
ConfigTimerA();
ADC10CTL1 = INCH_3 + CONSEQ_3; // A3/A2/A1, single sequence
ADC10CTL0 = ADC10SHT_2 + MSC + ADC10ON + ADC10IE;
ADC10DTC1 = 0x03; // 3 conversions
ADC10AE0 |= 0x0E; // P1.3,2,1 ADC10 option select
But there were no interrupt.
Then I added _enable_interrupt(); and everything works now! But in the example code(original post of this thread), there is no _enable_interrupt(); yet interrupts are still generated.
(the original code does not have turn off/on CPU commented out)
Thank you!
Holly Liang said:Then I added _enable_interrupt(); and everything works now! But in the example code(original post of this thread), there is no _enable_interrupt(); yet interrupts are still generated.
(the original code does not have turn off/on CPU commented out)
Thank you!
__bis_SR_register(CPUOFF + GIE); // LPM0, ADC10_ISR will force exit
The GIE part of that code enables interrupts.
Also you are actually reading four channels:
ADC10CTL1 = INCH_3 + CONSEQ_3; // A3/A2/A1, single sequence
because it reads consecutively down through A0, so you're reading A3/A2/A1/A0
**Attention** This is a public forum