OS 抽象层

[English]

抽象层介绍

  • OS抽象层主要为了适配Armino平台不同的操作系统

  • 对于不同的操作系统,OS抽象层对外提供一套统一的接口

  • 目前Armino平台OS抽象层支持的操作系统为FreeRTOS.

  • 目前Armino平台posix接口仅支持FreeRTOS V10操作系统,默认关闭,若使用,需要打开CONFIG_FREERTOS_POSIX配置开关

备注

  • 在使用FreeRTOS的posix功能的时候,在引用posix相关头文件之前,需要先引用FreeRTOS_POSIX.h头文件;

  • 可以在components/bk_rtos/freertos/posix/freertos_impl/include/portable/bk/FreeRTOS_POSIX_portable.h中自定义相关配置,比如某些功能或者数据结构想使用自定义或者编译器自带的,可以在该文件中屏蔽掉posix相关功能。

  • 在移植posix时,如果遇到与编译器自带的头文件有冲突的情况,请优先检查以上两条。

抽象层API

任务创建:

  • 在CPU0上创建任务:

    bk_err_t rtos_create_thread( beken_thread_t* thread,
                                uint8_t priority,
                                const char* name,
                                beken_thread_function_t function,
                                uint32_t stack_size,
                                beken_thread_arg_t arg )
    
    内部会将core id指定为CPU0。该函数是为了兼容单核架构的接口。
    
    参数说明:
    -thread: 指向创建任务的句柄
    -priority: 任务优先级
     需要注意的是:对于freertos操作系统内核,任务对应的优先级数字越大,则实际的优先级越大。
     而对于应用层而言则相反,创建任务时配置的优先级数字越大,实际的优先级越小。
     这是因为在SDK中,操作系统适配层做了统一的管理。所以用户视角看到的最大优先级为0,最小优先级为9。
     建议用户在创建优先级时配置为6到8的范围。
    -name :创建的任务名称
    -function:指向任务体入口函数
    -stack_size:任务堆栈的大小,单位为字节
    -arg:传递给任务函数体的参数
    
    返回值:
    -kNoErr:任务创建成功
    -kGeneralErr: 任务创建失败
    
  • 在CPU0或者CPU1上创建任务:

    bk_err_t rtos_smp_create_thread( beken_thread_t* thread,
                                     uint8_t priority,
                                     const char* name,
                                     beken_thread_function_t function,
                                     uint32_t stack_size,
                                     beken_thread_arg_t arg )
    
  • 将任务指定在CPU0上创建:

    bk_err_t rtos_core0_create_thread( beken_thread_t* thread,
                                       uint8_t priority,
                                       const char* name,
                                       beken_thread_function_t function,
                                       uint32_t stack_size,
                                       beken_thread_arg_t arg )
    
  • 将任务指定在CPU1上创建:

    bk_err_t rtos_core1_create_thread( beken_thread_t* thread,
                                       uint8_t priority,
                                       const char* name,
                                       beken_thread_function_t function,
                                       uint32_t stack_size,
                                       beken_thread_arg_t arg )
    
  • 不绑定核且在psram上创建任务:

    bk_err_t rtos_create_psram_thread( beken_thread_t* thread,
                                       uint8_t priority,
                                       const char* name,
                                       beken_thread_function_t function,
                                       uint32_t stack_size,
                                       beken_thread_arg_t arg )
    
  • 将任务指定在CPU0上且在psram中创建:

    bk_err_t rtos_core0_create_psram_thread( beken_thread_t* thread,
                                             uint8_t priority, const char* name,
                                             beken_thread_function_t function,
                                             uint32_t stack_size,
                                             beken_thread_arg_t arg )
    
  • 将任务指定在CPU1上且在psram中创建:

    bk_err_t rtos_core1_create_psram_thread( beken_thread_t* thread,
                                             uint8_t priority, const char* name,
                                             beken_thread_function_t function,
                                             uint32_t stack_size,
                                             beken_thread_arg_t arg )
    

备注

上述API中的CPU0和CPU1是从内核的视角,对应的逻辑CPU。

任务挂起与恢复:

  • 在某个core上挂起某个任务:

    void rtos_suspend_thread(beken_thread_t* thread)
    
    参数说明:
    -thread:任务的句柄,如果传入的参数为NULL,代表是挂起或恢复自身
    
  • 在某个core上挂起调度器:

    void rtos_suspend_all_thread(void)
    
  • 在某个core上恢复某个任务:

    void rtos_resume_thread(beken_thread_t* thread)
    
  • 在某个core上恢复调度器:

    void rtos_resume_all_thread(void)
    

其他任务相关接口:

除了对底层标准的任务接口进行封装外,适配层还提供了以下和任务相关的接口.

  • 任务删除:

    bk_err_t rtos_delete_thread( beken_thread_t* thread )
    
  • 判断指定的线程是否为当前正在运行的线程:

    bool rtos_is_current_thread(beken_thread_t *thread)
    
    参数:
    -Thread:指定的任务句柄
    
    返回值:
    -true:是当前任务
    -false: 不是当前任务
    
  • 获取当前正在运行的任务句柄:

    beken_thread_t*rtos_get_current_thread(void)
    
    返回值:当前任务句柄
    
  • 设置指定任务的优先级:

    bk_err_t rtos_thread_set_priority(
                beken_thread_t *thread,
                int priority)
    
  • 将一个任务挂起指定的时间,单位为秒:

    void rtos_thread_sleep(uint32_t seconds)
    
  • 将一个任务挂起指定的毫秒时间:

    bk_err_t rtos_delay_milliseconds(uint32_t num_ms )
    

备注

任务延时会触发系统调度

队列:

  • 初始化一个队列:

    bk_err_t rtos_init_queue( beken_queue_t* queue,
                            const char* name,
                            uint32_t message_size,
                            uint32_t number_of_messages )
    参数说明:
    -queue:队列的句柄
    -name: 队列的名称
    -message_size: 队列中消息的大小
    -number_of_messages:消息的总长度(等同于队列的深度)
    
    返回值:
    -kNoErr:队列操作成功
    -kGeneralErr: 队列操作失败
    
  • 往队列尾部发送消息:

    bk_err_t rtos_push_to_queue( beken_queue_t* queue,
                                 void* message,
                                 uint32_t timeout_ms )
    
    内部会判断当前是处于中断上下文还是任务上下文,从而调用不同的内核接口实现对应的功能
    
    参数说明:
    -timeout_ms:超时时间,可配置为
        0代表不超时
        BEKEN_WAIT_FOREVER,代表一直超时阻塞
        其他值,代表时间的超时时间
    
  • 往队列头部发送消息:

    bk_err_t rtos_push_to_queue_front( beken_queue_t* queue,
                                       void* message,
                                       uint32_t timeout_ms )
    
    内部会判断当前是处于中断上下文还是任务上下文,从而调用不同的内核接口实现对应的功能
    
  • 从队列接收消息:

    bk_err_t rtos_pop_from_queue( beken_queue_t* queue,
                                  void* message,
                                  uint32_t timeout_ms )
    
    内部调用的是xQueueReceive,仅支持在任务上下文使用
    
  • 删除一个队列:

    bk_err_t rtos_deinit_queue( beken_queue_t* queue )
    
  • 判断一个队列是否为空:

    bool rtos_is_queue_empty( beken_queue_t* queue )
    
    仅能在中断上下文中调用
    
  • 判断一个队列是否已满:

    bool rtos_is_queue_full( beken_queue_t* queue )
    
    仅能在中断上下文中调用
    

信号量:

  • 创建一个计数信号量,设置初始值为0:

    bk_err_t rtos_init_semaphore( beken_semaphore_t* semaphore,
                                  int maxCount )
    
  • 创建一个计数信号量,初始值设置为init_count:

    int rtos_get_semaphore_count( beken_semaphore_t* semaphore )
    
  • 获取当前的信号量计数值:

    int rtos_get_semaphore_count( beken_semaphore_t* semaphore )
    
  • 释放信号量:

    int rtos_set_semaphore( beken_semaphore_t* semaphore )
    
    支持在中断上下文或任务上下文使用
    
  • 获取信号量:

    bk_err_t rtos_get_semaphore( beken_semaphore_t* semaphore,
                                uint32_t timeout_ms )
    
    仅支持在任务上下文使用
    
    参数说明:
    -Semaphore: 信号量句柄
    -timeout_ms: 超时时间,可配置为
        0代表不超时
        BEKEN_WAIT_FOREVER,代表一直超时阻塞
        其他值,代表时间的超时时间
    
    返回值:
    -kNoErr:信号量操作成功
    -kGeneralErr或kTimeoutErr: 信号量操作失败
    
  • 删除一个已创建的信号量:

    bk_err_t rtos_deinit_semaphore( beken_semaphore_t* semaphore )
    

互斥锁:

  • 初始化一个互斥锁:

    bk_err_t rtos_init_mutex( beken_mutex_t* mutex )
    
  • 尝试获取一个互斥锁,超时时间为0:

    bk_err_t rtos_trylock_mutex(beken_mutex_t *mutex)
    
  • 无限等待获取一个互斥锁:

    bk_err_t rtos_lock_mutex( beken_mutex_t* mutex )
    
  • 释放一个互斥锁:

    bk_err_t rtos_unlock_mutex( beken_mutex_t* mutex )
    
  • 删除一个互斥锁:

    bk_err_t rtos_deinit_mutex( beken_mutex_t* mutex )
    
  • 初始化一个递归互斥锁:

    bk_err_t rtos_init_recursive_mutex( beken_mutex_t* mutex )
    
  • 获取一个递归互斥锁:

    bk_err_t rtos_lock_recursive_mutex( beken_mutex_t* mutex )
    
  • 释放一个递归互斥锁:

    bk_err_t rtos_unlock_recursive_mutex( beken_mutex_t* mutex )
    
  • 删除一个递归互斥锁:

    bk_err_t rtos_deinit_recursive_mutex( beken_mutex_t* mutex )
    

软件定时器:

  • 初始化一个单次软件定时器:

    bk_err_t rtos_init_oneshot_timer( beken2_timer_t *timer,
                                      uint32_t time_ms,
                                      timer_2handler_t function,
                                      void* larg,
                                      void* rarg )
    
  • 开启单次软件定时器:

    bk_err_t rtos_start_oneshot_timer( beken2_timer_t* timer )
    
  • 停止单次软件定时器:

    bk_err_t rtos_stop_oneshot_timer( beken2_timer_t* timer )
    
  • 复位单次软件定时器:

    bk_err_t rtos_oneshot_reload_timer( beken2_timer_t* timer )
    
  • 复位单次软件定时器,并重新设置定时时间与回调:

    bk_err_t rtos_oneshot_reload_timer_ex(beken2_timer_t *timer,
                                          uint32_t time_ms,
                                          timer_2handler_t function,
                                          void *larg,
                                          void *rarg)
    
  • 判断单次软件定时器是否初始化:

    bool rtos_is_oneshot_timer_init( beken2_timer_t* timer )
    
  • 判断单次软件定时器是否在运行:

    bool rtos_is_oneshot_timer_running( beken2_timer_t* timer )
    
  • 删除单次软件定时器:

    bk_err_t rtos_deinit_oneshot_timer( beken2_timer_t* timer )
    
  • 创建周期软件定时器:

    bk_err_t rtos_init_timer( beken_timer_t *timer,
                              uint32_t time_ms,
                              timer_handler_t function,
                              void* arg )
    
  • 开启周期软件定时器:

    bk_err_t rtos_start_timer( beken_timer_t* timer )
    
  • 停止周期软件定时器:

    bk_err_t rtos_stop_timer( beken_timer_t* timer )
    
  • 复位周期软件定时器:

    bk_err_t rtos_reload_timer( beken_timer_t* timer )
    
  • 修改周期软件定时器定时时间:

    bk_err_t rtos_change_period( beken_timer_t* timer,
                                 uint32_t time_ms)
    
  • 删除周期软件定时器:

    bk_err_t rtos_deinit_timer( beken_timer_t* timer )
    
  • 获取周期软件定时器到期时间:

    uint32_t rtos_get_timer_expiry_time( beken_timer_t* timer )
    
  • 判断周期软件定时器是否初始化:

    bool rtos_is_timer_init( beken_timer_t* timer )
    
  • 判断周期软件定时器是否在运行:

    bool rtos_is_timer_running( beken_timer_t* timer )
    

备注

  1. 软件定时器的精度与系统时钟节拍周期有关,如果配置的系统节拍数为1000,也就是节拍时钟为1ms。

  2. 软件定时器的回调函数中应快进快出,不允许使用任何可能引起软件定时器任务挂起或者阻塞的API接口,在回调函数中不能出现死循环。

事件:

  • 创建事件:

    bk_err_t rtos_init_event_flags( beken_event_t* event_flags )
    
  • 等待事件标志:

    beken_event_flags_t rtos_wait_for_event_flags( beken_event_t* event_flags,
                                    uint32_t flags_to_wait_for,
                                    beken_bool_t clear_set_flags,
                                    beken_event_flags_wait_option_t wait_option,
                                    uint32_t timeout_ms )
    
    参数说明:
    -event_flags:事件句柄
    -flags_to_wait_for:一个按位或的值,指定需要等待事件组中的哪些位置1
    -clear_set_flags:设置为pdTRUE时,当xEventGroupWaitBits()等待到满足任务唤醒的事件时,系统将清除由形参uxBitsToWaitFor 指定的事件标志位。
    -wait_option:pdTRUE : flags_to_wait_for 指定的位都置位的时候,“逻辑与”等待事件,并且在没有超时的情况下返回对应的事件标志位的值。否则其中任意一个置位
                            的时候,这也是常说的“逻辑或”等待事件,在没有超时的情况下函数返回对应的事件标志位的值。
    -timeout_ms:超时等待时间
    
    返回值:
    -返回事件中的哪些事件标志位被置位,返回值很可能并不是用户指定的事件位,需要对返回值进行判断再处理。
    
  • 设置事件标志:

    void rtos_set_event_flags( beken_event_t* event_flags, uint32_t flags_to_set )
    
    参数说明:
    -event_flags:事件句柄
    -flags_to_set:指定事件中的事件标志位
    
  • 设置事件标志:

    beken_event_flags_t rtos_clear_event_flags( beken_event_t* event_flags, uint32_t flags_to_clear )
    
  • 同步事件标志:

    beken_event_flags_t rtos_sync_event_flags( beken_event_t* event_flags,
                                               uint32_t flags_to_set,
                                               uint32_t flags_to_wait_for,
                                               uint32_t timeout_ms)
    
    原子地设置事件组中的位,然后等待同一事件组中的位组合被设置
    
  • 删除事件:

    bk_err_t rtos_deinit_event_flags( beken_event_t* event_flags )
    

更多OS API信息,请参考: