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 two 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 MP13:

  • Dedicated analog pads ANA0 and ANA1 (ADC1 channels 0 and 1) are available at the LGA pads.

  • Other ADC1 and ADC2 channels are available at castellated and LGA pads, multiplexed with other functions. Check the Hardware reference manuals for information about pads and ADC channels.

On the ConnectCore MP13 Development Kit:

  • A number of pads of the ConnectCore MP13 can be configured as ADC channels (multiplexed with other functionality). On the ConnectCore MP13 Development Kit, some of them are accessible on connectors:

    • GPIOA 5 (ADC1 channel 2) on MIKROBUS_PWM line, connector J31

Kernel configuration

You can manage the STM32MP13 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 MP13 kernel configuration file.

Kernel driver

The ADC drivers are located at:

File Description

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

STM32MP13 ADC core driver

drivers/iio/adc/stm32-adc.c

STM32MP13 ADC driver

Device tree bindings and customization

The STM32MP13 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 interface

  • The enabled channels

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

STM32MP13 ADC interface

STM32MP13 device tree
adc_1: adc@48003000 {
	compatible = "st,stm32mp13-adc-core";
	reg = <0x48003000 0x400>;
	interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&rcc ADC1>, <&rcc ADC1_K>;
	clock-names = "bus", "adc";
	interrupt-controller;
	#interrupt-cells = <1>;
	#address-cells = <1>;
	#size-cells = <0>;
	status = "disabled";

	adc1: adc@0 {
		compatible = "st,stm32mp13-adc";
		#io-channel-cells = <1>;
		#address-cells = <1>;
		#size-cells = <0>;
		reg = <0x0>;
		interrupt-parent = <&adc_1>;
		interrupts = <0>;
		dmas = <&dmamux1 9 0x400 0x80000001>;
		dma-names = "rx";
		nvmem-cells = <&vrefint>;
		nvmem-cell-names = "vrefint";
		status = "disabled";

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

adc_2: adc@48004000 {
	reg = <0x48004000 0x400>;
	compatible = "st,stm32mp13-adc-core";
	interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>;
	clocks = <&rcc ADC2>, <&rcc ADC2_K>;
	clock-names = "bus", "adc";
	interrupt-controller;
	#interrupt-cells = <1>;
	#address-cells = <1>;
	#size-cells = <0>;
	status = "disabled";

	adc2: adc@0 {
		compatible = "st,stm32mp13-adc";
		#io-channel-cells = <1>;
		#address-cells = <1>;
		#size-cells = <0>;
		reg = <0x0>;
		interrupt-parent = <&adc_2>;
		interrupts = <0>;
		dmas = <&dmamux1 10 0x400 0x80000001>;
		dma-names = "rx";
		nvmem-cells = <&vrefint>;
		nvmem-cell-names = "vrefint";
		status = "disabled";

		channel@13 {
			reg = <13>;
			label = "vrefint";
		};
		channel@14 {
			reg = <14>;
			label = "vddcore";
		};
		channel@16 {
			reg = <16>;
			label = "vddcpu";
		};
		channel@17 {
			reg = <17>;
			label = "vddq_ddr";
		};
	};
};

On the ConnectCore MP13 Development Kit, only ADC1 is enabled.

STM32MP13 device tree
&adc_1 {
	/* PA5 which is shared with MikroE PWM */
	pinctrl-names = "default";
	pinctrl-0 = <&ccmp13_adc1_pins>;
	vdda-supply = <&scmi_vdd_adc>;
	vref-supply = <&scmi_vdd_adc>;
	status = "okay";

	adc1: adc@0 {
		status = "okay";
		channel@2 {
			reg = <2>;
			st,min-sample-time-nsecs = <5000>;
		};
	};
};

IOMUX configuration

You must configure the pads that are to be used as ADCs as ANALOG inputs.

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

  1. Identify the pins you want configured as ADC. Verify that they are ADC-capable and note the ADC channel they are connected to. You can find this information on the Hardware reference manuals.

  2. Enable the desired channel indexes using the st,adc-channels property.

  3. Configure the IOMUX of the pins to operate as ANALOG.

  4. Compile the device tree and install it in your platform.

For example, ADC1 channel 2 is available on the ConnectCore MP13 Development Kit mikroBUS™ socket connector, which corresponds to pad GPIOA 5 of the CPU. To enable it:

ConnectCore MP13 Development Kit device tree
&adc {
	pinctrl-names = "default";
	pinctrl-0 = <&ccmp15_adc_pins>;
	status = "okay";

	adc1: adc@0 {
		st,adc-channels = <0 1 2>;
		/* 16.5 ck_cycles sampling time */
		st,min-sample-time-nsecs = <400>;
		status = "okay";
	};
};

&pinctrl {
	ccmp15_adc_pins: ccmp15_adc_pins-0 {
		pins {
			pinmux = <STM32_PINMUX('F', 13, ANALOG)>;
		};
	};
};

Voltage reference

The ADC block can use an external reference voltage supplied via the VREF+ pad.

External voltage reference

This external voltage reference cannot exceed the value of VDDA (3.0 V). To use an external voltage reference you need to make the following changes to your device tree:

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

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

    &adc {
    	vref-supply = <&external_vref>;
    };
  3. Disable the internal vrefbuf regulator:

    &vrefbuf {
    	status = "disabled";
    };
  4. Enable the VDDA regulator to remain on all the time. This is to prevent the analog block from draining voltage out of your external voltage reference.

    &vdda {
    	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:48003000.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_voltage2_raw
4030
# cat /sys/bus/iio/devices/iio\:device0/in_voltage_offset
0
# cat /sys/bus/iio/devices/iio\:device0/in_voltage_scale
0.805664062

The returned value in in_voltageX_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 = (4030 + 0) * 0.805664062 = 3.246 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 MP13 platform.

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

See ADC API for more information about the ADC APIx.