Bug in adc16/polling driver example

cancel
Showing results for 
Search instead for 
Did you mean: 

Bug in adc16/polling driver example

829 Views
robertpoor
Contributor V

We have uncovered a bug in the adc16/polling driver example that ships with the SDK2.1 distribution for the FRDM-KL27Z development board.  

Synopsis: The adc16/polling code example sets the ADC reference voltage to VREFH / VREFL (the default), but on the FRDM-KL27Z board, the VREFH input is left floating.  This leads to unpredictable readings.

Solution #1: Populate R17 on the FRDM-KL27Z board.  This will tie VREFH to the 3.3V VDD voltage source.

Solution #2: Modify driver_examples/adc16/polling/adc16_polling.c as follows by adding the line in boldface.  This has the effect of setting the ADC reference voltage to the VDD / VSS pair rather than the VREFH / VREFL pair:

adc16_polling.c
ADC16_GetDefaultConfig(&adc16ConfigStruct);
adc16ConfigStruct.referenceVoltageSource = kADC16_ReferenceVoltageSourceValt;
ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct);
Tags (3)
7 Replies

165 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Gilbert,

I do not suggest you use the procedure to read ADC sample in polling mode:

1)start ADC sampling

2)delay some time

3)read ADC sample

I suggest you read ADC sample with the following procedure:

1)start ADC sampling

2)poll the ADC status register to check whether the conversion is complete

3)read ADC sample after the the conversion is complete.

The ADC polling mode example gave the code:

C:\DriverE\Freescale\KSDK2.0_KL27\boards\frdmkl27z\driver_examples\adc16\polling

  while (1)
    {
        GETCHAR();
        /*
         When in software trigger mode, each conversion would be launched once calling the "ADC16_ChannelConfigure()"
         function, which works like writing a conversion command and executing it. For another channel's conversion,
         just to change the "channelNumber" field in channel's configuration structure, and call the
         "ADC16_ChannelConfigure() again.
        */
        ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
        while (0U == (kADC16_ChannelConversionDoneFlag &
                      ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP)))
        {
        }
        PRINTF("ADC Value: %d\r\n", ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP));
    }

Pls follow up it.

Regarding the negative value, when the MSB is 1, it is expressed as negative value, because of sign extending, it is possible that the value is expressed as negative, pls show the variable in Hex format to check the original value.

Hope it can help you

BR

xiangjun Rong

165 Views
gilbertmlliu
Contributor III

Hi Xiangjun,

Thanks for your promptly reply.

I followed your recommendation to use the software trigger mode, then my functions work fine without the time delay.

It is more efficient than the polling method, no need to waiting for the time delay.

Anyway, thanks again for your advice and greatly appreciate this!

Regards,

Gilbert

0 Kudos

165 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi, Robert,

Thank you for pointing the bug, I think it is okay to populate the R17, I do not know why the R17 is "DNP"

BR

Xiangjun Rong

0 Kudos

165 Views
gilbertmlliu
Contributor III

Hi Xiangjun,

I am running a freertos on my KL27, then I have two features that using the ADC, one is the temperature sensor (SE26) and the other is reading my battery level (SE9). So in my code, I am doing the mux aternative, i need to provide a short time after each read in order to get the correct value, otherwise, my value comes back negative.

In addition, i read this post and tried both solution, but i still have the same incorrect result. Do you have any other tips? Did I miss something? Please let me know what other information you need to understand more clearly.

Thank you.

Gilbert

0 Kudos

165 Views
xiangjun_rong
NXP TechSupport
NXP TechSupport

Hi,

pls list the ADC samples so that we can check it.

BR

xiangjun Rong

0 Kudos

165 Views
gilbertmlliu
Contributor III

Hi Xiangjun,

Please see my functions below. I do the ADC_Init in the main at the beginning, then I run my battlvl_read() and temperature_read() in my other task alternatively. I configured my reference voltage source to Valt, I also tried to connect my Vref to VDD as well. But my temperature read became negative value with the taskdelay. See result in the images.

void ADC16_GetDefaultConfig(adc16_config_t *config)
{
    assert(NULL != config);

    config->referenceVoltageSource = kADC16_ReferenceVoltageSourceValt;
    config->clockSource = kADC16_ClockSourceAsynchronousClock;
    config->enableAsynchronousClock = true;
    config->clockDivider = kADC16_ClockDivider8;
    config->resolution = kADC16_ResolutionSE12Bit;
    config->longSampleMode = kADC16_LongSampleCycle10;
    config->enableHighSpeed = true;
    config->enableLowPower = true;
    config->enableContinuousConversion = false;
}

void ADC_Init(void)
{
    ADC16_GetDefaultConfig(&adc16ConfigStruct);
    ADC16_Init(ADC16_BASE, &adc16ConfigStruct);
    ADC16_SetHardwareAverage(ADC16_BASE, kADC16_HardwareAverageCount32);
    ADC16_EnableHardwareTrigger(ADC16_BASE, false);                       
    ADC16_DoAutoCalibration(ADC16_BASE);
    adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;
    adc16ChannelConfigStruct.enableDifferentialConversion = false;
}

uint32_t BattLvl_Read()
{
    static uint32_t ADC_BattValue;

    adc16ChannelConfigStruct.channelNumber = BATTLVL_ADC16_USER_CHANNEL;
    ADC16_SetChannelConfig(ADC16_BASE, ADC16_CHANNEL_GROUP, adc16ChannelConfigStruct);
    vTaskDelay(15/portTICK_RATE_MS);
    ADC_BattValue = ADC16_GetChannelConversionValue(ADC16_BASE, ADC16_CHANNEL_GROUP);

    return ADC_BattValue;
}

int32_t Temperature_Read()
{
    static uint32_t ADC_TempValue;
    static int32_t ADC_CValue;
    adc16ChannelConfigStruct.channelNumber = TEMPSEN_ADC16_USER_CHANNEL;
    ADC16_SetChannelConfig(ADC16_BASE, ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
    vTaskDelay(15/portTICK_RATE_MS);
    ADC_TempValue = ADC16_GetChannelConversionValue(ADC16_BASE,ADC16_CHANNEL_GROUP);

    if (ADC_TempValue >= 917)
          ADC_CValue = 25 - (((ADC_TempValue - 917) * 100) / 204);                // Cold Slope
    else
          ADC_CValue = 25 + (((917 - ADC_TempValue) * 100) / 219);                // Hot Slope
        return ADC_CValue;
}

With time delay, ADC value reads properly on both functions.

With time delay.png

Without the time delay, the temperature read became negative.

Without time delay.png

Please advise. Thank you.

Gilbert

0 Kudos

165 Views
robertpoor
Contributor V

Thank you!  I found it was easier to add a line of code than to solder in a tiny resistor  :smileyhappy: so I went with Solution #2.

But I trust this will be resolved one way or another in a future release.  (It took me a long time to track this down, so it would help others in the future.)

0 Kudos