完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
总览
本文基于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连接引脚为(PB5PB6PB7),低电平点亮;串口为USART1(PA9,PA10),采用DMA+空闲中断的方式接收数据。我们利用STM32CubeMX来生成裸机工程(STM32CubeMX的使用本文不详细描述),设置如下: 1、引脚配置
2、时钟配置 3、串口配置 4、生成代码 勾选生成对应外设驱动的‘.c/.h’文件,生成代码。 打开工程,加入LED开关状态的宏定义和串口空闲中断接收的代码,具体如下(当然,如果你不使用DMA+空闲中断的方式,也可以不进行下边2中的修改,但是一定要重定向printf函数): 1、在main.h中加入LED宏定义代码。 1 #define LED1_ON() HAL_GPIO_WritePin(GPIOB, LED1_Pin, GPIO_PIN_RESET)2 #define LED1_OFF() HAL_GPIO_WritePin(GPIOB, LED1_Pin, GPIO_PIN_SET)3 4 #define LED2_ON() HAL_GPIO_WritePin(GPIOB, LED2_Pin, GPIO_PIN_RESET)5 #define LED2_OFF() HAL_GPIO_WritePin(GPIOB, LED2_Pin, GPIO_PIN_SET)6 7 #define LED3_ON() HAL_GPIO_WritePin(GPIOB, LED3_Pin, GPIO_PIN_RESET)8 #define LED3_OFF() HAL_GPIO_WritePin(GPIOB, LED3_Pin, GPIO_PIN_SET)2、实现串口空闲中断接收 在usart.h中加入如下代码: 1 #define UART1_BUFF_SIZE 256 //串口接收缓存区长度 2 typedef struct 3 { 4 uint8_t RxFlag; //空闲接收标记 5 uint16_t RxLen; //接收长度 6 uint8_t *RxBuff; //DMA接收缓存 7 }USART_RECEIVETYPE; 8 extern USART_RECEIVETYPE Uart1Rx; 9 void USART1_ReceiveIDLE(void);10 void UART_SendData(USART_TypeDef * Uart,uint8_t *buff,uint16_t size);11 在usart.c中加入如下代码12 static uint8_t Uar1tRxBuff[UART1_BUFF_SIZE+1]; //定义串口接收buffer13 USART_RECEIVETYPE Uart1Rx = {14 .RxBuff = Uar1tRxBuff,15 };16 17 void USART1_ReceiveIDLE(void) 18 { 19 uint32_t temp; 20 if((__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE) != RESET)) 21 {22 __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE); 23 temp = huart1.Instance->SR;24 temp = huart1.Instance->DR;25 HAL_UART_DMAStop(&huart1); 26 temp = huart1.hdmarx->Instance->CNDTR; 27 Uart1Rx.RxLen = UART1_BUFF_SIZE - temp; 28 Uart1Rx.RxFlag=1; 29 Uart1Rx.RxBuff[Uart1Rx.RxLen] = 0;30 HAL_UART_Receive_DMA(&huart1,Uart1Rx.RxBuff,UART1_BUFF_SIZE); 31 } 32 }33 void UART_SendByte(USART_TypeDef * Uart,uint8_t data)34 { 35 Uart->DR = data;36 while((Uart->SR&UART_FLAG_TXE)==0);37 while((Uart->SR&UART_FLAG_TC)==0); 38 }39 void UART_SendData(USART_TypeDef * Uart,uint8_t *buff,uint16_t size)40 {41 while(size--)42 {43 Uart->DR = *(buff++);44 while((Uart->SR&UART_FLAG_TXE)==0);45 }46 while((Uart->SR&UART_FLAG_TC)==0); 47 }48 ///重定向c库函数printf到USART149 int fputc(int ch, FILE *f)50 {51 /* 发送一个字节数据到USART1 */52 UART_SendByte(USART1, (uint8_t) ch);53 return (ch);54 }55 56 ///重定向c库函数scanf到USART157 int fgetc(FILE *f)58 {59 /* 等待串口1输入数据 */60 while((USART1->SR&UART_FLAG_RXNE)==0);61 return (int)USART1->DR&0xff;62 } 修改void MX_USART1_UART_Init(void),在最后加入以下代码: 1 //add for DMA.Idle interrupt2 __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_IDLE); 3 __HAL_UART_CLEAR_FLAG(&huart1,UART_FLAG_TC); 4 HAL_UART_Receive_DMA(&huart1, Uart1Rx.RxBuff, UART1_BUFF_SIZE); //开启DMA接收 5 __HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE); //使能空闲中断在stm32f1xx_it.c中声明USART1_ReceiveIDLE,并在串口中断中调用该函数: 1 void USART1_ReceiveIDLE(void); 2 3 void USART1_IRQHandler(void) 4 { 5 /* USER CODE BEGIN USART1_IRQn 0 */ 6 USART1_ReceiveIDLE(); 7 /* USER CODE END USART1_IRQn 0 */ 8 HAL_UART_IRQHandler(&huart1); 9 /* USER CODE BEGIN USART1_IRQn 1 */ 10 11 /* USER CODE END USART1_IRQn 1 */ 12 } 3、在main.c的main中添加代码验证裸机工程 1 while (1) 2 { 3 /* USER CODE END WHILE */ 4 5 /* USER CODE BEGIN 3 */ 6 LED1_ON(); 7 LED2_ON(); 8 LED3_ON(); 9 HAL_Delay(300); 10 LED1_OFF(); 11 LED2_OFF(); 12 LED3_OFF(); 13 HAL_Delay(300); 14 printf("This is the uart test!rn"); 15 if(Uart1Rx.RxFlag){ 16 Uart1Rx.RxFlag = 0; 17 UART_SendData(USART1,Uart1Rx.RxBuff,Uart1Rx.RxLen); 18 } 19 } 编译下载代码,程序正常运行,LED闪烁,同时打印字符串。 经过上述操作,我们已经完成了裸机工程的准备工作。 二、内核移植 1、下载LiteOS 注:LiteOS 最新特性都存放在 develop 分支中,建议取该分支代码进行学习。本文的代码即为 develop分支代码。 点击链接进入LiteOS代码仓库首页,切换至develop分支,点击右侧“Clone or download”按钮,选择Download ZIP,下载代码,如下图所示: LiteOS内核代码目录结构如下图所示: |
|
|
|
2、拷贝内核代码
在工程目录下新建LiteOS文件夹(文件夹名称个人自定义),从上一步下载的LiteOS内核源码中,将arch、kernel、targetsSTM32F103VET6_NB_GCCOS_CONFIG 拷贝至LiteOS文件夹内,如下图所示: arch 中是CPU架构相关的代码;kernel是LiteOS内核代码;OS_CONFIG中是配置内核功能的头文件,可用于裁剪内核功能,我们从官方提供的例程中拷贝过来(可从target文件夹给出的例子中任意拷贝一个)。 3、向MDK工程添加内核文件 打开MDK工程,打开Mange Project Items。
1 archarmarm-msrc 目录下的全部文件:2 los_hw.c3 los_hw_tick.c4 los_hwi.c5 archarmarm-mcortex-m3keil 目录下的:6 los_dispatch_keil.S 如下图所示: 注:点击AddFiles时,MDK默认添加.c类型的文件。los_dispatch_keil.S是汇编文件,因此在添加时,需要将文件类型选择为All files。
1 kernelbasecore 下面全部 .c 文件2 kernelbaseipc 下面全部 .c 文件3 kernelbasemembestfit_little 下面全部 .c 文件4 kernelbasememcommon 下面全部 .c 文件5 kernelbasememmembox 下面全部 .c 文件6 kernelbasemisc 下面全部 .c 文件7 kernelbaseom 下面全部 .c 文件8 kernelextendedtickless 下面全部 .c 文件 (如不使用tickless,可不添加)9 kernel 下面的 los_init.c 说明:liteos提供三套动态内存算法,位于kernel/base/mem目录下,分别为bestfit、bestfit_little、tlsf,我们本次移植的是bestfit_little.可根据需求移植其他的算法。kernelbasememmembox目录下是 LiteOS 提供的静态内存算法,与动态内存算法不冲突。 4、配置头文件 如下图所示,依次点击1、2、3,打开头文件配置窗口: 头文件配置如下图所示: 需要添加的头文件路径为: 1 archarmarm-minclude2 3 kernelinclude4 5 kernelbaseinclude6 7 kernelextendedinclude8 9 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大小进行修改。 这里我们使用的是STM32F103C8T6,其SRAM为20KB。
target_config.h 文件还有很多其他宏定义,主要是配置内核的功能。比如是否使用队列、软件定时器、是否使用时间片、信号量等。 经过以上的操作,LiteOS的移植就完成了。点击编译。 7、创建一个任务 经过前面的操作,移植工作就完成了,这里我们可以创建一个任务,使用LiteOS。在下边的例子中,我们创建了两个任务,一个任务按照2S的周期点亮LED1,另外一个任务按照400毫秒的周期点亮LED2。以下是代码实现: 1 /* Includes ------------------------------------------------------------------*/ 2 #include "main.h" 3 #include "dma.h" 4 #include "usart.h" 5 #include "gpio.h" 6 7 /* Private includes ----------------------------------------------------------*/ 8 /* USER CODE BEGIN Includes */ 9 #include "los_sys.h" 10 #include "los_task.ph" 11 #include "los_memory.ph" 12 /* USER CODE END Includes */ 13 /* Private function prototypes -----------------------------------------------*/ 14 void SystemClock_Config(void); 15 /* USER CODE BEGIN PFP */ 16 17 /* USER CODE END PFP */ 18 19 /* Private user code ---------------------------------------------------------*/ 20 /* USER CODE BEGIN 0 */ 21 static void Led1Task(void) 22 { 23 while(1) { 24 LED1_ON(); 25 LOS_TaskDelay(1000); 26 LED1_OFF(); 27 LOS_TaskDelay(1000); 28 } 29 } 30 static void Led2Task(void) 31 { 32 while(1) { 33 LED2_ON(); 34 LOS_TaskDelay(200); 35 LED2_OFF(); 36 LOS_TaskDelay(200); 37 } 38 } 39 UINT32 RX_Task_Handle; 40 UINT32 TX_Task_Handle; 41 static UINT32 AppTaskCreate(void) 42 { 43 UINT32 uwRet = LOS_OK; 44 TSK_INIT_PARAM_S task_init_param; 45 46 task_init_param.usTaskPrio = 4; 47 task_init_param.pcName = "RxTask"; 48 task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Led1Task; 49 task_init_param.uwStackSize = 512; 50 uwRet = LOS_TaskCreate(&RX_Task_Handle, &task_init_param); 51 if (uwRet != LOS_OK) 52 { 53 printf("Led1Task create failed,%Xn",uwRet); 54 return uwRet; 55 } 56 57 task_init_param.usTaskPrio = 4; 58 task_init_param.pcName = "TxTask"; 59 task_init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)Led2Task; 60 task_init_param.uwStackSize = 512; 61 uwRet = LOS_TaskCreate(&TX_Task_Handle, &task_init_param); 62 if (uwRet != LOS_OK) 63 { 64 printf("Led2Task create failed,%Xn",uwRet); 65 return uwRet; 66 } 67 return LOS_OK; 68 } 69 /* USER CODE END 0 */ 70 71 /** 72 * @brief The application entry point. 73 * @retval int 74 */ 75 int main(void) 76 { 77 /* USER CODE BEGIN 1 */ 78 UINT32 uwRet = LOS_OK; 79 80 /* USER CODE END 1 */ 81 82 83 /* MCU Configuration--------------------------------------------------------*/ 84 85 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 86 HAL_Init(); 87 88 /* USER CODE BEGIN Init */ 89 90 /* USER CODE END Init */ 91 92 /* Configure the system clock */ 93 SystemClock_Config(); 94 95 /* USER CODE BEGIN SysInit */ 96 97 /* USER CODE END SysInit */ 98 99 /* Initialize all configured peripherals */ 100 MX_GPIO_Init(); 101 MX_DMA_Init(); 102 MX_USART1_UART_Init(); 103 /* USER CODE BEGIN 2 */ 104 LOS_KernelInit(); 105 uwRet = AppTaskCreate(); 106 if(uwRet != LOS_OK) { 107 printf("LOS Creat task failedrn"); 108 //return LOS_NOK; 109 } 110 LOS_Start(); 111 /* USER CODE END 2 */ 112 113 /* Infinite loop */ 114 /* USER CODE BEGIN WHILE */ 115 while (1) 116 { 117 /* USER CODE END WHILE */ 118 119 /* USER CODE BEGIN 3 */ 120 //code below are used to verify the hardware. 121 LED1_ON(); 122 LED2_ON(); 123 LED3_ON(); 124 HAL_Delay(300); 125 LED1_OFF(); 126 LED2_OFF(); 127 LED3_OFF(); 128 HAL_Delay(300); 129 printf("This is the uart test!rn"); 130 } 131 /* USER CODE END 3 */ 132 } 133 134 /** 135 * @brief System Clock Configuration 136 * @retval None 137 */ 138 void SystemClock_Config(void) 139 { 140 RCC_OscInitTypeDef RCC_OscInitStruct = {0}; 141 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; 142 143 /** Initializes the CPU, AHB and APB busses clocks 144 */145 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;146 RCC_OscInitStruct.HSIState = RCC_HSI_ON;147 RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;148 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;149 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI_DIV2;150 RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL16;151 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)152 {153 Error_Handler();154 }155 /** Initializes the CPU, AHB and APB busses clocks 156 */157 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK158 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;159 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;160 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;161 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;162 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;163 164 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)165 {166 Error_Handler();167 }168 }169 170 /* USER CODE BEGIN 4 */171 172 /* USER CODE END 4 */173 174 /**175 * @brief This function is executed in case of error occurrence.176 * @retval None177 */178 void Error_Handler(void)179 {180 /* USER CODE BEGIN Error_Handler_Debug */181 /* User can add his own implementation to report the HAL error return state */182 183 /* USER CODE END Error_Handler_Debug */184 }185 186 #ifdef USE_FULL_ASSERT187 /**188 * @brief Reports the name of the source file and the source line number189 * where the assert_param error has occurred.190 * @param file: pointer to the source file name191 * @param line: assert_param error line source number192 * @retval None193 */194 void assert_failed(uint8_t *file, uint32_t line)195 { 196 /* USER CODE BEGIN 6 */197 /* User can add his own implementation to report the file name and line number,198 tex: printf("Wrong parameters value: file %s on line %drn", file, line) */199 /* USER CODE END 6 */200 }201 #endif /* USE_FULL_ASSERT */ 附件为移植好的工程代码。 (代码中有串口空闲中断+DMA的样例代码,可参考。利用串口空闲中断,可以很好的实现数据分帧) |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1780 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1621 浏览 1 评论
1081 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
728 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1679 浏览 2 评论
1938浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
731浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
570浏览 3评论
596浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
556浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-23 21:59 , Processed in 0.796749 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号