RISCV_mailbox使用参考


REVISION HISTORY

Revision No.
Description
Date
1.0 Initial release 08/18/2025

1. 概述

这个模块可以称为mailbox,但是mailbox也是一组片上的多个核心都可以访问到的寄存器,通过结合这些寄存器与共享内存,可用实现核间通信。在这里,用于uboot和FreeRTOS的通信。

2. 关键字说明

  • mailbox/mbx

    mbx是mailbox的缩写,狭义上特指芯片上一组多个核心都可以访问到的寄存器,广义上也指这个功能模块。

  • uboot

    linux的引导程序,运行在linux启动之前。

3. 功能描述

本模块用于uboot与FreeRTOS的简单通信。由于发送和接收都没有竞争保护,不能在多个并行任务中同时进行发送或接收。这个功能是单工的,接收和发送无法同时进行,一端在发送时,另一端无法发送。由于没有信道的竞争保护,通信的双方只能有一个主动端,即只有一端可以主动发送,另一端只能被动地在收到消息后回复。

3.1. 原理

在初始化时,先通过mailbox寄存器,通信双方确立一块共享内存,然后使用两个mailbox寄存器,一个用于通报arm to riscv的消息长度,当这个mailbox有非零值length时,表示共享内存里面有length长度的arm to riscv消息,另一个用于通报riscv to arm的消息长度,当这个mailbox有非零值length时,表示共享内存里面有length长度的riscv to arm消息。

由于共享内存只有一块,所以这个功能是单工的,发送和接收无法同时进行。

uboot部分的代码位于

Alkaid/boot/drivers/sstar/riscv/drv_riscv.c

FreeRTOS部分的代码位于

Alkaid/riscv/kernel/rtk/proj/sc/driver/sysdriver/mbx_msg/src/mbx_msg.c

3.2. 初始化

初始化主要用于双方确立一块共享内存,并通过最后的握手表示双方都已经就绪。

3.3. 接收

以riscv为例,流程如下

3.4. 发送

以riscv为例,流程如下

由于是单工的,发送时要先确保接收已经完成

3.5. 信道的竞争保护

在单端上,由于发送和接收都没有竞争保护,所以发送和接收都不支持多任务。在双端上,由于是单工的,且双方没有对信道的竞争机制,比如riscv发送时查询完MBX_ARM_TO_RISCV,确认其为0,但有可能arm同时在发送,且正好拷贝完成,只是还没写入MBX_ARM_TO_RISCV,就会导致arm端写入的数据被覆盖。为了防止这种情况的发生,通信的双方只能有一个主动端,即只有一方可以主动发送消息,另一方只能被动地在接收到消息后进行回复。

4. Mailbox Demo

4.1. Demo简介

Demo由两部分组成,一个是uboot app,一个是FreeRTOS下的app,两个app间使用mailbox进行通信。

在这个demo里,用户在uboot端手动发送消息到FreeRTOS端,FreeRTOS端收到消息后在尾部加上": id"再发送回来,其中id是一个计数,每次通信+1。

4.2. uboot app

uboot上需要打开如下配置

CONFIG_SSTAR_RISCV=y

可以通过make menuconfig配置

demo代码位于

Alkaid/boot/cmd/sstar/riscv.c

4.3. FreeRTOS app

FreeRTOS下默认是打开的,代码位于

Alkaid/riscv/kernel/rtk/proj/sc/application/uboot_app/src/uboot_app.c

运行结果如下

5. API参考

5.1. uboot API参考

本章介绍uboot上的api和数据。

API名称 功能
drv_riscv_init 模块初始化。
drv_riscv_deinit 模块反初始化。
drv_riscv_poll 查询是否有待接收的数据或者是否空闲可以发送。
drv_riscv_send 发送数据。
drv_riscv_recv 接收数据。

5.1.1. drv_riscv_init

  • 功能

    模块初始化。

  • 语法

    int drv_riscv_init(void);
    
  • 形参

    参数名称 参数含义 输入/输出
  • 返回值

    返回值 描述
    0 初始化成功
    -1 初始化失败
  • 依赖

    • 头文件:Alkaid/boot/drivers/sstar/riscv/drv_riscv.h

    • 库文件

5.1.2. drv_riscv_deinit

  • 功能

    模块反初始化。

  • 语法

    int drv_riscv_deinit(void);
    
  • 形参

    参数名称 参数含义 输入/输出
  • 返回值

    返回值 描述
    0 反初始化成功
  • 依赖

    • 头文件:Alkaid/boot/drivers/sstar/riscv/drv_riscv.h

    • 库文件

5.1.3. drv_riscv_poll

  • 功能

    查询是否有待接收的数据或者是否空闲可以发送。

  • 语法

    int drv_riscv_poll(int flag);
    
  • 形参

    参数名称 参数含义 输入/输出
    flag 只能是DRV_RISCV_POLLIN或者DRV_RISCV_POLLOUT。DRV_RISCV_POLLIN表示查询是否有待接收的数据,DRV_RISCV_POLLOUT表示查询是否可以发送 输入
  • 返回值

    返回值 描述
    0 查询接收时表示没有数据可以接收,查询发送时表示不可以发送
    -1 入参既不是DRV_RISCV_POLLIN也不是DRV_RISCV_POLLOUT时返回这个值
    其他值 查询接收时表示待接收的数据长度,查询发送时表示可以发送
  • 依赖

    • 头文件:Alkaid/boot/drivers/sstar/riscv/drv_riscv.h

    • 库文件

  • 举例

    见4.2
    

5.1.4. drv_riscv_send

  • 功能

    发送数据。

  • 语法

    int drv_riscv_send(const char *msg, int len);
    
  • 形参

    参数名称 参数含义 输入/输出
    msg 要发送的数据块头指针。 输入
    len 要发送的数据块长度(字节)。 输入
  • 返回值

    返回值 描述
    0 发送成功
    -1 发送失败
  • 依赖

    • 头文件:Alkaid/boot/drivers/sstar/riscv/drv_riscv.h

    • 库文件

  • 注意

    • 发送之前需要先用drv_riscv_poll(DRV_RISCV_POLLOUT)查询直到返回值非0,才可以发送。
  • 举例

    见4.2
    

5.1.5. drv_riscv_recv

  • 功能

    接收数据。

  • 语法

    int drv_riscv_recv(char *msg, int len);
    
  • 形参

    参数名称 参数含义 输入/输出
    msg 接收缓冲区指针。 输入
    len 接收缓冲区长度(字节)。 输入
  • 返回值

    返回值 描述
    >= 0 接收到的数据长度
  • 依赖

    • 头文件:Alkaid/boot/drivers/sstar/riscv/drv_riscv.h

    • 库文件

  • 注意

    • 接收之前需要先用drv_riscv_poll(DRV_RISCV_POLLIN)查询直到返回值非0,表示才有数据可以接收。
  • 举例

    见4.2
    
  • 相关主题

5.2. FreeRTOS API参考

本章介绍FreeRTOS上的API

API名 功能
drv_mbx_msg_init 模块初始化。
drv_mbx_msg_deinit 模块反初始化。
drv_mbx_msg_poll 查询是否可以发送或者是否有数据可以接收。
drv_mbx_msg_send 发送数据。
drv_mbx_msg_recv 接收数据。

5.2.1. drv_mbx_msg_init

  • 功能

    模块初始化。

  • 语法

    int drv_mbx_msg_init(void);
    
  • 形参

    参数名称 参数含义 输入/输出
  • 返回值

    返回值 描述
    0 成功
  • 依赖

    • 头文件:Alkaid/riscv/kernel/rtk/proj/sc/driver/sysdriver/mbx_msg/mbx_msg.h

    • 库文件

5.2.2. drv_mbx_msg_deinit

  • 功能

    反初始化。

  • 语法

    int drv_mbx_msg_deinit(void);
    
  • 形参

    参数名称 参数含义 输入/输出
  • 返回值

    返回值 描述
    0 成功
  • 依赖

    • 头文件:Alkaid/riscv/kernel/rtk/proj/sc/driver/sysdriver/mbx_msg/mbx_msg.h

    • 库文件

5.2.3. drv_mbx_msg_poll

  • 功能

    查询是否可以发送或者是否有数据可以接收。

  • 语法

    int drv_mbx_msg_poll(int flag);
    
  • 形参

    参数名称 参数含义 输入/输出
    flag 只能是DRV_MBX_MSG_POLLIN或者DRV_MBX_MSG_POLLOUT。DRV_MBX_MSG_POLLIN表示查询是否有待接收的数据,DRV_MBX_MSG_POLLOUT表示查询是否可以发送。 输入
  • 返回值

    返回值 描述
    0 查询接收时表示没有数据可以接收,查询发送时表示不可以发送,入参既不是DRV_RISCV_POLLIN也不是DRV_RISCV_POLLOUT时也返回这个值
    其他值 查询接收时表示待接收的数据长度,查询发送时表示可以发送
  • 依赖

    • 头文件:Alkaid/riscv/kernel/rtk/proj/sc/driver/sysdriver/mbx_msg/mbx_msg.h

    • 库文件

5.2.4. drv_mbx_msg_send

  • 功能

    发送数据。

  • 语法

    int drv_mbx_msg_send(const char *msg, int len);
    
  • 形参

    参数名称 参数含义 输入/输出
    msg 要发送的数据块头指针。 输入
    len 要发送的数据块长度(字节)。 输入
  • 返回值

    返回值 描述
    0 发送成功
    -1 发送失败
  • 依赖

    • 头文件:Alkaid/riscv/kernel/rtk/proj/sc/driver/sysdriver/mbx_msg/mbx_msg.h

    • 库文件

  • 注意

    • 发送前要使用drv_mbx_msg_poll(DRV_MBX_MSG_POLLIN)确认没有数据待接收,再使用drv_mbx_msg_poll(DRV_MBX_MSG_POLLOUT)确认可以发送。

5.2.5. drv_mbx_msg_recv

  • 功能

    接收数据。

  • 语法

    int drv_mbx_msg_recv(char *msg, int len);
    
  • 形参

    参数名称 参数含义 输入/输出
    msg 接收缓冲区指针 输入
    len 接收缓冲区长度(字节)。 输入
  • 返回值

    返回值 描述
    >= 0 接收到的数据长度
  • 依赖

    • 头文件:Alkaid/riscv/kernel/rtk/proj/sc/driver/sysdriver/mbx_msg/mbx_msg.h

    • 库文件

  • 注意

    • 接收前要使用drv_mbx_msg_poll(DRV_MBX_MSG_POLLIN)确认有数据待接收。

6. FAQ

N/A