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_GetDefaultConfig(&adc16ConfigStruct); adc16ConfigStruct.referenceVoltageSource = kADC16_ReferenceVoltageSourceValt; ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct);
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:
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_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
while (0U == (kADC16_ChannelConversionDoneFlag &
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
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!
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.
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;
adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;
adc16ChannelConfigStruct.enableDifferentialConversion = false;
static uint32_t ADC_BattValue;
adc16ChannelConfigStruct.channelNumber = BATTLVL_ADC16_USER_CHANNEL;
ADC16_SetChannelConfig(ADC16_BASE, ADC16_CHANNEL_GROUP, adc16ChannelConfigStruct);
ADC_BattValue = ADC16_GetChannelConversionValue(ADC16_BASE, ADC16_CHANNEL_GROUP);
static uint32_t ADC_TempValue;
static int32_t ADC_CValue;
adc16ChannelConfigStruct.channelNumber = TEMPSEN_ADC16_USER_CHANNEL;
ADC16_SetChannelConfig(ADC16_BASE, ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
ADC_TempValue = ADC16_GetChannelConversionValue(ADC16_BASE,ADC16_CHANNEL_GROUP);
if (ADC_TempValue >= 917)
ADC_CValue = 25 - (((ADC_TempValue - 917) * 100) / 204); // Cold Slope
ADC_CValue = 25 + (((917 - ADC_TempValue) * 100) / 219); // Hot Slope
With time delay, ADC value reads properly on both functions.
Without the time delay, the temperature read became negative.
Please advise. Thank you.
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.)