360sysrt RT

编辑:
发布时间: 2020-12-24 19:38:54
分享:
前言

从本文开始,记录自己的RT-Thread学习笔记,基于STM32L475VET6讲解,相关开发板用RTT&正点原子的潘多拉IoT Board开发板。本文先从Nano开始学起,个人觉得对于初学者,还是先学会Nano的移植,把内核部分向学一遍,再去学组件和设备驱动以及其他的东西,这里包括RT-Thread的内核移植、FinSH移植,相关代码到GitHub下载:https://github.com/sanjaywu/STM32L475_PANDORA_RT-Thread_DEMO

一、获取裸机工程

1、裸机工程可到GitHub下载:https://github.com/sanjaywu/STM32L475_PANDORA_DEMO,下载完成之后,打开工程文件夹,可以发现如下文件:

2、接着我们把HARDWARE、SYSTEM和USMART这三个文件删除,HARDWARE文件夹是裸机的外设驱动,在讲解移植的时候不需要用到,SYSTEM文件夹有delay延时、串口驱动和相关类型宏定义,在移植RT-Thread的时候,我们会重新实现delay延时和串口驱动以及类型宏定义。

二、下载 RT-Thread Nano 源码

1、RT-Thread Master 的源码可从 RT-Thread GitHub 仓库下载,Nano 就是从里面扣出来的,去掉了一些组件和各种开发板的 BSP,保留了 OS的核心功能,但足够我们使用。RT-Thread 官方并没有将抠出来的Nano 放 到 他 们 的 官 方 网 站 , 而 是 作 为 一 个 Package 放 在 了 KEIL 网 站:http://www.keil.com/dd2/pack/,目前最新的是3.1.1版本,打开这条连接,然后拉到下面找到RT-Thread的Package:

三、往裸机工程添加 RT-Thread 源码

1、在前面下载好的裸机工程里,再新建一个文件夹为RT-Thread的,然后将上面下载好的Nano版源码拷贝到这个文件:

打开libcpu —> arm,因为用的是STM32L4xx,是cortex-m4,所以只需保留cortex-m4即可,其它都删除:

剩下的include和src文件设RT-Thread的头文件和内核源码,不能删除,保留完整。

接着,新建一个文件夹来放设备驱动,命名device_drivers。这里为什么要用RT-Thread设备驱动呢,因为RT-Thread的finsh功能实现需要串口,这里就用先只设备驱动里面的串口驱动来实现,自己从RT-Thread的master版本中整理出来,代码可以看工程里面的,这样既能实现finsh也能实现rt_kprintf。当然你也可以自己写一个串口驱动,只不过后面一直finsh就会很麻烦,读写函数都要改掉,而且容易出错。

最终移植整理好之后,RT-Thread的文件如下:

四、修改rtconfig.h#ifndef __RTTHREAD_CFG_H__#define __RTTHREAD_CFG_H__/* RT-Thread内核部分 */#define RT_NAME_MAX 8 //内核对象名称最大长度,大于该长度的名称多余部分会被自动裁掉#define RT_ALIGN_SIZE 4 //字节对齐时设定对齐的字节个数。常使用ALIGN进行字节对齐#define RT_THREAD_PRIORITY_MAX 32 //定义系统线程优先级数;通常用RT_THREAD_PRIORITY_MAX-1定义空闲线程的优先级#define RT_TICK_PER_SECOND 1000 //定义时钟节拍,为1000时表示1000个tick每 秒,一个tick为1ms#define RT_USING_OVERFLOW_CHECK //检查栈是否溢出,未定义则关闭#define RT_DEBUG //定义该宏开启debug模式,未定义则关闭#define RT_DEBUG_INIT 0 //开启debug模式时:该宏定义为0时表示关闭打印组件初始化信息,定义为1时表示启用#define RT_DEBUG_THREAD 0 //开启debug模式时:该宏定义为0时表示关闭打印线程切换信息,定义为1时表示启用#define RT_USING_HOOK //定义该宏表示开启钩子函数的使用,未定义则关闭#define IDLE_THREAD_STACK_SIZE 256 //定义了空闲线程的栈大小/* 线程间同步与通信部分,该部分会使用到的对象有信号量、互斥量、事件、邮箱、消息队列、信号等 */#define RT_USING_SEMAPHORE //定义该宏可开启信号量的使用,未定义则关闭#define RT_USING_MUTEX //定义该宏可开启互斥量的使用,未定义则关闭#define RT_USING_EVENT //定义该宏可开启事件集的使用,未定义则关闭#define RT_USING_MAILBOX //定义该宏可开启邮箱的使用,未定义则关闭#define RT_USING_MESSAGEQUEUE //定义该宏可开启消息队列的使用,未定义则关闭#define RT_USING_SIGNALS //定义该宏可开启信号的使用,未定义则关 闭/* 内存管理部分 */#define RT_USING_MEMPOOL //定义该宏可开启静态内存池的使用,未定义则关闭#define RT_USING_MEMHEAP //定义该宏可开启两个或以上内存堆拼接的使用,未定义则关闭#define RT_USING_SMALL_MEM //定义该宏可开启开启小内存管理算法,未定义则关闭//#define RT_USING_SLAB //定义该宏可开启SLAB内存管理算法,未定义则关闭#define RT_USING_HEAP //定义该宏可开启堆的使用,未定义则关闭/* 内核设备对象 */#define RT_USING_DEVICE //表示开启了系统设备的使用,使用设备驱动#define RT_USING_CONSOLE //定义该宏可开启系统控制台设备的使用,未定义则关闭#define RT_CONSOLEBUF_SIZE 128 //定义控制台设备的缓冲区大小#define RT_CONSOLE_DEVICE_NAME "uart1" //控制台设备的名称/* 自动初始化方式 */#define RT_USING_COMPONENTS_INIT //定义该宏开启自动初始化机制,未定义则关闭#define RT_USING_USER_MAIN //定义该宏 启设置应用入口为main函数#define RT_MAIN_THREAD_STACK_SIZE 2048 //定义main线程的栈大小/* FinSH */#define RT_USING_FINSH //定义该宏可开启系统FinSH调试工具的使用,未定义则关闭#ifdef RT_USING_FINSH#define FINSH_THREAD_NAME "tshell" //开启系统FinSH时:将该线程名称定义为tshell#define FINSH_USING_HISTORY //开启系统FinSH时:使用历史命令#define FINSH_HISTORY_LINES 5 //开启系统FinSH时:对历史命令行数的定义#define FINSH_USING_SYMTAB //开启系统FinSH时:定义该宏开启使用Tab键,未定义则关闭#define FINSH_THREAD_PRIORITY 20 //开启系统FinSH时:定义该线程的优先级#define FINSH_THREAD_STACK_SIZE 4096 //开启系统FinSH时:定义该线程的栈大小#define FINSH_CMD_SIZE 80 //开启系统FinSH时:定义命令字符长度#define FINSH_USING_MSH //开启系统FinSH时:定义该宏开启MSH功能#define FINSH_USING_MSH_DEFAULT //开启系统FinSH时:开启MSH功能时,定义该宏默认使用MSH功能#define FINSH_USING_MSH_ONLY //开启系统FinSH时:定义该宏,仅使用MSH功能#endif/* 关于 MCU */#define STM32L475VE //定义该工程使用的MCU为STM32L475VE#define RT_HSE_VALUE 8000000 //定义时钟源频率#define RT_USING_LED //定义该宏开启LED的使用#define RT_USING_SERIAL //定义该宏开启串口的使用#define BSP_USING_UART1 //定义该宏开启UART1的使用#endif/* __RTTHREAD_CFG_H__ */五、修改board.c

1、添加系统时钟初始函数,这里使用HAl库将系统初始化为80MHz:

void _Error_Handler{/* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while { } /* USER CODE END Error_Handler_Debug */}/* * @brief System Clock Configuration * @retval None*/void SystemClock_Config{RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct;__HAL_RCC_PWR_CLK_ENABLE; /* Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLM = 1; RCC_OscInitStruct.PLL.PLLN = 20; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if != HAL_OK) { _Error_Handler; } /* Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1| RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if != HAL_OK) { _Error_Handler; } /* Configure the main internal regulator output voltage */ if != HAL_OK) { _Error_Handler; }}

2、修改Tick相关函数,初始化SysTick,:

/** * HAL adaptation */HAL_StatusTypeDef HAL_InitTick{ /* Return function status */ return HAL_OK;}uint32_t HAL_GetTick{ return rt_tick_get * 1000 / RT_TICK_PER_SECOND;}void HAL_SuspendTick{ return ;}void HAL_ResumeTick{ return ;}void HAL_Delay{ return ;}void SysTick_Handler{ /* enter interrupt */ rt_interrupt_enter; rt_tick_increase; /* leave interrupt */ rt_interrupt_leave;}

3、修改rt_hw_board_init函数,初始化SysTick:

/** * This function will initial your board. */void rt_hw_board_init{/* 使用HAL库,初始化HAL */HAL_Init;/* 初始化系统时钟和SysTick */ SystemClock_Config;SysTick_Config;/* 硬件 BSP 初始化统统放在这里,比如 LED,串口,LCD 等 */#ifdef RT_USING_LEDled_init;#endif#ifdef RT_USING_SERIAL stm32_hw_usart_init;#endif /* Call components board initial ) */#ifdef RT_USING_COMPONENTS_INIT rt_components_board_init;#endif#if defined && definedrt_console_set_device;#endif#if defined && defined rt_system_heap_init, rt_heap_end_get);#endif}

4、增加RT-Thread堆空间大小,因为finsh需要和其他线程需要,我这里先修改为16K,后期使用具体看MCU的RAM和实际需要调节:

这里我们重点关注几个文件夹: BSP、RT-Thread_bsp、RT-Thread_device_drviers、RT-Thread_libcpu。

BSP,放用户自己写的驱动,如LED驱动、LCD驱动等:

RT-Thread_bsp:放RT-Thread做的BSP、board.c、board.h、rt_config.h,放RT-Thread做的BSP可以是串口驱动等:

RT-Thread_device_drviers:放RT-Thread的设备驱动框架,如串口、I2C、SPI等,我们目前只先用到串口:

3、添加相关头文件到工程:

七、修改main.c

1、将main函数修改如下:

#include "main.h"#include "board.h"#include "rtthread.h"int main{ u32 count = 1; while { LED_R; rt_kprintf; rt_thread_mdelay; LED_R; rt_thread_mdelay; rt_kprintf; count++; } return 0;}

2、保存工程,然后编译工程,下载到开发板,观察LED灯情况,会亮500ms后再灭500ms,同时串口打印相关信息:

3、测试finsh功能:

为更加直观看finsh相关功能,将main函数的串口打印代码注释掉,然后重新编译,下载到开发板:

#include "main.h"#include "board.h"#include "rtthread.h"int main{u32 count = 1;while{LED_R;//rt_kprintf;rt_thread_mdelay;LED_R;rt_thread_mdelay;//rt_kprintf;count++;}return 0;}

接着打开串口,打印如下信息:

按tab键:

启动流程如下:

启动流程图——来源RT-Thread编程指南

这部分启动代码,大致可以分为四个部分:初始化与系统相关的硬件;初始化系统内核对象,例如定时器、调度器、信号;创建 main 线程,在 main 线程中对各类模块依次进行初始化;初始化定时器线程、空闲线程,并启动调度器。rt_hw_board_init 中完成系统时钟设置,为系统提供心跳、串口初始化,将系统输入输出终端绑定到这个串口,后续系统运行信息就会从串口打印出来。

参考文献:

1、[野火®]《RT-Thread 内核实现与应用开发实战—基于STM32》

2、RT-THREAD 编程指南

相关阅读
热门精选
孩子 皮肤