Accessing EEPROM 24C02 using C#/.NET

Hi,

I send you this message because, I am making a POC for a project , using a Verdin i.MX 8M Plus and the Dahlia board, with a 10’’ capacitive touchscreen.

Here is my config.

torizon@verdin-imx8mp-15230103:~$ sudo tdx-info

Software summary
------------------------------------------------------------
Bootloader:               U-Boot
Kernel version:           5.15.129-6.5.0+git.6f8fd49366db #1-TorizonCore SMP PREEMPT Fri Dec 22 11:15:52 UTC 2023
Kernel command line:      root=LABEL=otaroot rootfstype=ext4 quiet logo.nologo vt.global_cursor_default=0 plymouth.ignore-serial-consoles splash fbcon=map:3 ostree=/ostree/boot.1/torizon/fe091cbe7b665ff6d9d5d618cb20c42c90c242fffeaceccf204eacd186b2f597/0
Distro name:              NAME="TorizonCore"
Distro version:           VERSION_ID=6.5.0-build.8
Distro variant:           VARIANT="Docker"
Hostname:                 verdin-imx8mp-15229850
------------------------------------------------------------

Hardware info
------------------------------------------------------------
HW model:                 Toradex Verdin iMX8M Plus WB on Verdin Development Board
Toradex version:          0058 V1.1B
Serial number:            15229850
Processor arch:           aarch64
------------------------------------------------------------
torizon@verdin-imx8mp-15230103:~$
[Configuration]
Verdin iMX8M Plus Evaluation Kit with Touchscreen
with:
SOM i.MX8M Plus Quad 4GB WB IT v1.1B
Dahlia Carrier Board v1.1D
Verdin DSI to LVDS rev 1.1A
Capacitive Touch Display 10.1" v1.0A

I can develop console application in C#/.NET with VS Code and Torizon IDE Extension, and I want to access the peripherals (I2C, ADC, UART) and use an LTE Modem to access Internet, using C#/.NET.

For the moment, I just want to develop the logic of my application which uses mostly hardware communication interfaces (I2C, ADC, UART) since this is an IoT application for swimming pool fleet automated management.

For, now I have developed a small application which reads the content of the internal EEPROM 24C02 located at the address 0x57 on I2C bus 3.

torizon@verdin-imx8mp-15229850:~$ i2cdetect -y -r 3
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f
00:                         -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- UU -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- UU -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: UU -- -- -- -- -- -- -- -- -- UU -- -- -- -- UU
50: UU -- -- -- -- -- -- UU -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --


torizon@verdin-imx8mp-15229850:~$ sudo i2cdump -f -y -r 0x00-0x7F 3 0x57
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 00 40 01 cf 02 40 08 00 01 00 01 00 03 00 9b 00    .@???@?.?.?.?.?.
10: 01 40 21 00 86 82 ac 00 ff ff ff ff ff ff ff ff    ?@!.???.........
20: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
30: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
40: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
50: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
60: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................
70: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff    ................

I have developed a small C#/.NET console application for reading the content of the EEPROM for evaluating what I can achieve using C#/.NET for accessing peripherals of the Verdin i.MX 8M Plus.

I have made a simple sample application working with is the internal EEPROM ST 24C02 .

using System.Device.I2c ;

namespace GpioDemo 
{

    public class  Program {
        public static void Main()
        {
            // Create new connection settings for bus ID 3 and device address 0x57 where the ST M24C02 FMN6TP is located 
            // Ref : https://www.st.com/en/memories/m24c02-r.html 
            // Toradex Verdin iMX8M Plus V1.1 HW Datasheet : https://artifacts.toradex.com/artifactory/website-hwdocs-prod-frankfurt/verdin/modules/imx8mp/datasheet/v1_1/rev_1_04/verdin_imx8mp_datasheet.pdf
            I2cConnectionSettings settings = new I2cConnectionSettings(3, 0x57);

            // Create an I2C device with the specified settings
            I2cDevice device = I2cDevice.Create(settings);

            // Declare a buffer of 16 bytes
            Span<byte> readBuffer = new byte[16];
            Span<byte> writeBuffer = new byte[2];
            for(int address = 0; address<255; address+=16) {
                //Specity the address where to read from
                device.WriteByte((byte)address);

                //Read 16 bytes from the ST 24C02 (Sequential Read)
                device.Read(readBuffer);
                
                //Display 16 bytes read
                Console.WriteLine("Address {0:X2} : {1} {2}",address,BitConverter.ToString(readBuffer.ToArray()),System.Text.Encoding.UTF8.GetString(readBuffer)); 
            }

            //Write a sentence in the EEPROM
            string sentence = "Welcome to Torizon IDE Extension v2 ApolloX," +
                                "Version v2.4.2," +
                                "Last released 2024-04-22, 13:11:32," +
                                "Identifier toradex.apollox-vscode";

            byte[] bufferSentence = System.Text.Encoding.UTF8.GetBytes(sentence);
            for(int address = 0; address<sentence.Length; address++) {
                //Specity the address where to write to
                writeBuffer[0] = (byte)address;
                writeBuffer[1] = bufferSentence[address];

                //Write the byte at the adrress specified
                device.Write(writeBuffer);

                //Wait 5ms since this is the delay to respect between each write operation for the ST 24C02
                Task.Delay(5).Wait();
            }

            for(int address = 0; address<255; address+=16) {
                //Specity the address where to read from
                device.WriteByte((byte)address);

                //Read 16 bytes from the ST 24C02 (Sequential Read)
                device.Read(readBuffer);
                
                //Display 16 bytes read
                Console.WriteLine("Address {0:X2} : {1} {2}",address,BitConverter.ToString(readBuffer.ToArray()),System.Text.Encoding.UTF8.GetString(readBuffer)); 
            }
        }
    }
}

My docker-compose.yml is as follow:

version: "3.9"
services:
  demo-gpio-debug:
    build:
      context: .
      dockerfile: Dockerfile.debug
    image: ${LOCAL_REGISTRY}:5002/demo-gpio-debug:${TAG}
    ports:
      - 2222:2222
    volumes:
      - type: bind
        source: /dev
        target: /dev
    device_cgroup_rules:
      # For I2C
      - 'c 89:* rmw'

  demo-gpio:
    build:
      context: .
      dockerfile: Dockerfile
    image: ${DOCKER_LOGIN}/demo-gpio:${TAG}
    volumes:
      - type: bind
        source: /dev
        target: /dev
    device_cgroup_rules:
      # For I2C
      - 'c 89:* rmw'

This works fine because after the execution of my program on my SOM Verdin i.MX 8M Plus, I can dump the content of the EEPROM using the i2ctools, such as i2cdump, and I see the content written.

torizon@verdin-imx8mp-15229850:~$ sudo i2cdump -f -y -r 0x00-0x7F 3 0x57
Password: 
No size specified (using byte-data access)
     0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f    0123456789abcdef
00: 57 65 6c 63 6f 6d 65 20 74 6f 20 54 6f 72 69 7a    Welcome to Toriz
10: 6f 6e 20 49 44 45 20 45 78 74 65 6e 73 69 6f 6e    on IDE Extension
20: 20 76 32 20 41 70 6f 6c 6c 6f 58 2c 56 65 72 73     v2 ApolloX,Vers
30: 69 6f 6e 20 76 32 2e 34 2e 32 2c 4c 61 73 74 20    ion v2.4.2,Last 
40: 72 65 6c 65 61 73 65 64 20 32 30 32 34 2d 30 34    released 2024-04
50: 2d 32 32 2c 20 31 33 3a 31 31 3a 33 32 2c 49 64    -22, 13:11:32,Id
60: 65 6e 74 69 66 69 65 72 20 74 6f 72 61 64 65 78    entifier toradex
70: 2e 61 70 6f 6c 6c 6f 78 2d 76 73 63 6f 64 65 20    .apollox-vscode 
torizon@verdin-imx8mp-15229850:~$

The only thing that, I would like to ask you is if this is a good option to use the package System.Device.I2c, System.Device.Gpio, System.Device.Spi or System.Device.Pwm of .NET Core to build my IoT application instead of using C or C++.

I find that coding in C#/.NET is more structured than in C/C++. I like C and C++, but this is better organized in C# from my point of view, and I plan to use Avalonia as well, for the UI (linux desktop app + and chromium browser app) over Torizon, so C#/.NET makes sense.

Also, I want to ask you why for .NET Console app, the display of the console app is not on my touchscreen plugged to my Dahlia board with a virtual keyboard in case of we call Console.Read or Console.ReadLine. The ouputs are displayed in VS Code Debug Console.

This would be a good option if this is possible or maybe I have to use another C# template.

Many thanks

Sincerely,
François.

Hello @flepron,

I hope you are doing well :slight_smile:
From your post, it looks like your I2C access (from the output of i2cdump) is working just fine.

Regarding how to access these interfaces from a docker container in Avalonia framework: I believe it should work fine with the system libraries such as System.Device.I2c, System.Device.Gpio, System.Device.Spi or System.Device.Pwm. At least from a quick build using these libraries in our Avalonia framework, I can tell you that I did not encounter any issues. Have you tested this code on the module? Are you asking this because you face some issues there? If that’s the case, could you please share more information?

As for the console application’s display not appearing on your touchscreen, this behavior is expected because the console output in a .NET application (or any application not specifically designed for a graphical environment) is directed to the standard output (stdout), which, in the context of debugging with VS Code, appears in the Debug Console. To display output on your touchscreen, you would typically need to develop a graphical user interface (GUI) application on Avalonia that renders to the screen.

For input, like using a virtual keyboard for Console.Read or Console.ReadLine , you would need to integrate a virtual keyboard into your Avalonia application. You will find an example here on how the virtual keyboard was implemented on an Avalonia application by my colleague @matheus.tx.
Also, here you will find how the xfce service has been added into the docker-compose.yml file for this to work: wince-alternative-demos/avaloniaDemo/docker-compose.yml at a9d7b4721f804500d10177b5571864fa6dee10a7 · microhobby/wince-alternative-demos · GitHub
Feel free to look into the other files in his github project. You will find another example using the System.Device libraries here: wince-alternative-demos/avaloniaDemo/Hardware/DemoHardware.cs at a9d7b4721f804500d10177b5571864fa6dee10a7 · microhobby/wince-alternative-demos · GitHub