跳到主要内容

在 Linux 下控制 RP2040

Intel J4125 与 RP2040 和 40-PIN GPIO 的关系介绍

在 Radxa X2L 上集成了 Intel J4125 的 CPU 和一块 RP2040 MCU,两者通过 USB 和 UART 两种方式进行通信。 RP2040 在系统中以 USB 存储设备的形式存在,程序烧录时只需将文件拖拽至该 USB 设备中即可。 此外,它们还共用 UART 通信接口,使得 Intel J4125 能够通过 UART 控制 RP2040,例如,通过 UART 接口实现对 RP2040 GPIO 的操控。 两者关系,如图所示:

40-PIN 使用

为了操作 RP2040 上的 IO 资源, 我们需要一套完善的软件环境,如 MicroPython 或者 C/C++ SDK,在这里我们主要介绍一套 C/C++ SDK,即 pico-sdk 和 pico-example。 pico-sdk 主要是提供了一些操作 RP2040 的 API, 而 pico-examples 则为我们提供了一套程序编译框架,我们可以根据 pico-examples 提供的编译框架来添加我们自己的程序。

PICO-SDK

  1. 简介

    Pico SDK(以下简称 SDK)提供了使用 C、C++ 或汇编语言为基于 RP2040 的设备(如 Raspberry Pi Pico/Radxa X2L)编写程序所需的标头、库和构建系统。

    SDK 旨在提供非嵌入式 C 开发人员和嵌入式 C 开发人员都熟悉的 API 和编程环境。单个程序一次在设备上运行,并以常规方法启动main()。 支持标准 C/C++ 库以及用于访问 RP2040 的所有硬件(包括 PIO(可编程 IO))的 C 级库/API。

  2. 使用

提示

既可以在 PC 端的 Linux 环境中下载 pico-sdk/pico-examples 以及安装相应工具,也可以在 Radxa X2L 的 Linux 环境下。为方便起见,我们可以直接在 Radxa X2L 的 Linux 环境中进行操作。

  • 安装必要工具
sudo apt update -y
sudo apt install -y git cmake gcc-arm-none-eabi libnewlib-arm-none-eabi libstdc++-arm-none-eabi-newlib
  • 获取代码
git clone https://github.com/raspberrypi/pico-sdk.git
cd pico-sdk
git submodule update --init

PICO-EXAMPLES

  1. 简介

    pico-examples 是一个官方示例代码库,展示了如何使用 Raspberry Pi Pico 和 Pico SDK 来实现各种功能。 它提供了一系列的示例,涵盖了从基本 GPIO 操作到复杂的通信协议,使开发者能够快速上手并理解如何在 Pico 上进行开发。

  2. 使用

提示

既可以在 PC 端的 Linux 环境中下载 pico-sdk/pico-examples 以及安装相应工具,也可以在 Radxa X2L 的 Linux 环境下。为方便起见,我们可以直接在 Radxa X2L 的 Linux 环境中进行操作。

  • 获取代码
git clone https://github.com/raspberrypi/pico-examples.git --branch master
  • 编译
export PICO_SDK_PATH=path/to/pico-sdk
cd pico-examples
mkdir build
cd build
cmake .. && make -j4

示例

RP2040 单独控制 40-PIN GPIO

GPIO

1. 准备
  • 一块 Radxa X2L
  • 一个 LED
2. 连接
Radxa X2L<-->LED
PIN_5<-->LED
PIN_1<-->VCC
PIN_9<-->GND
提示

这里的 PIN_5 对应 下面代码中的 GPIO29, 详细请参考 GPIO 定义

3. 测试
  • 将以下代码替换 pico-examples/blink/blink.c

    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);
    }
    }

  • 编译

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

    成功编译后,在 pico-examples/build/blink/ 目录下会产生一个名为 blink.uf2 的文件

  • 烧录

    • 重启 RP2040
    • 将 blink.uf2 文件拖入到 RP2040 中,待 RP2040 消失后, LED 会开始闪烁

CPU 通过 UART 来控制 RP2040 的 40-PIN GPIO

风扇

本段示例旨在为用户提供一个 Radxa X2L CPU 与 MCU RP2040 通信的例子,通过获取 Radxa X2L CPU 的温度,当达到指定温度时,让风扇转起来。

1. 连接

将风扇的 pwm 引脚连接到 PIN_3, 风扇 VCC 连接 Radxa X2L 的 VCC, 风扇 GND 连接 Radxa X2L 的 GND

2. Radxa X2L 安装所需要的 Python 库
pip install pyserial psutil
sudo apt-get update
sudo apt-get install stress
sudo apt-get install minicom
3. 在 Radxa X2L 上新建一个 Temperature.py 的文件,内容如下:
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 Host
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. 在 pico-examples/pwm/CMakeLists.txt 里面添加一个 pwm_fan 的目录
提示

关于 pico-examples 如何使用请参考上面 pico-sdk/pico-examples 部分

将 pico-example/pwm/CMakeLists.txt 替换称以下代码

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. 在 pico-examples/pwm/pwm_fan/ 目录下新建一个 CMakeLists.txt, 内容如下:
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. 在 pico-examples/pwm/pwm_fan/ 目录下新建一个 pwm_fan.c,内容如下:
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. 编译
cd pico-examples/build
rm -rf *
cmake ..
make -j$(nproc)

成功编译后,在 build/pwm/pwm_fan 目录下会产生一个名为 pwm_fan.uf2 的文件

8. 烧录
  • 重启 RP2040
  • 将 pwm_fan.uf2 文件拖入到 RP2040 中,待 RP2040 消失后, 程序开始读取 /dev/ttyS0 的消息
9. 板端运行 Temperature.py
sudo python3 Temperature.py

程序成功运行的话,该程序会获取 Radxa X2L 当前温度,将温度发送到串口 /dev/ttyS0,并格式化输出温度,如 "CPU Temperature: 42.0°C"

10. 板端运行 minicom
sudo minicom -D /dev/ttyS0 -b 115200

查看 RP2040 是否有接收到来自 Radxa X2L 发送的温度,若成功接收到, minicom 会输出相应温度,如: "Received temperature: 42.00°C"