1.背景说明
本文是参考`瑞萨RA6M3开发实践指南`文章教程,基于瑞萨HMI-Board BSP :1.1.1 版本 RT-Thread 5.0.1 版本操作步骤进行记录,整理成的文档。
1.1 本章内容
使用RT-Thread Studio创建开发板的程序,编写UART的程序,实现串口打印数据的功能,同时使用Finsh Shell控制开发板上的LED。
1.2 模块介绍
开发板上提供了两个串口连接,分别是在P109和P110的串口9,通过调试器的虚拟串口与上位机通讯。(UART9 为默认日志输出端口)
另一个串口位于P205和P206的串口4,TXD和RXD引脚引出到Ardinuo接口上,在开发板上也直接标出了。
1.3 开发软件
根据《实践指南说明》安装fsp3.5.0和RT-Thread Studio(2.2.6)。
2. 步骤说明
安装好开发环境后,首先对RT-Thread Studio的SDK Manager中安装包进行检查,确定相关的软件支持包已经安装。
2.1.新建工程
点击工具栏中的文件->新建->RT-Thread项目
选择目标开发板以及工程默认位置,这里一定要选择HMI_Board,对应的BSP版本为1.1.1。
点击完成后,就可以得到一个打印信息、支持Finsh以及一秒钟翻转LED的程序。
这个程序是一个完整的程序,点击编译后可以直接下载运行。在此基础上我们就可以根据自己的需要编写相应的驱动程序。
由RT-Thread Studio创建的软件工程本身就是一个演示了LED翻转和串口功能的例程,我们上来就可以得到可以运行的使用了串口输出信息的程序。需要注意的是,rtthread为了方便开发者调试,在系统中嵌入了Finsh这个简易的控制台程序,根据用户使能的模块提供了不同的控制指令。新创建的工程编译通过后,利用板载的daplink将固件烧写到开发板上。
其中list的功能很多,后面跟随不同的参数可以实现不同的功能。
如图所示,可以产看当前系统中的线程、定时器、信号量、互斥量、事件、邮箱、消息队列以及设备的实例个数。可以帮助开发者掌握当前系统的运行状态。另外reboot功能可以减少设备上下电的次数,方便远程调试。
Finsh的除了上述已经定义好的功能,还支持自定义函数,可以帮助开发者自定义一些测试函数,方便针对特定情境进行测试。
开发板默认使用uart9作为调试串口,在开发板上的Ardinuo接口上,引出了uart4。开发板默认是不开启uart4,为了能使用uart4,首先使用FSP工具配置相关的引脚。
点击工程中的RA Smart Configurator,可以启动代码配置工具对MCU的外设进行配置。
在Stack栏中的New Stack->Connnectivity->UART添加新的UART实例。
修改General栏中的通道和设备名称
在Pins引脚栏中设定使用的引脚和引脚的工作模式。
点击右上角 “Generate Project Content”,即可关闭FSP工具。
回到工程中点击RT-Thread Settings,对工程中要使用的硬件进行配置。
在配置界面的硬件一栏中勾选Enable UART4,
保存文件后,就可以在工程中添加uart4,并在工程调用相关的串口函数。
2.2. 编写测试程序
通过串口发送字符串,是嵌入式应用中的基本程序,检验串口是否正常工作。在hal_entry.c中添加以下代码:
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2021-10-10 Sherman first version
*/
#include <rtthread.h>
#include "hal_data.h"
#include <rtdevice.h>
#define LED_PIN BSP_IO_PORT_02_PIN_09 /* Onboard LED pins */
#define SAMPLE_UART_NAME "uart4" /* 串口设备名称 */
static rt_device_t serial; /* 串口设备句柄 */
char str[] = "hello RT-Thread!\r\n";
void hal_entry(void)
{
rt_kprintf("\nHello RT-Thread!\n");
/* 查找串口设备 */
serial = rt_device_find(SAMPLE_UART_NAME);
rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING); // 串口设备使用模式为 (发送阻塞 接收非阻塞) 模式
while (1)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
/* 发送字符串 */
rt_device_write(serial, 0, str, (sizeof(str) - 1));
}
}
硬件连接如图:
下面使用Finsh的自定义功能实现uart4的回环功能。具体的代码如下:
#include <rtthread.h>
#include "hal_data.h"
#include <rtdevice.h>
#define LED_PIN BSP_IO_PORT_02_PIN_09 /* Onboard LED pins */
void hal_entry(void)
{
while (1)
{
rt_pin_write(LED_PIN, PIN_HIGH);
rt_thread_mdelay(500);
rt_pin_write(LED_PIN, PIN_LOW);
rt_thread_mdelay(500);
}
}
#include <rtthread.h>
#include <rtdevice.h>
#define SAMPLE_UART_NAME "uart4" /* 串口设备名称 */
/* 串口接收消息结构 */
struct rx_msg
{
rt_device_t dev;
rt_size_t size;
};
/* 串口设备句柄 */
static rt_device_t serial;
/* 消息队列控制块 */
static struct rt_messagequeue rx_mq;
/* 接收数据回调函数 */
static rt_err_t uart_input(rt_device_t dev, rt_size_t size)
{
struct rx_msg msg;
rt_err_t result;
msg.dev = dev;
msg.size = size;
result = rt_mq_send(&rx_mq, &msg, sizeof(msg));
if (result == -RT_EFULL)
{
/* 消息队列满 */
rt_kprintf("message queue full!\n");
}
return result;
}
static void serial_thread_entry(void *parameter)
{
struct rx_msg msg;
rt_err_t result;
rt_uint32_t rx_length;
static char rx_buffer[1024 + 1];
while (1)
{
rt_memset(&msg, 0, sizeof(msg));
/* 从消息队列中读取消息 */
result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER);
rt_kprintf("recv result = %d \r\n",result);
if (result > 0)
{
/* 从串口读取数据 */
rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size);
rx_buffer[rx_length] = '\0';
/* 通过串口设备 serial 输出读取到的消息 */
rt_device_write(serial, 0, rx_buffer, rx_length);
/* 打印数据 */
// rt_kprintf("%s\n",rx_buffer);
}
}
}
static int uart_dma_sample(int argc, char *argv[])
{
rt_err_t ret = RT_EOK;
char uart_name[RT_NAME_MAX];
static char msg_pool[1024];
char str[] = "hello RT-Thread!\r\n";
if (argc == 2)
{
rt_strncpy(uart_name, argv[1], RT_NAME_MAX);
}
else
{
rt_strncpy(uart_name, SAMPLE_UART_NAME, RT_NAME_MAX);
}
/* 查找串口设备 */
serial = rt_device_find(uart_name);
if (!serial)
{
rt_kprintf("find %s failed!\n", uart_name);
return RT_ERROR;
}
/* 初始化消息队列 */
rt_mq_init(&rx_mq, "rx_mq",
msg_pool, /* 存放消息的缓冲区 */
sizeof(struct rx_msg), /* 一条消息的最大长度 */
sizeof(msg_pool), /* 存放消息的缓冲区大小 */
RT_IPC_FLAG_FIFO); /* 如果有多个线程等待,按照先来先得到的方法分配消息 */
/* 以 DMA 接收及轮询发送方式打开串口设备 */
rt_device_open(serial, RT_DEVICE_FLAG_RX_NON_BLOCKING | RT_DEVICE_FLAG_TX_BLOCKING);
/* 设置接收回调函数 */
rt_device_set_rx_indicate(serial, uart_input);
/* 发送字符串 */
rt_device_write(serial, 0, str, (sizeof(str) - 1));
/* 创建 serial 线程 */
rt_thread_t thread = rt_thread_create("serial", serial_thread_entry, RT_NULL, 1024, 25, 10);
/* 创建成功则启动线程 */
if (thread != RT_NULL)
{
rt_thread_startup(thread);
}
else
{
ret = RT_ERROR;
}
return ret;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(uart_dma_sample, uart device dma sample);
测试效果如图所示:
4.章节总结
使用RT-Thread和FSP进行开始还是很方便的,在FSP中修改相关引脚的功能,RT-Thread中使用配置工具对BSP进行使能。同时RT-Thread官网上还有详细的文档和示例代码,帮助新手快速搭建工程和入门嵌入式开发是一个不错的选择。