MCUXpresso IDE v10.2.1 [Build 795] [2018-07-25]
MKL26Z256VLH4
I am working on a Medical device. It needs to read 2 ADC inputs, a battery voltage and temperature.
I have 2 questions.
1) The ADC channel are on ADC0_SE11 pin 45, and ADC0_SE6b pin 62.
Are the channel numbers 0x11 and 0x6B?
0x6B is higher then 31, so that does not look correct.
2) See my attached project. I setup 2 ADCs in interrupt mode, so they use ADC0_IRQHandler().
Since ADC0_IRQHandler() is shared by the ADC channels, it must be able to determine which ADC channel has caused the interrupt.
How do I set up and use 2 ADCs inputs?
Thanks,
Bruce Graham
Senior Software Engineer
TechnoSoft Innovations, Inc
Hi Bruce Graham,
1)
Please check the "Table 3-35. ADC0 channel assignment" of KL26P121M48SF4RM.
2)
You can refer: Using DMA to Emulate ADC Flexible Scan Mode with SDK 2.x
Best Regards,
Robin
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
The provided example is for a MCU with a EDMA controller, so the example did not help.
.
I created a simple app that polls the ADC value on pin 45 of my MKL16Z256VLH4 board.
The code came from the ADC16 polling example.
See attached.
.
I started with a FRDM-KL26Z board, and replace the KL26Z with a KL16Z.
In the code, I set the input to ADC0_SE11 pin 45.
.
When the app runs, the ADC conversion completes, but the ADC value does not change when the voltage on pin 45 changes.
The ADC value jumps between 0 and 4, so is it possible that my code is reading the wrong ADC channel?
.
Can somebody point out the program with the code?
.
Thanks,
Bruce
I would have provided the code, but I don't know to add it. So, I pasted main and support functions.
Bruce
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "board.h"
#include "peripherals.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "MKL16Z4.h"
#include "fsl_debug_console.h"
/* TODO: insert other include files here. */
void FloatToStringNew(char *str, float f, char size);
/* TODO: insert other definitions and declarations here. */
// Table 3-35. ADC0 channel assignment" of KL26P121M48SF4RM
#define ADC16_CHANNEL_BATT_VOLT 0x11 // ADC0_SE11 pin 45
//#define ADC16_CHANNEL_BATT_TEMP 0x06 // ADC0_SE6b pin 62
#define ADC16_CHANNEL_GROUP 0
/* BATT_VOLT
4.2V full charge
3.4V low, must charge
3.3V protection kicks in
Vin 4.2V (Full Charge)
|
10k
|---- Vout (BATT_VOLT)
4.7k
|
GND
Vout = (Vin * R2) / (R1 + R2)
Vout = (Vin * 4700) / (10000 + 4700)
= 19740 / 14700
Max BATT_VOLT = 1.34V
*/
#define VOLTS_PER_BIT (3.3f / 4096.0f) // Vref / 12 full scale 0x0FFF
float ADC_ValueToVoltage(uint16_t iAdcValue)
{
float fVolts = VOLTS_PER_BIT * (float)iAdcValue;
return fVolts;
}
/*
* @brief Application entry point.
*/
int main(void)
{
adc16_config_t adc16ConfigStruct;
adc16_channel_config_t adc16ChannelConfigStruct;
/* Init board hardware. */
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitBootPeripherals();
/* Init FSL debug console. */
BOARD_InitDebugConsole();
PRINTF("Hello World\n");
ADC16_GetDefaultConfig(&adc16ConfigStruct);
ADC16_Init(ADC0, &adc16ConfigStruct);
PRINTF(" referenceVoltageSource: %d\n", adc16ConfigStruct.referenceVoltageSource);
PRINTF(" clockSource: %d\n", adc16ConfigStruct.clockSource);
PRINTF(" enableAsynchronousClock: %d\n", adc16ConfigStruct.enableAsynchronousClock);
PRINTF(" clockDivider: %d\n", adc16ConfigStruct.clockDivider);
PRINTF(" resolution: %d\n", adc16ConfigStruct.resolution);
PRINTF(" longSampleMode: %d\n", adc16ConfigStruct.longSampleMode);
PRINTF(" enableHighSpeed: %d\n", adc16ConfigStruct.enableHighSpeed);
PRINTF(" enableLowPower: %d\n", adc16ConfigStruct.enableLowPower);
PRINTF("enableContinuousConversion: %d\n", adc16ConfigStruct.enableContinuousConversion);
ADC16_EnableHardwareTrigger(ADC0, false);
#if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
if (kStatus_Success == ADC16_DoAutoCalibration(ADC0))
{
PRINTF("ADC16_DoAutoCalibration() Done.\r\n");
}
else
{
PRINTF("ADC16_DoAutoCalibration() Failed.\r\n");
}
#endif // FSL_FEATURE_ADC16_HAS_CALIBRATION
adc16ChannelConfigStruct.channelNumber = ADC16_CHANNEL_BATT_VOLT;
adc16ChannelConfigStruct.enableInterruptOnConversionCompleted = false;// Disable the interrupt.
#if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
adc16ChannelConfigStruct.enableDifferentialConversion = false;
#endif // FSL_FEATURE_ADC16_HAS_DIFF_MODE
while(1)
{
//PRINTF("Press any key to get user channel's ADC value ...\r\n");
//GETCHAR(); // Input any key in terminal console.
ADC16_SetChannelConfig(ADC0, ADC16_CHANNEL_GROUP, &adc16ChannelConfigStruct);
while (kADC16_ChannelConversionDoneFlag != ADC16_GetChannelStatusFlags(ADC0, ADC16_CHANNEL_GROUP))
{
}
uint16_t iValueAdc = ADC16_GetChannelConversionValue(ADC0, ADC16_CHANNEL_GROUP);
float fBatteryVoltage = ADC_ValueToVoltage(iValueAdc);
#if 1
char szBatteryVoltage[32];
FloatToStringNew(szBatteryVoltage, fBatteryVoltage, 6);
PRINTF("ADC Value: 0x%04X %s Volts\r\n", iValueAdc, szBatteryVoltage);
#else
PRINTF("ADC Value: 0x%04X %f Volts\r\n", iValueAdc, fBatteryVoltage);
#endif
}
}
#if 1
// convert float to string one decimal digit at a time
// assumes float is < 65536 and ARRAYSIZE is big enough
// problem: it truncates numbers at size without rounding
// str is a char array to hold the result, float is the number to convert
// size is the number of decimal digits you want
void FloatToStringNew(char *str, float f, char size)
{
int pos; // position in string
char len; // length of decimal part of result
int value; // decimal digit(s) to convert
pos = 0; // initialize pos, just to be sure
value = (int)f; // truncate the floating point number
itoa(value, str, 10); // this is kinda dangerous depending on the length of str
// now str array has the digits before the decimal
strcat(str, ".");
if (f < 0 ) // handle negative numbers
{
f *= -1;
value *= -1;
}
len = strlen(str); // find out how big the integer part was
pos = len; // position the pointer to the end of the integer part
while(pos < size) // process remaining digits
{
f = f - (float)value; // hack off the whole part of the number
f *= 10; // move next digit over
value = (int)f; // get next digit
itoa(value, &str[pos], 10); // convert digit to string
pos++;
}
str[pos] = 0;
}
#endif
The ADC problem occurs with:
ADC0_SE6b pin 62 FRDM dev kit J2-12
ADC0_SE7b pin 63 FRDM dev kit J2-8
ADC0_SE11 pin 45 FRDM dev kit J4-10
.
The LIGHT_SNS works:
ADC0_SE3 pin 11 FRDM dev kit J4-5.
.
Why does ADC0_SE3 work, but not ADC0_SE6b, ADC0_SE7b and ADC0_SE11?
.
Thanks,
Bruce
I created a new app using the KL26Z SDK, and the problems have changed.
.
The ADC problem occurs with:
ADC0_SE6b pin 62 FRDM dev kit J2-12 is stuck at 0x0FFF
ADC0_SE7b pin 63 FRDM dev kit J2-8 is reading noise about 0x0A00
ADC0_SE11 pin 45 FRDM dev kit J4-10 values are not linear
ADC0_SE3 pin 11 FRDM dev kit J4-5 0x0C12 at 2.4895 Volts, 0x0FF5 3.2911 Volts
.
The values returned from ADC0_SE11 are not linear.
ADC16_DoAutoCalibration() passed.
.
#define VOLTS_PER_BIT (3.3f / 4096.0f) // Vref / 12 full scale 0x0FFF
fComputedVolts = VOLTS_PER_BIT * (float)iAdcValue;
.
See values below.
Input ADC Computed V
===== ====== ==========
3.3 V 0x0F17 3.1122 V
3.0 V 0x0E19 2.9076 V
2.5 V 0x0C04 2.4782 V
2.0 V 0x0A01 2.0633 V
1.5 V 0x07E0 1.6242 V
1.0 V 0x0612 1.2520 V
0.5 V 0x0465 0.9063 V
0.0 V 0x0387 0.7275 V
Input is Orange. Computed V is Blue.
.
Is there a known ADC failure problem with the KL16Z SDK?
What is up with the non-linear ADC readings?
.
Thanks,
Bruce