I extended the sample application from
SDK_2.1_FRDM-KL27Z/boards/frdmkl27z/driver_examples/adc16/polling
to read multiple ADC channels. What I observe is that the first channel to be polled gets a reasonable value, the other channels polled after that get a full-scale reading (0xffff). After inserting a delay between readings, I get reasonable values on all the channels.
My question: is there some flag that I must honor, or some known delay I must insert, when switching between input channels on the ADC?
Here is the code in question:
#include "fsl_debug_console.h"
#include "board.h"
#include "fsl_adc16.h"
#include "pin_mux.h"
#include "clock_config.h"
#define DEMO_ADC16_BASE ADC0
#define DEMO_ADC16_CHANNEL_GROUP 0U
#define CH08_ADC16_USER_CHANNEL 8U /* PTB0, A0-ADC0_SE8 */
#define CH09_ADC16_USER_CHANNEL 9U /* PTB1, A0-ADC0_SE9 */
#define CH11_ADC16_USER_CHANNEL 11U /* PTC2, A0-ADC0_SE11 */
void delay(void) {
for (uint32_t i = 0; i < 400000; i++) {
__NOP();
}
}
/**
* Initialize a channel_config struct: no interrupts, no differential conversion.
*/
void initChannelConfig(adc16_channel_config_t *config, int channelNumber) {
config->channelNumber = channelNumber;
config->enableInterruptOnConversionCompleted = false;
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
config->enableDifferentialConversion = false;
#endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
}
/*
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 "ADC16_ChannelConfigure() again.
*/
/**
* Read a sample from the ADC on the provided channel using polling.
*/
uint32_t pollChannel(adc16_channel_config_t *config) {
ADC16_SetChannelConfig(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP, config);
while (0U == (kADC16_ChannelConversionDoneFlag &
ADC16_GetChannelStatusFlags(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP))) {
}
return ADC16_GetChannelConversionValue(DEMO_ADC16_BASE, DEMO_ADC16_CHANNEL_GROUP);
}
int main(void) {
adc16_config_t adc16ConfigStruct;
adc16_channel_config_t ch08ChannelConfig;
adc16_channel_config_t ch09ChannelConfig;
adc16_channel_config_t ch11ChannelConfig;
BOARD_InitPins();
BOARD_BootClockRUN();
BOARD_InitDebugConsole();
PRINTF("\r\nADC16 polling example.\r\n");
ADC16_GetDefaultConfig(&adc16ConfigStruct);
adc16ConfigStruct.resolution=kADC16_ResolutionSE16Bit;
adc16ConfigStruct.enableLowPower = true;
adc16ConfigStruct.longSampleMode = kADC16_LongSampleCycle24;
ADC16_Init(DEMO_ADC16_BASE, &adc16ConfigStruct);
ADC16_EnableHardwareTrigger(DEMO_ADC16_BASE, false); /* Make sure the software trigger is used. */
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
if (kStatus_Success == ADC16_DoAutoCalibration(DEMO_ADC16_BASE)) {
PRINTF("ADC16_DoAutoCalibration() Done.\r\n");
} else {
PRINTF("ADC16_DoAutoCalibration() Failed.\r\n");
}
#endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
PRINTF("Press any key to get user channel's ADC value ...\r\n");
initChannelConfig, &ch08ChannelConfig, CH08_ADC16_USER_CHANNEL);
initChannelConfig, &ch09ChannelConfig, CH09_ADC16_USER_CHANNEL);
initChannelConfig, &ch11ChannelConfig, CH11_ADC16_USER_CHANNEL);
while (1) {
GETCHAR();
uint32_t ch08_val = pollChannel(&ch08ChannelConfig);
delay(); // without this delay, ch09_val reads as 0xffff
uint32_t ch09_val = pollChannel(&ch09ChannelConfig);
delay(); // without this delay, ch11_val reads as 0xffff
uint32_t ch11_val = pollChannel(&ch11ChannelConfig);
PRINTF("CH08: %d \tCH09: %d \tCH11: %d\r\n", ch08_val, ch09_val, ch11_val);
}
Example output WITHOUT the calls to delay():
CH08: 47808 CH09: 65535 CH11: 65535
Example output WITH the calls to delay():
CH08: 47808 CH09: 46678 CH11: 48726