【LiteOS学习笔记】01 移植LiteOS到STM32F103ZET6(基于Keil-MDK)
项目开发使用了华为物联网平台,趁此机会学习华为LiteOS的使用。经过多次尝试,终于在STM32F103上成功移植了LiteOS内核。本文记录了移植LiteOS的全过程,供有需要的朋友们参考。LiteOS移植有两种方案:接管中断方案与非接管中断方案。如果接管中断,则中断的创建与管理由LiteOS负责,移植过程比较复杂。反之,非接管中断方案移植过程简单,更适合初学者。本次移植采用不接管中断的方式,中
LiteOS学习笔记
文章目录
前言
项目开发使用了华为物联网平台,趁此机会学习华为LiteOS的使用。经过多次尝试,终于在STM32F103上成功移植了LiteOS内核。本文记录了移植LiteOS的全过程,供有需要的朋友们参考。
LiteOS移植有两种方案:接管中断方案与非接管中断方案。如果接管中断,则中断的创建与管理由LiteOS负责,移植过程比较复杂。反之,非接管中断方案移植过程简单,更适合初学者。本次移植采用不接管中断的方式,中断的创建与管理方式与裸机工程相同。
一、移植准备
1.1 硬件环境
- 开发板:正点原子的STM32F1精英版,主控芯片STM32F103ZET6
- 调试器:ST-Link
1.2 软件环境
- LiteOS版本:LiteOS-develop
- 工程创建:STM32CubeMX v 6.4.0, HAL库版本1.8.5
- 代码编写:Kel MDK v 5.33
二、移植步骤
2.1 使用STM32CubeMX创建裸机工程
- 选择芯片
- 配置调试器与时钟基准
- 配置RCC
- 我们将利用点灯实验验证移植,因此需要配置GPIO控制LED。
- 为了输出调试信息到PC,配置串口
- 配置时钟树
- 工程管理与代码生成
2.2 重定向printf函数输出到串口
参考文章【STM32Cube_09】重定向printf函数到串口输出的多种方法 实现printf函数的重定向。笔者采用了最简单的方式 - 使用MDK自带的MicroLib,具体操作如下:
13. 点击工具栏上的 按钮→Target→勾选Use MicroLIB选项。
14. 点击Porject窗口→Application/User/Core→打开usart.c,在文件最末尾添加如下代码:
/* USER CODE BEGIN 1 */
#include <stdio.h> /*导入标准输入输出函数库*/
/* 重写fputc函数实现重定向*/
int fputc(int ch, FILE* stream)
{
/*阻塞数据发送,直到USART1空闲*/
while((USART1->SR & 0x40)==0);
/*利用USART1发送ch*/
USART1->DR = ch;
return ch;
}
/* USER CODE END 1 */
至此,裸机工程全部创建完毕。
2.3 获取LiteOS源码
Gitee和GitHub均可获取LiteOS源码。笔者尝试了多个版本,最终使用develop分支移植成功,源码下载连接如下:
- Giee下载地址 https://gitee.com/LiteOS/LiteOS/tree/develop/
- GitHub下载地址 https://github.com/LiteOS/LiteOS/tree/develop
2.4 复制LiteOS源码到工程目录
解压后的LiteOS-develop源码目录如图所示:
笔者此次只移植了LiteOS内核,需要复制arch、kernel、osdepends和target四个目录下的内容到STM32工程,具体如表1所示:
文件路径 | 需要移植的内容 | 说明 |
---|---|---|
…\arch\arm\arm-m| include与src 目录内所有内容 | M核中断、调度、tick相关代码 | |
…\arch\arm\arm-m\cortex-m3\keil | los_dispatch_keil.S | 适配Cortex-M3架构与MDK环境的LiteOS系统调度文件 |
…\kernel | 除\kernel\base\mem\bestfit\之外的全部内容 | 内核文件,kernel\base\mem下的\bestfit与\bestfit_little选择一个移植 |
…\osdepends\liteos\cmsis\ | 目录内所有内容 | LiteOS提供的cmsis os接口实现 |
…\targets\STM32F103VET6_NB_GCC\OS_CONFIG | 目录内所有内容 | LiteOS配置文件 |
-
在裸机工程目录下新建LiteOS目录
-
在LiteOS目录下创建Arch、Kernel、CMSIS和Config四个子目录
-
复制LiteOS-develop\arch\include与\src文件夹到<裸机工程>\LiteOS\Arch
-
复制\arch\arm\arm-m\cortex-m3\keil\los_dispatch_keil.S到<裸机工程>\LiteOS\Arch
复制完成后,<裸机工程目录>\Arch目录下内容如下图所示
-
复制LiteOS-develop\kernel\的所有内容到<裸机工程目录>Kernel
完成后,<裸机工程>/LiteOS/Kernel目录下的内容如下图所示:
-
复制LiteOS-develop\osdepends\liteos\cmsis\目录下的cmsis_liteos.c、cmsis_os.h以及Makefile文件到<裸机工程>\LiteOS\CMSIS
完成后,<裸机工程>\LiteOS\CMSIS\目录下内容如下图所示:
-
从源码示例工程\LiteOS-develop\targets\STM32F103VET6_NB_GCC\OS_CONFIG中复制los_builddef.h、los_printf.h以及非接管中断方案的配置文件target_config.h到<裸机工程>\LiteOS\Config
完成后,<裸机工程>\LiteOS\Config\目录下内容如下图所示:
至此,需要的LiteOS源码已经全部复制到STM32工程目录下。
2.5 添加LiteOS源码到MDK
虽然LiteOS源码已经复制到了STM32工程目录下,但是现在在MDK中还看不到LiteOS源码,不能编译LiteOS,我们需要将源码加入到MDK,具体操作如下:
8. 在MDK工程窗口中选择工程右键→管理工程项目
9. 新建LiteOS/Arch、LiteOS/Kernel、LiteOS/CMSIS和LiteOS/Config四个分组
10. 将<裸机工程>\LiteOS\Arch\src\中的所有*.c文件添加到LiteOS/Arch分组
11. 将<裸机工程>\LiteOS\Arch\目录下的los_dispatch_keil.s文件也添加到LiteOS/Arch分组
至此,LiteOS/Arch分组的内容添加完毕,具体如下图所示:
12. 添加<裸机工程>\LiteOS\Kernel\base路径下core、ipc、misc和om文件夹内所有的*.c文件到LiteOS/Kernel分组。
13. 添加<裸机工程>\LiteOS\Kernel\base\mem\路径下bestfit_little、common、membox文件夹下的所有*.c文件到LiteOS/Kernel分组。
mem文件夹中的代码实现内存管理功能。LiteOS提供三种动态内存算法,分别是bestfit、bestfit_little和tlsf。这三者不能同时移植,必须从中选择一种,本次我们选择移植bestfit_little算法。comm和membox下的源码与静态内存管理有关,一并添加到分组当中。
14. 添加<裸机工程>\LiteOS\Kernel\路径下的los_init.c文件到LiteOS/Kernel分组
至此,LiteOS/Kernel分组的内容添加完毕,具体如下图所示:
15. 添加<裸机工程>\LiteOS\CMSIS路径下的cmsis_liteos.c到MDK工程的LiteOS/CMSIS分组
16. 最后,将<裸机工程>\LiteOS\Config路径下的三个头文件添加到MDK工程的LiteOS/Config分组
至此,LiteOS内核的所有源码都添加到了MDK工程。
2.6 添加头文件搜索路径到MDK工程
为了保证MDK的Linker能够顺利链接资源,最终生成可烧录的文件,我们还需要修改工程配置,添加头文件的存放路径。
17. 点击MDK工具栏上的按钮,按下图所示步骤,添加头文件引用路径。
至此,所有需要移植的LiteOS内容已全部添加到MDK工程。
2.7 屏蔽PendSV与SysTick中断响应
LiteOS内核使用了SysTick与PendSV中断,并在源码中实现了void PendSV_Handler(void)与void SysTick_Handler(void)中断响应。因此我们需要在用户代码中屏蔽这两个函数,避免编译错误。
- 点击MDK的Porject窗口→Application/User/Core→打开stm32f1xx_it.c。这个文件负责STM32所有中断响应函数的实现,我们找到并注释掉void PendSV_Handler(void)与void SysTick_Handler(void)两个函数的实现代码。
注意:如果使用了CubeMX的代码生成功能修改代码,上述两个中断响应函数的注释会失效,需要进行重新注释或删除这两个函数。
修改完成后,点击工具栏上的编译按钮,编译整个工程。正常情况下,编译错误和警告应当都是0,如下图所示。
至此,LiteOS的内核就全部移植完毕了,接下来我们将修改main.c文件,测试内核是否移植成功。
三、测试移植效果
点击MDK的Porject窗口→Application/User/Core→修改main.c文件,如下所示:
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "los_sys.h"
#include "los_typedef.h"
#include "los_task.ph"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
UINT32 Test_Task_Handler;
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
static void Test_Task(void);
static UINT32 Create_Test_Task(void);
static UINT32 AppTaskCreate(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
static void Test_Task(void)
{
while(1)
{
printf("Welcom to Huawei LiteOS on STM32F103ZE!\r\n");
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
LOS_TaskDelay(2000);
}
}
static UINT32 Create_Test_Task()
{
UINT32 uwRet = LOS_OK;
TSK_INIT_PARAM_S task_init_param;
task_init_param.usTaskPrio = 5;
task_init_param.pcName = "Test_Task";
task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Test_Task;
task_init_param.uwStackSize = 0x1000;
uwRet = LOS_TaskCreate(&Test_Task_Handler,&task_init_param);
return uwRet;
}
static UINT32 AppTaskCreate(void)
{
UINT32 uwRet = LOS_OK;
uwRet = Create_Test_Task();
if(uwRet!=LOS_OK)
{
printf("Failed to create Test_Task! The error code is 0x%x\r\n",uwRet);
return LOS_NOK;
}
return uwRet;
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
UINT32 uwRet;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
uwRet = LOS_KernelInit();
if(uwRet != LOS_OK)
{
printf("Failed to initialized LiteOS kernel, the error code is 0x%x\r\n",uwRet);
return LOS_NOK;
}
uwRet = AppTaskCreate();
if(uwRet != LOS_OK)
return LOS_NOK;
LOS_Start();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
编译工程,烧录代码到开发板,可以看到发光二极管DS0以2秒为周期闪烁。
连接开发板到PC,可以每隔2s在串口助手中收到一条Welcom to Huawei LiteOS on STM32F103ZE!消息。
至此,LiteOS内核移植成功。
更多推荐
所有评论(0)