Integrating an ADC Pi with the Radxa X2L
At AB Electronics UK, we have always focused on the Raspberry Pi when developing our development 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.
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.