赞
踩
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,便于调试
下载RT-Thread v4.1.1解压如下图,下载可能有点慢,文末提供压缩包
在工程目录下创建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
新建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
将如下代码拷贝进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)
{
}
}
#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); } }
0错误 0警告,点击下载
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。