In last week’s blog, we examined the hardware build required in Vivado to implement Mailboxes and mutexes for Inter Processor Communication (IPC).
Now, we are going to look at how we can transfer data from one processor to the other using the Mailbox.
Remember, in this system we are using one of the Zynq Processing Systems (PS) A9 cores and a MicroBlaze in the programmable logic (PL).
Both the processors are connected to the Mailbox using AXI, as such we can send and receive messages with ease using the provided APIs in the board support package (BSP).
Exporting the design from Vivado to Xilinx SDK will import the hardware specification in to SDK. Examining the HDF file in the hardware project will show both the MicroBlaze and the Cortex-A9 memory map.
With the hardware definition imported, the next step is to create two applications — one for the Arm Cortex-A9 and another for the MicroBlaze. When we create these applications, be sure to select the appropriate processor and enable the application to create the BSP as well.
Once this is completed, we should have the following in our SDK Project Explorer:
- Hardware platform describing the Vivado design — this should be used as the reference hardware platform for all application and BSPs.
- Two board support packages — one each for the PS Arm A9 and MicroBlaze application.
- Two applications — one each for the PS Arm A9 and MicroBlaze.
In this application, the MicroBlaze is going to report when it is up and running, and the status of the LED on or off.
To do this, we will be using the Mailbox APIs provided by the BSPs, both offer the same APIs for use.
These are contained within xmbox.h file and give us the ability to initialize and configure the Mailbox for use.
To read and write from the Mailbox, there are several functions:
- XMbox_Read ( XMbox * InstancePtr, u32 * BufferPtr, u32 RequestedBytes, u32 * BytesRecvdPtr)
- XMbox_ReadBlocking ( XMbox * InstancePtr, u32 * BufferPtr, u32 RequestedBytes )
- XMbox_Write(XMbox* InstancePtr,u32 * BufferPtr,u32 RequestedBytes, u32 * BytesSentPtr )
- XMbox_WriteBlocking ( XMbox * InstancePtr, u32 * BufferPtr, u32 RequestedBytes )
In the above functions, the instance pointer references the Mailbox declaration, the buffer pointer points to where we are storing the TX or RX data. While the requested bytes are the size of the transfer, the read and write functions also report on the number of bytes actually sent or received as this may be different to the that requested.
I should point out that for all functions the number of bytes sent or received should be multiple of four; if not, some padding is necessary. If a multiple of four bytes is not requested, an assertion will be generated.
Of course, the blocking read and write do not report the number of bytes actually sent or received as the function actually blocks until the requested number of bytes are sent or received.
Along with the send and receive functions there are also many housekeeping functions:
- Interrupt enabling, status and disabling
- FIFO threshold definition for send and receive interrupts
- FFIO management and control, including checking empty and full, flushing, and resetting
By using these functions, we are able to create simple applications for the Arm A9 core and the MicroBlaze.
The A9 program is simple. Once the Mailbox is initialized, it loops around for ever waiting for messages from the MicroBlaze before printing them out over the terminal.
The MicroBlaze application is a little more complex. It sends a message to the A9 core at startup and then each time the LED is toggled, it also sends a messages regarding the state of the LED.
To run this on the Zynq, we need to create a new debug configuration which downloads both processors. To ensure success in a multiprocessor environment, we need to consider the startup of both processors. In this debug configuration, select:
When the debug configuration is running, the device will be configured and the applications for both processors will be downloaded. Both processors will then be paused at the entry point of main().
For this example application, start the A9 processors first and then the MicroBlaze processor.
When I did this with the example code above, I saw the following in my terminal window:
Both processors are communicating! Next, we need to examine the mutex which we will do in the upcoming blog.
See My FPGA / SoC Projects: Adam Taylor on Hackster.io
Get the Code: ATaylorCEngFIET (Adam Taylor)
Access the MicroZed Chronicles Archives with over 290 articles on the Zynq / Zynq MpSoC updated weekly at MicroZed Chronicles.