An Analog-to-Digital Converter (ADC) is a device that translates an analog voltage to a digital value that a microprocessor can understand.

The STMicroelectronics system-on-module has three ADC controllers, each with up to 20 channels. The ADC controllers are 12-bit successive approximation analog-to-digital converters.

Available ADC pins

On the ConnectCore MP25:

  • Dedicated analog pads ANA0 and ANA1 are available at the LGA pads.

    • ANA0 (ADC1/ADC2/ADC3 channel 0)

    • ANA1 (ADC1/ADC2/ADC3 channel 1)

  • A number of ADC channels are available at outer LGA ring and LGA pads, multiplexed with other functions. Check the Hardware reference manuals for information about pads and ADC channels.

On the ConnectCore MP25 Development Kit:

  • ANA0 (ADC1/ADC2/ADC3 channel 0) is accessible on the Flexible IO expansion connector J8

  • ANA1 (ADC1/ADC2/ADC3 channel 1) is accessible on the Flexible IO expansion connector J8

  • GPIOG 1 (ADC1 channel 6) is accessible on MIKROBUS_ADC line, connector J39

  • GPIOG 2 (ADC2 channel 2) is accessible on MIKROBUS_RST line, connector J39

Kernel configuration

You can manage the STM32MP25 ADC drivers support through the following kernel configuration options:

  • STM32 ADC core driver (CONFIG_STM32_ADC_CORE)

  • STM32 ADC driver (CONFIG_STM32_ADC)

These options are enabled as built-in on the default ConnectCore MP25 kernel configuration file.

Kernel driver

The ADC drivers are located at:

File Description

drivers/iio/adc/stm32-adc-core.c

STM32MP25 ADC core driver

drivers/iio/adc/stm32-adc.c

STM32MP25 ADC driver

Device tree bindings and customization

The STM32MP25 ADC device tree binding is documented at Documentation/devicetree/bindings/iio/adc/st,stm32-adc.yaml.

The device tree must contain entries for:

  • The ADC interfaces

  • The enabled channels

  • The IOMUX (for ADC channels on non-dedicated pads)

STM32MP25 ADC interfaces and channels

The STM32MP25 device tree defines:

  • The three ADC interfaces as child nodes of the ADC core

  • The channels of each interface as child nodes inside each ADC interface

STM32MP25 device tree
adc_12: adc@404e0000 {
	compatible = "st,stm32mp25-adc-core";
	[...]
	status = "disabled";

	adc1: adc@0 {
		compatible = "st,stm32mp25-adc";
		[...]
		status = "disabled";

		channel@14 {
			reg = <14>;
			label = "vrefint";
		};
	};

	adc2: adc@100 {
		compatible = "st,stm32mp25-adc";
		[...]
		status = "disabled";

		channel@14 {
			reg = <14>;
			label = "vrefint";
		};
		channel@15 {
			reg = <15>;

			label = "vddcore";
		};
		channel@17 {
			reg = <17>;
			label = "vddcpu";
		};
		channel@18 {
			reg = <18>;
			label = "vddgpu";
		};
	};
};

adc_3: adc@404f0000 {
	compatible = "st,stm32mp25-adc-core";
	[...]
	status = "disabled";

	adc3: adc@0 {
		compatible = "st,stm32mp25-adc";
		[...]
		status = "disabled";

		channel@14 {
			reg = <14>;
			label = "vrefint";
		};
		channel@15 {
			reg = <15>;
			label = "vddcore";
		};
		channel@17 {
			reg = <17>;
			label = "vddcpu";
		};
		channel@18 {
			reg = <18>;
			label = "vddgpu";
		};
	};
};

ConnectCore MP25 Development Kit ADC interfaces and channels

  • ADC1/ADC2/ADC3 channels 0 and 1 are enabled. These channels are available at dedicated analog pads ANA0 and ANA1.

  • ADC1 channel 6 is enabled on GPIO PG1.

STM32MP25 device tree
&adc_12 {
	vref-supply = <&external_vref>;
	vdda-supply = <&scmi_vdda18adc>;
	pinctrl-names = "default";
	pinctrl-0 = <&ccmp25_adc_pins>;
	status = "okay";

	adc1: adc@0 {
		status = "okay";

		channel@0 {
			reg = <0>;
			/* 16.5 ck_cycles sampling time */
			st,min-sample-time-ns = <400>;
		};
		channel@1 {
			reg = <1>;
			/* 16.5 ck_cycles sampling time */
			st,min-sample-time-ns = <400>;
		};
		channel@6 {
			reg = <6>;
			/* 16.5 ck_cycles sampling time */
			st,min-sample-time-ns = <400>;
		};
	};
};

[...]

&pinctrl {
	ccmp25_adc_pins: ccmp25_adc_pins-0 {
		pins {
			pinmux = <STM32_PINMUX('G', 1, ANALOG)>;
		};
	};
};

Select and configure an ADC channel

Follow these steps to configure ADC channels on your custom design:

  1. Identify the pins you want configured as ADC on the Hardware reference manuals. Pins that are ADC-capable list a additional function like ADCn_INPx, where n is the ADC interface and x the channel.

  2. Add a channel@x as a subnode of the ADCn interface, and property reg = <x>; inside.

  3. Configure the IOMUX of the pads to operate as ANALOG inputs. (Pads ANA0 and ANA1 are dedicated ADC pins and do not need any IOMUX configuration.)

For example, pad PG1 of the CPU has additional function ADC1_INP6. This pad is available on the ConnectCore MP25 Development Kit mikroBUS™ socket connector.

Example device tree entry for ADC channel
&adc12 {
	status = "okay";

	channel@6 {
		reg = <6>;
		label = "PG1";
		st,min-sample-time-nsecs = <400>;
	};
};

&pinctrl {
	ccmp25_adc_pins: ccmp25_adc_pins-0 {
		pins {
			pinmux = <STM32_PINMUX('G', 1, ANALOG)>;
		};
	};
};

Voltage reference

The ADC block supports the following voltage references:

  • External voltage reference supplied through VREF+ pad.

External voltage reference

The external voltage reference must be between the following values:

  • Min: 1.1 V

  • Max: 1.8 V (VDDA)

To use an external voltage reference you need to make the following changes to your device tree:

  1. A fixed regulator node for the external regulator, with its voltage: For example, for a 1.2 V reference:

    / {
    	regulators {
    		external_vref: regulator@99 {
    			reg = <99>;
    			compatible = "regulator-fixed";
    			regulator-name = "external-vref";
    			regulator-min-microvolt = <1200000>;
    			regulator-max-microvolt = <1200000>;
    		};
    	};
    };
  2. Set the property vref-supply of the adc node to this new regulator:

    &adc {
    	vref-supply = <&external_vref>;
    };
  3. Enable the VDDA regulator to remain on all the time. This prevents the analog block drain voltage out of your external voltage reference when the system goes to suspend.

    &&scmi_vdda18adc {
    	regulator-always-on;
    };

Formula

The value read on the ADC inputs responds to the formula:

\$V = (V_(RAW) + V_(OFFSET)) * V_(SCALE)\$

where:

  • VRAW is the input voltage converted by the ADC.

  • VOFFSET is the ADC voltage offset.

  • VSCALE is the ADC voltage scale value. This is automatically calculated basing on the Voltage reference on your device tree.

Using the ADCs

The ADC drivers are designed as standard Industrial I/O (IIO) device drivers that can be accessed from the sysfs or from user applications.

Sysfs access

When enabled, the ADC drivers create the corresponding device entries in the IIO sysfs directory (/sys/bus/iio/devices). To determine which entry corresponds to which driver, read the name descriptors with:

Reading an ADC name through the sysfs
# grep "" /sys/bus/iio/devices/iio\:device*/name
/sys/bus/iio/devices/iio:device0/name:404e0000.adc:adc@0

In this example, device0 corresponds to ADC1.

The driver creates:

  • A file entry in_voltage_offset with the voltage offset.

  • A file entry in_voltage_scale with the voltage scale.

  • A file entry in_voltageX_raw for each ADC channel, where X corresponds to the channel number.

Read the input value of a channel with:

Reading an ADC through the sysfs
# cat /sys/bus/iio/devices/iio\:device0/in_voltage6_raw
37474
# cat /sys/bus/iio/devices/iio\:device0/in_voltage_offset
0
# cat /sys/bus/iio/devices/iio\:device0/in_voltage_scale
0.439453125

The returned value in in_voltage6_raw is a decimal number with the result of the conversion. In the example, and according to the Formula:

\$V = (V_(RAW) + V_(OFFSET)) * V_(SCALE) -> V = (37474 + 0) * 0.439453125 = 1.715 mV\$

Sample application

An example application called apix-adc-example is included in the dey-examples-digiapix recipe (part of dey-examples package) of the meta-digi layer. This application shows how to access the ADCs using Digi APIx library on the ConnectCore MP25 platform.

Go to GitHub to see the application instructions and source code.

See ADC API for more information about the ADC APIx.