任务介绍
本项目实现了Funpack第4-2期活动SAME51J20A Curiosity Nano板卡的自命题任务,基于SAME51开发板实现了对RT-Thread操作系统的移植,并在此软硬件基础上控制OLED屏幕,实现了一个简易游戏机,支持通过扩展板按键进行游戏操作,同时与OLED屏幕联动显示游戏画面和状态信息。
硬件平台
本次使用Microchip推出的SAME51J20A Curiosity Nano开发板,是一款面向嵌入式开发的高性能评估平台。该开发板搭载了基于ARM Cortex-M4内核的SAME51系列MCU,具备丰富的外设资源,包括多个I2C接口、SPI接口、ADC/DAC模块等,非常适合用于实时嵌入式系统的开发。开发板集成了调试器接口、USB接口、用户可编程LED与按键,便于快速搭建原型系统。
在软件方面,本项目采用RT-Thread实时操作系统作为底层运行环境。RT-Thread以其轻量级、高可扩展性和良好的跨平台支持而著称,适用于资源受限的嵌入式设备。通过将RT-Thread移植至SAME51平台,实现了多线程调度、设备驱动管理以及图形界面显示等功能。
主控设备:Microchip SAME51J20A Curiosity Nano开发板
- 搭载SAME51 MCU(ARM Cortex-M4F)
- 集成USB-C接口与调试器
- 板载2个用户可编程LED指示灯
- 支持多线程实时操作系统(RT-Thread)

传感执行器扩展板
- 128x64 SSD1306 OLED显示屏
- 按键
任务分析与实现
本系统实现了基于RT-Thread实时操作系统的嵌入式游戏平台,主要功能包括:
三通道数据交互:
- 游戏输入采集
- 方向按键扫描频率:10Hz
- 支持四向移动输入
- OLED显示控制
- 显示刷新率:15Hz
- 图形化界面渲染
- RTOS任务调度
- 多线程架构保障响应实时性
- 系统资源动态管理
方案框图:
RT-Thread 的移植过程
本项目基于 Microchip SAME51J20A Curiosity Nano 开发板完成了 RT-Thread 操作系统的成功移植,并在此基础上实现了对 OLED 屏幕的控制与简易游戏机功能。以下详细描述了 RT-Thread 移植的关键流程和核心要点。
一、移植前的准备
1. 硬件环境
- 主控芯片:Microchip SAME51J20A(ARM Cortex-M4F 内核)
- 开发板:SAME51J20A Curiosity Nano
- 外设资源:
- I2C 接口用于驱动 SSD1306 OLED 显示屏
- GPIO 控制方向按键输入
- USART 串口调试输出
2. 软件环境
- RT-Thread 版本:RT-Thread Master 分支(实时更新版)
- 编译工具链:GCC ARM Embedded (arm-none-eabi-gcc)
- 构建工具:env 命令行工具 +
RT-Thread Studio - 底层支持库:Atmel START 提供 HAL 支持
二、移植的核心步骤
1. BSP(Board Support Package)创建
BSP 是 RT-Thread 针对特定硬件平台的支持包,主要包括启动代码、CPU 初始化、中断向量表、时钟配置以及设备驱动适配。
a. 启动文件配置 (startup_same51.c)
- 定义中断向量表(包括异常处理和外设中断)
- 设置堆栈指针、初始化 .data 和
.bss段 - 调用
rtthread_startup()进入 RT-Thread 内核
void Reset_Handler(void)
{
uint32_t *pSrc, *pDest;
/* Initialize the relocate segment */
pSrc = &_etext;
pDest = &_srelocate;
if (pSrc != pDest) {
for (; pDest < &_erelocate;) {
*pDest++ = *pSrc++;
}
}
/* Clear the zero segment */
for (pDest = &_szero; pDest < &_ezero;) {
*pDest++ = 0;
}
/* Set the vector table base address */
pSrc = (uint32_t *)&_sfixed;
SCB->VTOR = ((uint32_t)pSrc & SCB_VTOR_TBLOFF_Msk);
#if __FPU_USED
/* Enable FPU */
SCB->CPACR |= (0xFu << 20);
__DSB();
__ISB();
#endif
/* Initialize the C library */
__libc_init_array();
/* Branch to rtthread_startup function */
rtthread_startup();
/* Infinite loop */
while (1)
;
}
b. 内核入口函数 (rtthread_startup)
- 初始化内核对象(线程、信号量、定时器等)
- 创建空闲线程
- 启动调度器并进入 main 函数
int rtthread_startup(void)
{
rt_hw_board_init();
rt_system_kernel_init();
rt_application_init();
rt_thread_idle_init();
rt_schedule();
return 0;
}
2. 板级初始化 (board.c)
完成 CPU、内存、时钟、串口等基础资源配置:
void SystemInit(void) {
// Keep the default device state after reset
SystemCoreClock = __SYSTEM_CLOCK;
return;
}
void rt_hw_board_init(void)
{
/* Initializes MCU, drivers and middleware */
atmel_start_init();
/* enable USART stdout module */
hw_board_init_usart();
/* UART driver initialization is open by default */
#ifdef RT_USING_SERIAL
rt_hw_uart_init();
#endif
/* init systick */
SysTick_Config(CONF_CPU_FREQUENCY / RT_TICK_PER_SECOND);
/* set pend exception priority */
NVIC_SetPriority(PendSV_IRQn, (1 << __NVIC_PRIO_BITS) - 1);
#ifdef RT_USING_HEAP
#if defined(__ARMCC_VERSION)
rt_system_heap_init((void*)&Image$$RW_IRAM1$$ZI$$Limit, (void*)HEAP_END);
#elif __ICCARM__
rt_system_heap_init((void*)HEAP_BEGIN, (void*)HEAP_END);
#else
/* init memory system */
rt_system_heap_init((void*)&__bss_end, (void*)HEAP_END);
#endif
#endif
/* Set the shell console output device */
#if defined(RT_USING_CONSOLE) && defined(RT_USING_DEVICE)
rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
}
3. 设备驱动适配
a. 串口驱动 (serial.c)
- 使用 USART 异步接口实现标准输入输出
- 注册中断回调以支持接收数据通知机制
static int serial_putc(struct rt_serial_device *serial, char c)
{
struct usart_async_descriptor* desc = ...;
while (!usart_async_is_tx_empty(desc));
_usart_async_write_byte(&TARGET_IO.device, (uint8_t)c);
return 1;
}
b. I2C 总线驱动 (sam_i2c.c)
- 封装
struct rt_i2c_bus_device_ops操作集 - 实现
master_xfer函数用于主模式下的读写操作 - 注册 I2C 总线设备并初始化硬件参数
const struct rt_i2c_bus_device_ops sam_i2c_ops = {
.master_xfer = sam_i2c_master_xfer,
.slave_xfer = sam_i2c_slave_xfer,
.i2c_bus_control = sam_i2c_bus_control,
};
int rt_hw_i2c_init(void)
{
sam_i2c0.parent.ops = &sam_i2c_ops;
rt_i2c_bus_device_register(&sam_i2c0.parent, "i2c0");
i2c_m_sync_enable(sam_i2c0.i2c_desc);
return 0;
}
4. 外设驱动注册与自动初始化
使用 RT-Thread 提供的组件自动初始化机制,确保各模块按顺序初始化:
#ifdef RT_USING_COMPONENTS_INIT
INIT_BOARD_EXPORT(rt_hw_i2c_init); // 自动调用注册函数
#endif
代码详解
整体软件流程图:
一、硬件初始化与传感器配置
系统上电后首先完成外设初始化序列,关键流程如下:
- 配置GPIO引脚为输入/输出模式,确保按键与LED正常工作
- 初始化I2C接口,设置标准速率(100kHz),用于驱动OLED显示屏
- 启动RTOS内核并创建基础任务
void hardware_init(void)
{
/* 初始化LED GPIO */
gpio_set_pin_direction(LED0_PIN, GPIO_DIRECTION_OUT);
gpio_set_pin_level(LED0_PIN, true); // 初始点亮LED表示系统运行
/* 初始化方向按键 */
gpio_set_pin_direction(JOY_UP_PIN, GPIO_DIRECTION_IN);
gpio_set_pin_pull_mode(JOY_UP_PIN, GPIO_PULL_UP);
/* 初始化I2C接口 */
i2c_m_sync_enable(&I2C_0);
i2c_m_sync_set_baudrate(&I2C_0, 0, 100000UL); // 设置I2C速率为100kHz
/* 初始化OLED显示屏 */
oled_init(&I2C_0);
}
二、游戏任务调度
#define THREAD_PRIORITY 25
#define THREAD_STACK_SIZE 1024
#define THREAD_TIMESLICE 5
static rt_thread_t tid1 = RT_NULL;
static void u8g2_game_space_trash_entry(void *parameter)
{
u8g2.begin();
u8g2.setFont(u8g2_font_6x10_tr);
u8g2.setFontDirection(0);
u8g2.setFontRefHeightAll();
st_Setup(u8g2.getU8g2());
for(;;)
{
st_Step(y, /* is_auto_fire */ 1, /* is_fire */ rt_pin_read(pin_fire));
u8g2.firstPage();
do
{
st_Draw(0);
} while( u8g2.nextPage() );
if ( rt_pin_read(pin_down) ) {
y++;
}
if ( rt_pin_read(pin_up) ) {
y--;
}
}
}
static void u8g2_game_space_trash(int argc,char *argv[])
{
tid1 = rt_thread_create("tu8g22",
u8g2_game_space_trash_entry, RT_NULL,
THREAD_STACK_SIZE,
THREAD_PRIORITY, THREAD_TIMESLICE);
/* 如果获得线程控制块,启动这个线程 */
if (tid1 != RT_NULL)
rt_thread_startup(tid1);
}
MSH_CMD_EXPORT(u8g2_game_space_trash, u8g2 game space trash sample);
效果展示

遇到的难题与解决办法
问题:新平台支持RT-Thread,遇到系统启动异常的
解法
整个移植过程中,需重点关注:
- 中断向量表与异常处理机制
- 系统时钟、滴答定时器的准确配置
- 核心驱动(如串口、I2C)的适配过程中,注意外设时钟开启与配置。
活动感想
通过本项目实践,深入掌握了RT-Thread操作系统在嵌入式平台上的移植方法、,深入掌握了 RT-Thread 在 Cortex-M4 架构上的启动流程、中断管理机制及设备驱动编写规范。Microchip SAME51J20A 开发板良好的硬件兼容性与 Atmel START 工具链的强大支持极大提升了开发效率。整个移植过程中,需重点关注:
- 中断向量表与异常处理机制
- 系统滴答定时器的准确配置
- 核心驱动(如串口、I2C)的适配与优化
I2C总线通信机制以及图形界面渲染技巧。SAME51J20A开发板出色的性能表现和Microchip官方完善的SDK文档极大提升了开发效率。整个项目过程中,体会到嵌入式系统需要硬件、固件、应用层的紧密配合,每一个细节的优化都能显著提升整体体验。
感谢硬禾学堂和得捷电子联合举办的Funpack活动,祝硬禾的活动越办越好!