思澈科技软件开发工具包  2.20
Mailbox

硬件邮箱(Mailbox)驱动程序提供用于处理器间通信的 API,即 HCPU<->LCPU。 它封装了硬件邮箱模块通知功能和软件环形缓冲区机制,使设备的行为类似于UART设备。

以HCPU和LCPU的通信为例,设备mb_h2l1作为HCPU端的tx设备(只写)和LCPU端的rx设备(只读),设备mb_l2h1作为HCPU端的rx设备和LCPU端的tx设备。 用户还可以使用复合设备 bdmb_hl1 进行双向通信(支持写入和读取),因为它结合了设备 mb_h2l1 和 mb_l2h1。 调用 rt_device_write 时,数据将写入环形缓冲区,并向接收处理器发出中断。 如果接收者通过调用 rt_device_set_rx_indicate 注册了 rx_ind 回调,它将收到通知,然后使用 rt_device_read 从环形缓冲区读取数据。

HCPU 可用设备:

  • mb_l2h1
  • mb_h2l1
  • mb_l2h2
  • mb_h2l2
  • bdmb_hl1
  • bdmb_hl2

LCPU 可用设备:

  • mb_h2l1
  • mb_l2h1
  • mb_h2l2
  • mb_l2h2
  • bdmb_lh1
  • bdmb_lh2

驱动配置

可以在 On-chip Peripheral Drivers->Enable HwMailbox 菜单中启用邮箱设备。

图 1:HCPU HwMailbox 选择菜单

使用可以在 custom_mem_map.h 中重新定义环形缓冲区地址和大小宏来修改默认缓冲区位置和大小。 mem_map.h中定义了默认值,如HCPU2LCPU_MB_CH1_BUF_START_ADDR、HCPU2LCPU_MB_CH1_BUF_SIZE。

为了避免非法访问,环形缓冲区必须位于发送方子系统的 RAM 空间中。 例如 HCPU2LCPU_MB_CH1_BUF_START_ADDR 是 HCPU 到 LCPU 通信的缓冲区地址,该缓冲区必须在 HPSYS RAM 空间中。

使用邮箱驱动程序

使用只读和只写邮箱设备,

/* HCPU side code */
static rt_mq_t mbox_mq;
static rt_err_t rx_ind(rt_device_t dev, rt_size_t size)
{
rt_mq_send(mbox_mq, &size, sizeof(size));
}
void hcpu_example(void)
{
tx_dev = rt_device_find("mb_h2l1");
rt_device_open(tx_dev, RT_DEVICE_OFLAG_WRONLY);
rx_dev = rt_device_find("mb_l2h1");
/* it's suggest to set rx_indicate before opening the device
* because once rx device is opened, interrupt may be received,
* if rx_ind is not registered, it would miss the notification to read the data
*/
rt_device_set_rx_indicate(rx_dev, rx_ind);
rt_device_open(rx_dev, RT_DEVICE_OFLAG_RDONLY);
uint8_t data[4];
rt_size_t len;
data[0] = 1;
data[1] = 2;
data[2] = 3;
data[3] = 4;
len = rt_device_write(tx_dev, 0, data, sizeof(data));
RT_ASSERT(len == sizeof(data));
/* receive loopbacked data */
uint32_t data_size;
mbox_mq = rt_mq_create("mbox_mq", sizeof(uint32_t), 30, RT_IPC_FLAG_FIFO);
while (rt_mq_recv(mbox_mq, &data_size, sizeof(data_size), RT_WAITING_FOREVER) == RT_EOK)
{
uint8_t *loopback_data = rt_malloc(data_size);
RT_ASSERT(loopback_data);
len = rt_device_read(rx_dev, 0, loopback_data, data_size);
RT_ASSERT(len == data_size);
/* compare loopback data */
memcmp(data, loopback_data, sizeof(data));
rt_free(loopback_data);
}
}
/* LCPU side code */
static rt_mq_t mbox_mq;
static rt_err_t lcpu_rx_ind(rt_device_t dev, rt_size_t size)
{
rt_mq_send(mbox_mq, &size, sizeof(size));
}
void lcpu_example(void)
{
tx_dev = rt_device_find("mb_l2h1");
rt_device_open(tx_dev, RT_DEVICE_OFLAG_WRONLY);
rx_dev = rt_device_find("mb_h2l1");
rt_device_set_rx_indicate(rx_dev, rx_ind);
rt_device_open(rx_dev, RT_DEVICE_OFLAG_RDONLY);
/* loop back the received data */
uint32_t data_size;
mbox_mq = rt_mq_create("mbox_mq", sizeof(uint32_t), 30, RT_IPC_FLAG_FIFO);
while (rt_mq_recv(mbox_mq, &data_size, sizeof(data_size), RT_WAITING_FOREVER) == RT_EOK)
{
rt_size_t len;
uint8_t *data = rt_malloc(data_size);
RT_ASSERT(data);
len = rt_device_read(rx_dev, 0, data, data_size);
RT_ASSERT(len == data_size);
len = rt_device_write(tx_dev, 0, data, data_size);
rt_free(data);
}
}

使用双向邮箱设备,

/* HCPU side code */
static rt_mq_t mbox_mq;
static rt_err_t rx_ind(rt_device_t dev, rt_size_t size)
{
rt_mq_send(mbox_mq, &size, sizeof(size));
}
void hcpu_example(void)
{
mb_dev = rt_device_find("bdmb_hl1");
/* it's suggest to set rx_indicate before opening the device
* because once rx device is opened, interrupt may be received,
* if rx_ind is not registered, it would miss the notification to read the data
*/
rt_device_set_rx_indicate(mb_dev, rx_ind);
rt_device_open(mb_dev, RT_DEVICE_OFLAG_RDWR);
uint8_t data[4];
rt_size_t len;
data[0] = 1;
data[1] = 2;
data[2] = 3;
data[3] = 4;
len = rt_device_write(mb_dev, 0, data, sizeof(data));
RT_ASSERT(len == sizeof(data));
/* receive loopbacked data */
uint32_t data_size;
mbox_mq = rt_mq_create("mbox_mq", sizeof(uint32_t), 30, RT_IPC_FLAG_FIFO);
while (rt_mq_recv(mbox_mq, &data_size, sizeof(data_size), RT_WAITING_FOREVER) == RT_EOK)
{
uint8_t *loopback_data = rt_malloc(data_size);
RT_ASSERT(loopback_data);
len = rt_device_read(mb_dev, 0, loopback_data, data_size);
RT_ASSERT(len == data_size);
/* compare loopback data */
memcmp(data, loopback_data, sizeof(data));
rt_free(loopback_data);
}
}
/* LCPU side code */
static rt_mq_t mbox_mq;
static rt_err_t rx_ind(rt_device_t dev, rt_size_t size)
{
rt_mq_send(mbox_mq, &size, sizeof(size));
}
void lcpu_example(void)
{
mb_dev = rt_device_find("bdmb_lh1");
/* it's suggest to set rx_indicate before opening the device
* because once rx device is opened, interrupt may be received,
* if rx_ind is not registered, it would miss the notification to read the data
*/
rt_device_set_rx_indicate(mb_dev, rx_ind);
rt_device_open(mb_dev, RT_DEVICE_OFLAG_RDWR);
/* loop back the received data */
uint32_t data_size;
mbox_mq = rt_mq_create("mbox_mq", sizeof(uint32_t), 30, RT_IPC_FLAG_FIFO);
while (rt_mq_recv(mbox_mq, &data_size, sizeof(data_size), RT_WAITING_FOREVER) == RT_EOK)
{
rt_size_t len;
uint8_t *data = rt_malloc(data_size);
RT_ASSERT(data);
len = rt_device_read(mb_dev, 0, data, data_size);
RT_ASSERT(len == data_size);
len = rt_device_write(mb_dev, 0, data, data_size);
rt_free(data);
}
}
len
uint16_t len
Definition: bf0_ble_ancs.h:226
data
uint8_t data[]
Definition: bf0_ble_ancs.h:227