Question

I'm working with the NXP LPC1788 microcontroller, and I'm trying to write code that will let me perform ADC measurements on analog channels 0-7. The code I have right now is:

uint16_t getADCChannelValue(uint8_t adcChannel)
{
  uint16_t adc_value;

  ADC_ChannelCmd(LPC_ADC, adcChannel, ENABLE);
  ADC_StartCmd(LPC_ADC, ADC_START_NOW);

  // Wait for measurement to complete.
  while (!(ADC_ChannelGetStatus(LPC_ADC, adcChannel, ADC_DATA_DONE)));

  adc_value = ADC_ChannelGetData(LPC_ADC, adcChannel);
  ADC_ChannelCmd(LPC_ADC, adcChannel, DISABLE);

  // With delay - code works. Without delay - channel 0 is correct,
  // channels 1-7 have values close to channel 0 (~2150) (incorrect).
  //OS_Delay(1);

  return adc_value;
}

With the delay, the code seems to work, but I don't want an arbitrary delay in there. I've been playing around with the code for hours, and for whatever reason, the overrun flag is set when the delay is there (that is, it complains about an overrun when the function is outputting the correct value).

I'm applying voltage only to analog channel 0. This is the output I get when the delay is included:

Channel 0 = 2151
Channel 1 = 35
Channel 2 = 33
Channel 3 = 34
Channel 4 = 32
Channel 5 = 34
Channel 6 = 32
Channel 7 = 31

And when it is not included:

Channel 0 = 2150
Channel 1 = 2151
Channel 2 = 2151
Channel 3 = 2150
Channel 4 = 2150
Channel 5 = 2150
Channel 6 = 2149
Channel 7 = 2150

Has anyone written any code that will let me run through all the ADC channels and record their values as quickly as possible without arbitrary delays?

Was it helpful?

Solution

Tag, I think that you should be using "burst mode". Here's what I have as the ADC initialisation code:

void adcHandlerInit()
{
  // Clear all bits of the analog pin registers except for the filter disable
  // bit.
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_23)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_24)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_25)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_26)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_1 * 32
                             + BRD_ADC_CH_PIN_30)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_1 * 32
                             + BRD_ADC_CH_PIN_31)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_12)*sizeof(uint32_t)))) = 1 << 8;
  *((uint32_t *)(LPC_IOCON_BASE + ((BRD_ADC_CH_PORT_0 * 32
                             + BRD_ADC_CH_PIN_13)*sizeof(uint32_t)))) = 1 << 8;

  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_23, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_24, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_25, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_26, BRD_ADC_CH_FUNC_NO_1);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_1, BRD_ADC_CH_PIN_30, BRD_ADC_CH_FUNC_NO_3);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_1, BRD_ADC_CH_PIN_31, BRD_ADC_CH_FUNC_NO_3);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_12, BRD_ADC_CH_FUNC_NO_3);
  PINSEL_ConfigPin(BRD_ADC_CH_PORT_0, BRD_ADC_CH_PIN_13, BRD_ADC_CH_FUNC_NO_3);

  /* Configuration for ADC :
  *  ADC conversion rate = 400Khz
  */
  ADC_Init(LPC_ADC, 400000);

  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_0, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_1, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_2, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_3, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_4, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_5, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_6, DISABLE);
  ADC_IntConfig(LPC_ADC, BRD_ADC_INTR_7, DISABLE);

  // Start burst mode.
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_0, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_1, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_2, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_3, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_4, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_5, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_6, ENABLE);
  ADC_ChannelCmd(LPC_ADC, ADC_CHANNEL_7, ENABLE);
  ADC_StartCmd(LPC_ADC, ADC_START_CONTINUOUS);
  ADC_BurstCmd(LPC_ADC, ENABLE);
}

The part at the bottom is important. It will make the microcontroller perform repeated measurements on all the ADC channels. After that, you can just get the channel voltage value with:

uint16_t getADCChannelValue(uint8_t adcChannel)
{
  return (uint16_t)ADC_ChannelGetData(LPC_ADC, adcChannel);
}

This should help you out. However, it would be nice to see a way to do this without using burst mode, so anyone else with a correct answer that doesn't rely on burst mode should be awarded the accepted answer in place of me.

OTHER TIPS

I noticed that on different controllers of the same type and the same production batch each controller acts different.

I also have the problem that sometimes channel 0 is doing a wrong measurements

This problem was solved by adding a delay between Enabling the channel and start cmd. This delay was 1us.

Still, this delay is not enhough for each controller. Now it is 4us. But its not a hopefull solution.

un16 adcMeasureChannelBlocked(un8 channel)
{
un16 value;

// Enable channel
ADC_ChannelCmd(LP_ADC_PERHIPHERAL, channel, ENABLE);

// Reset delay timer
adcTimeOutTimer = timingGetTicks();
while(!(timingHasElapsed(&adcTimeOutTimer, TIMING_TIME_US(4))));

// Start measurement
ADC_StartCmd(LP_ADC_PERHIPHERAL, ADC_START_NOW);

// Reset timeout timer
adcTimeOutTimer = timingGetTicks();

// Wait until done
while(!ADC_ChannelGetDoneStatus(LP_ADC_PERHIPHERAL, channel, &value));
{
    if (timingHasElapsed(&adcTimeOutTimer, TIMING_TIME_MS(2)))
    {
        bmsStatusEvent(STATUS_EVT_SET,ERROR_HW_ADC_DATA);
    }
}

// Disable channel
ADC_ChannelCmd(LP_ADC_PERHIPHERAL, channel, DISABLE);

return value;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top