Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
nano移植
国产MCU移植
在 HK32F030 上移植 RT-Thread Nano
发布于 2021-06-03 18:17:48 浏览:2500
订阅该版
[tocm] # 在 HK32F030 上移植 RT-Thread Nano 这是一个航顺 HK32F030 的 RT-Thread Nano 移植示例,记录了在 Keil 裸机工程的基础上进行 RT-Thread Nano 移植的全过程。在按[文档中心](https://docs.rt-thread.org/#/rt-thread-version/rt-thread-nano/nano-port-keil/an0039-nano-port-keil)的指导进行移植的过程中基本没有遇到问题,只是由于 HK32F030 的RAM 较小,无法启用 FinSH。移植工程已经分享在gitee [RT-Thread-Nano-HK32F030](https://gitee.com/CraztTnspt/rt-thread-nano-hk32-f030)。 **硬件信息:** MCU: 航顺 HK32F030MF4P6 , RAM: 2KB, ROM:16KB 开发板:[hk32f030 - 立创EDA](https://lceda.cn/whj4674672/hk32f030) 由 @whj467467222 设计 ## 参考文档 [RT-Thread Nano 简介与下载](https://docs.rt-thread.org/#/rt-thread-version/rt-thread-nano/an0038-nano-introduction) ## 0.准备移植 在移植 RT-Thread Nano 之前,需要准备一个能正常运行的裸机工程。航顺的库文件包 `HK32F030Mxx_Library_V1.1.4.7z` 中提供了 HK32F030 的标准库、启动文件等,还有一个裸机工程模板,整理后得到这里移植使用的裸机工程。工程目录如下: ![image-20210602205409137.png](https://oss-club.rt-thread.org/uploads/20210603/02f497e31f6ad7f9038a6fa4ffd94c90.png) | Group | 功能 | | ----------- | ---------------------------------------- | | Startup | HK32 启动和初始化文件 | | Application | 应用文件 | | Libraries | 外设库文件 | | Drivers | 驱动文件(待实现),中断以及部分配置文件 | 编译后烧录,看到LED闪烁,裸机程序正常运行。实测可以使用Jlink 或 CMSIS-DAP 烧录调试,而使用 ST-Link 无法识别到 HK32F030。 ![image-20210602210107535.png](https://oss-club.rt-thread.org/uploads/20210603/ab4e1a947974c4e09d6b23ec7b2c45b7.png.webp) 之后就可以开始 RT-Thread Nano 的移植了。 ## 1.[Nano Pack 安装](https://docs.rt-thread.org/#/rt-thread-version/rt-thread-nano/nano-port-keil/an0039-nano-port-keil?id=nano-pack-安装) Nano Pack 可以在 Keil MDK IDE 内进行安装,也可以手动安装。这里选择手动安装Pack,从官网下载安装文件:[RT-Thread Nano 离线安装包](https://download.rt-thread.org/download/mdk/RealThread.RT-Thread.3.1.3.pack),下载结束后双击文件进行安装。 然后将 RT-Thread Nano 添加到工程中。如下图,点击 Manage Run-Time Environment。 ![image-20210602211016534.png](https://oss-club.rt-thread.org/uploads/20210603/3e3ea114283bd8023fd7e6f33bf6e0d1.png) 在 Manage Rum-Time Environment 内打开 RTOS 栏,勾选 kernal,点击 OK 后就将 RT-Thread 内核加入到工程中了。 ![image-20210602211104232.png](https://oss-club.rt-thread.org/uploads/20210603/4a12fb012f3e83b1348ea96c4032e310.png) 现在能在 Keil 的 Project 栏看到 RTOS,展开后可以看到 RT-Thread Nano 的文件已经加入了工程。 ![image-20210602211316338.png](https://oss-club.rt-thread.org/uploads/20210603/a7fece57a28d13f5f14360c24a98cf01.png) ## 2.适配 RT-Thread Nano ### 中断与异常处理 RT-Thread 会接管异常处理函数 `HardFault_Handler()` 和悬挂处理函数 `PendSV_Handler()`,这两个函数已由 RT-Thread 实现,所以需要删除工程里中断服务例程文件 `Drivers/hk32f030m_it.c` 中的这两个函数,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。 ### 系统时钟配置 现在需要在 `RTOS/board.c` 中实现 `系统时钟配置`(为 MCU、外设提供工作时钟)与 `os tick 的配置 `(为操作系统提供心跳 / 节拍)。 ``` void rt_hw_board_init() { /* System Clock Update */ SystemCoreClockUpdate(); /* System Tick Configuration */ _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND); /* Call components board initial (use INIT_BOARD_EXPORT()) */ #ifdef RT_USING_COMPONENTS_INIT rt_components_board_init(); #endif #if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP) rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get()); #endif } ``` 上面的代码中,`SystemCoreClockUpdate()` 对系统时钟进行更新,`_SysTick_Config()` 配置了 OS Tick。此处 OS Tick 使用滴答定时器 systick 实现,需要在 board.c 中实现 `SysTick_Handler()` 中断服务例程,调用 RT-Thread 提供的 `rt_tick_increase()` ,如下: ``` void SysTick_Handler(void) { /* enter interrupt */ rt_interrupt_enter(); rt_tick_increase(); /* leave interrupt */ rt_interrupt_leave(); } ``` 由于 `SysTick_Handler()` 中断服务例程由用户在 board.c 中重新实现,作为系统 OS Tick,所以还需要删除工程里中原本已经实现的 `SysTick_Handler()` ,避免在编译时产生重复定义。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。 ### 内存堆初始化 系统内存堆的初始化在 board.c 中的 rt_hw_board_init() 函数中完成,内存堆功能是否使用取决于宏 RT_USING_HEAP 是否开启,RT-Thread Nano 默认不开启内存堆功能,这样可以保持一个较小的体积,不用为内存堆开辟空间。开启系统 heap 将可以使用动态内存功能,如使用 rt_malloc、rt_free 以及各种系统动态创建对象的 API。若需要使用系统内存堆功能,则打开 RT_USING_HEAP 宏定义即可,此时内存堆初始化函数 rt_system_heap_init() 将被调用。 ## 3.编写第一个应用 移植好 RT-Thread Nano 之后,则可以开始编写第一个应用代码验证移植结果。此时 main() 函数就转变成 RT-Thread 操作系统的一个线程,现在可以在 main() 函数中实现第一个应用:板载 LED 指示灯闪烁。 1. 首先在文件首部增加 RT-Thread 的相关头文件 `
` 。 2. 在 main() 函数中(也就是在 main 线程中)实现 LED 闪烁代码:初始化 LED 引脚、在循环中点亮 / 熄灭 LED。 3. 将延时函数替换为 RT-Thread 提供的延时函数 rt_thread_mdelay()。该函数会发起系统调度,切换到其他线程运行,体现了线程的实时性。 此时可以看到 LED 闪烁,虽然现象与裸机程序一致,但 RT-Thread 已经在 HK32F030 上成功运行。 > 使用 RTOS 造成固件变大后,通过CMSIS-DAP 烧录程序可能出现失败现象: > > ![image-20210602214136770.png](https://oss-club.rt-thread.org/uploads/20210603/968c4aa919f851a1d5b979fee96c104a.png) > > 将 CMSIS-DAP 的 SW 调试速度调低为 500kHz 后烧录成功: > > ![image-20210602214001408.png](https://oss-club.rt-thread.org/uploads/20210603/a97e3175307710148234ef85e46590fe.png) ## 4.移植控制台 FinSH > 由于 RAM 的大小有限,这里 FinSH 的移植未能完成 ### 在 Nano 上添加 UART 控制台 在 RT-Thread Nano 上添加 UART 控制台打印功能后,就可以在代码中使用 RT-Thread 提供的打印函数 rt_kprintf() 进行信息打印,从而获取自定义的打印信息,方便定位代码 bug 或者获取系统当前运行状态等。实现控制台打印(需要确认 rtconfig.h 中已使能 `RT_USING_CONSOLE` 宏定义),需要完成基本的硬件初始化,以及对接一个系统输出字符的函数,本小节将详细说明。 #### 实现串口初始化 使用串口对接控制台的打印,首先需要初始化串口,如引脚、波特率等。 `uart_init()` 需要在 board.c 中的 `rt_hw_board_init()` 函数中调用。 ``` static int uart_init(void); ``` **示例代码**:如下是基于 HK32 库的 HK32F030 串口初始化程序,参考航顺例程编写。实现了串口的发送并配置了串口中断接收。 ``` #define USART1_TX_PORT GPIOA #define USART1_TX_PIN GPIO_Pin_3 #define USART1_TX_IO_CLK_EN() RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE) #define USART1_RX_PORT GPIOD #define USART1_RX_PIN GPIO_Pin_6 #define USART1_RX_IO_CLK_EN() RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOD, ENABLE) static void USART_GPIO_Configurature(void); static void USART_NVIC_Configurature(void); static int uart_init(void); static int uart_init(void) { USART_InitTypeDef m_usart; USART_GPIO_Configurature(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); m_usart.USART_BaudRate = 115200; m_usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None; m_usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; m_usart.USART_Parity = USART_Parity_No; m_usart.USART_StopBits = USART_StopBits_1; m_usart.USART_WordLength = USART_WordLength_8b; USART_Init(USART1, &m_usart); USART_Cmd(USART1, ENABLE); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_NVIC_Configurature(); return 0; } //INIT_BOARD_EXPORT(uart_init); static void USART_GPIO_Configurature(void) { GPIO_InitTypeDef m_gpio; USART1_TX_IO_CLK_EN(); USART1_RX_IO_CLK_EN(); m_gpio.GPIO_Mode = GPIO_Mode_AF; m_gpio.GPIO_OType = GPIO_OType_PP; m_gpio.GPIO_Pin = USART1_TX_PIN; m_gpio.GPIO_PuPd = GPIO_PuPd_NOPULL; m_gpio.GPIO_Speed = GPIO_Speed_10MHz; GPIO_Init(USART1_TX_PORT, &m_gpio); GPIO_PinAFConfig(USART1_TX_PORT,GPIO_PinSource3,GPIO_AF_1); m_gpio.GPIO_Pin = USART1_RX_PIN; GPIO_Init(USART1_RX_PORT, &m_gpio); GPIO_PinAFConfig(USART1_RX_PORT,GPIO_PinSource6,GPIO_AF_1); } static void USART_NVIC_Configurature(void) { NVIC_SetPriority(USART1_IRQn,0); NVIC_EnableIRQ(USART1_IRQn); } ``` #### 实现 rt_hw_console_output 实现 finsh 组件输出一个字符,即实现 uart 输出一个字符: > > 注:注意:RT-Thread 系统中已有的打印均以 `\n` 结尾,而并非 `\r\n`,所以在字符输出时,需要在输出 `\n` 之前输出 `\r`,完成回车与换行,否则系统打印出来的信息将只有换行。 **示例代码**:如下是基于HK32 库实现的串口驱动对接 rt_hw_console_output() ``` void USART1_SendByte(uint8_t ch) { while((USART1->ISR & USART_ISR_TXE) == 0); USART1->TDR = ch; } void rt_hw_console_output(const char *str) { rt_size_t i = 0, size = 0; char a = '\r'; size = rt_strlen(str); for (i = 0; i < size; i++) { if (*(str + i) == '\n') { USART1_SendByte((uint8_t)a); } USART1_SendByte(*(str + i)); } } ``` 将对应代码加入 board.c ,编译并烧录后,可以看到终端(或串口助手中输出的rtt logo): ![image-20210603093645924.png](https://oss-club.rt-thread.org/uploads/20210603/feeb70f9965a6894dfed1564cb4b4b1b.png) 至此就可以使用 `rt_kprintf()` 打印调试信息了。 ### 在 Nano 上添加 FinSH 组件 [RT-Thread FinSH](https://www.rt-thread.org/document/site/programming-manual/finsh/finsh/) 是 RT-Thread 的命令行组件(shell),提供一套供用户在命令行调用的操作接口,主要用于调试或查看系统信息。它可以使用串口 / 以太网 / USB 等与 PC 机进行通信。这里使用串口方式,在 Nano 上实现 FinSH 功能。 #### Keil 添加 FinSH 源码 打开 Manage Run-Environment: ![keil-add-src.png](https://oss-club.rt-thread.org/uploads/20210603/ac0a3e2ef9a87615f9975daa1a2b36d0.png) 勾选 shell 然后点击OK,将 FinSH 组件的源码到工程。 ![image-20210603094848231.png](https://oss-club.rt-thread.org/uploads/20210603/75751128f61c8c388ff50ed1a5743dcd.png) 这时看到 RTOS Group 中加入了以下 FinSH 文件: ![image-20210603095001169.png](https://oss-club.rt-thread.org/uploads/20210603/4d714e0b2135ec715e4a96f2803493a6.png) #### 实现 rt_hw_console_getchar() 要实现 FinSH 组件功能(既可以打印也能输入命令进行调试),需要在 board.c 中对接控制台输入函数,实现字符输入: - rt_hw_console_getchar():控制台获取一个字符,即在该函数中实现 uart 获取字符,可以使用查询方式获取(注意不要死等,在未获取到字符时,需要让出 CPU),也可以使用中断方式获取。 **示例代码**:(未实现) ``` char rt_hw_console_getchar(void) { int ch = -1; // 接收一个字符 ... return ch; } ``` #### 加入 FinSH 后 RAM 空间不足 这时编译会出现报错: ![image-20210603100342507.png](https://oss-club.rt-thread.org/uploads/20210603/bac7969445368ef54220dec2f90c2432.png) 看编译输出应该是存储空间不足,超出RAM大小154 Bytes,尝试将编译器优化等级调高至 Level2 ,但仍会报错。 ![image-20210603103003557.png](https://oss-club.rt-thread.org/uploads/20210603/a5abd8db77a5bc736fbc89f1224f9de2.png) 然后尝试在 `rtconfig.h` 中调小 RT_CONSOLEBUF_SIZE 与 FINSH_THREAD_STACK_SIZE ,编译成功。可以看此时的内存占用:`Program Size: Code=9458 RO-data=922 RW-data=144 ZI-data=1832` ,ROM占用为 Code+RO+RW=10524 Byte,RAM 占用为 RW+ZI=1976 Byte,RAM即将耗尽。同时因为调小了线程运行栈,程序运行时会产生 hard fault,因此不再考虑将 finsh 移植至nano上。 为了正常使用,应当关闭 FinSH 组件,在`RTE_Components.h`中注释 RTE_USING_FINSH,此时程序大小为:`Program Size: Code=5756 RO-data=572 RW-data=120 ZI-data=1264` ,ROM占用为 Code+RO+RW=6448 Byte,RAM 占用为 RW+ZI=1384 Byte,剩余空间较为充裕。也可以通过在 Manage Run-Environment 中关闭 shell,移除 FinSH 组件。 至此,在 HK32F030MF4P6 上的 RT-Thread Nano 移植工作就完成了。
0
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
crazt
Email: i@crazt.moe
文章
1
回答
2
被采纳
0
关注TA
发私信
相关文章
1
有木有移植rt-thread(nano)到riscv 32位MCU上
2
关于esp32的rt-thread nano移植
3
nano-MDK移植-kprintf函数问题?
4
nano添加usb无法通信
5
MDK移植rt-thread nano时按照官方文档移植最新的出现问题
6
M0内核单片机移植RT_Thread卡在 SysTick_IRQHandler
7
ChipON(芯旺微)的32位芯片nano finsh移植
8
nano版本下的finsh_config.h文件
9
nano版本context_gcc编译失败
10
官网RT-Thread nano pack 中board.c配置错误
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
编译报错
Debug
SFUD
msh
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1443
个答案
289
次被采纳
张世争
805
个答案
174
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
4
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
1
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部