cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Executing MicroBlaze Applications from the PSU DDR in Vitis

stephenm
Moderator
Moderator
3 0 961

The MicroBlaze™ CPU is a family of drop-in, modifiable preset 32-bit/64-bit RISC microprocessor configurations.

The MicroBlaze processor meets the requirements of many diverse applications including Industrial, Medical, Automotive, Consumer, and Communications markets. The MicroBlaze uses a Harvard architecture, and typically this is via a dual LMB BRAM in the PL. However, In this Blog we will discuss how we can execute a MicroBlaze Application from the PSU DDR on the Zynq UltraScale ZCU104 board.

Upon exiting reset, the MicroBlaze will fetch its instructions from the memory address specified in the C_BASE_VECTORS parameter in the MicroBlaze Configuration. In our case, this C_BASE_VECTORS will be set to a region in the PSU DDR.

However, this poses a potential problem as depending on the boot flow employed, the PSU DDR might not be configured before the PL. This can cause the MicroBlaze to hang. To prevent this, we can use the Reset Mode signal on the MicroBlaze.

reset_mode.PNG

In the table above, we can see the various configurations for the reset_mode. The configurations that best suits our use case is "01", where the MicroBlaze is held in reset until we are ready. We will use the GPIO via the EMIO on the PSU to bring the MicroBlaze out of reset.

Creating the Hardware:

The Vivado IP Integrator Block Design can be seen below:

bd.PNG

Users can customize their design as they see fit.

The key components configurations are discussed below.

MicroBlaze Configuration:

Use the Block Automation tool in Vivado IP Integrator to Initially configure the MicroBlaze as shown below. Here, I have removed the local memory, and used 64K of cache:

mb_config.PNG

To enable the reset_mode and wakeup pins, users need to enable the Discrete Ports in the MicroBlaze configuration:

discrete.PNG

In the Zynq UltraScale PS configurations, I have enabled two slave ports; one for memory, one for the peripherals:

slave_interfaces.PNG

I have enabled the GPIO via the EMIO so that I can control the MicroBlaze wakeup:

emio_gpio.PNG

We can also access all of the Zynq UltraScale IP that are enabled from our MicroBlaze. To do this, enable the Address Fragmentation:

addr_frag.PNG

We discussed the reset mode above. We will hold the MicroBlaze in reset until we are ready.

To hold the MicroBlaze in reset, we can use the Constant IP from the IP catalog:

constant.PNG

Finally, connect the GPIO and the Constant IP:

reset_pin.PNG

The MicroBlaze Address map is shown below:

addr_map.PNG

Users can right click on an address segment, and either add or exclude from the address map.

That is it for the hardware configuration. We can Generate the Output Products, Create the HDL wrapper, and Generate the Bitstream then export the Hardware.

This will generate the XSA to be used in Vitis to generate our Software.

Creating the Software:

The Vitis IDE can be used to generate the MicroBlaze application. Vitis will also create the boot images including the FSBL and the PMUFW automatically.

However, because we want to control the GPIO EMIO from the FSBL, we will opt to not have the tools generate the boot images:

generate_boot_images.PNG

Generate the MicroBlaze Hello World application:

app_details.PNG

hello_world.PNG

We can add new project applications as shown below. For example, for the Zynq FSBL:

add_apps.PNG

cortexa53_app.PNG

Note: the FSBL does not support 64 bit to 32 bit handoff. So, because the MicroBlaze is 32 bits, we should also have the FSBL set to 32 bits:

fsbl_domain.PNG

fsbl.PNG

Repeat for the PMUFW:

pmu_app.PNG

zynqmp_pmufw.PNG

You should see all of the application projects as shown below:

all_app_project.PNG

Because we added the PS UART to the MicroBlaze address map, we can use this for the STDIN/OUT in the BSP:

bsp_settings.PNG

stdin.PNG

We can see the MicroBlaze Hello World Linker here:

mb_linker.PNG

This is placed at the base address of the DDR (0x00000000). Users need to keep this in mind when creating a boot image so that applications do not overlap.

Programming via the SD Card

First update the FSBL.

We can use the Xil_Out32 API to toggle the GPIO.

Add the xil_io header file to the xfsbl_handoff.c file:

 

 

/***************************** Include Files *********************************/
#include "xfsbl_hw.h"
#include "xil_cache.h"
#include "psu_init.h"
#include "xfsbl_main.h"
#include "xfsbl_image_header.h"
#include "xfsbl_bs.h"
#include "xil_io.h"

 

 

I have added this to the XFsbl_HandoffExit function

 

 

Xil_Out32(0xff0a0018, 0x1);
Xil_Out32(0xff0a02c4, 0x1);
Xil_Out32(0xff0a02c8, 0x1);
Xil_Out32(0xff0a004c, 0x1);

XFsbl_Printf(DEBUG_GENERAL,"Toggle GPIO \n\r");

 

 

I have also enabled the FSBL debug info:

debug_info.PNG

Create the boot image:

create_boot_image.PNG

I have removed the FSBL and PMUFW and added them again with the correct image type.

Make sure that the partition images are in the correct order (use the up and down controls to rearrange them)

boot_gui.PNG

sd_card_flow.PNG

Note: because we are sharing the same UART here, users can place a delay in the Hello World app.

Programming via JTAG:

 

 

connect
 
fpga -no-rev -f design_1_wrapper/bitstream/design_1_wrapper.bit
  
# Add the Microblaze PMU to target
targets -set -nocase -filter {name =~ "PSU"}
mwr 0xFFCA0038 0x1FF
# Download PMUFW to PMU
target -set -filter {name =~ "MicroBlaze PMU"}
dow zynqmp_pmufw/Debug/zynqmp_pmufw.elf
con
   
# write bootloop and release A53-0 reset
targets -set -nocase -filter {name =~ "PSU"}
mwr 0xffff0000 0x14000000
mwr 0xFD1A0104 0x380E
  
# Download FSBL to A53 #0, and the Hello World app to DDR
targets -set -filter {name =~ "Cortex-A53 #0"}
dow zynqmp_fsbl/Debug/zynqmp_fsbl.elf
con
after 500
stop
dow hello_world/Debug/hello_world.elf
 
# Handle PS PL
targets -set -nocase -filter {name =~ "PSU"}
source design_1_wrapper/hw/psu_init.tcl
psu_post_config
after 500
psu_ps_pl_reset_config
after 500
psu_ps_pl_isolation_removal
after 500
 
# Wake up Microblaze
targets -set -nocase -filter {name =~ "PSU"}
mwr -force 0xff0a0018 0x00000001
mwr -force 0xff0a02c4 0x00000001
mwr -force 0xff0a02c8 0x00000001
mwr -force 0xff0a004c 0x00000001

 

 

You should see output similar to the following:

tcl_flow_console.PNG