Bare-metal Application with Vitis
Create a software platform, understand the BSP and control an AXI GPIO with low-level and high-level drivers.
Chargement…
Create a software platform, understand the BSP and control an AXI GPIO with low-level and high-level drivers.
A bare-metal application runs C or C++ on the processor without a full operating system. The standalone domain supplies startup, libraries, and basic services without Linux-style process isolation or scheduling.
Import the XSA into Vitis, create the platform, and select the processor domain. The LED UART console receives UART commands and controls AXI GPIO.
| Element | Content |
|---|---|
| Platform | Hardware description imported from the XSA |
| Domain | Target processor, operating system and BSP |
| Application | C or C++ sources, linker script and build options |
Compilation is cross-compilation: tools run on the workstation and produce ARM code for the board. The ELF contains code, data, and debug information. JTAG can load it into initialized memory; standalone boot later requires a boot image.
The BSP supplies drivers and xparameters.h symbols matching hardware:
#include "xgpio.h"
#include "xparameters.h"
XGpio leds;
int init_leds(void)
{
int status;
status = XGpio_Initialize(&leds, XPAR_FPT_LED_BANK_DEVICE_ID);
if (status != XST_SUCCESS) {
return XST_FAILURE;
}
XGpio_SetDataDirection(&leds, 1, 0x0U);
XGpio_DiscreteWrite(&leds, 1, 0x0U);
return XST_SUCCESS;
}XGpio_Initialize associates the software instance with GPIO. Its return code is checked before channel 1 becomes an output with zero data. This listing uses the device-ID API; adapt initialization to BSP headers when your flow instead uses a base address.
The structured level-1 driver simplifies multiple instances:
void write_led_pattern(u32 pattern)
{
XGpio_DiscreteWrite(&leds, 1, pattern & 0xFFU);
}0xFFU masks eight LEDs. Use 0x0FU for four.
Level 0 avoids the instance structure but requires explicit base addresses and offsets:
#include "xgpio_l.h"
void configure_led_registers(void)
{
XGpio_WriteReg(XPAR_ZCU_LED_BASEADDR, XGPIO_TRI_OFFSET, 0x0U);
XGpio_WriteReg(XPAR_ZCU_LED_BASEADDR, XGPIO_DATA_OFFSET, 0x0U);
}A zero bit in XGPIO_TRI_OFFSET selects output. XGPIO_DATA_OFFSET holds data. Base symbols must match the actual BSP; this fragment represents another instance.
In the LED console, + and - move the pattern and 0 through 7 select an LED. A small stopwatch can read buttons, debounce them, process serial commands, and update state:
| Command | Effect |
|---|---|
g | Starts the stopwatch |
s | Stops the stopwatch |
r or c | Clears the elapsed time |
timer_is_running defines a small state machine. UART and LEDs expose its result.
A software delay near 10 ms only illustrates sequencing. Frequency, optimization, and caches change its duration. Accurate timing requires a hardware timer, optionally with interrupts.
Read platform.c to see what init_platform() does: caches or standard UART on some targets, little on others. It does not automatically initialize every peripheral.
Place cleanup_platform() on actual exit paths, including initialization failures. It is unreachable after an infinite loop.
In Vitis, review operations that configure PL, initialize PS, and load ELF. For inactive GPIO, check XSA, BSP symbols, driver status, direction, address, then pin constraints and wiring.
Vitis UG1400 documents the flow; embeddedsw provides driver sources.
Test your knowledge - Chapter quiz