以下内容为本人的烂笔头,如需要转载,请全文无改动地复制粘贴,原文链接 「ENG八戒」https://mp.weixin.qq.com/s/flGxC-5658gWQM-bclRT1g
一、前言
在上一篇文章中,我们完成了 RA-Eco-RA2L1 开发板的软件开发环境搭建、工程创建以及程序烧录验证,成功打通了从工程创建到程序运行的完整开发链路。

对于嵌入式开发而言,串口几乎是最重要的调试手段之一。无论是系统初始化、状态输出还是问题定位,都离不开串口日志。
本篇将基于上一篇创建的工程,体验瑞萨 FSP(Flexible Software Package)的外设开发流程,实现 UART 串口打印功能,并构建类似 printf() 的日志输出接口,为后续外设开发和调试打下基础。
二、FSP 串口驱动简介
RA 系列 MCU 的串口驱动由 FSP 提供统一封装。
在 FSP 中,串口驱动主要包含:
- 控制块(Control Block)
- 配置结构体(Configuration)
- 回调函数(Callback)
- API 接口
工程生成后,并不会直接生成对应外设或者硬件的对象,需要在配置界面按需添加外设,才可以看到类似如下的对象:
bash
g_uart0_ctrl
g_uart0_cfg
其中:
bash
R_SCI_UART_Open()
用于初始化串口。
bash
R_SCI_UART_Write()
用于发送数据。
bash
R_SCI_UART_Read()
用于接收数据。
相比直接操作寄存器,FSP 已经完成了底层驱动封装,开发者只需要关注应用逻辑即可。
三、FSP 配置 UART
在 e² studio 中打开:
bash
configuration.xml
进入 FSP Configuration 界面。

如上图,添加一个 UART 驱动实例:
bash
Stacks
└── New Stack
└── Connectiviy
└── UART(r_sci_uart)
添加完成后,点击 "Stacks" 标签页的外设,进入底部属性栏:

属性配置如下:
| 参数 | 配置值 |
|---|---|
| Name | g_uart0 |
| Channel | 0 |
| Baudrate | 115200 |
| Data Bits | 8 |
| Stop Bits | 1 |
| Parity | None |
| Callback | user_uart_callback |
| 其它 | 默认 |
对应 IO 口还需要跳转到 FSP Configuration 界面窗口 Pins 标签页配置,可直接点击上图中属性栏 "Pins" -> "RXD0"/"TXD0" 右则的跳转箭头进行跳转(在双击 "RXD0"/"TXD0" 后出现跳转箭头):

找到 "Pin Configuration" -> "Pin Function" -> "Operation Mode",选择 "Asynchronous UART"。
至此,UART 配置完成。
FSP 会自动生成对应代码:
bash
g_uart0_ctrl
g_uart0_cfg
开发者无需手动编写初始化代码。
四、实现 UART 回调函数
如上配置,FSP 的 UART 发送采用异步机制。
因此需要通过回调函数 user_uart_callback 获取发送完成事件。
添加代码如下:
bash
static volatile bool uart_send_complete_flag = false;
void user_uart_callback(uart_callback_args_t * p_args)
{
if (UART_EVENT_TX_COMPLETE == p_args->event)
{
uart_send_complete_flag = true;
}
}
当底层发送完成后,FSP 会自动调用该函数。
随后通知应用层当前发送已经结束。
这种分层的设计方式避免了应用层直接访问底层硬件状态,提高了代码的可移植性。
五、封装串口发送接口
为了简化后续开发,首先封装一个统一发送函数。
bash
static void uart_send(const uint8_t * data,
uint32_t len)
{
if ((NULL == data) || (0 == len))
{
return;
}
err = R_SCI_UART_Write(&g_uart0_ctrl,
(uint8_t *)data,
len);
if (FSP_SUCCESS != err)
{
__BKPT(0);
}
while (!uart_send_complete_flag)
{
}
uart_send_complete_flag = false;
}
这里采用了最简单的同步等待方式:
- 发起发送
- 等待发送完成回调
- 返回调用者
对于调试日志这种场景来说,这种方式简单且稳定。
六、实现 UART_PRINT
有了发送接口之后,就可以进一步封装类似 printf() 的日志输出功能。
实现代码如下:
bash
static void UART_PRINT(const char * fmt, ...)
{
char buffer[256];
va_list args;
va_start(args, fmt);
vsnprintf(buffer,
sizeof(buffer),
fmt,
args);
va_end(args);
uart_send((uint8_t *)buffer,
strlen(buffer));
}
这里利用:
bash
vsnprintf()
将格式化字符串写入缓存。
随后调用:
bash
uart_send()
将缓存数据输出到串口,完成发送。
这样后续调试时即可直接使用:
bash
UART_PRINT("value=%d\r\n", value);
输出串口日志。
开发体验与 PC 平台下的 printf() 非常接近。
七、应用程序实现
进入 hal_entry() 时,先对 UART 初始化。
bash
err = R_SCI_UART_Open(&g_uart0_ctrl,
&g_uart0_cfg);
if (FSP_SUCCESS != err)
{
__BKPT(0);
}
有调试器连接时,如果初始化失败,运行到这里自动断住。没有调试器连接,则可能触发 HardFault 或者 UsageFault。
初始化成功后输出启动信息:
bash
UART_PRINT("\r\n");
UART_PRINT("=====================================\r\n");
UART_PRINT("RA2L1 UART Demo\r\n");
UART_PRINT("e2studio + FSP 6.4 + LLVM\r\n");
UART_PRINT("=====================================\r\n");
随后周期性输出测试数据:
bash
int int_i = 55;
float float_i = 66.2f;
char str[] = "hello e2studio";
循环打印:
bash
while (1)
{
UART_PRINT("int_i = %d\r\n", int_i);
UART_PRINT("float_i = %.2f\r\n", float_i);
UART_PRINT("str = %s\r\n", str);
UART_PRINT("-------------------------------------\r\n");
int_i++;
R_BSP_SoftwareDelay(
1000,
BSP_DELAY_UNITS_MILLISECONDS);
}
这样既验证了:
- 整数格式化输出
- 浮点格式化输出
- 字符串格式化输出
也验证了 UART 发送功能工作正常。
点击工具栏的 "构建" 图标,或者菜单栏选择 "项目" -> "构建项目" 来执行工程构建。

编译成功。
八、运行效果验证
对照前面的 IO 口配置,通过 "USB 转 TTL 模块" 连接电脑 USB 和开发板。

连接完成,确保电脑端能成功识别串口设备。
打开电脑串口调试助手,配置如下:
| 参数 | 配置 |
|---|---|
| 波特率 | 115200 |
| 数据位 | 8 |
| 停止位 | 1 |
| 校验位 | None |
打开串口终端后,可以看到如下输出:

开发板上有红色的复位(RESET)按钮,点击可重启设备。
从输出结果可以看到:
- UART 初始化正常
- 格式化输出正常
- 浮点打印正常
- 周期发送稳定
整个串口打印功能已经成功运行。
九、开发体验分析
通过本次 UART 实践,可以初步体验到 FSP 的开发模式。
优点
- 图形化配置方便
- 驱动初始化简单
- API 接口统一
- 代码结构清晰
- 适合快速开发
可以优化的地方
当前实现采用:
bash
发送 -> 等待完成 -> 返回
属于阻塞式发送。
后续可以尝试:
- 环形缓冲区
- DMA 发送
- RTOS 消息队列
进一步提高日志输出效率。
对于当前评测阶段而言,已经完全满足调试需求。
十、总结
本篇基于 RA-Eco-RA2L1 开发板和 FSP 框架,实现了 UART 串口打印功能,并封装了类似 printf() 的日志输出接口。
通过实际开发体验可以发现,FSP 已经对底层驱动进行了较好的封装,开发者无需直接操作寄存器即可快速完成外设开发。相比传统 MCU 开发模式,开发效率有明显提升,同时避免了寄存器的错误操作。
至此,开发环境搭建、工程创建、程序下载以及串口日志功能均已验证完成。
后续评测将继续体验板载更多功能,进一步熟悉 RA2L1 的开发流程和外设能力。