Skip to main content

Control RP2040 on Linux

Introduction to Intel N100 and RP2040 and 40-PIN GPIO Relationships

The Radxa X2L integrates an Intel J4125 CPU and a RP2040 MCU, which communicate with each other via USB and UART. The RP2040 exists as a USB memory device in the system, and the program can be burned by dragging and dropping the files to the USB device. In addition, they share the same UART communication interface, which enables Intel J4125 to control the RP2040 through UART, for example, to realize the control of RP2040 GPIO through the UART interface. The relationship between the two is shown in the following figure:

Control RP2040 on Linux

In order to operate the IO resources on RP2040, we need a complete software environment, such as MicroPython or C/C++ SDK, here we mainly introduce a set of C/C++ SDKs, namely pico-sdk and pico-examples. pico-sdk mainly provides some APIs to operate the RP2040, while pico-examples provides a compilation framework for us to add our own programs according to the compilation framework provided by pico-examples. pico-sdk provides some APIs to operate the RP2040, while pico-examples provides a compilation framework for us to add our own programs according to the compilation framework provided by pico-examples.

PICO-SDK

1. Introduction

The Raspberry Pi Pico SDK (henceforth the SDK) provides the headers, libraries and build system necessary to write programs for the RP2040-based devices (such as the Raspberry Pi Pico/Radxa X2L) in C, C++ or assembly language.

The SDK is designed to provide an API and programming environment that is familiar both to non-embedded C developers and embedded C developers alike. A single program runs on the device at a time and starts with a conventional main() method. Standard C/C++ libraries are supported along with C level libraries/APIs for accessing all of the RP2040's hardware include PIO (Programmable IO).

2. Usage

tip

You can either download pico-sdk/pico-examples and install the tools on your PC in a Linux environment, or you can do it in the Linux environment of Radxa X2L. For convenience, we can do this directly in the Linux environment of Radxa X2L.

  • Install the necessary tools
sudo apt update -y
sudo apt install -y git cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
  • Get the code
git clone https://github.com/raspberrypi/pico-sdk.git
cd pico-sdk
git submodule update --init

PICO-EXAMPLES

1. Introduction

pico-examples is an official example codebase that shows how to use the Raspberry Pi Pico and the Pico SDK to implement a variety of features. It provides a range of examples covering everything from basic GPIO operations to complex communication protocols to get developers up to speed and understanding how to develop on the Pico.

2. Usage

tip

You can either download pico-sdk/pico-examples and install the tools on your PC in a Linux environment, or you can do it in the Linux environment of Radxa X2L. For convenience, we can do this directly in the Linux environment of Radxa X2L.

  • Get the code
git clone https://github.com/raspberrypi/pico-examples.git --branch master
  • Compile
export PICO_SDK_PATH=path/to/pico-sdk
cd pico-examples
mkdir build
cd build
cmake .. && make -j4

Examples

RP2040 Individually control

GPIO
1. Preparation
  • One Radxa X2L
  • One LED
2. Connection
Radxa X2L<-->LED
PIN_5<-->LED
PIN_1<-->VCC
PIN_9<-->GND
tip

Here PIN_5 corresponds to GPIO29 in the following code, please refer to GPIO Definition for details.

3. Test
  • Replace pico-examples/blink/blink.c with the following code

    blink.c

    #include "pico/stdlib.h"
    #define BLINK_PIN 29 // GPIO29

    int main() {

    gpio_init(BLINK_PIN);
    gpio_set_dir(BLINK_PIN, GPIO_OUT);

    while (true) {
    gpio_put(BLINK_PIN, 1);
    sleep_ms(250);
    gpio_put(BLINK_PIN, 0);
    sleep_ms(250);
    }
    }

  • Compile

    cd pico-examples/build
    rm -rf *
    cmake ..
    make -j$(nproc)

    After successful compilation, a file named blink.uf2 will be created in the pico-examples/build/blink/ directory.

  • Flash

    • Reboot RP2040
    • Drag the blink.uf2 file into the RP2040, and when the RP2040 disappears, the LED will start blinking.

Communication between CPU and RP2040

FAN

The purpose of this paragraph is to provide the user with an example of the Radxa X2L CPU communicating with the MCU RP2040 by obtaining the temperature of the Radxa X2L CPU and making the fan spin up when the specified temperature is reached.

1. Connection

Connect the fan's pwm pin to PIN_3, the fan VCC to Radxa X2L's VCC, and the fan GND to Radxa X2L's GND.

2. Install the required Python libraries On the Radxa X2L
pip install pyserial psutil
sudo apt-get update
sudo apt-get install stress
sudo apt-get install minicom
3. Create a new Temperature.py file on the Radxa X2L with the following contents:
Temperature.py

import psutil
import serial
import time

SERIAL_PORT = '/dev/ttyS0'
BAUD_RATE = 115200

set = serial.Serial(SERIAL_PORT, BAUD_RATE)

def get_cpu_temperature():
# get temperature from PC
temps = psutil.sensors_temperatures()
if 'coretemp' in temps:
cpu_temp = temps['coretemp'][0].current
return cpu_temp
else:
return None

try:
while True:
temp = get_cpu_temperature()
if temp is not None:
print(f"CPU Temperature: {temp}°C")
set.write(f"{temp}\n".encode())
else:
print("Unable to read temperature.")
time.sleep(1)
except KeyboardInterrupt:
set.close()
print("Program terminated.")

4. Add a directory for pwm_fan inside pico-examples/pwm/CMakeLists.txt
tip

About how to use pico-examples, Please refer to the pico-sdk/pico-examples section above

Replace pico-example/pwm/CMakeLists.txt with the following code

CMakeLists.txt

if (TARGET hardware_pwm)
add_subdirectory_exclude_platforms(hello_pwm)
add_subdirectory_exclude_platforms(led_fade)
add_subdirectory_exclude_platforms(measure_duty_cycle)
add_subdirectory_exclude_platforms(pwm_fan)
else()
message("Skipping PWM examples as hardware_pwm is unavailable on this platform")
endif()

5. Create a new CMakeLists.txt in the pico-examples/pwm/pwm_fan/ directory with the following contents:
CMakeLists.txt

add_executable(pwm_fan
pwm_fan.c
)

# pull in common dependencies and additional pwm hardware support
target_link_libraries(pwm_fan pico_stdlib hardware_pwm)

# create map/bin/hex file etc.
pico_add_extra_outputs(pwm_fan)

# add url via pico_set_program_url
example_auto_set_url(pwm_fan)

6. Create a new pwm_fan.c in the pico-examples/pwm/pwm_fan/ directory with the following contents:
pwm_fan.c
    #include <stdio.h>
#include <stdlib.h>
#include "pico/stdlib.h"
#include "hardware/uart.h"
#include "hardware/pwm.h"

#define UART_ID uart0
#define BAUD_RATE 115200
#define UART_TX_PIN 0
#define UART_RX_PIN 1
#define FAN_PWM_PIN 28
#define TEMP_THRESHOLD 60.0

void set_pwm_duty_cycle(uint slice_num, uint channel, float duty_cycle) {
if (duty_cycle < 0.0f) duty_cycle = 0.0f;
if (duty_cycle > 100.0f) duty_cycle = 100.0f;
uint16_t level = (uint16_t)(duty_cycle * (float)(1 << 16) / 100.0f);
pwm_set_gpio_level(FAN_PWM_PIN, level);
}

int main() {
stdio_init_all();

uart_init(UART_ID, BAUD_RATE);
gpio_set_function(UART_TX_PIN, GPIO_FUNC_UART);
gpio_set_function(UART_RX_PIN, GPIO_FUNC_UART);

uart_set_format(UART_ID, 8, 1, UART_PARITY_NONE);
uart_set_fifo_enabled(UART_ID, false);

gpio_set_function(FAN_PWM_PIN, GPIO_FUNC_PWM);
uint slice_num = pwm_gpio_to_slice_num(FAN_PWM_PIN);
pwm_config config = pwm_get_default_config();
pwm_config_set_clkdiv(&config, 4.0f);
pwm_init(slice_num, &config, true);

char buffer[32];
int index = 0;

printf("Waiting for data...\n");

while (1) {
if (uart_is_readable(UART_ID)) {
char c = uart_getc(UART_ID);
if (c == '\n') {
buffer[index] = '\0';
float temperature = atof(buffer);
printf("Received temperature: %.2f°C\n", temperature);
if (temperature > TEMP_THRESHOLD) {
set_pwm_duty_cycle(slice_num, PWM_CHAN_A, 100.0f);
} else {
set_pwm_duty_cycle(slice_num, PWM_CHAN_A, 0.0f);
}
index = 0;
} else {
buffer[index++] = c;
if (index >= sizeof(buffer)) {
index = sizeof(buffer) - 1;
}
}
}
}

return 0;
}

7. Compile
cd pico-examples/build
rm -rf *
cmake ..
make -j$(nproc)

After successful compilation, a file named pwm_fan.uf2 is generated in the build/pwm/pwm_fan directory

8. Flash
  • Reboot RP2040
  • Drag the pwm_fan.uf2 file into the RP2040, and after the RP2040 disappears, the program starts to read the messages from /dev/ttyS0.
9. Run Temperature.py on the board
sudo python3 Temperature.py

If the program runs successfully, the program gets the current temperature of the Radxa X2L computer, sends the temperature to the serial port /dev/ttyS0, and formats the output temperature such as “CPU Temperature: 42.0°C”

10. Run the minicom on the board
sudo minicom -D /dev/ttyS0 -b 115200

Check if the RP2040 has received the temperature from the Radxa X2L, if it has, the minicom will output the corresponding temperature, e.g. “Received temperature: 42.00°C”.