总览

本文基于STM32F103C8T6,详细讲述华为LiteOS的移植过程。开发工具是MDK5。LiteOS官方已经适配过cortex M系列内核的单片机,因此移植过程非常简单。

LiteOS有两种移植方案:OS接管中断和非接管中断方式。接管中断的方式,是由LiteOS创建很管理中断,需要修改stm32启动文件,移植比较复杂。STM32的中断管理做的很好,用不着由LiteOS管理中断,所以我们下边的移植方案,都是非接管中断的方式的。中断的使用,跟在裸机工程时是一样的。

在target_config.h 中将 LOSCFG_PLATFORM_HWI 宏定义为 NO,即为不接管中断方式。该值默认为NO 。

移植的主要步骤如下:

1、添加内核文件

2、配置头文件

3、移除systick和pendsv中断

4、修改target_config.h

5、重定向printf函数(一般在裸机工程中就会实现)

说明:内核运行过程中会通过串口打印一些错误信息。如果日志功能开启、而又没有重定向printf函数的话,则会导致日志打印出错,程序异常卡死。之前我就是没有重定向printf函数,结果出了莫名其妙的问题,程序异常卡死在创建任务的地方。

下边我们通过新建一个裸机工程,一步步讲解如何进行移植。以下是详细过程。

一、创建裸机工程

我们这次使用的是一个STM32F103C8T6的最小系统板,板载有三个LED、一个串口。LED连接引脚为(PB5\PB6\PB7),低电平点亮;串口为USART1(PA9,PA10),采用DMA+空闲中断的方式接收数据。我们利用STM32CubeMX来生成裸机工程(STM32CubeMX的使用本文不详细描述),设置如下:

1、引脚配置

配置PB5\PB6\PB7为推挽输出方式;

配置PA9\PA10为USART1复用功能;

配置PA13为SWDIO功能,PA14为SWCLK功能(下载及调试)

使能串行调试功能

2、时钟配置

3、串口配置

4、生成代码

勾选生成对应外设驱动的‘.c/.h’文件,生成代码。

打开工程,加入LED开关状态的宏定义和串口空闲中断接收的代码,具体如下(当然,如果你不使用DMA+空闲中断的方式,也可以不进行下边2中的修改,但是一定要重定向printf函数):

1、在main.h中加入LED宏定义代码。

#define LED1_ON() HAL_GPIO_WritePin(GPIOB, LED1_Pin, GPIO_PIN_RESET)

#define LED1_OFF() HAL_GPIO_WritePin(GPIOB, LED1_Pin, GPIO_PIN_SET)

#define LED2_ON() HAL_GPIO_WritePin(GPIOB, LED2_Pin, GPIO_PIN_RESET)

#define LED2_OFF() HAL_GPIO_WritePin(GPIOB, LED2_Pin, GPIO_PIN_SET)

#define LED3_ON() HAL_GPIO_WritePin(GPIOB, LED3_Pin, GPIO_PIN_RESET)

#define LED3_OFF() HAL_GPIO_WritePin(GPIOB, LED3_Pin, GPIO_PIN_SET)

2、实现串口空闲中断接收

在usart.h中加入如下代码:

#define UART1_BUFF_SIZE 256 //串口接收缓存区长度

typedef struct

{

uint8_t RxFlag; //空闲接收标记

uint16_t RxLen; //接收长度

uint8_t *RxBuff; //DMA接收缓存

}USART_RECEIVETYPE;

extern USART_RECEIVETYPE Uart1Rx;

void USART1_ReceiveIDLE(void);

void UART_SendData(USART_TypeDef * Uart,uint8_t *buff,uint16_t size);

在usart.c中加入如下代码

static uint8_t Uar1tRxBuff[UART1_BUFF_SIZE+1]; //定义串口接收buffer

USART_RECEIVETYPE Uart1Rx = {

.RxBuff = Uar1tRxBuff,

};

void USART1_ReceiveIDLE(void)

{

uint32_t temp;

if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET))

{

__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE);

temp = huart1.Instance->SR;

temp = huart1.Instance->DR;

HAL_UART_DMAStop(&huart1);

temp = huart1.hdmarx->Instance->CNDTR;

Uart1Rx.RxLen = UART1_BUFF_SIZE - temp;

Uart1Rx.RxFlag=1;

Uart1Rx.RxBuff[Uart1Rx.RxLen] = 0;

HAL_UART_Receive_DMA(&huart1,Uart1Rx.RxBuff,UART1_BUFF_SIZE);

}

}

void UART_SendByte(USART_TypeDef * Uart,uint8_t data)

{

Uart->DR = data;

while((Uart->SR&UART_FLAG_TXE)==0);

while((Uart->SR&UART_FLAG_TC)==0);

}

void UART_SendData(USART_TypeDef * Uart,uint8_t *buff,uint16_t size)

{

while(size--)

{

Uart->DR = *(buff++);

while((Uart->SR&UART_FLAG_TXE)==0);

}

while((Uart->SR&UART_FLAG_TC)==0);

}

///重定向c库函数printf到USART1

int fputc(int ch, FILE *f)

{

/* 发送一个字节数据到USART1 */

UART_SendByte(USART1, (uint8_t) ch);

return (ch);

}

///重定向c库函数scanf到USART1

int fgetc(FILE *f)

{

/* 等待串口1输入数据 */

while((USART1->SR&UART_FLAG_RXNE)==0);

return (int)USART1->DR&0xff;

}

修改void MX_USART1_UART_Init(void),在最后加入以下代码:

//add for DMA.Idle interrupt

__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE);

__HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_TC);

HAL_UART_Receive_DMA(&huart1, Uart1Rx.RxBuff, UART1_BUFF_SIZE); //开启DMA接收

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能空闲中断

在stm32f1xx_it.c中声明USART1_ReceiveIDLE,并在串口中断中调用该函数:

void USART1_ReceiveIDLE(void);

void USART1_IRQHandler(void)

{

/* USER CODE BEGIN USART1_IRQn 0 */

USART1_ReceiveIDLE();

/* USER CODE END USART1_IRQn 0 */

HAL_UART_IRQHandler(&huart1);

/* USER CODE BEGIN USART1_IRQn 1 */

/* USER CODE END USART1_IRQn 1 */

}

3、在main.c的main中添加代码验证裸机工程

while (1)

{

/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */

LED1_ON();

LED2_ON();

LED3_ON();

HAL_Delay(300);

LED1_OFF();

LED2_OFF();

LED3_OFF();

HAL_Delay(300);

printf("This is the uart test!\r\n");

if(Uart1Rx.RxFlag){

Uart1Rx.RxFlag = 0;

UART_SendData(USART1,Uart1Rx.RxBuff,Uart1Rx.RxLen);

}

}

编译下载代码,程序正常运行,LED闪烁,同时打印字符串。

经过上述操作,我们已经完成了裸机工程的准备工作。

二、内核移植

1、下载LiteOS

LiteOS 开源代码路径:https://github.com/LiteOS/LiteOS

注:LiteOS 最新特性都存放在 develop 分支中,建议取该分支代码进行学习。本文的代码即为 develop分支代码。

点击链接进入LiteOS代码仓库首页,切换至develop分支,点击右侧“Clone or download”按钮,选择Download ZIP,下载代码,如下图所示:

LiteOS内核代码目录结构如下图所示:

2、拷贝内核代码

在工程目录下新建LiteOS文件夹(文件夹名称个人自定义),从上一步下载的LiteOS内核源码中,将arch、kernel、targets\STM32F103VET6_NB_GCC\OS_CONFIG 拷贝至LiteOS文件夹内,如下图所示:

arch 中是CPU架构相关的代码;kernel是LiteOS内核代码;OS_CONFIG中是配置内核功能的头文件,可用于裁剪内核功能,我们从官方提供的例程中拷贝过来(可从target文件夹给出的例子中任意拷贝一个)。

3、向MDK工程添加内核文件

打开MDK工程,打开Mange Project Items。

添加arch分组

在Groups添加 LiteOS/Arch分组,添加以下文件:

arch\arm\arm-m\src 目录下的全部文件:

los_hw.c

los_hw_tick.c

los_hwi.c

arch\arm\arm-m\cortex-m3\keil 目录下的:

los_dispatch_keil.S

如下图所示:

注:点击AddFiles时,MDK默认添加.c类型的文件。los_dispatch_keil.S是汇编文件,因此在添加时,需要将文件类型选择为All files。

添加kernel分组

在Groups添加 LiteOS/kernel分组,添加以下文件:

kernel\base\core 下面全部 .c 文件

kernel\base\ipc 下面全部 .c 文件

kernel\base\mem\bestfit_little 下面全部 .c 文件

kernel\base\mem\common 下面全部 .c 文件

kernel\base\mem\membox 下面全部 .c 文件

kernel\base\misc 下面全部 .c 文件

kernel\base\om 下面全部 .c 文件

kernel\extended\tickless 下面全部 .c 文件 (如不使用tickless,可不添加)

kernel 下面的 los_init.c

说明:liteos提供三套动态内存算法,位于kernel/base/mem目录下,分别为bestfit、bestfit_little、tlsf,我们本次移植的是bestfit_little.可根据需求移植其他的算法。kernel\base\mem\membox目录下是 LiteOS 提供的静态内存算法,与动态内存算法不冲突。

4、配置头文件

如下图所示,依次点击1、2、3,打开头文件配置窗口:

头文件配置如下图所示:

需要添加的头文件路径为:

arch\arm\arm-m\include

kernel\include

kernel\base\include

kernel\extended\include

OS_CONFIG

5、移除Systick和pendsv中断

打开stm32f1xx_it.c,找到 SysTick_Handler 和 PendSV_Handler

将这两个中断处理函数屏蔽掉。否则会出现如下编译错误。

说明:liteos内核使用到了systick和pendsv这两个中断,并在内核代码中有对应实现

6、修改target_config.h

OS_CONFIG/target_config.h 文件,该文件主要用于配置MCU驱动头文件、RAM大小、内核功能等,需要根据自己的环境进行修改。

我们主要需要修改以下两处:

MCU驱动头文件

根据使用的MCU,包含对应的头文件。

SRAM大小

根据使用的MCU芯片SRAM大小进行修改。

这里我们使用的是STM32F103C8T6,其SRAM为20KB。

不接管中断

设置LOSCFG_PLATFORM_HWI 宏定义为 NO(该值默认为NO,一般无需修改,出于谨慎,移植过来还是要检查下)

target_config.h 文件还有很多其他宏定义,主要是配置内核的功能。比如是否使用队列、软件定时器、是否使用时间片、信号量等。

经过以上的操作,LiteOS的移植就完成了。点击编译。

7、创建一个任务

经过前面的操作,移植工作就完成了,这里我们可以创建一个任务,使用LiteOS。在下边的例子中,我们创建了两个任务,一个任务按照2S的周期点亮LED1,另外一个任务按照400毫秒的周期点亮LED2。以下是代码实现:

/* Includes ------------------------------------------------------------------*/

#include "main.h"

#include "dma.h"

#include "usart.h"

#include "gpio.h"

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include "los_sys.h"

#include "los_task.ph"

#include "los_memory.ph"

/* USER CODE END Includes */

/* Private function prototypes -----------------------------------------------*/

void SystemClock_Config(void);

/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/

/* USER CODE BEGIN 0 */

static void Led1Task(void)

{

while(1) {

LED1_ON();

LOS_TaskDelay(1000);

LED1_OFF();

LOS_TaskDelay(1000);

}

}

static void Led2Task(void)

{

while(1) {

LED2_ON();

LOS_TaskDelay(200);

LED2_OFF();

LOS_TaskDelay(200);

}

}

UINT32 RX_Task_Handle;

UINT32 TX_Task_Handle;

static UINT32 AppTaskCreate(void)

{

UINT32 uwRet = LOS_OK;

TSK_INIT_PARAM_S task_init_param;

task_init_param.usTaskPrio = 4;

task_init_param.pcName = "RxTask";

task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Led1Task;

task_init_param.uwStackSize = 512;

uwRet = LOS_TaskCreate(&RX_Task_Handle, &task_init_param);

if (uwRet != LOS_OK)

{

printf("Led1Task create failed,%X\n",uwRet);

return uwRet;

}

task_init_param.usTaskPrio = 4;

task_init_param.pcName = "TxTask";

task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Led2Task;

task_init_param.uwStackSize = 512;

uwRet = LOS_TaskCreate(&TX_Task_Handle, &task_init_param);

if (uwRet != LOS_OK)

{

printf("Led2Task create failed,%X\n",uwRet);

return uwRet;

}

return LOS_OK;

}

/* USER CODE END 0 */

/**

* @brief The application entry point.

* @retval int

*/

int main(void)

{

/* USER CODE BEGIN 1 */

UINT32 uwRet = LOS_OK;

/* 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_DMA_Init();

MX_USART1_UART_Init();

/* USER CODE BEGIN 2 */

LOS_KernelInit();

uwRet = AppTaskCreate();

if(uwRet != LOS_OK) {

printf("LOS Creat task failed\r\n");

//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 */

//code below are used to verify the hardware.

LED1_ON();

LED2_ON();

LED3_ON();

HAL_Delay(300);

LED1_OFF();

LED2_OFF();

LED3_OFF();

HAL_Delay(300);

printf("This is the uart test!\r\n");

}

/* USER CODE END 3 */

}

/**

* @brief System Clock Configuration

* @retval None

*/

void SystemClock_Config(void)

{

RCC_OscInitTypeDef RCC_OscInitStruct = {0};

RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

/** Initializes the CPU, AHB and APB busses clocks

*/

RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;

RCC_OscInitStruct.HSIState = RCC_HSI_ON;

RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;

RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;

RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;

if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != 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_DIV2;

RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)

{

Error_Handler();

}

}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**

* @brief This function is executed in case of error occurrence.

* @retval None

*/

void Error_Handler(void)

{

/* USER CODE BEGIN Error_Handler_Debug */

/* User can add his own implementation to report the HAL error return state */

/* USER CODE END Error_Handler_Debug */

}

#ifdef USE_FULL_ASSERT

/**

* @brief Reports the name of the source file and the source line number

* where the assert_param error has occurred.

* @param file: pointer to the source file name

* @param line: assert_param error line source number

* @retval None

*/

void assert_failed(uint8_t *file, uint32_t line)

{

/* USER CODE BEGIN 6 */

/* User can add his own implementation to report the file name and line number,

tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

/* USER CODE END 6 */

}

#endif /* USE_FULL_ASSERT */

附件为移植好的工程代码。

(代码中有串口空闲中断+DMA的样例代码,可参考。利用串口空闲中断,可以很好的实现数据分帧)

往期文章精选

stm32f103移植python_【LiteOS】STM32F103-LiteOS移植教程(详细篇)相关推荐

  1. 【LiteOS】STM32F103-LiteOS移植教程(详细篇)

    总览 本文基于STM32F103C8T6,详细讲述华为LiteOS的移植过程.开发工具是MDK5.LiteOS官方已经适配过cortex M系列内核的单片机,因此移植过程非常简单. LiteOS有两种 ...

  2. 【LiteOS】LiteOS移植教程(STM32F103C8+MDK)

    总览 本文基于STM32F103C8T6,详细讲述华为LiteOS的移植过程.开发工具是MDK5.LiteOS官方已经适配过cortex M系列内核的单片机,因此移植过程非常简单.     LiteO ...

  3. 手把手带你做LiteOS的树莓派移植

    摘要:树莓派是英国的慈善组织"Raspberry Pi 基金会"开发的一款基于arm的微型电脑主板.本文介绍基于LiteOS的树莓派移植过程. 本文分享自华为云社区<2021 ...

  4. 【华为云技术分享】小熊派华为物联网操作系统LiteOS裸机驱动移植02-LCD驱动移植及使用

    1. LCD裸机驱动 小熊派开发板使用的LCD屏幕为1.3寸的TFT彩屏,色彩深度16bit,分辨率240*240,使用 SPI 接口与 MCU 之间通信. 如果你对裸机玩转LCD屏幕还不熟悉,请先阅 ...

  5. OpenHarmony LiteOS C-SKY指令集移植指北

    摘要:本文介绍在OpenHarmony社区LiteOS-M项目中新增C-SKY指令集的开发流程,以及适配相应qemu工程的方法和步骤,供LiteOS内核相关开发者学习交流. 本文分享自华为云社区< ...

  6. 移植uCOS-II到STM32F103平台攻略

    文章目录 移植uCOS-II到STM32F103平台 感谢声明 移植前准备工作 移植过程 下载到开发板操作 移植uCOS-II到STM32F103平台 感谢声明 首先感谢wang328452854博主 ...

  7. stm32f103各个型号芯片之间程序移植(stm32的兼容问题)

    stm32f103各个型号芯片之间程序移植(stm32的兼容问题) 1.stm32f103系列的各个型号的芯片差别一般不大,都是一些flash大小不一样,一般是向下兼容(大容量芯片兼容中容量芯片)还有 ...

  8. Microchip Studio 7.0项目移植(从ICC AVR移植到Microchip Studio 7.0)

    Microchip Studio 7.0 系列教程 1.Microchip Studio 7.0 如何修改字体大小Microchip Studio 7.0 如何修改字体大小 2.MicroChip S ...

  9. U-Boot移植教程之二:移植

    内容来自 韦东山<嵌入式Linux应用开发完全手册> 一.U-Boot移植 开发板smdk2410的配置适用于大多数S3C2410单板,或是只需要极少的修改即可使用.但是目前U-Boot中 ...

最新文章

  1. MySQL中表的操作
  2. 程序员面试拼多多,来看看这些面试题你掌握的有多少呢?
  3. 释放锁以及添加线程对于队列的变化
  4. java空格 逗号_Java将字符串中的空格换为逗号
  5. Javascript框架库漏洞验证
  6. java标签组件命名_java编程规范之java命名规范
  7. php接收ajax的表单数据,怎样用Ajax提交表单并接收其中的json数据
  8. 自己学Docker:4.開始了解Docker的工作模式
  9. 2021日喀则市江孜高考成绩查询,2021西藏高考成绩查询时间 西藏高考成绩查询入口...
  10. 使用git作为首页以及克隆上传创建下载删除
  11. Linux netstat 命令安装
  12. MFC中调用WPF教程
  13. 405服务器响应失败,服务器返回HTTP响应代码:405
  14. 处女作《Web全栈开发进阶之路》出版了!
  15. [原创] 我了解北京地区消费贷利息情况
  16. Win10安装应用或打开应用时提示“用户账户控制 为了对电脑进行保护,已经阻止此应用”
  17. 哈达玛矩阵的相关基础知识
  18. Andorid基础 Android系统层次框架结构
  19. J4125小主机部署软路由笔记01
  20. npm私服发包及使用

热门文章

  1. Windows内核漏洞学习笔记
  2. java实现0001....A000...ZA00...ZA99-ZB00...ZZZZ流水号的自动生成
  3. 军队文职(数学2+物理)——考试介绍
  4. 为什么剩余数不能相加_2017年国家公务员考试行测指导:数学运算之剩余问题...
  5. WPF真入门教程12--ListView控件
  6. 实现平衡二叉树(AVL树)的旋转
  7. Java基础学习之cookie
  8. docker mysql修改配置文件
  9. 深度长文:中国产业大迁移全景图
  10. java 并发问题存在的原因 解决方案