本帖最后由 废废 于 2023-12-28 21:25 编辑

1.前言
       感谢本次社区与极海半导体的支持,本次基于APM32F035开发板上移植RT-Thread Nano操作系统以及finsh组件,完成后新建线程进程测试,虽然是一块电机控制板,但完全不影响移植操作系统,同时引出串口,方便了finsh组件的移植。先进行操作系统的测试,然后后续计划的是手搓FOC,时间会漫长一点。
2.芯片简介     
针对电机驱动市场,即将推出高性能、高性价比电机专用APM32F035系列 MCU,该系列型号基于Arm® Cortex®-M0+内核,主频可达72MHz,内置 Vector Computer(MDU+CORDIC)多种专用数学运算加速器,集成高速 ADC、运放、比较器、及 CAN 控制器等外设资源,搭配电机控制通用开发平台,有效提升电机控制性能,降低产品运行成本。
235446um83ooku8nem3ox3
3.RT-Thread简介   
  RT-Thread Nano 是一个极简版的硬实时内核,它是由 C 语言开发,采用面向对象的编程思维,具有良好的代码风格,是一款可裁剪的、抢占式实时多任务的 RTOS。其内存资源占用极小,功能包括任务处理、软件定时器、信号量、邮箱和实时调度等相对完整的实时操作系统特性。
在资源足够的情况下可移植finsh组件,如下为RT-Thread软件框图:
235446pyduu6k3u29tud8m
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内核安装包,双击安装就可以:
235446c9tfft99rv80aft9
现在打开一个官方例程,这里使用的systick
235447i7igqidagqg79mng
在首届面点击RunTime Environment,进入选择RTOS,选址RT-Thread,勾选kernel
235447ojyjydt59nbyhj9r
接下来编译一下,根据提示去修改,编译会出现如下错误,这里是需要添加操作系统的时钟配置。
235447o61qvgsqcbswb9bs
添加操作系统心跳配置
235448kiiigtdwgllxddcx
接下来在board.c文件中添加滴答定时器中断处理函数。
235448grkori6drourui6r
再次编译一下,发现void SysTick_Handler()重定义,在apm32f035_init.c文件中重定义,打开apm32f035_init.c文件,将void SysTick_Handler(void)屏蔽。
235448u12kew2hw14166i5
编译代码,出现空间不够的情况。
235448qazrrjmt9dw33sad
调整rtconfig.h文件,关闭动态内存
235448my9gat7l2xxfhfey
在main.c文件中,包含#include <rtthread.h>头文件,将延时函数调整为操作系统的延时函数。
235448jy8l8ho6brdl68hz
下载代码,灯已经开始闪烁,操作系统已经跑起来了。
4.2 Finsh控制台添加
同样在添加kernel源码的地方,添加shell,如下所示:
235449rl4ue2us3uu33u2s
先编译一下,会报错,根据报错步骤去实现需要添加的函数或者功能。如下所示,首先需要使能在配置文件中包含finsh_config.h
235449cnucjuwwrluzmjfc
接下来继续编译,如下所示,需要添加串口接收函数。接收一个字符
235449g8rvn57vvrrr4rtv
添加字符获取函数,添加相关头文件
235450a7573doa588y7o79
接下来,接收设置完了,添加输出,没有是不完美的。在rtconfig.h中使能宏定义
235450o5dspxs866fvmbhv
编译一下,根据提示进行更改。添加串口初始化,将主函数中串口初始化挪过来就行了。
235450x9pw4nmm07wm6mww
接下来添加输出字符函数,同样的需要在board.c文件中添加相应的头文件。
235450cgo73ztr71apkyq7
4.3 创建线程
把上面都移植完成后,创建两个线程进行演示,创建一个LED的和一个打印线程的,如下所示。
  1. #include "main.h"
  2. #include <rtthread.h>
  3. #define DEBUG_USART         USART2

  4. static struct rt_thread led_thread;
  5. static rt_uint8_t rt_led_thread_stack[1024];
  6. static struct rt_thread print_thread;
  7. static rt_uint8_t rt_print_thread_stack[1024];

  8. static void led_thread_entry(void* parameter)
  9. {
  10.     while (1)
  11.     {
  12.         APM_MINI_LEDToggle(LED3);
  13.         rt_thread_delay(200);   /* ??500?tick */
  14.     }
  15. }

  16. static void print_thread_entry(void* parameter)
  17. {
  18.     while (1)
  19.     {
  20.         rt_kprintf("Hello APM32F035\r\n");
  21.         rt_thread_delay(2000);  
  22. <span style="white-space: normal;"><span style="white-space:pre">                </span>}</span>
  23. }

  24. /* USART Write Data */
  25. void USART_Write(USART_T* usart, uint8_t* dat);
  26. int main(void)
  27. {
  28.     APM_MINI_LEDInit(LED3);
  29. <span style="white-space: normal;"><span style="white-space:pre">        </span>  rt_thread_init(&led_thread,                 /* 线程控制块 */</span>
  30.                 "led1",                       /* 线程名字 */
  31.                 led_thread_entry,            /* 线程入口函数 */
  32.                 RT_NULL,                      /* 线程入口函数参数 */
  33.                 &rt_led_thread_stack[0],     /* 线程栈起始地址 */
  34.                 sizeof(rt_led_thread_stack), /* 线程栈大小 */
  35.                 10,                            /* 线程的优先级 */
  36.                 20);                          /* 线程时间片 */
  37. <span style="white-space: pre; white-space: normal;">                                                                </span>
  38. <span style="white-space: normal;"><span style="white-space:pre">        </span> rt_thread_init(&print_thread,                 /* 线程控制块 */</span>
  39.                 "rgb",                       /* 线程名字 */
  40.                 print_thread_entry,            /* 线程入口函数 */
  41.                 RT_NULL,                      /* 线程入口函数参数 */
  42.                 &rt_print_thread_stack[0],     /* 线程栈起始地址 */
  43.                 sizeof(rt_print_thread_stack), /* 线程栈大小 */
  44.                 11,                            /* 线程的优先级 */
  45.                 20);                          /* 线程时间片 */<span style="white-space:pre">                                                </span>
  46.     rt_thread_startup(&led_thread);             /* 启动线程,开启调度 */
  47. <span style="white-space: normal;"><span style="white-space:pre">                </span>rt_thread_startup(&print_thread);             /* 启动线程,开启调度 */</span>
  48. }


4.4 验证
给开发板接上串口,打开终端,复位,查看开发板输出:
235450jezw99lv21lelva7



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