[APM32F4]你了解OSAL是个什么吗

## 前言
    最近在学习操作系统,发现了OSAL这个玩意儿,网上查了一下,OSAL的主要目的是提供一个统一的接口,使得上层应用程序能够独立于底层操作系统的具体实现,从而简化多平台开发的复杂性。目前已经有大佬已经完成了OSAL的移植框架,下面简单讲讲怎么将这个玩意儿移植到APM32F407。
## 什么是OSAL?
    OSAL 是“操作系统抽象层”(Operating SystemAbstraction Layer)的缩写。简单来说,OSAL 是一种帮助软件开发者与不同操作系统进行交互的工具或接口。它的主要作用是提供一个统一的平台,使得开发者可以在编写代码时不必过多关心具体操作系统的细节,使得软件能够更容易地在不同的操作系统上运行。
## 为什么需要 OSAL?
    1. 兼容性:不同的操作系统(如Windows、Linux、MacOS 等)有各自的系统调用和管理方式。OSAL 可以隐藏这些差异,让开发者只需要使用统一的接口就能达到相同的效果。
    2. 可移植性:使用OSAL 编写的程序更容易在不同的环境中运行。这样,开发者不需要为每个操作系统单独编写一套代码,只需编写一次,通过OSAL 就可以在多种平台上使用。
    3. 简化开发:OSAL提供了一套简化的开发接口,减少了与底层操作系统交互时的复杂性,开发者可以更专注于应用的功能实现,而不是底层细节。
## OSAL 的组成部分
    OSAL 通常包括一些基本的组件和功能,例如:
        - 线程管理:提供创建、销毁和管理线程的功能。
        - 时间管理:提供时间延迟、计时器等功能。
        - 内存管理:提供动态内存分配和释放的接口。
        - 文件系统访问:提供统一的方式来读写文件。

    想象一下,你正在开发一个需要访问文件和网络的应用。如果不使用 OSAL,当你想要在 Windows 上和 Linux 上运行此应用时,你可能需要分别处理这两个系统的文件和网络接口,这会让工作变得复杂而繁琐。而如果你使用了 OSAL,你只需调用 OSAL 提供的统一函数,无需关心实际底层的实现。
## 源码
    获取地址:https://github.com/mcuwty/osal,其内部代码结构如下。

## 移植
    这份代码原来是在linux上编译运行的,我把它移植到了windows的keil编译环境上。可以直接去geehy官网直接下载一个F4的SDK包,使用里面的模板工程进行移植。
    1、将osal整个文件夹复制到工程路径下。

    2、添加必要的头文件以及源文件
    我这里对OSAL源文件做了一个简单的结构优化,不过总体上不影响使用。

    3、修改注释掉apm32f4xx_int.h中的Sys_Handler,重新实现timer.c文件。
复制
/****************************************************************************************

 * 文件名  :timer.c

 * 描述    :硬件定时器配置文件,为osal操作系统提供系统时钟,移植时需要修改的文件

 * 开发平台:

 * 库版本  :

 ***************************************************************************************/

#include "timer.h"

#include "osal_timer.h"



//硬件定时器初始化,设定系统时钟

void OSAL_TIMER_TICKINIT(void)

{

        SysTick_Config(SystemCoreClock / 1000);

}



//开启硬件定时器

void OSAL_TIMER_TICKSTART(void )

{



}



//关闭硬件定时器

void OSAL_TIMER_TICKSTOP(void )

{



}



//此处添加硬件定时器中断溢出函数,并调用系统时钟更新函数osal_update_timers()

/**

  * [url=home.php?mod=space&uid=247401]@brief[/url]  This function handles SysTick Handler.

  * @param  None

  * @retval None

  */

void SysTick_Handler(void)

{

        osal_update_timers();

}


    4、编写serial_task.c文件

复制
/****************************************************************************************

 * 文件名  :serial_task.c

 * 描述    :系统串口通信任务

 * 开发平台:

 * 库版本  :

 ***************************************************************************************/

#include "application.h"



#include <string.h>

#include <stdarg.h>

#include <stdio.h>



#include "Board.h"



uint8 Serial_TaskID;                                        //系统串口通信任务ID



/*********************************************************************

 * LOCAL FUNCTION PROTOTYPES

 */



/*********************************************************************

 * FUNCTIONS

 *********************************************************************/

//串口通信任务初始化

void Serial_Task_Init(uint8 task_id)

{

    Serial_TaskID = task_id;



    //串口配置初始化

    USART_Config_T usartConfig;

    usartConfig.baudRate = 115200;

    usartConfig.hardwareFlow = USART_HARDWARE_FLOW_NONE;

    usartConfig.mode = USART_MODE_TX_RX;

    usartConfig.parity = USART_PARITY_NONE;

    usartConfig.stopBits = USART_STOP_BIT_1;

    usartConfig.wordLength = USART_WORD_LEN_8B;

    APM_TINY_COMInit(COM1, &usartConfig);

        

    APM_TINY_LEDInit(LED2);

    APM_TINY_LEDInit(LED3);

}



//串口通信任务事件处理

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;

            }



            // Release the memory

            osal_msg_deallocate( (uint8 *)MSGpkt );



            // Next  获取下一个消息

            MSGpkt = (osal_sys_msg_t *)osal_msg_receive( task_id );

        }



        // return unprocessed events

        return (task_event ^ SYS_EVENT_MSG);

        }

          

        if(task_event & PRINTF_STR)

        {

            static int dir = 1;



                if(dir)

                {

                        dir = 0;

                        APM_TINY_LEDOn(LED2);

                }

                else

                {

                        dir = 1;

                        APM_TINY_LEDOff(LED2);

                }

                

                printf("APM32F407 printf !\r\n");

                  

                return task_event ^ PRINTF_STR;

        }



        return 0;

}

    5、编写main函数。
复制
/*!

 * [url=home.php?mod=space&uid=288409]@file[/url]        main.c

 *

 * [url=home.php?mod=space&uid=247401]@brief[/url]       Main program body

 *

 * [url=home.php?mod=space&uid=895143]@version[/url]     V1.0.3

 *

 * [url=home.php?mod=space&uid=212281]@date[/url]        2023-07-31

 *

 * @attention

 *

 *  Copyright (C) 2021-2023 Geehy Semiconductor

 *

 *  You may not use this file except in compliance with the

 *  GEEHY COPYRIGHT NOTICE (GEEHY SOFTWARE PACKAGE LICENSE).

 *

 *  The program is only for reference, which is distributed in the hope

 *  that it will be useful and instructional for customers to develop

 *  their software. Unless required by applicable law or agreed to in

 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT

 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.

 *  See the GEEHY SOFTWARE PACKAGE LICENSE for the governing permissions

 *  and limitations under the License.

 */



/* Includes */

#include "main.h"

#include "Board.h"

#include "stdio.h"

#include "apm32f4xx_gpio.h"

#include "apm32f4xx_adc.h"

#include "apm32f4xx_misc.h"

#include "apm32f4xx_usart.h"

#include "apm32f4xx_tmr.h"



/** @addtogroup Examples

  @{

  */



/** @addtogroup ADC_AnalogWindowWatchdog

  @{

  */



/** @defgroup ADC_AnalogWindowWatchdog_Macros Macros

  @{

*/



/* printf using USART1  */

#define DEBUG_USART  USART1



#define APM_COMInit  APM_TINY_COMInit



/**@} end of group ADC_AnalogWindowWatchdog_Macros*/



/** @defgroup ADC_AnalogWindowWatchdog_Functions Functions

  @{

  */



#include "application.h"



/*!

 * [url=home.php?mod=space&uid=247401]@brief[/url]     Main program

 *

 * @param     None

 *

 * @retval    None

 */

int main(void)

{    

        //系统硬件、外设等初始化

        

        //禁止中断

    HAL_DISABLE_INTERRUPTS();



    //osal操作系统初始化

    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, 1000);



        //启动osal系统,不会再返回

        osal_start_system();

}





#if defined (__CC_ARM) || defined (__ICCARM__) || (defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050))



/*!

* [url=home.php?mod=space&uid=247401]@brief[/url]       Redirect C Library function printf to serial port.

*              After Redirection, you can use printf function.

*

* @param       ch:  The characters that need to be send.

*

* @param       *f:  pointer to a FILE that can recording all information

*              needed to control a stream

*

* @retval      The characters that need to be send.

*

* @note

*/

int fputc(int ch, FILE* f)

{

    /* send a byte of data to the serial port */

    USART_TxData(DEBUG_USART, (uint8_t)ch);



    /* wait for the data to be send */

    while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);



    return (ch);

}



#elif defined (__GNUC__)



/*!

* [url=home.php?mod=space&uid=247401]@brief[/url]       Redirect C Library function printf to serial port.

*              After Redirection, you can use printf function.

*

* @param       ch:  The characters that need to be send.

*

* @retval      The characters that need to be send.

*

* @note

*/

int __io_putchar(int ch)

{

    /* send a byte of data to the serial port */

    USART_TxData(DEBUG_USART, ch);



    /* wait for the data to be send */

    while (USART_ReadStatusFlag(DEBUG_USART, USART_FLAG_TXBE) == RESET);



    return ch;

}



/*!

* [url=home.php?mod=space&uid=247401]@brief[/url]       Redirect C Library function printf to serial port.

*              After Redirection, you can use printf function.

*

* @param       file:  Meaningless in this function.

*

* @param       *ptr:  Buffer pointer for data to be sent.

*

* @param       len:  Length of data to be sent.

*

* @retval      The characters that need to be send.

*

* @note

*/

int _write(int file, char* ptr, int len)

{

    int i;

    for (i = 0; i < len; i++)

    {

        __io_putchar(*ptr++);

    }



    return len;

}



#else

#warning Not supported compiler type

#endif



/**@} end of group ADC_AnalogWindowWatchdog_Functions */

/**@} end of group ADC_AnalogWindowWatchdog */

/**@} end of group Examples */
## 现象

## 总结
    OSAL 是一种能够帮助开发者编写更灵活、可移植代码的工具。通过抽象化操作系统的底层细节,OSAL使得在不同环境中开发和运行软件变得更简单。
    针对OSAL跟RTOS的区别,我做了一份简单的表格。
  
特性
  
OSAL(操作系统抽象层)
RTOS(实时操作系统)
定义
OSAL 是一种软件层,提供对不同操作系统的抽象,以便于在不同平台上进行可移植和可重用的代码开发。
RTOS 是一种操作系统,设计用于实时应用程序中,确保任务在严格的时间约束内执行。
目标
实现代码的可移植性,简化对不同操作系统的适配过程。
提供实时任务调度和响应能力,确保时间敏感的操作具备准确性和可靠性。
应用场景
被用于需要在多个不同操作系统上运行的应用程序中,例如嵌入式系统。
被用于对时间要求严格的应用场景,如飞行控制、医疗设备、工业自动化等。
抽象层级
提供更高层次的抽象,隐藏底层操作系统的细节。
涉及底层硬件管理,提供任务调度、中断管理、时间管理等基本功能。
复杂性
通常较低,功能较简单,主要关注可移植性。
较高,需处理更多的底层细节和实时性要求。
性能
性能开销较小,主要取决于底层操作系统的表现。
性能要求高,需确保任务在严格时间内执行。
易用性
提供一致的接口,简化开发步骤。
需要对实时调度算法、任务优先级等有深入理解。

    如果有条件的话,最好选择使用实时操作系统(RTOS),因为它的功能比较丰富。如果不使用RTOS,操作系统抽象层(OSAL)也是一个不错的选择。不过,使用OSAL之前,最好先对它的源码有一定的了解,这样在遇到问题时才能更有效地解决。

附件:

1.   APM32F4 OSAL.zip (807.36 KB)


2. 

 osal源码.zip (176.79 KB)。
---------------------
作者:DKENNY
链接:https://bbs.21ic.com/icview-3394814-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。

   

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值