硬件邮箱(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 空间中。
使用邮箱驱动程序
使用只读和只写邮箱设备,
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");
rt_device_set_rx_indicate(rx_dev, rx_ind);
rt_device_open(rx_dev, RT_DEVICE_OFLAG_RDONLY);
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);
memcmp(
data, loopback_data,
sizeof(
data));
rt_free(loopback_data);
}
}
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);
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 *
data = rt_malloc(data_size);
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);
}
}
使用双向邮箱设备,
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");
rt_device_set_rx_indicate(mb_dev, rx_ind);
rt_device_open(mb_dev, RT_DEVICE_OFLAG_RDWR);
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);
memcmp(
data, loopback_data,
sizeof(
data));
rt_free(loopback_data);
}
}
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");
rt_device_set_rx_indicate(mb_dev, rx_ind);
rt_device_open(mb_dev, RT_DEVICE_OFLAG_RDWR);
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 *
data = rt_malloc(data_size);
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);
}
}