前言
RT-Thread官网有很多通过IDE一键移植的方法,本文选择的是手动移植,文末提供移植好的完整工程。
RT-Thread 有3个版本,分别是标准版本、Nano版本、Smart版本,本文选择的是最简单的Nano版本,RT-Thread Nano 是一个极简版的硬实时内核,其架构如下:
其启动流程如下,黄色表示 libcpu 移植相关的内容(RT-Thread提供的libcpu文件已完成 ),绿色部分表示板级移植相关的内容(需要我们完成)
基础工程
演示STM32F103移植RT-Thread完整过程,基础工程采用STM32CubeMX生成
需要注意如下几点:
①取消HardFault_Handler、PendSV_Handler、SysTick_Handler中断函数
SysTick_Handler
在board.c
中实现
HardFault_Handler
、PendSV_Handle
r在context_rvds.S
中实现(RT-Thread已完成)
②将基准时钟由SysTick换成其它,例如TIM4
③使能UART1,便于调试
1.下载源码
下载RT-Thread v4.1.1解压如下图,下载可能有点慢,文末提供压缩包
2.拷贝源码
在工程目录下创建RT-Thread目录,并创libcpu
目录和bsp
目录
将rt-thread-v4.1.1中的include
和src
文件夹拷贝进RT-Thread
将rt-thread-v4.1.1 libcpu\arm中的cortex-m3
文件夹拷贝进RT-Thread\libcpu
在RT-Thread\bsp下创建board.c
在RT-Thread下创建rtconfig.h
3.添加到工程
新建RT-Thread组
添加RT-Thread\src中的全部.c
文件
添加RT-Thread\libcpu\cortex-m3中的cpuport.c
和context_rvds.S
添加RT-Thread\lbsp中的board.c
头文件路径包含RT-Thread和RT-Thread\include
4.修改配置
将如下代码拷贝进board.c
#include <rthw.h>
#include <rtthread.h>
#include "main.h"
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
/*
* Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP
* the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes
*/
#define RT_HEAP_SIZE (15*1024)
static rt_uint8_t rt_heap[RT_HEAP_SIZE];
RT_WEAK void *rt_heap_begin_get(void)
{
return rt_heap;
}
RT_WEAK void *rt_heap_end_get(void)
{
return rt_heap + RT_HEAP_SIZE;
}
#endif
void SysTick_Handler(void)
{
rt_interrupt_enter();
rt_tick_increase();
rt_interrupt_leave();
}
/**
* This function will initial your board.
*/
void rt_hw_board_init(void)
{
extern void SystemClock_Config(void);
HAL_Init();
SystemClock_Config();
SystemCoreClockUpdate();
/*
* 1: OS Tick Configuration
* Enable the hardware timer and call the rt_os_tick_callback function
* periodically with the frequency RT_TICK_PER_SECOND.
*/
HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/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
}
#ifdef RT_USING_CONSOLE
static UART_HandleTypeDef UartHandle;
static int uart_init(void)
{
/* TODO: Please modify the UART port number according to your needs */
UartHandle.Instance = USART1;
UartHandle.Init.BaudRate = 115200;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&UartHandle) != HAL_OK)
{
while (1);
}
return 0;
}
INIT_BOARD_EXPORT(uart_init);
void rt_hw_console_output(const char *str)
{
rt_size_t i = 0, size = 0;
char a = '\r';
__HAL_UNLOCK(&UartHandle);
size = rt_strlen(str);
for (i = 0; i < size; i++)
{
if (*(str + i) == '\n')
{
HAL_UART_Transmit(&UartHandle, (uint8_t *)&a, 1, 1);
}
HAL_UART_Transmit(&UartHandle, (uint8_t *)(str + i), 1, 1);
}
}
#endif
#ifdef RT_USING_FINSH
char rt_hw_console_getchar(void)
{
/* Note: the initial value of ch must < 0 */
int ch = -1;
if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE) != RESET)
{
ch = UartHandle.Instance->DR & 0xff;
}
else
{
rt_thread_mdelay(10);
}
return ch;
}
#endif
将如下代码拷贝进rtconfig.h
/* RT-Thread config file */
#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__
#define RT_USING_LIBC
// <<< Use Configuration Wizard in Context Menu >>>
// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
// <i>Default: 32
#define RT_THREAD_PRIORITY_MAX 32
// <o>OS tick per second
// <i>Default: 1000 (1ms)
#define RT_TICK_PER_SECOND 1000
// <o>Alignment size for CPU architecture data access
// <i>Default: 4
#define RT_ALIGN_SIZE 4
// <o>the max length of object name<2-16>
// <i>Default: 8
#define RT_NAME_MAX 8
// <c1>Using RT-Thread components initialization
// <i>Using RT-Thread components initialization
#define RT_USING_COMPONENTS_INIT
// </c>
#define RT_USING_USER_MAIN
// <o>the stack size of main thread<1-4086>
// <i>Default: 512
#define RT_MAIN_THREAD_STACK_SIZE 512
// </h>
// <h>Debug Configuration
// <c1>enable kernel debug configuration
// <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o>enable components initialization debug configuration<0-1>
// <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
// <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>
// <h>Hook Configuration
// <c1>using hook
// <i>using hook
//#define RT_USING_HOOK
// </c>
// <c1>using idle hook
// <i>using idle hook
//#define RT_USING_IDLE_HOOK
// </c>
// </h>
// <e>Software timers Configuration
// <i> Enables user timers
#define RT_USING_TIMER_SOFT 0
#if RT_USING_TIMER_SOFT == 0
#undef RT_USING_TIMER_SOFT
#endif
// <o>The priority level of timer thread <0-31>
// <i>Default: 4
#define RT_TIMER_THREAD_PRIO 4
// <o>The stack size of timer thread <0-8192>
// <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE 512
// </e>
// <h>IPC(Inter-process communication) Configuration
// <c1>Using Semaphore
// <i>Using Semaphore
#define RT_USING_SEMAPHORE
// </c>
// <c1>Using Mutex
// <i>Using Mutex
#define RT_USING_MUTEX
// </c>
// <c1>Using Event
// <i>Using Event
#define RT_USING_EVENT
// </c>
// <c1>Using MailBox
// <i>Using MailBox
#define RT_USING_MAILBOX
// </c>
// <c1>Using Message Queue
// <i>Using Message Queue
#define RT_USING_MESSAGEQUEUE
// </c>
// </h>
// <h>Memory Management Configuration
// <c1>Memory Pool Management
// <i>Memory Pool Management
//#define RT_USING_MEMPOOL
// </c>
// <c1>Dynamic Heap Management(Algorithm: small memory )
// <i>Dynamic Heap Management
#define RT_USING_HEAP
#define RT_USING_SMALL_MEM
//#define RT_USING_MEMHEAP
//#define RT_MEMHEAP_FAST_MODE
#define RT_USING_SMALL_MEM_AS_HEAP
// </c>
// <c1>using tiny size of memory
// <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>
// <h>Console Configuration
// <c1>Using console
// <i>Using console
#define RT_USING_CONSOLE
// </c>
// <o>the buffer size of console <1-1024>
// <i>the buffer size of console
// <i>Default: 128 (128Byte)
#define RT_CONSOLEBUF_SIZE 256
// </h>
// <h>FinSH Configuration
// <c1>include finsh config
// <i>Select this choice if you using FinSH
//#include "finsh_config.h"
// </c>
// </h>
// <h>Device Configuration
// <c1>using device framework
// <i>using device framework
//#define RT_USING_DEVICE
// </c>
// </h>
// <<< end of configuration section >>>
#endif
此时的main()
已经变成了一个线程,所以需要屏蔽掉main()
中硬件相关的操作
相关操作移到了board.c
中rt_hw_board_init()
的执行,后期有硬件相关初始化也要添加到rt_hw_board_init()
中
rt_hw_board_init()
会在线程启动前被调用
可能细心的同学会发现,我们没有修改过启动文件,应该最先执行main()
,但是实际最先执行的是rtthread_startup()
,main()
反而变成了一个线程,为什么呢?请参考我的另一篇博客
在MDK(ARMCC)中使用 $ Sub $ $ 和 $ Super $ $
int main(void)
{
// HAL_Init();
// SystemClock_Config();
// MX_GPIO_Init();
// MX_USART1_UART_Init();
while (1)
{
}
}
5.验证demo
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "rtthread.h"
int main(void)
{
// HAL_Init();
// SystemClock_Config();
// MX_GPIO_Init();
// MX_USART1_UART_Init();
while (1)
{
rt_kprintf("hello world!\r\n");
rt_thread_delay(1000);
}
}
6.完整工程和RT-Thread源码
0错误 0警告,点击下载