1.前言
感谢本次社区与极海半导体的支持,本次基于APM32F035开发板上移植RT-Thread Nano操作系统以及finsh组件,完成后新建线程进程测试,虽然是一块电机控制板,但完全不影响移植操作系统,同时引出串口,方便了finsh组件的移植。先进行操作系统的测试,然后后续计划的是手搓FOC,时间会漫长一点。
2.芯片简介
针对电机驱动市场,即将推出高性能、高性价比电机专用APM32F035系列 MCU,该系列型号基于Arm® Cortex®-M0+内核,主频可达72MHz,内置 Vector Computer(MDU+CORDIC)多种专用数学运算加速器,集成高速 ADC、运放、比较器、及 CAN 控制器等外设资源,搭配电机控制通用开发平台,有效提升电机控制性能,降低产品运行成本。

3.RT-Thread简介
RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。
在资源足够的情况下可移植finsh组件,如下为RT-Thread软件框图:

RT-Thread Nano 支持可裁剪,通过rtconfig.h进行,在本次使用过程中也会用到,需要裁剪一些功能。
同时最关心的就是RT-Thread Nano的使用资源情况了,对 RAM 与 ROM 的开销非常小,在支持 semaphore 和 mailbox 特性,并运行两个线程 (main 线程 + idle 线程) 情况下,ROM 和 RAM 依然保持着极小的尺寸,RAM 占用约 1K 左右,ROM 占用 4K 左右,但实际可能不止,接下来就开始RT-Thread的移植。
4.移植步骤
4.1 Kernel添加
下载RT-Thread Nano内核安装包,双击安装就可以:

现在打开一个官方例程,这里使用的systick

在首届面点击RunTime Environment,进入选择RTOS,选址RT-Thread,勾选kernel

接下来编译一下,根据提示去修改,编译会出现如下错误,这里是需要添加操作系统的时钟配置。

添加操作系统心跳配置

接下来在board.c文件中添加滴答定时器中断处理函数。

再次编译一下,发现void SysTick_Handler()重定义,在apm32f035_init.c文件中重定义,打开apm32f035_init.c文件,将void SysTick_Handler(void)屏蔽。

编译代码,出现空间不够的情况。

调整rtconfig.h文件,关闭动态内存

在main.c文件中,包含#include <rtthread.h>头文件,将延时函数调整为操作系统的延时函数。

下载代码,灯已经开始闪烁,操作系统已经跑起来了。
4.2 Finsh控制台添加
同样在添加kernel源码的地方,添加shell,如下所示:

先编译一下,会报错,根据报错步骤去实现需要添加的函数或者功能。如下所示,首先需要使能在配置文件中包含finsh_config.h

接下来继续编译,如下所示,需要添加串口接收函数。接收一个字符

添加字符获取函数,添加相关头文件

接下来,接收设置完了,添加输出,没有是不完美的。在rtconfig.h中使能宏定义

编译一下,根据提示进行更改。添加串口初始化,将主函数中串口初始化挪过来就行了。

接下来添加输出字符函数,同样的需要在board.c文件中添加相应的头文件。

4.3 创建线程
把上面都移植完成后,创建两个线程进行演示,创建一个LED的和一个打印线程的,如下所示。
#include "main.h"
#include <rtthread.h>
#define DEBUG_USART USART2
static struct rt_thread led_thread;
static rt_uint8_t rt_led_thread_stack[1024];
static struct rt_thread print_thread;
static rt_uint8_t rt_print_thread_stack[1024];
static void led_thread_entry(void* parameter)
{
while (1)
{
APM_MINI_LEDToggle(LED3);
rt_thread_delay(200); /* ??500?tick */
}
}
static void print_thread_entry(void* parameter)
{
while (1)
{
rt_kprintf("Hello APM32F035\r\n");
rt_thread_delay(2000);
<span style="white-space: normal;"><span style="white-space:pre"> </span>}</span>
}
/* USART Write Data */
void USART_Write(USART_T* usart, uint8_t* dat);
int main(void)
{
APM_MINI_LEDInit(LED3);
<span style="white-space: normal;"><span style="white-space:pre"> </span> rt_thread_init(&led_thread, /* 线程控制块 */</span>
"led1", /* 线程名字 */
led_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
&rt_led_thread_stack[0], /* 线程栈起始地址 */
sizeof(rt_led_thread_stack), /* 线程栈大小 */
10, /* 线程的优先级 */
20); /* 线程时间片 */
<span style="white-space: pre; white-space: normal;"> </span>
<span style="white-space: normal;"><span style="white-space:pre"> </span> rt_thread_init(&print_thread, /* 线程控制块 */</span>
"rgb", /* 线程名字 */
print_thread_entry, /* 线程入口函数 */
RT_NULL, /* 线程入口函数参数 */
&rt_print_thread_stack[0], /* 线程栈起始地址 */
sizeof(rt_print_thread_stack), /* 线程栈大小 */
11, /* 线程的优先级 */
20); /* 线程时间片 */<span style="white-space:pre"> </span>
rt_thread_startup(&led_thread); /* 启动线程,开启调度 */
<span style="white-space: normal;"><span style="white-space:pre"> </span>rt_thread_startup(&print_thread); /* 启动线程,开启调度 */</span>
}
复制代码4.4 验证
给开发板接上串口,打开终端,复位,查看开发板输出:

5.总结
本次完成RT-Thread操作系统的移植,实现了线程的创建,同时操作操作系统正常运行,添加了finsh组件。总体下来的感觉还好,就是电机控制板的原理图官网居然没有,找技术要的。感觉这种可以放在官网上,避免来回折腾。个人建议:
- 板子可以做成地板加核心板的方式,核心板引出GPIO。
- 引出开发板的CAN接口,把优势给隐藏了。
- 添加RS485总线接口,芯片支持2路uart,是够用的。