When beginning to grapple with the Raspberry Pi at a lower level, it may be helpful to establish early on the truer nature of the device: that the Raspberry Pi is by no means some ARM device with a GPU attached to it. Rather, it is somewhat the reverse.
It seems this potential for bias toward ARM may stem (unintentionally) from two areas. Firstly, from a marketing perspective the device is often advertised in an ARM-centric fashion (the Raspberry Pi 3 is currently strap-lined by the Foundation itself as “A 1.2GHz 64-bit quad-core ARMv8 CPU” with “VideoCore IV 3D graphics core” being the last component mentioned). And of course, when entering at a lower level, ARM code and the ARM core itself become very much the general focus; the programmer’s model somewhat gravitates around ARM.
The Raspberry Pi is by no means some ARM device with a GPU attached to it. Rather, it is almost the other way around.
But the reality is perhaps better understood slightly differently, and the sooner the better. The BCM2837 SoC used in the Raspberry Pi is exactly that: an SoC (“System on a Chip”). So there is perhaps an advantage in recognising and correcting any inadvertent early bias that the Raspberry Pi is principally some kind of ARM chip, because it is in fact a complete system on a chip, with an ARM core being just one part of the package.
Interestingly, and by way of illustration, when the Raspberry Pi is first turned on, it is actually the VideoCore IV that gets everything started (the ARM is held in reset). Understanding exactly what happens at this stage is somewhat nebulous because the VideoCore IV element of the SoC is actually a Broadcom component, and is one part of the Raspberry Pi that remains somewhat “under wraps” (complete documentation for it is not readily available). But if sufficiently interested, the VideoCore IV is undoubtedly a diversion all of its own: to learn how it works, where its strengths lie, and even how it can be programmed. (And again, this may be something to pause and consider early on, because the VideoCore IV is, yes, also a processor. It is essentially another class of processor sitting there on the Raspberry Pi, waiting to be used.)
So sitting on the Raspberry Pi is not just one, but two processors: an ARM, and a VideoCore IV. And what is interesting, is getting them to talk to each other.
The VideoCore IV carries a number of properties (functions, if you will) – over 50 actually – that the ARM can make use of. For a list, see here: [https://github.com/raspberrypi/firmware/wiki/Mailbox-property-interface] (viewing this list should reinforce the essential principle that the ARM is only part of the SoC.) But in order to make use of those properties, the ARM needs to be able to communicate with the VideoCore IV to request them.
Thankfully, the ARM and the VideoCore IV actually have a mechanism for communicating with each other, and it is through “mailboxes”. This is a logical concept, where both the ARM and the VideoCore IV have their own mailbox. And by filling these with suitably formatted “messages”, each is able to read and respond to the other. (The analogy with real-world mailboxes should be fairly plain.)
From a programmer’s perspective, the mailbox for dispatching messages from the ARM to the VideoCore IV is viewed as a memory-mapped set of registers. So providing the location and nature of the mailbox registers are known, and certainly if the general protocol (property tags, message formats, etc.) surrounding them are understood, it becomes possible to write code and demonstrate both the ARM and VideoCore IV working together to achieve something useful.
To demonstrate mailboxes, a small example has been put together: [https://github.com/abbeycatuk/mailbox]. What follows is a brief description of certain aspects which, when worked through with the code, should hopefully clarify how useful this mailbox mechanism is.
The example makes use of four “property tags” offered by the VideoCore IV, in order to configure the display on the Raspberry Pi. These are:
There are actually two mailboxes, and each mailbox has a number of “channels” associated with it. Mailbox 0 is used for communicating from the ARM to the VideoCore IV (mailbox 1 is reserved for communications in the other direction). In terms of channels, channel 8 is used for the sending of property tags across, so the end result is that code must utilise channel 8 of mailbox 0 (zero).
The base address for peripherals on the Raspberry Pi 3 is 0x3f000000, and the mailbox registers can be found at offset 0xb880. Specifically there is a Read, a Status, and a Write register. When communicating property tags from the ARM to the VideoCore IV, since mailbox 0 (zero) is to be used, the register addresses are defined as:
#define ARM_MAILBOX_REGISTERS ( ARM_PERIPHERAL_BASE_ADDRESS + 0xb880 ) #define ARM_MAILBOX_READ_REGISTER ( ARM_MAILBOX_REGISTERS + 0x00 ) #define ARM_MAILBOX_STATUS_REGISTER ( ARM_MAILBOX_REGISTERS + 0x18 ) #define ARM_MAILBOX_WRITE_REGISTER ( ARM_MAILBOX_REGISTERS + 0x20 )
A message itself is simply a well defined set of words in memory that identify three things:
- the size of the data structure being passed as a whole
- one or more property tags
- a terminating property tag
The document referred here: [https://github.com/raspberrypi/firmware/wiki/Mailboxes] describes the consistent format for a property tag, which is essentially:
|0x00||property tag identifier|
|0x04||size of the value buffer (in bytes)|
|0x08||indicates “process request”|
|0x0C||(request/response parameter space)|
(The number of bytes reserved from offset 0x0C onwards are available on the way out to provide information to the VideoCore IV, and on the way back to provide responses from the VideoCore IV.)
In terms of procedural protocol, the process is generally straightforward: the mailbox is polled until it is confirmed as not currently full. At that point, the memory address pointing at the message structure (always a multiple of 16, which leaves the bottom 4-bits clear) is written to the mailbox Write register (that way the channel number can be quite neatly placed into the bottom 4 “spare” bits).
Once complete, the mailbox Read register can be polled until a response is available. At that point, the memory block that was used for sending the message can be checked for any data that has been returned by the VideoCore IV.
The Raspberry Pi goes beyond just being an ARM device. Notably, it offers both an ARM core and a VideoCore IV that work quite nicely together. Hopefully this post has provided some useful information that reinforces or at least helps identify the complementary nature of both the ARM core and the VideoCore IV in the Raspberry Pi, illustrating not only how the VideoCore IV provides quite a broad set of functions that the ARM can use, but also the basics of how to actually make those requests.