概述
Mailbox有助于ARM和VideoCore之间的通信。下面列出了可用Mailbox/channel。每个Mailbox都是一个8位深的32位字FIFO,可由ARM和VC读取/写入。只有Mailbox 0的状态可以触发ARM上的中断,因此Mailbox 0始终用于从VC到ARM的通信,Mailbox 1用于ARM到VC。ARM永远不应该写Mailbox 0或读Mailbox 1。
树莓派Mailbox0和Mailbox1通信流程:
Channel(通道)
下面列出了当前定义的Mailbox通道,其中包含指向描述消息格式的页面的链接。
邮箱0定义以下渠道:
0:电源管理
1:帧缓冲
2:虚拟UART
3:VCHIQ
4:LED
5:按钮
6:触摸屏
7:属性标签(ARM - > VC)
8:属性标签(VC - > ARM)
Mailbox寄存器
以下给出了Mailbox各个寄存器的地址偏移量,MailBox0的基地址是0x3F00B880,Mailbox使用和配置流程详见:
这里
#define VIDEOCORE_MBOX (0x3F00B880)
#define MAILBOX0_READ ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x00))
#define MAILBOX0_PEEK ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x10))
#define MAILBOX0_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x14))
#define MAILBOX0_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x18))
#define MAILBOX0_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x1C))
#define MAILBOX1_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x20))
#define MAILBOX1_PEEK ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x30))
#define MAILBOX1_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x34))
#define MAILBOX1_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x38))
#define MAILBOX1_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x3C))
#define ARM_MS_FULL BIT(31)
#define ARM_MS_EMPTY BIT(30)
#define ARM_MC_IHAVEDATAIRQEN BIT(0)
树莓派Mailbox访问一般流程:
要从邮箱中读取:
1、读取状态寄存器,直到没有设置empty标志
2、从读寄存器读取数据
3、如果低4位与所需的通道编号不匹配,则从1开始重复
4、高28位是返回的数据
写入邮箱:
1、读取状态寄存器,直到未设置full标志
2、将数据(移入高28位)与通道(低4位)一起写入写寄存器
还有一些注意详见:这里
MailBox接口编码查询详见:这里
树莓派Mailbox数据包格式
- U32: 整个数据包大小,单位字节(包括头,end标记和字节对齐填充)
- U32: 请求/回复代码
-
请求代码:
- 0x00000000: process request
-
回复代码:
- 0x80000000: 请求成功
- 0x80000001: error
-
tag有如下格式:
- U32: tag identifier
- U32: value buffer size, 单位字节
- U32:
- 请求代码:
- b31: 0
- b30-b0: reserved
- 回复代码:
- b31: 1
- b30-b0: value length, 单位字节
- 请求代码:
- U8…: value buffer
- U8…: 整个tag以32字节对齐
- U32: 0x0 (end tag)
- U8…: padding
示例代码
#include "reg.h"
#include "uart.h"
#define VIDEOCORE_MBOX (0x3F00B880)
#define MAILBOX0_READ ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x00))
#define MAILBOX0_PEEK ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x10))
#define MAILBOX0_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x14))
#define MAILBOX0_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x18))
#define MAILBOX0_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x1C))
#define MAILBOX1_WRITE ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x20))
#define MAILBOX1_PEEK ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x30))
#define MAILBOX1_SENDER ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x34))
#define MAILBOX1_STATUS ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x38))
#define MAILBOX1_CONFIG ((volatile unsigned int*)(VIDEOCORE_MBOX + 0x3C))
#define ARM_MS_FULL BIT(31)
#define MBOX_RESPONSE BIT(31)
#define ARM_MS_EMPTY BIT(30)
#define ARM_MC_IHAVEDATAIRQEN BIT(0)
#define MBOX_REQUEST 0
/* channels */
#define MBOX_CH_POWER 0
#define MBOX_CH_FB 1
#define MBOX_CH_VUART 2
#define MBOX_CH_VCHIQ 3
#define MBOX_CH_LEDS 4
#define MBOX_CH_BTNS 5
#define MBOX_CH_TOUCH 6
#define MBOX_CH_COUNT 7
#define MBOX_CH_PROP 8
/* tags */
#define MBOX_TAG_GETSERIAL 0x10004
#define MBOX_TAG_LAST 0
#define ALIGN(n) __attribute__((aligned(n)))
/* mailbox message buffer */
volatile unsigned int mbox_buffer[64] ALIGN(16);
int mailbox_call(unsigned char channel)
{
unsigned int address = (unsigned int)(((unsigned long)mbox_buffer & ~0xF) | (channel & 0xF));
puts("mailbox_call check prewrite\n");
while (*MAILBOX1_STATUS & ARM_MS_FULL);
*MAILBOX1_WRITE = address;
while (1) {
puts("mailbox_call check preread\n");
while (*MAILBOX0_STATUS & ARM_MS_EMPTY);
puts("mailbox_call reading\n");
if (address == *MAILBOX0_READ)
return mbox_buffer[1] == MBOX_RESPONSE;
}
puts("mailbox_call error\n");
return 0;
}
void get_serial(void)
{
mbox_buffer[0] = 8 * 4;
mbox_buffer[1] = MBOX_REQUEST;
mbox_buffer[2] = MBOX_TAG_GETSERIAL; // tag identifier
mbox_buffer[3] = 8; // buffer size
mbox_buffer[4] = 8; // buffer size
mbox_buffer[5] = 0; // clear buffer data
mbox_buffer[6] = 0; // clear buffer data
mailbox_call(MBOX_CH_PROP);
puts("My serial number is\n");
hex(mbox_buffer[6]);
hex(mbox_buffer[5]);
}