【LiteOS学习笔记】01 移植LiteOS到STM32F103ZET6(基于Keil-MDK)

LiteOS学习笔记



前言

项目开发使用了华为物联网平台,趁此机会学习华为LiteOS的使用。经过多次尝试,终于在STM32F103上成功移植了LiteOS内核。本文记录了移植LiteOS的全过程,供有需要的朋友们参考。

LiteOS移植有两种方案:接管中断方案与非接管中断方案。如果接管中断,则中断的创建与管理由LiteOS负责,移植过程比较复杂。反之,非接管中断方案移植过程简单,更适合初学者。本次移植采用不接管中断的方式,中断的创建与管理方式与裸机工程相同。


一、移植准备

1.1 硬件环境

  1. 开发板:正点原子的STM32F1精英版,主控芯片STM32F103ZET6
  2. 调试器:ST-Link

1.2 软件环境

  1. LiteOS版本:LiteOS-develop
  2. 工程创建:STM32CubeMX v 6.4.0, HAL库版本1.8.5
  3. 代码编写:Kel MDK v 5.33

二、移植步骤

2.1 使用STM32CubeMX创建裸机工程

  1. 选择芯片
    在这里插入图片描述
  2. 配置调试器与时钟基准
    在这里插入图片描述
  3. 配置RCC
    在这里插入图片描述
  4. 我们将利用点灯实验验证移植,因此需要配置GPIO控制LED。
    在这里插入图片描述
  5. 为了输出调试信息到PC,配置串口
    在这里插入图片描述
  6. 配置时钟树
    在这里插入图片描述
  7. 工程管理与代码生成
    在这里插入图片描述在这里插入图片描述

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分支移植成功,源码下载连接如下:

2.4 复制LiteOS源码到工程目录

解压后的LiteOS-develop源码目录如图所示:
LiteOS-develop源码目录
笔者此次只移植了LiteOS内核,需要复制arch、kernel、osdepends和target四个目录下的内容到STM32工程,具体如表1所示:

表1 - 移植清单
文件路径需要移植的内容说明
…\arch\arm\arm-m| include与src 目录内所有内容M核中断、调度、tick相关代码
…\arch\arm\arm-m\cortex-m3\keillos_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配置文件
  1. 在裸机工程目录下新建LiteOS目录
    在这里插入图片描述

  2. 在LiteOS目录下创建Arch、Kernel、CMSIS和Config四个子目录
    在这里插入图片描述

  3. 复制LiteOS-develop\arch\include与\src文件夹到<裸机工程>\LiteOS\Arch
    在这里插入图片描述

  4. 复制\arch\arm\arm-m\cortex-m3\keil\los_dispatch_keil.S到<裸机工程>\LiteOS\Arch
    在这里插入图片描述
    复制完成后,<裸机工程目录>\Arch目录下内容如下图所示
    在这里插入图片描述

  5. 复制LiteOS-develop\kernel\的所有内容到<裸机工程目录>Kernel
    在这里插入图片描述
    完成后,<裸机工程>/LiteOS/Kernel目录下的内容如下图所示:
    在这里插入图片描述

  6. 复制LiteOS-develop\osdepends\liteos\cmsis\目录下的cmsis_liteos.c、cmsis_os.h以及Makefile文件到<裸机工程>\LiteOS\CMSIS
    在这里插入图片描述
    完成后,<裸机工程>\LiteOS\CMSIS\目录下内容如下图所示:
    在这里插入图片描述

  7. 从源码示例工程\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工具栏上的Options for Target...按钮,按下图所示步骤,添加头文件引用路径。

在这里插入图片描述
至此,所有需要移植的LiteOS内容已全部添加到MDK工程。

2.7 屏蔽PendSV与SysTick中断响应

LiteOS内核使用了SysTick与PendSV中断,并在源码中实现了void PendSV_Handler(void)与void SysTick_Handler(void)中断响应。因此我们需要在用户代码中屏蔽这两个函数,避免编译错误。

  1. 点击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内核移植成功。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值