Basic bare-metal user application

Yuhei Horibe
6 min readApr 29, 2019

--

In this section, how to develop simple software for SoC will be explained.

Software programming on SoC

To develop the software which runs on SoC, we need to know how the hardware and software communicates.

There are 3 different types of interfaces between processor (software) and device (hardware).

  1. Memory Mapped I/O
  2. IRQ (Interrupt Request)
  3. DMA (Direct Memory Access)

In most cases, actions are initiated by processor(s), and device(s) will respond to that commands/requests from the processor(s). The first one, Memory Mapped I/O is always the communication from the processor(s) to device(s). Processor can read/write directly from/to the register/registerfiles/SRAMs in device via address bus and data bus. Those registers/registerfiles/SRAMs are mapped directly into memory address, therefore, those are accessible using pointers.

The second one, IRQ (Interrupt Request) is opposite. This is always requested from device to host. Interrupts are requested in the situations like below;

  1. When Command Finished
  2. Input from human or sensors heppened
  3. Timer (Periodical interrupt)
  4. Emergency (power loss, hardware failure, data loss, and so on)

Usually, commands/requests from the processor(s) to device(s) takes a while to complete. In this case, it is inefficient to wait for the completion in while-loop (this is called busy-wait and used in simple embedded system). Instead, IRQs (Interrupt Requests) is used to prevent wasting processing resources. Processor(s) sends commands/requests to device(s), and it will be device’s responsibility to notify the command completion(s) to the processor(s). When commands/requests complete, device will notify the processor(s) by triggering interrupt requests. When interrupt is requested;

  1. Processor pauses processing and stores current contexts
  2. Special function called interrupt handler will be served
  3. When the interrupt handler finishes its job, processor retrieves the original contexts, and resumes the original process

Sometimes, storing/recovering contexts is interrupt handler’s responsibility. Interrupt handling will be explained in detail in later sections.

Lastly, DMA happens when processor has to send large chunk(s) of data to device, or processor has to receive blocks of data from the device. In this case, it is inefficient to let processor(s) copy data. Instead, when DMA is requested (it could be requested from both processor, or device), it will be device’s responsibility to copy data from main memory to device, or from device to main memory. During this process, separate hardware called “DMA controller” manages the bus to avoid contentions. Also , DMA triggers interrupt when DMA is completed (or error happened during DMA).

In this section, the focus will be on Memory Mapped I/O.

Preparation in Vivado

To create the software project, IDE (Xilinx SDK) needs to know the hardware structure. Open previous hardware project, select “Files” → “Export” → “Hardware Design” to create .hdf (Hardware Design Hand-off) file.

Create software project in Xilinx SDK

Open Xilinx SDK, and it will ask you where the work space directly is. Select the same directly as hardware project directly.

Click “Create Application Project”.

To pass the design handoff files, select “New” right beside “Hardware Platform” drop-box.

In “Target Hardware Specification” box, click “Browse” button, and select “hdf” file in “<project name>.sdk” folder in Vivado hardware project. In this example, “AXI_module.sdk/MyProcessingSystem_wrapper.hdf” is specified. Click “Finish” → “Next”.

Select “Hello World” in list-box, and “Finish”. It will generate the source code which will send characters “Hello World” via UART serial interface.

When the new SDK project is created, make sure your own hardware device is added. You can check 2 different points;

Firstly, in “system.mss”, the driver for your own device is added (see the picture below).

system.mss

Secondly, open “system.hdf” and make sure your own device is listed; In this example, my module “my_adder_0” is mapped to the physical address 0x43c0 0000.

system.hdf

Open “<project name>” → “src” →”helloworld.c”. This is the main source code of this project.

If you compile this project and download it onto the target board, it will send string “Hello World” via UART port. But it won’t access our device. As it was mentioned before, Memory Mapped I/O device is accessible via pointer, specifying the physical address of the device (in this case, 0x43c0 0000 is the device’s base address). So in this example, very simple register write code will be added.

Actually, when this software project is created, the device driver for our own device is generated automatically. So we can use generated device driver to access our device, but in that case, we need to add few more lines (including #include statements), also, I want to make Memory Mapped I/O understandable, I meant to choose this way.

Downloading bitstream and user application

After modifying the C source code, click “Project” → “Build All” to generate executable on Zedboard. To make this application working, follow these steps;

  1. Download bitstream (hardware design)
  2. Download user application (software)

To do this, connect device and PC via USB-JTAG cable (make sure jumper settings are correct), and power on the device. Also, make sure USB-JTAG device driver is installed correctly (See previous section).

Select “Xilinx” → “Program FPGA”.

Program FPGA dialogue

To program FPGA, Bitstream has to be specified. Click “Browse” and specify the bitstream file. It is in <hardware project name>.runs/imple_1/<hardware name>_wrapper.bit. In this example, it is “AXI_module.runs/impl_1/MyProcessingSystem_wrapper.bit”. Click “Program”. If the FPGA is correctly programmed, blue LED on the board is turned on (It depends on the board).

Next, the application program should be downloaded. Select “Run” →”Debug”.

Debug As dialogue

Then, “Debug As” dialogue shows up. Select default “Launch on Hadware (System Debugger)” and “OK”.

When you click “OK”, debugger console will be opened.

Debugger Console

To run this program, click “play” button at the top. (To get back to the original Project Explorer, click the icon on top right. Currently, “bug” icon is selected).

LEDs are turned on like “0000 1010”. If LEDs are not flashing, that means, either, hardware or software is wrong (Could be both, but most likely be hardware).

--

--

Responses (2)