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.

ADC12 does not working

Other Parts Discussed in Thread: MSP430F5438A

Hello,

I am developing a code with msp430f5438a. The code consists in an adquisition of a voltage by the ADC12 and this value is transmit from the UART port to the computer.

The problem is the ADC12 only reads a random value and when you change the voltage at this port, the value at ADC12 not change.

I attach the code for more information:

#include <msp430.h>
#include <stdlib.h>
////////////////////////////////////////////////////////////////////////////////////////
/////                           Defines                                            /////
////////////////////////////////////////////////////////////////////////////////////////
#define MAX_SIZE 0xff //int equivale a 2 bytes --> 256 bytes
////////////////////////////////////////////////////////////////////////////////////////
/////                      User's functions                                        /////
////////////////////////////////////////////////////////////////////////////////////////
void ADC_CONF (void)
{
    //ADC12 configuration
P6SEL |= 0x80;                            // P6.7 ADC option select
ADC12CTL0 = ADC12SHT02 + ADC12ON;         // Sampling time, ADC12 on
ADC12CTL1 = ADC12SHP;                     // Use sampling timer
ADC12IE = 0x01;                           // Enable interrupt
ADC12MCTL0 |= ADC12INCH_7;
ADC12CTL0 |= ADC12ENC;
}
void UART_CONF (void)
{
 //UART configuration
P3SEL = 0x30;                             // P3.4,5 = USCI_A0 TXD/RXD
   UCA0CTL1 |= UCSWRST;                      // **Put state machine in reset**
   UCA0CTL1 |= UCSSEL_2;                     // SMCLK
   UCA0BR0 = 6;                              // 1MHz 9600 (see User's Guide)
   UCA0BR1 = 0;                              // 1MHz 9600
   UCA0MCTL = UCBRS_0 + UCBRF_13 + UCOS16;   // Modln UCBRSx=0, UCBRFx=0,
                                             // over sampling
   UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
}
void uartSend (unsigned char *pucData, unsigned char ucLength)
{
  while(ucLength--)
  {
    // Wait for TX buffer to be ready for new data
    while(!(UCA1IFG & UCTXIFG));
    // Push data to TX buffer
    UCA0TXBUF = *pucData;
    // Update variables
    ucLength--;
    pucData++;
  }
  // Wait until the last byte is completely sent
  while(UCA0STAT & UCBUSY);
}
void store_buffer (unsigned char *buffer, unsigned char length, unsigned int value)
{
while(length--)
{
*buffer=value;
length--;
buffer++;
}
}
////////////////////////////////////////////////////////////////////////////////////////
/////                           Variables declaration                              /////
////////////////////////////////////////////////////////////////////////////////////////
int ADC_IN=0;
unsigned int UART_OUT=0;
unsigned int i=0;
unsigned char t=0;
unsigned char *buffer1;
//unsigned int *buffer2;
////////////////////////////////////////////////////////////////////////////////////////
/////                           Main Program                                       /////
////////////////////////////////////////////////////////////////////////////////////////
int main(void)
{
  WDTCTL = WDTPW + WDTHOLD;                 // Stop WDT
 ADC_CONF ();
 UART_CONF();
  buffer1= (unsigned char*) malloc (MAX_SIZE * sizeof (unsigned char)); //256bytes reserved for buffer1
 // buffer2= (unsigned int*) malloc (MAX_SIZE * sizeof (unsigned int)); //256bytes reserved for buffer2
  // Pin configuration
      P1DIR |= BIT0;                            // P1.0 output
//  __delay_cycles(10000);
  while (1)
  {
    ADC12CTL0 |= ADC12SC;                   // Start sampling/conversion
    
    __bis_SR_register(LPM0_bits + GIE);     // LPM0, ADC12_ISR will force exit
    __no_operation();                       // For debugger
  }
}
////////////////////////////////////////////////////////////////////////////////////////
/////                           Interrupts                                         /////
////////////////////////////////////////////////////////////////////////////////////////
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = ADC12_VECTOR
__interrupt void ADC12_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(ADC12_VECTOR))) ADC12_ISR (void)
#else
#error Compiler not supported!
#endif
{
  switch(__even_in_range(ADC12IV,34))
  {
  case  0: break;                           // Vector  0:  No interrupt
  case  2: break;                           // Vector  2:  ADC overflow
  case  4: break;                           // Vector  4:  ADC timing overflow
  case  6:   // Vector  6:  ADC12IFG0
   ADC_IN = ADC12MEM0;
   UART_OUT=ADC_IN/16;
   store_buffer (buffer1, MAX_SIZE, UART_OUT);
 uartSend (buffer1, MAX_SIZE);
   __bic_SR_register_on_exit(LPM0_bits);   // Exit active CPU
 break;
  case  8: break;                           // Vector  8:  ADC12IFG1
  case 10: break;                           // Vector 10:  ADC12IFG2
  case 12: break;                           // Vector 12:  ADC12IFG3
  case 14: break;                           // Vector 14:  ADC12IFG4
  case 16: break;                           // Vector 16:  ADC12IFG5
  case 18: break;                           // Vector 18:  ADC12IFG6
  case 20: // Vector 20:  ADC12IFG7
 break;
  case 22: break;                           // Vector 22:  ADC12IFG8
  case 24: break;                           // Vector 24:  ADC12IFG9
  case 26: break;                           // Vector 26:  ADC12IFG10
  case 28: break;                           // Vector 28:  ADC12IFG11
  case 30: break;                           // Vector 30:  ADC12IFG12
  case 32: break;                           // Vector 32:  ADC12IFG13
  case 34: break;                           // Vector 34:  ADC12IFG14
  default: break; 
  }
}
Thanks in advance
  • Hi Miguel, 

    I'll look into this for you. When you notice the value of the ADC  not changing are you checking the value of ADC_IN within CCS using a breakpoint or are you viewing it through the UART on your PC? Have you checked that the UART is operating correctly?

    Also, are your sure that your sampling time is set for a long enough period? I don't see any bugs in the code at first glance but I'll keep digging. Be sure to check that your connection are correct as well.

    Best regards, 
    Caleb Overbay

  • Hi Miguel, 

    I looked a little closer at your code and saw that you were using malloc to initialize buffer1. We do not fully support the malloc function and this could be the root of your problem. I believe the malloc is not working properly and your store_buffer function is not actually storing anything in the buffer. Try allocating the memory at start up with unsigned char buffer1[256]; instead. Try this out and let me know if it works.

    Best regards, 

    Caleb Overbay

  • In store_buffer your loop is decrementing the length value twice. This function is called with a length of MAX_SIZE=255, which (notably) is an odd number. Because it is odd, the loop, counting down by 2, will count past 0, and the underflow will wrap "length" back to 255. This will continue indefinitely, writing over memory until it overwrites something important. This is presumably how your program ended up at ISR_TRAP.

    ->Recommendation: use "length--" only once in the loop (remove the other).

    ->uartSend has the same mistake.

    I'm not quite clear why you're calling store_buffer and uartSend with a length of MAX_SIZE; the effect (once those functions are fixed) is to send out the same value 255 times.

    ->If this was not your intent, call those functions with 1, not MAX_SIZE.

    ->I also agree with Caleb's recommendation to not use malloc, even if it works correctly. malloc has a number of attributes which make it unattractive for embedded work.

  • The objective is store the ADC values in a buffer and after send this buffer to the computer. MAX_SIZE is the maximum size available (256 bytes in the buffer). By this reason I implemented the function in this way. 

    How do you program functions to store and send the buffer?

    ---I also agree with Caleb's recommendation to not use malloc, even if it works correctly. malloc has a number of attributes which make it unattractive for embedded work.---- If the use of malloc is not good, which is the way to keep the size of a pointer?

    Thanks for the response.

  • Hi Caleb,

    So without malloc how can I save the memory for the pointer?

    Do you say use the buffer without pointers? I do not understand very well what you say.

    Thanks to the quick response
  • Hi Miguel,

    Instead of using malloc, you can create a fixed size array when defining the variable. For example: char buffer1[256]; creates an array that can hold 256 chars. You can still pass this as a pointer to store_buffer if you'd like.

    However, as Bruce was explaining your store_buffer and uartSend function has an infinite loop in it because you decrement length twice causing underflow that is not caught. Also, your store_buffer function is just placing value into all 255 available spaces. I'm not sure that you need to store anything in a buffer before placing it in UCA0TXBUF.

    Best regards,
    Caleb Overbay
  • Hi Caleb,

    this code is a preview version. In the final code I need the buffer in order to store the value of 8 ADC channels, for this reason I need a buffer, while one buffer is sending the data in other buffer newvalues are being stored.

    So, how can I modify the function to send and store correctly a buffer? I tried removing a decrement length but the function is not working.

    Thanks for everything,

    Miguel

  • Hi Miguel, 

    It looks like you used some of TI's code examples to construct what you currently have, so I'll assume you know where to find the examples. I would take a look at the ADC12, Repeated Single Channel Conversions example (msp430x54xA_adc12_07.c). This example is storing the results of multiple ADC conversions into a buffer. The careful thing to do here is ensure you are referencing and keeping track of the correct index of the buffer. Let me know if you need some more guidance on this.

    Best regards, 

    Caleb Overbay

  • Hi Caleb,

    sorry for not answering before, I could not. I gonna try to use this example, and I will comment the results and doubts.

    Thanks

  • Hi  Caleb,

    I am trying to test the example which you tell me. In a first moment the code was working succesfully, but when I loaded the same code another time the ADC12MEM0 always is 1824 and it not changes when the input voltage is different. In addition the buffer "results" always is storing a value 7 and I am not understandting why.

    I tried with other new chip but the result is the same.

    Can you help me?

  • Hi Miguel, 

    Have you made any changes to the example project, and if so what changes were made? The fact that it doesn't work on another chip, makes me believe it is an issue with the code. Have you tried stepping through using the debug mode and checking the value of the ADC registers to ensure they are what you expect? You could also place a break point where the valu gets stored in the array and make sure the value actually being read from the ADC is getting placed there. 

    Best regards, 

    Caleb Overbay

  • Hi Caleb,

    I do not know what is happenning. Today I tried the code example other time and now it is working, but when I put the ADC12MEM0 in the watch expression its value not changes, instead if I see the register value, it is correct.

  • Hi Miguel,

    Instead of putting ADC12MEM0 in the watch expression, I recommend saving the value of ADC12MEM0 in a temp variable and watching that instead. It's strange that it seems to be working again when it wasn't previously. This may seem trivial, but have you checked that all your connections were correct and you were suing the right pins?

    Best regards,
    Caleb Overbay

**Attention** This is a public forum