40-PIN 使用指南
Intel J4125 与 RP2040 和 40-PIN GPIO 的关系介绍
在 Radxa X2L 上集成了 Intel J4125 的 CPU 和一块 RP2040 MCU,两者通过 USB 和 UART 两种方式进行通信。 RP2040 在系统中以 USB 存储设备的形式存在,程序烧录时只需将文件拖拽至该 USB 设备中即可。 此外,它们还共用 UART 通信接口,使得 Intel N100 能够通过 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
-
简介
Pico SDK(以下简称 SDK)提供了使用 C、C++ 或汇编语言为基于 RP2040 的设备(如 Raspberry Pi Pico/Radxa X2L)编写程序所需的标头、库和构建系统。
SDK 旨在提供非嵌入式 C 开发人员和嵌入式 C 开发人员都熟悉的 API 和编程环境。单个程序一次在设备上运行,并以常规方法启动main()。 支持标准 C/C++ 库以及用于访问 RP2040 的所有硬件(包括 PIO(可编程 IO))的 C 级库/API。
-
使用
既可以在 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
-
简介
pico-examples 是一个官方示例代码库,展示了如何使用 Raspberry Pi Pico 和 Pico SDK 来实现各种功能。 它提供了一系列的示例,涵盖了从基本 GPIO 操作到复杂的通信协议,使开发者能够快速上手并理解如何在 Pico 上进行开发。
-
使用
既可以在 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 会开始闪烁
I2C
1. 准备
- 一块 Radxa X2L
- 一个 I2C OLED 1306
2. 连接
Radxa X2L | <--> | OLED |
---|---|---|
PIN_5 | <--> | SCL |
PIN_3 | <--> | SDA |
PIN_1 | <--> | VCC |
PIN_9 | <--> | GND |
这里的 PIN_5 对应 下面代码中的 GPIO29 的复用属性 I2C0 SDA, PIN_3 对应 下面代码中的 GPIO28 的复用属性 I2C0 SCL, 详细请参考 GPIO 定义
3. 测试
- 将以下代码替换 pico-examples/i2c/lcd_1602_i2c/lcd_1602_i2c.c
lcd_1602_i2c.c
#include <stdio.h>
#include <string.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "pico/binary_info.h"
#define I2C_ID i2c0
#define I2C_SDA_PIN 28
#define I2C_SCL_PIN 29
// commands
const int LCD_CLEARDISPLAY = 0x01;
const int LCD_RETURNHOME = 0x02;
const int LCD_ENTRYMODESET = 0x04;
const int LCD_DISPLAYCONTROL = 0x08;
const int LCD_CURSORSHIFT = 0x10;
const int LCD_FUNCTIONSET = 0x20;
const int LCD_SETCGRAMADDR = 0x40;
const int LCD_SETDDRAMADDR = 0x80;
// flags for display entry mode
const int LCD_ENTRYSHIFTINCREMENT = 0x01;
const int LCD_ENTRYLEFT = 0x02;
// flags for display and cursor control
const int LCD_BLINKON = 0x01;
const int LCD_CURSORON = 0x02;
const int LCD_DISPLAYON = 0x04;
// flags for display and cursor shift
const int LCD_MOVERIGHT = 0x04;
const int LCD_DISPLAYMOVE = 0x08;
// flags for function set
const int LCD_5x10DOTS = 0x04;
const int LCD_2LINE = 0x08;
const int LCD_8BITMODE = 0x10;
// flag for backlight control
const int LCD_BACKLIGHT = 0x08;
const int LCD_ENABLE_BIT = 0x04;
// By default these LCD display drivers are on bus address 0x27
static int addr = 0x27;
// Modes for lcd_send_byte
#define LCD_CHARACTER 1
#define LCD_COMMAND 0
#define MAX_LINES 2
#define MAX_CHARS 16
/* Quick helper function for single byte transfers */
void i2c_write_byte(uint8_t val) {
i2c_write_blocking(I2C_ID, addr, &val, 1, false);
}
void lcd_toggle_enable(uint8_t val) {
// Toggle enable pin on LCD display
// We cannot do this too quickly or things don't work
#define DELAY_US 600
sleep_us(DELAY_US);
i2c_write_byte(val | LCD_ENABLE_BIT);
sleep_us(DELAY_US);
i2c_write_byte(val & ~LCD_ENABLE_BIT);
sleep_us(DELAY_US);
}
// The display is sent a byte as two separate nibble transfers
void lcd_send_byte(uint8_t val, int mode) {
uint8_t high = mode | (val & 0xF0) | LCD_BACKLIGHT;
uint8_t low = mode | ((val << 4) & 0xF0) | LCD_BACKLIGHT;
i2c_write_byte(high);
lcd_toggle_enable(high);
i2c_write_byte(low);
lcd_toggle_enable(low);
}
void lcd_clear(void) {
lcd_send_byte(LCD_CLEARDISPLAY, LCD_COMMAND);
}
// go to location on LCD
void lcd_set_cursor(int line, int position) {
int val = (line == 0) ? 0x80 + position : 0xC0 + position;
lcd_send_byte(val, LCD_COMMAND);
}
static void inline lcd_char(char val) {
lcd_send_byte(val, LCD_CHARACTER);
}
void lcd_string(const char *s) {
while (*s) {
lcd_char(*s++);
}
}
void lcd- _init() {
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x03, LCD_COMMAND);
lcd_send_byte(0x02, LCD_COMMAND);
lcd_send_byte(LCD_ENTRYMODESET | LCD_ENTRYLEFT, LCD_COMMAND);
lcd_send_byte(LCD_FUNCTIONSET | LCD_2LINE, LCD_COMMAND);
lcd_send_byte(LCD_DISPLAYCONTROL | LCD_DISPLAYON, LCD_COMMAND);
lcd_clear();
}
int main() {
i2c_init(I2C_ID, 100 * 1000);
gpio_set_function(I2C_SDA_PIN, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL_PIN, GPIO_FUNC_I2C);
gpio_pull_up(I2C_SDA_PIN);
gpio_pull_up(I2C_SCL_PIN);
// Make the I2C pins available to picotool
bi_decl(bi_2pins_with_func(I2C_SDA_PIN, I2C_SCL_PIN, GPIO_FUNC_I2C));
lcd_init();
static char *message[] =
{
"RP2040 by", "Raspberry Pi",
"A brand new", "microcontroller",
"Twin core M0", "Full C SDK",
"More power in", "your product",
"More beans", "than Heinz!"
};
while (1) {
for (int m = 0; m < sizeof(message) / sizeof(message[0]); m += MAX_LINES) {
for (int line = 0; line < MAX_LINES; line++) {
lcd_set_cursor(line, (MAX_CHARS / 2) - strlen(message[m + line]) / 2);
lcd_string(message[m + line]);
}
sleep_ms(2000);
lcd_clear();
}
}
}
- 编译
cd pico-examples/build
rm -rf *
cmake ..
make -j$(nproc)
成功编译后,在 pico-examples/build/i2c/lcd_1602_i2c/ 目录下会产生一个名为 lcd_1602_i2c.uf2 的文件
-
烧录
- 重启 RP2040
-
将 lcd_1602_i2c.uf2 文件拖入到 RP2040 中,待 RP2040 消失后, OLED 会一段文本