2. STM32CubeMX移植OSAL
在STM32平台(或者任何平台)移植分为如下的步骤
创建基本的工程,初始化系统时钟、Systick定时器(或者其他定时器)、初始化基本外设(串口、LED) 将OSAL代码添加到工程,将头文件添加到工程。本文移植的OSAL源代码为GitHub - hotsauce1861/gcc-stm32-osal: ARM-GCC下STM32F1工程模板,运行OSAL操作系统。 运行工程,排除基本的错误。 移植OSAL定时器接口,移植全局中断接口,移植内存管理相关配置。 了解OSAL基本的运行逻辑,完成基本外设的运行操作(串口、LED)。 移植完成的代码如下: https://gitee.com/Pencil888/osal-stm32
2.1 创建基本的工程
打开STM32CubeMx,选择需要配置的芯片,创建工程。 选择RCC(时钟配置),选择外部时钟。 选择SYS(系统配置),选择调试接口为Serial Write,也可以其他调试接口。 选择 Clock Configuration
,按照下图完成时钟配置。 配置LED外设 配置UART1外设 输出工程
2.2 将OSAL代码添加到工程
下载OSAL移植代码 git close https://github.com/hotsauce1861/gcc-stm32-osal.git
,或者直接访问 https://github.com/hotsauce1861/gcc-stm32-osal.git
进行下载。 打开Keil工程,将 OSAL
文件夹拷贝的 上方创建的工程目录下,并将osal 、hal
中的文件添加到keil工程中。 将 include 文件夹添加到C++头文件
2.3 解决基本的错误
SysTick_Handler(void)
重复定义,将 time.h
中的 Systick_Handler(void)
注释掉,在Stm32f1xx_it.c
中Systick_Handler(void)
中添加osal_update_timers();
# include "osal_timer.h"
void SysTick_Handler ( void )
{
osal_update_timers ( ) ;
HAL_IncTick ( ) ;
}
发现好多重复定义,将 type.h
中的 #include "stm32f10x.h"
注释掉 type.h
中 SUCCESS
和 ERROR
有重复定义,将这两个宏定义修改名称,并且在OSAL 中也进行修改。(这里表达的不太详细,但是实际操作一下就会了。很简单)再次运行,已经没有错误。
2.4 移植OSAL接口
移植定时器接口,在上方解决基本的错误中第一点已经完成。 打开和关闭全局中断,打开type.h
,修改如下的代码
# define CLI ( ) __disable_irq ( ) ;
# define SEI ( ) __enable_irq ( ) ;
移植内存相关配置,在32位的单片机。不用修改,具体其中配置的含义在第三个章节有具体分析。
2.5 了解OSAL基本的运行逻辑,完成基本外设的运行操作
创建osal_main.c
文件,添加如下的代码
# include "application.h"
int osal_main ( void )
{
HAL_DISABLE_INTERRUPTS ( ) ;
osal_init_system ( ) ;
osal_add_Task ( Serial_Task_Init, Serial_Task_EventProcess, 1 ) ;
osal_Task_init ( ) ;
osal_mem_kick ( ) ;
HAL_ENABLE_INTERRUPTS ( ) ;
osal_start_reload_timer ( Serial_TaskID, PRINTF_STR, 500 ) ;
osal_start_system ( ) ;
return AERROR;
}
创建serial_task.c
文件,这是任务的初始化、循环函数的文件。
# include "application.h"
# include <string.h>
# include <stdarg.h>
# include <stdio.h>
# include "main.h"
# include "usart.h"
# include "gpio.h"
uint8 Serial_TaskID;
void Serial_Task_Init ( uint8 task_id)
{
Serial_TaskID = task_id;
}
uint16 Serial_Task_EventProcess ( uint8 task_id, uint16 task_event)
{
if ( task_event & SYS_EVENT_MSG )
{
osal_sys_msg_t * MSGpkt;
MSGpkt = ( osal_sys_msg_t * ) osal_msg_receive ( task_id ) ;
while ( MSGpkt )
{
switch ( MSGpkt-> hdr. event )
{
case OSAL_PRINTF:
break ;
default :
break ;
}
osal_msg_deallocate ( ( uint8 * ) MSGpkt ) ;
MSGpkt = ( osal_sys_msg_t * ) osal_msg_receive ( task_id ) ;
}
return ( task_event ^ SYS_EVENT_MSG) ;
}
if ( task_event & PRINTF_STR)
{
static int dir = 1 ;
if ( dir)
{
dir = 0 ;
HAL_GPIO_WritePin ( LED0_GPIO_Port, LED0_Pin, GPIO_PIN_SET) ;
}
else
{
dir = 1 ;
HAL_GPIO_WritePin ( LED0_GPIO_Port, LED0_Pin, GPIO_PIN_RESET) ;
}
HAL_UART_Transmit ( & huart1, "Hello World!" , sizeof ( "Hello World!" ) - 1 , 1000 ) ;
return task_event ^ PRINTF_STR;
}
return 0 ;
}
application.h
其中实现了一些消息队列和任务的定义
# ifndef APPLICATION_H
# define APPLICATION_H
# include "osal.h"
# include "osal_timer.h"
# include "osal_event.h"
# include "osal_memory.h"
# include "osal_msg.h"
typedef struct
{
osal_event_hdr_t hdr;
unsigned char * Data;
} General_SerialData_t;
extern uint8 Serial_TaskID;
extern void Serial_Task_Init ( uint8 task_id) ;
extern uint16 Serial_Task_EventProcess ( uint8 task_id, uint16 task_event) ;
extern void osal_printf ( char * format, . . . ) ;
# define SYS_EVENT_MSG 0x8000
# define PRINTF_STR 0X0001
# define OSAL_PRINTF 0X01
# endif
在main()
函数中调用osal_main();
观察代码运行结果: