Hi,
I'm trying to test adc module of iMX6UL. I keep getting "ADC calibration failed" error. When I read count values from /sys/bus/iio/devices/iio:device0/in_voltageX_raw, it kind of works. But indeed there seems to be a calibration problem. When I apply 0V to the pin, I read 320. However, it reaches max value (4095) at about 1V despite the reference being 3.3V. In between 0V and 1V, the count seems to rise linearly.
Some background information:
1) Custom board based on iMX6UL EVK board.
2) BSP version: L3.14.52_1.1.0_ga
3) Device tree:
&adc1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_adc1>;
vref-supply = <®_vref_3v3>;
status = "okay";
};
reg_vref_3v3: regulator-vref {
compatible = "regulator-fixed";
regulator-name = "vref-3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
};
pinctrl_adc1: adc1grp {
fsl,pins = <
MX6UL_PAD_GPIO1_IO08__GPIO1_IO08 0xb0 /* I only use Analog channel 1 input 8
>;
};
Also in imx6ul.dtsi:
adc1: adc@02198000 {
...
num-channels = <10>;
...
};
4) Both VDDA_ADC_3P3 and ADC_VREFH are tied to the same 3.3V supply.
5) The pin is also configured as GPIO in U-boot.
MX6_PAD_GPIO1_IO08__GPIO1_IO08 | MUX_PAD_CTRL(NO_PAD_CTRL),
vf610_adc driver:
I checked the vf610_adc driver and calibration function. FWIW, I added the following lines to see the values of adc related registers before and after the calibration attempt.
static void vf610_adc_calibration(struct vf610_adc *info)
{
int adc_gc, hc_cfg;
int timeout;
if (!info->adc_feature.calibration)
return;
dev_err(info->dev, "VF610_REG_ADC_HC0 = %x\n", readl(info->regs + VF610_REG_ADC_HC0));
dev_err(info->dev, "VF610_REG_ADC_HC1 = %x\n", readl(info->regs + VF610_REG_ADC_HC1));
dev_err(info->dev, "VF610_REG_ADC_HS = %x\n", readl(info->regs + VF610_REG_ADC_HS));
dev_err(info->dev, "VF610_REG_ADC_R0 = %x\n", readl(info->regs + VF610_REG_ADC_R0));
dev_err(info->dev, "VF610_REG_ADC_R1 = %x\n", readl(info->regs + VF610_REG_ADC_R1));
dev_err(info->dev, "VF610_REG_ADC_CFG = %x\n", readl(info->regs + VF610_REG_ADC_CFG));
dev_err(info->dev, "VF610_REG_ADC_GC = %x\n", readl(info->regs + VF610_REG_ADC_GC));
dev_err(info->dev, "VF610_REG_ADC_GS = %x\n", readl(info->regs + VF610_REG_ADC_GS));
dev_err(info->dev, "VF610_REG_ADC_CV = %x\n", readl(info->regs + VF610_REG_ADC_CV));
dev_err(info->dev, "VF610_REG_ADC_OFS = %x\n", readl(info->regs + VF610_REG_ADC_OFS));
dev_err(info->dev, "VF610_REG_ADC_CAL = %x\n", readl(info->regs + VF610_REG_ADC_CAL));
dev_err(info->dev, "VF610_REG_ADC_PCTL = %x\n", readl(info->regs + VF610_REG_ADC_PCTL));
/* enable calibration interrupt */
hc_cfg = VF610_ADC_AIEN | VF610_ADC_CONV_DISABLE;
writel(hc_cfg, info->regs + VF610_REG_ADC_HC0);
adc_gc = readl(info->regs + VF610_REG_ADC_GC);
writel(adc_gc | VF610_ADC_CAL, info->regs + VF610_REG_ADC_GC);
timeout = wait_for_completion_timeout(&info->completion, VF610_ADC_TIMEOUT);
if (timeout == 0)
dev_err(info->dev, "Timeout for adc calibration\n");
dev_err(info->dev, "VF610_REG_ADC_HC0 = %x\n", readl(info->regs + VF610_REG_ADC_HC0));
dev_err(info->dev, "VF610_REG_ADC_HC1 = %x\n", readl(info->regs + VF610_REG_ADC_HC1));
dev_err(info->dev, "VF610_REG_ADC_HS = %x\n", readl(info->regs + VF610_REG_ADC_HS));
dev_err(info->dev, "VF610_REG_ADC_R0 = %x\n", readl(info->regs + VF610_REG_ADC_R0));
dev_err(info->dev, "VF610_REG_ADC_R1 = %x\n", readl(info->regs + VF610_REG_ADC_R1));
dev_err(info->dev, "VF610_REG_ADC_CFG = %x\n", readl(info->regs + VF610_REG_ADC_CFG));
dev_err(info->dev, "VF610_REG_ADC_GC = %x\n", readl(info->regs + VF610_REG_ADC_GC));
dev_err(info->dev, "VF610_REG_ADC_GS = %x\n", readl(info->regs + VF610_REG_ADC_GS));
dev_err(info->dev, "VF610_REG_ADC_CV = %x\n", readl(info->regs + VF610_REG_ADC_CV));
dev_err(info->dev, "VF610_REG_ADC_OFS = %x\n", readl(info->regs + VF610_REG_ADC_OFS));
dev_err(info->dev, "VF610_REG_ADC_CAL = %x\n", readl(info->regs + VF610_REG_ADC_CAL));
dev_err(info->dev, "VF610_REG_ADC_PCTL = %x\n", readl(info->regs + VF610_REG_ADC_PCTL));
adc_gc = readl(info->regs + VF610_REG_ADC_GS);
if (adc_gc & VF610_ADC_CALF)
dev_err(info->dev, "ADC calibration failed\n");
info->adc_feature.calibration = false;
}
Here are the results:
BEFORE (Note that all values are in hex format)
VF610_REG_ADC_HC0 = 1f
VF610_REG_ADC_HC1 = 1f
VF610_REG_ADC_HS = 0
VF610_REG_ADC_R0 = 0
VF610_REG_ADC_R1 = 0
VF610_REG_ADC_CFG = 10488
VF610_REG_ADC_GC = 20
VF610_REG_ADC_GS = 0
VF610_REG_ADC_CV = 0
VF610_REG_ADC_OFS = 0
VF610_REG_ADC_CAL = 0
VF610_REG_ADC_PCTL = 0
AFTER (Note that all values are in hex format)
VF610_REG_ADC_HC0 = 9f
VF610_REG_ADC_HC1 = 1f
VF610_REG_ADC_HS = 0
VF610_REG_ADC_R0 = 58
VF610_REG_ADC_R1 = 0
VF610_REG_ADC_CFG = 10488
VF610_REG_ADC_GC = 20
VF610_REG_ADC_GS = 2
VF610_REG_ADC_CV = 0
VF610_REG_ADC_OFS = 0
VF610_REG_ADC_CAL = f
VF610_REG_ADC_PCTL = 0
* We see that CALF bit of VF610_REG_ADC_GS is set, hence the calibration error.
* It seems that a conversion is performed and VF610_REG_ADC_R0 is loaded with some value. Reference manual says "While calibration is active, no ADC register can be written and no stop mode may be entered or the calibration routine will be aborted causing the CAL bit to clear and the CALF bit to set." Can this be the cause of calibration error? Or is it just the consequence of the error?
* Somehow VF610_REG_ADC_CAL is loaded with 0xf. What does this mean?
On a related note, since VF610_REG_ADC_CAL register value is only 4-bit long (16 distinct values, 0 to 15), I also tried loading every value manually and checked the performance that way. But nothing seems to change. The count still reaches 4095 at 1V every time. What exactly does this value represent?
Can someone please shed some light on this topic? What might I be missing?
Thanks.
Durmus
Solved! Go to Solution.
Hi igor,
You are right. Turns out it was a hardware issue. My guess is that ADC_VREFH ball of i.MX6UL was not making contact with PCB.
In the mean time, I had another board assembled and adc calibration is successful now.
Thanks.
Durmus
Any answers, comments on this one?
Hi Durmus
reason may be working touchscreen, please check in dts pinctrl_tsc: tscgrp
in imx_v7_defconfig :
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_IMX6UL_TSC=y
for preventing processor to enter low power mode one can try to set governor as:
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
Best regards
igor
-----------------------------------------------------------------------------------------------------------------------
Note: If this post answers your question, please click the Correct Answer button. Thank you!
-----------------------------------------------------------------------------------------------------------------------
Hi igor,
iMX6UL touchscreen is already disabled in my device tree. Furthermore, I removed the driver from kernel and tried that way. But nothing changed.
Also, scaling_governor is already set as "performance".
Maybe, I should also point out that I'm using L3.14.52_1.1.0_ga BSP if that makes a difference. I checked the latest vf610_adc driver (kernel 4.7). Some temperature sensor related code seems to be added but I didn't see anything significant. hw_init and calibration routines are still the same.
What else might be the reason for this?
Thanks.
Durmus
Hi Durmus
could you try to reproduce this on i.MX6UL EVK to exclude
hardware issues.
Best regards
igor
Hi igor,
You are right. Turns out it was a hardware issue. My guess is that ADC_VREFH ball of i.MX6UL was not making contact with PCB.
In the mean time, I had another board assembled and adc calibration is successful now.
Thanks.
Durmus