Integrating an ADC Pi with the Radxa X2L


10 February 2024  |  Reading Time: 14 minutes

At AB Electronics UK, we have always focused on the Raspberry Pi when developing our expansion boards. However that does not mean we ignore all the other great small board computers available today.

We test our boards on a wide range of computer platforms from companies like Orange Pi, Odroid and Asus, and if they work together, we add them to the compatibility list on each of our product pages.

One computer that recently caught our eye is the Radxa X2L. Radxa are best known for their Rock series of ARM based computers that share many characteristics of the Raspberry Pi. For the X2L, Radxa took a different approach.

The Radxa X2L is a compact yet powerful computer designed for various applications, from desktop computing to IoT projects. The board is physically larger than the Raspberry Pi, around 3 times bigger. It is powered by an Intel® Celeron® J4125 Processor. Using an x64 processor means it can natively run Windows 10 or the wide range of Linux distributions available for x64 based computers.

One of its distinguishing features is the inclusion of the RP2040 microcontroller to control its GPIO header. The RP2040, developed by Raspberry Pi, offers high performance with its dual-core ARM Cortex-M0+ processor, making it suitable for real-time tasks and peripheral control.

However, this setup presents a unique challenge for integrating devices like the ADC Pi, which rely on I2C digital communications. The microcontroller architecture on the RP2040 differs significantly from the typical direct Linux control over GPIO pins found in other single-board computers. This difference necessitates building a bridge between the microcontroller environment and the Linux system to communicate with peripherals like the ADC Pi. We looked at several possible solutions to this interfacing problem before finding one that should work reliably and can be modified to suit individual needs.

Solution: A Microcontroller Program for ADC Pi Communication

The key to integrating the ADC Pi with the Radxa X2L lies in deploying a microcontroller program on the RP2040. This program is responsible for directly interfacing with the ADC Pi, reading analogue values, and then sending these readings to the Linux system via the serial port in a structured format, such as JSON strings.

This approach allows for real-time data acquisition from the ADC Pi while leveraging the processing power and flexibility of the Radxa X2L's Linux environment for data processing, storage, or further actions.

Implementing the Solution

On the RP2040

The first step involves programming the RP2040 to communicate with the ADC Pi.

We used the ADC Pi MicroPython library for the Raspberry Pi Pico that is available from our GitHub repository athttps://github.com/abelectronicsuk/ABElectronics_MicroPython_Libraries/tree/main/ADCPi

The pins for the I2C bus on the GPIO header are usually found on pin 3 for SDA and 5 for SCL. On the RP2040, these are connected to pins 28 for SDA and 29 for SCL.

An example MicroPython script can be seen below.

    #!/usr/bin/env python

    import time
    import json
    from ADCPi import ADCPi
    
    def main():
        # I2C addresses of 0x68 and 0x69, bit rate 12 with SDA on pin 28 and SCL on pin 29
        adc = ADCPi(0x68, 0x69, 12,28,29)
    
        while True:
            try:
                # get ADC values
                a1 = adc.read_voltage(1)
                a2 = adc.read_voltage(2)
                a3 = adc.read_voltage(3)
                a4 = adc.read_voltage(4)
                a5 = adc.read_voltage(5)
                a6 = adc.read_voltage(6)
                a7 = adc.read_voltage(7)
                a8 = adc.read_voltage(8)
                
                # create an array using the adc values
                data = [a1, a2, a3, a4, a5, a6, a7, a8]
                
                # Create the JSON object with the data array
                output_dict = {
                    "board": "adcpi",
                    "data": data
                }
                
                # Convert to JSON string
                json_string = json.dumps(output_dict)
                
                print(json_string)
                
                # wait 0.1 seconds between reads
                time.sleep(0.1)
            
            except:
                # show error message if the read fails
                output_dict = {
                    "board": "adcpi",
                    "error": "read error"
                }
                
                # Convert to JSON string
                json_string = json.dumps(output_dict)
                
                print(json_string)
    
    
    if __name__ == "__main__":
        main()

An ADCPi object is used to setup I2C communication between the RP2040 and the ADC Pi. A while loop continuously initiates data reads from the ADC Pi's inputs and format these readings into JSON strings.

The program then writes these strings to the RP2040's serial output, effectively turning the microcontroller into a bridge between the analogue world and the digital, Linux-driven Radxa X2L.

On the Radxa X2L

On the Linux side, a Python script, like the one shown below, can be used to read the JSON strings from the serial port. This script continuously monitors the serial port for new data, decodes the JSON strings, and processes the analogue values for any application needs, from simple logging to real-time monitoring and control.

Here's a basic outline of such a Python script:

    import json
    import serial
    import os
    import sys
    import time
    
    # Function to clear the screen
    def clear_screen():
        if os.name == 'nt':  # for Windows
            _ = os.system('cls')
        else:  # for macOS and Linux(here, os.name is 'posix')
            _ = os.system('clear')
    
    # Setup serial connection
    serial_port = '/dev/ttyACM0'
    baud_rate = 9600  # Adjust this depending on your device
    
    try:
        ser = serial.Serial(serial_port, baud_rate)
        print("Serial port opened successfully. Reading data...")
        buffer = ''  # Initialize a buffer to accumulate data
    
        while True:
            data_in = ser.read(ser.inWaiting() or 1)  # Read available data or block for one byte
            if data_in:
                # Decode byte to string and accumulate in buffer
                buffer += data_in.decode('utf-8')
                
                # Check if a complete message has been received (indicated by a newline)
                if '\n' in buffer:
                    # Split buffer at the first newline; [0] is the complete message, [1] is the start of the next message
                    complete_message, buffer = buffer.split('\n', 1)
                    
                    # Clear the screen before printing new values
                    clear_screen()
                    
                    # Attempt to parse the JSON string
                    try:
                        data_dict = json.loads(complete_message)
                        data_array = data_dict["data"]
                        
                        # Print each value in the data array as separate rows
                        for i, value in enumerate(data_array, start=1):
                            print(f"Channel {i}: {value}")
                    except json.JSONDecodeError:
                        print("Error decoding JSON. Check the format of the incoming data.")
    
    except serial.SerialException as e:
        print(f"Error opening serial port: {e}")
    except KeyboardInterrupt:
        print("Program terminated by user.")
    finally:
        ser.close()  # Ensure the serial port is closed on exit

Integrating the ADC Pi with the Radxa X2L via the RP2040 microcontroller shows the flexibility and power of combining dedicated microcontrollers with Linux single-board computers. This setup not only overcomes the challenge of reading analogue inputs on devices without native ADCs but also opens a range of possibilities for advanced IoT applications, data acquisition, and control systems.


Back to the Blog