Jump to content

Weird Problem with analogRead() and mySerial.print()

Recommended Posts

I'm trying to develop my current project entirely in Energia. Since Energia is still in development, I'm breaking the code down into chunks and making sure that things work as expected.


The following code gets 3 values from the ADC (TEMPSENSOR and 2 analog inputs), divides each value by 4, and writes the resulting values out to the Serial Monitor. I can vary the voltage to the analog inputs with a potentiometer. This is using 0101E0006 on a 2553 on a Rev. 1.4 Launchpad with the crystal installed.


#define CO_IN A4   //P1.4
#define RH_IN A5   //P1.5

uint32_t co_volts;
uint32_t rh_volts;
uint32_t temp_raw;
uint8_t co_value;
uint8_t rh_value;
uint8_t temp;

TimerSerial mySerial;

void setup(){

void loop(){
 delay(100);  //the delays are to make sure the references and the adc have settled
 temp_raw = analogRead(TEMPSENSOR);
 temp = temp_raw/4;  


 co_volts = analogRead(CO_IN);
 co_value = co_volts/4;

 rh_volts = analogRead(RH_IN);
 rh_value = rh_volts/4;

 mySerial.print("T: ");
 mySerial.print(temp, DEC);
 mySerial.print("C: ");
 mySerial.print(co_value, DEC);
 mySerial.print("R: ");
 mySerial.println(rh_value, DEC);

I can see the outputs vary as the pots are rotated. The output in the Serial Monitor is of the form-

T: 244	C: 189	R: 0

The problem is that the output values are shifted. The printed value for T is actually the value for R; the value for C is actually T; and R is actually C.


The code is fairly simple and I can't see anything wrong with it. Is there something I have overlooked/gotten wrong, or have I stumbled into another bug?




Link to post
Share on other sites

Some additional information in case anyone is interested.


If I change the code so that each analog Read() is called 2 times- for example:

  temp_raw = analogRead(TEMPSENSOR);
   temp_raw = analogRead(TEMPSENSOR);
 temp = temp_raw/4;

The output is in the order expected.


I edited the title of this thread to make it more indicative of what the problem is.

Link to post
Share on other sites

I took a look at this problem and I'm seeing the same results as you. I tried changing the analogRead code so that instead of sleeping and waiting for the ADC interrupt, it just sits in a busy while loop. That seems to fix it. Sitting in a busy loop isn't a very power friendly solution though.


If you want the gory details here is a patch:


diff --git a/hardware/msp430/cores/msp430/wiring_analog.c b/hardware/msp430/cores/msp430/wiring_analog.c

index 1bb2539..0543aa9 100644

--- a/hardware/msp430/cores/msp430/wiring_analog.c

+++ b/hardware/msp430/cores/msp430/wiring_analog.c

@@ -179,14 +179,22 @@ uint16_t analogRead(uint8_t pin)

if(pin > 7 && pin != 10) // ADC on pin?

return 0;

ADC10CTL0 &= ~ENC; // disable ADC

+#if 0

ADC10CTL0 = analog_reference + // set analog reference

- ADC10ON + ADC10SHT_3 + ADC10IE; // turn ADC ON; sample + hold @ 64

Link to post
Share on other sites

After conferring with Robert he thinks and I concur that the problem is probably that the watchdog isr is kicking off

between the time the ADC capture starts and before it has completed. The watchdog timer reenables the CPU

which causes the analogRead code to continue execution when it really isn't ready. The code below seems to

work and is somewhat more power friendly. It uses a combination of sleeping and checking the ADC busy bit.


uint16_t analogRead(uint8_t pin) {


// make sure we have an ADC

#if defined(__MSP430_HAS_ADC10__)

// 0000 A0

// 0001 A1

// 0010 A2

// 0011 A3

// 0100 A4

// 0101 A5

// 0110 A6

// 0111 A7

// 1010 Internal temperature sensor


//TODO: Only int. temp. sensor requires Tsample > 30us.

// The below ADC configuration applies this rule to all channels right now.

// ADC10CLK = 5MHz / 5 = 1Mhz

// Tsample = S&H / ADC10CLK = 64 / 1 MHz = 64 us

// Tconver = 13 / ADC10CLK = 13 / 1 MHz = 13 us

// Total time per sample = Tconvert + Tsample = 64 + 13 = 67 us = ~15k samples / sec

if (pin > 7 && pin != 10) // ADC on pin?

return 0;


ADC10CTL0 &= ~ENC; // disable ADC

ADC10CTL0 = analog_reference | // set analog reference

ADC10ON | ADC10SHT_3 | ADC10IE; // turn ADC ON; sample + hold @ 64

Link to post
Share on other sites

Thanks, rick!


I patched wiring_analog.c and my code runs as expected.


I wish I had the experience to go into the internals of Energia and contribute by fixing these things, but I don't. But I guess that he who finds bugs (and reports them) also contributes.


Thanks, again,


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.

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...