Implementing a MicroBlaze processor in a FPGA design is very popular in many applications. The MicroBlaze allows us to handle serial processing which otherwise would require complex state machines. The MicroBlaze can be configured as a microcontroller, real-time processor or application processor. When we’ve used MicroBlaze in the past, we have configured it using one of these applications.
There is, however, another instantiation of MicroBlaze that we can make called the MicroBlaze MicroController System (MCS). The MCS is an integrated MicroBlaze solution that includes local memories, UART, timers, and a GPIO in a single module. The MCS is intended to have a small footprint in both logic resources and program memory. The MCS uses either a three or five-stage pipeline depending if the optimization is for area or performance.
One advantage of the MCS is that the integrated MCS enables further optimization compared to creating the equivalent system using the MicroBlaze and discrete elements.
The main differences between the MCS and MicroBlaze can be seen in the table below.
The MCS provides an excellent solution for many applications where we want to interact with a GPIO or provide a simple UART interface.
The MCS solution provides the following:
UART – With configurable baud rate, stop bits and interrupt or polled mode.
Fixed Interval Timer (FIT) – Four fixed internal timers with a 32-bit range. Each of the FITs provide a dedicated output which generate a 50:50 duty cycle output.
Periodic Interval Timer (PIT) – Four Periodic Interval Timers which can be changed at run time.
Interrupts – The interrupt controller for the IO module can also work with external interrupts.
GPIO – Four general-purpose outputs and four general-purpose inputs banks.
To get started exploring the MCS, I am going to create a project targeting the Arty S7-50 board. With the project open, the MCS can be added into a new block diagram and the GPIO outputs can be connected to the push buttons, switches, LEDs, and RGB LEDs available on the Arty S7-50.
In this simple project, the application can be built and the XSA exported into Vitis where we can create the application.
The application in Vitis will be interacting with the IO module. This is different than when we worked with the AXI GPIO previously. If the UART is enabled when the platform is created, it will be mapped as the STDIN, STDOUT. For everything else, we need to use the IO module to drive the outputs and general-purpose inputs. In this example, the code reads the DIP switches and drives the LEDs on a one-second loop.
XIOModule_Config *IOCfgPtr = IOModule.CfgPtr;
switches = XIOModule_DiscreteRead(&IOModule, 1);
xil_printf("DIP Switches %x\n\r",switches);
Since the MCS does not provide the ability to run from external memory, the ELF file that is generated by Vitis and contains the application must be merged with the bit stream in Vivado. This ensures that the application for the MCS starts running immediately once the FPGA is configured.
Of course, we want to ensure the application will fit in the BRAM used for the MCS when we develop these applications. We also want to ensure we are not allocating too much BRAM in the MCS definition phase and leaving it unused.
We can see the byte size of the compiled program as reported in the build console when we compile the program in Vitis.
We can use this value to ensure the BRAM is optimally sized to confirm that the application is the smallest possible, the optimization flags are set correctly, and no debug is included.