MCP3428 Kernel driver

Hi Toradex,

I’m continuing to develop on my AM62 Som + Mallow board + Custom board.

After successfully connect to the pca gpio expander, I try now to communicate with my two ADC Microchip MCP3428 via i2c.

Unlike pca9575, the kernel module is not in ‘Yes’ by default but in ‘m’. So I need to enable the module at run time. I can see my two adc on port i2c3 at adress 0x68 and 0x6c with i2cdetect.

After using insmod to enable the module, the two devices are not UU but still appearing with their adress in i2cdetect.

So how to let the systeme pointing to the right driver please ?

My dts are written in the way, via the compatible command. But as the module is loaded after boot and may be after overlay operation, may be I would need to reload something ?

The own difference i can see with docuemntation example mcp6050 and my pca is that the kernel module is enable by me in the user space.

Here the step followed and my dts:

cd tcbdir

source tcb-env

rm -r torizon-core-docker-verdin-am62-Tezi_6.7.0-devel-202406+build.24.CUSTOM/

torizoncore-builder build

torizoncore-builder images unpack torizon-core-docker-verdin-am62-Tezi_6.7.0-devel-202406+build.24.CUSTOM/

torizoncore-builder deploy --remote-host 192.168.0.132 --remote-username torizon --remote-password flo --reboot

ssh torizon@192.168.0.132

sudo insmod /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc/mcp3422.ko

i2cdetect -r -y 3

I can see my two mcp3422 ADC in 0x68 and 0x6c, but no UU to mention that driver is ready to be used.

My dts content:

/dts-v1/;
/plugin/;

#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>

/ {
compatible = “toradex,verdin-am62”;
};
/* Verdin I2C_1 */
&main_i2c1 {
pca9575@20{
status = “okay”;
compatible= “nxp,pca9575”;
reg = <0x20>;
gpio-controller;
#gpio-cells = <2>;
};
};

/* Verdin I2C_3 */
&main_i2c3 {
adc@68 {
compatible = “microchip,mcp3428”;
reg = <0x68>;
};
};

readlink /sys/bus/i2c/devices/4-0068
…/…/…/devices/platform/bus@f0000/20030000.i2c/i2c-4/4-0068

I also wonder for production how to automate the insmod.
Should I rebuild my own os with the CONFIG option to ’ yes’ may be?

Thank you !

Hi, I’m the Toradex AI Assistant. I’m in early beta, and I would appreciate your feedback.
The Toradex Support team will follow up with you shortly!

Did you like my answer?

:+1: :-1:


Hello,

To ensure that your MCP3428 ADC devices are correctly recognized and managed by the Linux kernel on your Toradex module, you need to ensure that the device tree and kernel module are properly configured and loaded. From your description, it seems you’ve already taken several correct steps towards this goal. Here are some additional suggestions and clarifications to help you further:

  1. Device Tree Configuration: Your device tree snippet for the MCP3428 looks correct. Ensure that the I2C bus (main_i2c3) to which the MCP3428 devices are connected is correctly enabled and configured in the device tree. The compatible property for MCP3428 is correctly set to "microchip,mcp3428", and the reg property matches the I2C addresses of your devices.

  2. Loading the Kernel Module: Using insmod to manually load the kernel module is a valid approach for testing, but for a more permanent solution, especially for production, you might consider integrating the module into your kernel image or ensuring it’s loaded automatically at boot time. This can be achieved by adding the module to the /etc/modules-load.d/ directory in your root filesystem.

  3. Automatic Device Creation: The absence of “UU” in the i2cdetect output suggests that the kernel has not created device nodes for your ADCs, possibly because the driver did not bind to the devices. This could be due to a mismatch in the device tree or an issue with the driver itself. Ensure that the driver supports automatic device creation upon loading, or you may need to manually create device nodes.

  4. Device Tree Overlays: Since you’re working with Torizon, consider using Device Tree Overlays to dynamically configure hardware settings without needing to recompile the entire device tree. This can be particularly useful for enabling or configuring kernel modules at runtime.

  5. Automating Module Loading: For production, automating the loading of the mcp3422 kernel module can be achieved by either setting the kernel configuration option to build this driver directly into the kernel (y) instead of as a module (m), or by using a startup script that executes insmod or modprobe to load the module at boot time. The former requires recompiling the kernel with the modified configuration, while the latter can be implemented in the root filesystem.

  6. Rebuilding the OS: If you decide to change the kernel configuration to include the MCP3428 driver directly in the

Please, also check if these links can help you solve your problem:

I2C (Linux) | Toradex Developer Center.

Greetings @FloSolio,

First of all, if you have a device configured in the device tree and it refers to driver, and that driver is a kernel module then in most cases it should be automatically loaded by the kernel for use.

Though in your case it seems like this is not happening. Typically device trees refer to drivers via the compatible field. I see you have compatible = “microchip,mcp3428”;. However, if I look in the mcp3422 driver source code which you say this peripheral uses: mcp3422.c « adc « iio « drivers - linux-toradex.git - Linux kernel for Apalis, Colibri and Verdin modules

Then I see the only compatible that is coded in this driver is mcp3422. Perhaps this is the reason the driver is not managing your peripherals?

Another thing is I see in your dts content the node for the mcp device doesn’t have status = "okay".

If it’s not any of these, maybe could you check the dmesg logs? Perhaps there’s a helpful log there from the driver or from the device tree.

Best Regards,
Jeremias

Hi @jeremias.tx ,

I tried to add status okay without success. I also try to modify in dts mcp3428 by mcp3422 without success too.

Dmesg indicates this error message just after calling insmod. Is seems to point to an IO error.

sudo insmod /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc/mcp3422.ko

mcp3422: probe of 4-0068 failed with error -121

I tried to add the second adc on adress 0x6c in the dts but I get the same message:

[ 39.252345] mcp3422: probe of 4-006c failed with error -121
[ 39.252772] mcp3422: probe of 4-0068 failed with error -121

ANother think that I don’t understand is that i can’t use modprob :sweat_smile:

sudo modprobe /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc/mcp3422.ko
Password:
modprobe: FATAL: Module /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc/mcp3422.ko not found in directory /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae

It seems that modprob doesn’t accept path like insmod but modprob seems to be clever and load dependency if needed.

Hi ,

I succeed in making it worked !

The problem was the dts.

My devices are connected to i2c3_hdmi that is in fact mcu_i2c0 in the dts, and not main_i2c3.

Next step, read the value :slight_smile: .

Glad you were able to resolve your issue!

My devices are connected to i2c3_hdmi that is in fact mcu_i2c0 in the dts, and not main_i2c3.

This makes sense the “probe” error you got does imply that the driver couldn’t establish communication with the peripherals. But, since the peripherals are seen by i2cdetect that would mean they are connected properly just not where the driver thinks they are connected.

Best Regards,
Jeremias

Hi Jeremias,

I try now to rad my adc channels into docker.

At the moment, I run insmod manually when i’m connected to ssh.
But if i run my python into docker, i need to have access to adc folder.

I know that i need to bind the good folder, i also need to insert the kernel module with insmod into docker.

Is it the good way to proceed ? I tried by mounting some volume but without success.

I’m not sure at the moment this is the good way to go.

=> ERROR [container-test1-debug 4/11] RUN sudo insmod /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/d 0.6s

[container-test1-debug 4/11] RUN sudo insmod /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc/mcp3422.ko:
0.503 insmod: ERROR: could not load module /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc/mcp3422.ko: No such file or directory

devices:
  - /dev/gpiochip0:/dev/gpiochip0
  - /dev/gpiochip1:/dev/gpiochip1

volumes:
  - type: bind
    source: /sys/bus/i2c/devices/3-0068/iio\:device2
    target: /adc
  - /lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc:/lib/modules/6.1.80-6.7.0-devel+git.79fe3839eaae/kernel/drivers/iio/adc

Wait you’re still having to manually insmod your kernel module? It’s not auto-loading?

Also I would suggest loading the kernel module before running your container. The container inherits the kernel of the system it’s running on top of. So if the driver is already loaded before the container runs it should inherit this. In this way you don’t have to worry about loading anything in the container itself. This is how it works in our ADC example: How to Use ADC on Torizon OS | Toradex Developer Center

You can see we don’t have to load kernel drivers or anything in the container as long as it’s available outside of the container in the kernel already. Otherwise managing peripherals would be more of a pain inside containers.

Though I’m still curious why you have to manually insmod this kernel module and it’s not being automatically loaded.

Best Regards,
Jeremias

Hi Jeremias,

I also found in between that container should inherit from kernel. So my point is to auto-load the driver.
Dmesg doesn’t point to the driver, so it is really not automatically load at boot.
Is it because of my custom dts ? I don’t think so because 'im able to run the driver and linking to the good i2c adresses.

but may be there is an option to add in the customization file, like auto-load ?

I was able to read the adc value in a container by running the container manually in the terminal via:

docker run --rm -it --mount source=/sys/devices/platform/bus@f0000/bus@f0000:bus@4000000/4900000.i2c/i2c-3/3-0068,target=/adc,type=bind torizon/debian:${CT_TAG_DEBIAN}

But i’m not able to read the path to the adc value when i’m using my application code based on torizon pyhton example. The mounting point fail. I guess it is because i go through a dockerfile and a docker compose. I tried volumes, devices, and even --mount option but without success yet. red the mpu6050 and adc documentation to try to find the solution.

So i tried to modify my dts in the same spirit than MPU6050:

/* Verdin I2C_3 */

&mcu_i2c0 {
adc_flo68:mcp3422@68 {
compatible = “microchip,mcp3428”, “microchip,mcp3422”;
reg = <0x68>;
status = “okay”;
};

adc_flo6c:mcp3422@6c {
compatible = “microchip,mcp3428”, “microchip,mcp3422”;
reg = <0x6c>;
status = “okay”;
};
};

Is it because of my custom dts ?

Well the strange thing is that normally in my experience if there is an entry in the device tree that refers to a driver then that driver should be automatically loaded during boot time as needed. But that doesn’t seem to be happening here.

but may be there is an option to add in the customization file, like auto-load ?

Well your other option would be to create an entry in /etc/modules-load.d that loads your kernel module during boot as described here: modules-load.d

Then you can capture this configuration file via TorizonCore Builder to create a persistent customization in your OS image.

But i’m not able to read the path to the adc value when i’m using my application code based on torizon pyhton example. The mounting point fail.

Could you elaborate on the error here. What do yo umean the “mounting point fails” exactly? Do you have a specific error message you are getting?

It could be a permission issue with the ADC, maybe something like what is described here: Libiio-dev permission errors while creating buffer for ads1015 from container

Best Regards,
Jeremias

Hi Jeremias,

May be you can try to use my dts to test and check why it is not loaded at boot time ?

Please not that insmod but also modprobe now works.

I’m not able to read in my python application, the error i have is that the path is not existing.

I try by using the full path name that works when i run a container “manually” without vs code and docker compose like you did in the tutorial:

By manually, i mean launch a new container like this :

docker run --rm -it --mount source=/sys/devices/platform/bus@f0000/bus@f0000:bus@4000000/4900000.i2c/i2c-3/3-0068,
target=/adc,
type=bind torizon/debian:${CT_TAG_DEBIAN}

And print with :

cat /adc/iio:device2/in_voltage0_raw

Is there a way to deploy faster with vscode please?
Each time I modify the python, all the container are clean, rebuild etc… and it takes ages !

You’re talking about multiple different topics now. I would appreciate it if you would keep these threads to one main topic per thread. Otherwise it’s very easy to start getting the conversation confused.

May be you can try to use my dts to test and check why it is not loaded at boot time ?

I found a thread on the raspberry pi forums that suggest this is an issue with the mcp3422 driver: https://forums.raspberrypi.com/viewtopic.php?t=258294

Until someone in the Linux community fixes the driver’s behavior I guess that’s just how it is.

I’m not able to read in my python application, the error i have is that the path is not existing.

Okay let’s summarize. If you manually start your container with docker run --rm -it --mount source=/sys/devices/platform/bus@f0000/bus@f0000:bus@4000000/4900000.i2c/i2c-3/3-0068, target=/adc, type=bind torizon/debian:${CT_TAG_DEBIAN}. Then execute cat /adc/iio:device2/in_voltage0_raw inside this container, that works fine correct?

When your python application tries to access the ADC file-path it complains it does not exist. Can you first confirm whether the container started by VSCode for debugging has this file path inside it or not.

Is there a way to deploy faster with vscode please?
Each time I modify the python, all the container are clean, rebuild etc… and it takes ages !

You’ll have to be a bit more specific, what do you mean it “takes ages”. Is it abnormally long?

Best Regards,
Jeremias