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
Solved! Go to Solution.
Xiangjun:
You are right to suspect a problem with VREF! However, the problems discussed in this thread are specific to the FRDM-KL27Z board, NOT the 32 pin MKL27Z64VFM4 part.
We have solved the problem for the FRDM board -- please see Bug in adc16/polling driver example for an explanation. In short, the VREFH input on the FRDM board is left floating, and the adc16 code example uses VREFH for VREF, leading to unpredictable results. The solution is to configure the ADC to use the "alternate" reference source, in other word, VDD. I've tested it, and it works reliably.
The problems that Hy has discussed with you regarding the 32 pin part are (probably) unrelated to this, and would best be split off into another thread. To avoid any confusion, I will mark this thread as solved and start a separate thread for that purpose.
Thank you!
Internal Vref Closed sample code .
This code add your code . Problem fixed
vref_config_t vrefUserConfig;
VREF_GetDefaultConfig(&vrefUserConfig); /* Gets a default configuration. */
VREF_Init(VREF, &vrefUserConfig);
VREF_SetTrimVal(VREF,0);
Hi, all
After communicating with Hy Mai, i see that customer uses MKL27Z64VFM4 with 32 pin LQFP package,and the ADC sample will saturate to 0xFFFF in 16 bits mode when the analog voltage exceeds 2.5V. In other words, the question now is what is the ADC voltage reference?
First of all, we should download the KL27P64M48SF2RM from the link for MKL27Z64VFM4 with 32 pin LQFP package:
ARM Cortex-M0+|Ultra-Low Power Kinetis KL2x USB MCU|NXP
Based on the RM, this is the section to discuss the reference voltage of ADC:
Because I have not the board with MKL27Z64VFM4, pls have try for the follwoing setting:
1)connect a 0.1uF capacitor on the PTE30 pin, have a test without modifying any code.
2)change the VREFH setting with ADCx_SC2[REFSEL]=2b'01 and have the ADC sample.
BR
Xiangjun Rong
Xiangjun:
You are right to suspect a problem with VREF! However, the problems discussed in this thread are specific to the FRDM-KL27Z board, NOT the 32 pin MKL27Z64VFM4 part.
We have solved the problem for the FRDM board -- please see Bug in adc16/polling driver example for an explanation. In short, the VREFH input on the FRDM board is left floating, and the adc16 code example uses VREFH for VREF, leading to unpredictable results. The solution is to configure the ADC to use the "alternate" reference source, in other word, VDD. I've tested it, and it works reliably.
The problems that Hy has discussed with you regarding the 32 pin part are (probably) unrelated to this, and would best be split off into another thread. To avoid any confusion, I will mark this thread as solved and start a separate thread for that purpose.
Thank you!
Hi, all
As I said I think the code is okay. The issue cames from the external hardware signal impedance, I see that you test the signal from PTB0/PTB1 pins, if you use ADC to sample analog signal, the analog signal should have low impedance, if the analog signal have high impedance, the drifting, inaccurate sample... will happens.
Pls have the following tests:
1)connect the GND or VDD to the PTB0 or PTB1, what is the result? I think the drifting will disappear.
2)the analog signal is from sensor, pls tell us the ananlog signal output impedance. If it has high impedance, i suggest you connect an analog buffer, and connect the PTB0 or PTB1 to the analog buffer output. The analog buffer consists of an OP AMP, for example OP07/27/37, connect the inverting pin of AMP to the output pin of AMP, connect the sensor output to non-inverting pin, it is okay.
Pls have a try
BR
Xiangjun Rong
Xiangjun Rong:
It's interesting that you say the analog input should be driven by a low impedance such as an op amp.
The data sheet (KL27P64M48SF2) specifies that you should use an RC low-pass filter (section 6.3.1) with a maximum impedance of 5 k Ohms (section 5.3.6.1.1). But I also note that the data sheet advises "the analog source resistance must be kept as low as possible." Still, it seems like an impedance as high as 5 k should be permissible.
Hy: Are you in a position to drive the input from a low-impedance voltage source (e.g. a power supply or an op amp voltage follower)?
A A/D input should always be driven with the lowest possible impedance.
Analog Devices goes into details as to why here:
A Simple R/C filter at the input serves several different functions.
Anti-Aliasing for sampled systems.
A stable fixed capacitance to the driver compared to the switching going on in the A/D.
Most often over looked it keeps switching noise from the A/D inside the chip from escaping to a large degree.
Bob:
You should know that our production application drives the A/D inputs directly from Op Amp voltage followers with RC filters on their inputs, so in the final version, yes, the A/D inputs will be driven from low impedance sources.
Also, as I mentioned, the original problem I observed went away when I drove all three inputs from a 1V source, the observed problems went away. So I believe this issue is closed, but the engineers at NXP apparently want to investigate some other aspects of it.
To ALL:
Please refer to our schematics that were provided. We direct drive the A/D converter with LMV341 op amps for all three signals fed to the a/d converter.
Hi,
i have reviewed your code, especially,
uint32_t pollChannel(adc16_channel_config_t *config){} I think the code is okay. Maybe you use C++ to develop code and declare the variable asuint32_t ch09_val = pollChannel(&ch09ChannelConfig); can you declare the variableuint32_t ch09_val as void main(void) {uint32_t ch09_val;uint32_t ch08_val;uint32_t ch11_val; .............. while(1) {ch08_val = pollChannel(&ch08ChannelConfig); ........ } If you still have issue, can you have a debug by step by step and check the ADC register and variable to get the cause? BR Xiangjun Rong
I believe I tracked down the source of the problem: in the original run, the inputs were floating and not driven from a voltage source. In that mode, they become sensitive to the charge time (somehow). When I tied all three ADC inputs to a 1V source, they all read the same values with or without the delay.
Thank you for your help.
Hi Xiangjun,
I sent you an email describing the offset/drifting problem with the ADC16_polling demo code from KSDK2.0.
Please let me know if you have received it.
Regards,
hy