#技术资源# #申请原创# 本文的移植是在官方蓝牙例程的MCU部分例程上进行了移植,现在对移植过程和注意事项在此说明一下。
移植的环境是MDK,并已提前安装了rt-threadnano的支持包
在 Manage Rum-Time Environment 里 "Software Component" 栏找到 RTOS,Variant 栏选择 RT-Thread,然后勾选 kernel,点击 "OK" 就添加 RT-Thread 内核到工程了。
现在可以在 Project 看到 RT-Thread RTOS 已经添加进来了,展开 RTOS,可以看到添加到工程的文件:
文件图标上带钥匙的是只读文件,属于系统内核文件,我们不需要修改,只有board.c和rtconfig.h这两个文件有我们需要修改和配置的地方
中断与异常处理
RT-Thread 会接管异常处理函数 HardFault_Handler() 和悬挂处理函数 PendSV_Handler(),这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。这两个函数在at32wb415_int.c文件内
系统时钟配置
需要在 board.c 中实现 系统时钟配置(为 MCU、外设提供工作时钟)与 os tick 的配置(为操作系统提供心跳 / 节拍)。需要将原来在main.c内的system_clock_config();函数去掉
如下代码所示,用户需要在 board.c 文件中系统初始化和 OS Tick 的配置,用户需在 timer 定时器中断服务函数调用 rt_os_tick_callback function,cortex-m 架构使用 SysTick_Handler()
内存堆初始化
系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认开启内存堆功能,需要关闭此宏,这样可以保持一个较小的体积。
至此,和内核相关的设置就配置完成,接下来我们要处理一些初始化函数,因为在rt-threadnano中的main函数是个线程,原来一些底层初始化再放在这个函数内就不太合适了,需要将初始化函数使用rt-thread的自动初始化功能放到板级初始化过程中
还需要在main.c的while (1)内添加一个系统延时函数,好让此线程挂起,让系统能够实现调度,这点非常重要!!!
另外,at32_board_init内的delay_init();函数要关闭,因为里面用到SysTick,会干扰系统,这里一定要注意!!!at32wb415_board.c里的延时函数也都不要用,也都是由SysTick实现的,和系统有冲突。
在 RT-Thread Nano 上添加控制台与 FinSH
本篇文档分为两部分:
第一部分是添加 UART 控制台(实现打印):用来向控制台对接的终端输出打印信息;该部分只需要实现两个函数,串口初始化和系统输出函数,即可完成 UART 控制台打印功能。
第二部分是移植 FinSH 组件(实现命令输入),用以在控制台输入命令调试系统;该部分的实现基于第一部分,只需要添加 FinSH 组件源码并再对接一个系统输入函数即可实现。
下面将对这两部分进行说明。
在 Nano 上添加 UART 控制台(实现打印)
在 RT-Thread Nano 上添加 UART 控制台打印功能后,就可以在代码中使用 RT-Thread 提供的打印函数 rt_kprintf() 进行信息打印,从而获取自定义的打印信息,方便定位代码 bug 或者获取系统当前运行状态等。实现控制台打印(需要确认 rtconfig.h 中已使能 RT_USING_CONSOLE 宏定义),需要完成基本的硬件初始化,以及对接一个系统输出字符的函数,本小节将详细说明。
实现串口初始化
注:此部分为 3.1.5 版本中 #error TODO 2 的部分:#error "TODO 2: Enable the hardware uart and config baudrate."
使用串口对接控制台的打印,首先需要初始化串口,如引脚、波特率等。 初始化的串口函数 uart_init() 有以下两种调用方式,二选一:
方法一:默认使用宏 INIT_BOARD_EXPORT() 进行自动初始化,不需要显式调用,如下所示。
方法二:可以使用显式调用:uart_init() 需要在 board.c 中的 rt_hw_board_init() 函数中调用。
串口初始化时在板级自动初始化中实现了,使用的是串口1中断+DMA方式,具体配置可以看一下我之前的帖子。
实现 rt_hw_console_output
注:此部分为 3.1.5 版本中 #error TODO 3 的部分:#error "TODO 3: Output the string 'str' through the uart."
实现 finsh 组件输出一个字符,即在该函数中实现 uart 输出字符:
/* 实现 2:输出一个字符,系统函数,函数名不可更改 */
void rt_hw_console_output(const char *str);
实现效果如下
在 Nano 上添加 FinSH 组件(实现命令输入)
RT-Thread FinSH 是 RT-Thread 的命令行组件(shell),提供一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息。
在 RT-Thread Nano 上添加 FinSH 组件,实现 FinSH 功能的步骤主要如下:
添加 FinSH 源码到工程。
实现函数对接。
添加 FinSH 源码到工程
点击 Manage Run-Environment:
勾选 shell,这将自动把 FinSH 组件的源码到工程:
然后在 rtconfig.h 中打开 finsh 相关选项,如下图:
实现 rt_hw_console_getchar
注:此部分为 3.1.5 版本中 #error TODO 4 的部分:#error "TODO 4: Read a char from the uart and assign it to 'ch'."
要实现 FinSH 组件功能:既可以打印也能输入命令进行调试,控制台已经实现了打印功能,现在还需要在 board.c 中对接控制台输入函数,实现字符输入:
/* 实现 3:finsh 获取一个字符,系统函数,函数名不可更改 */
char rt_hw_console_getchar(void);
rt_hw_console_getchar():控制台获取一个字符,即在该函数中实现 uart 获取字符,可以使用查询方式获取(注意不要死等,在未获取到字符时,需要让出 CPU),推荐使用中断方式获取(我这里用的是中断+DMA方式)。
这里我使用了ringbuffer和信号量来处理中断+DMA接收的数据,数据接收完成后释放信号量通知rt_hw_console_getchar()读取收到的数据
DMA收到的数据批量写入ringbuffer,中断+DMA的实现查看我之前的帖子。
到这里所以的移植就都结束了,实现了内核移植,并使用串口中断+DMA的方式实现了shell收发。
|