Bar
SpaceWire UK
Specialist providers of VHDL Intellectual Property & Design Services
BarBarBarBar
Tutorial
Missing Image!
Part 9 - Create & build 3rd software project

Introduction

This tutorial details the steps required for using Vitis to create & deploy a very simple ARM Cortex-A9 based bare metal software application to access the LED's and slide switches on the ZedBoard hardware.

Aims

The aims of this tutorial are as follows :-
  1. Setup environment
  2. Create project area
  3. Launch Vitis
  4. Create project
  5. Build platform
  6. Create new source file
  7. Build project
  8. Archive project

1. Setup environment

Setup Xilinx design environment for the 2021.2 toolset.
steve@Linux-Steve:/home/steve$ source xilinx.sh
Xilinx tools available tools at /opt/Xilinx :-
1) 2021.2 - Vivado - SDK - Vitis - PetaLinux
0) Exit
Please select tools required or exit : 1

Tools are as follows :-
vivado @ /opt/Xilinx/Vivado/2021.2/bin/vivado
vitis @ /opt/Xilinx/Vitis/2021.2/bin/vitis
petalinux-build @ /opt/Xilinx/PetaLinux/2021.2/tool/tools/common/petalinux/bin/petalinux-build

2. Create project area

Create the project directory along with a subdirectory for the software.
steve@Linux-Steve:/home/steve$ mkdir -p /home/steve/projects/leds_buttons/sw

3. Launch Vitis

Launch Vitis IDE and specify the new Workspace to use.
steve@Linux-Steve:/home/steve$ vitis -workspace /home/steve/projects/leds_buttons/sw &

4. Create project

The Vitis IDE : Welcome window will now appear. Create a project by clicking on Create Application Project under the Project heading. Missing Image! The New Application : Project Create a New Project window will now appear. Review the information provided and then click Next. Missing Image! The New Application Project : Platform window will now appear. Select the exported hardware platform from Vivado by entering the Create a new platform form hardware (XSA) tab and setting the XSA File to /home/steve/projects/leds_buttons/fw/system_wrapper.xsa. Click Next to continue. Missing Image! The New Application Project : Application Project Details window will now appear. Set the Application project name to leds_buttons and then click Next. Missing Image! The New Application Project : Domain window will now appear. The default settings as shown are fine for this project. Click Next to contune. Missing Image! The New Application Project : Templates window will now appear. Create an empty application by selecting Empty Application(C) from the Available Templates section. Click Finish to contune. Missing Image! The Vitis IDE cockpit window will now appear. This is the window where all the action happens. Missing Image!

5. Build platform

Build the platform by right clicking on system_wrapper inside the Explorer tab and selecting Build Project. Missing Image!

6. Create new source file

Create a new source file inside the leds_buttons application project. Right click on src then select New » File. Missing Image! In the Create New File dialog set the File name to leds_buttons.c and click Finish to continue. Missing Image! The new source file is automatically opened in the Vitis IDE for editing. Missing Image! Copy the code below into the newly created leds_buttons.c and save it by selecting File » Save from the main menu.

leds_buttons.c

  1. //
  2. // Includes
  3. //
  4. #include "xparameters.h"
  5. #include "xgpio.h"
  6. #include "xscugic.h"
  7. #include "xil_exception.h"
  8. #include <stdio.h>


  9. //
  10. // Defines
  11. //
  12. #define CHANNEL_LEDS 1
  13. #define CHANNEL_BTNS 2

  14. #define BUTTON_CENTER 0x01
  15. #define BUTTON_DOWN   0x02
  16. #define BUTTON_LEFT   0x04
  17. #define BUTTON_RIGHT  0x08
  18. #define BUTTON_UP     0x10

  19. //
  20. // Global Variables
  21. //
  22. static XScuGic Intc;


  23. //
  24. // Instances
  25. //
  26. XGpio Gpio;


  27. //
  28. // Rotate right
  29. //
  30. u8 ror(u8 num) {
  31.   return (num >> 1) | (num << 7);
  32. }


  33. //
  34. // Rotate left
  35. //
  36. u8 rol(u8 num) {
  37.   return (num << 1) | (num >> 7);
  38. }


  39. //
  40. // Interrupt service routine
  41. //
  42. void GpioIsr(void *InstancePtr)
  43. {
  44.   u32 btns;
  45.   u32 leds;
  46.   u8 width = 0;

  47.   XGpio *GpioPtr = (XGpio *)InstancePtr;

  48.   // Disable button interrupts
  49.   XGpio_InterruptDisable(GpioPtr, XGPIO_IR_CH2_MASK);

  50.   // Only deal with button interrupts
  51.   if ((XGpio_InterruptGetStatus(GpioPtr) & XGPIO_IR_CH2_MASK) != XGPIO_IR_CH2_MASK) {
  52.     return;
  53.   }

  54.   // Obtain register values for LED's & buttons
  55.   leds = XGpio_DiscreteRead(&Gpio, CHANNEL_LEDS);
  56.   btns = XGpio_DiscreteRead(&Gpio, CHANNEL_BTNS);

  57.   // Print button status
  58.   xil_printf("ISR called, button register = 0x%x\n\r", btns);

  59.   // Determine LED bar width
  60.   for (u8 i=0; i<=7; i++) {
  61.     if ((0b00000001 << i) & leds) {
  62.       width++;
  63.     }
  64.   }

  65.   // Handle button functionality
  66.   switch (btns) {

  67.     // Set LED bar width to 4
  68.     case BUTTON_CENTER :
  69.       leds = 0b00111100;
  70.       break;

  71.     // Rotate LED's left
  72.     case BUTTON_LEFT :
  73.       if (width == 0) {
  74.         leds = 0b00000001;
  75.       } else {
  76.         leds = (u8)rol(leds);
  77.       }
  78.       break;

  79.     // Rotate LED's right
  80.     case BUTTON_RIGHT :
  81.       if (width == 0) {
  82.         leds = 0b10000000;
  83.       } else {
  84.         leds = (u8)ror(leds);
  85.       }
  86.       break;

  87.     // Increase illuminated LED's
  88.     case BUTTON_UP :
  89.       if (width == 0) {
  90.      leds = 0b00001000;
  91.       } else if (width & 1) {
  92.         leds = leds | rol(leds);
  93.       } else {
  94.         leds = leds | ror(leds);
  95.       }
  96.       break;

  97.     // Decrease illuminated LED's
  98.     case BUTTON_DOWN :
  99.       if (width == 8) {
  100.      leds = 0b01111111;
  101.       } else if (width & 1) {
  102.         leds = leds & rol(leds);
  103.       } else {
  104.         leds = leds & ror(leds);
  105.       }
  106.       break;

  107.     // Do nothing
  108.     default:
  109.       break;
  110.   }

  111.   // Update LED's
  112.   XGpio_DiscreteWrite(&Gpio, CHANNEL_LEDS, leds);

  113.   // Clear pending interrupts
  114.   XGpio_InterruptClear(GpioPtr, XGPIO_IR_CH2_MASK);

  115.   // Enable button interrupts
  116.   XGpio_InterruptEnable(GpioPtr, XGPIO_IR_CH2_MASK);
  117. }


  118. //
  119. // Setup interrupt system
  120. //
  121. int SetupInterruptSystem()
  122. {
  123.   int Result;
  124.   XScuGic *IntcInstancePtr = &Intc;

  125.   XScuGic_Config *IntcConfig;

  126.   // Initialise interrupt controller
  127.   IntcConfig = XScuGic_LookupConfig(XPAR_PS7_SCUGIC_0_DEVICE_ID);
  128.   if (NULL == IntcConfig) {
  129.     return XST_FAILURE;
  130.   }

  131.   // Comment
  132.   Result = XScuGic_CfgInitialize(IntcInstancePtr, IntcConfig, IntcConfig->CpuBaseAddress);
  133.   if (Result != XST_SUCCESS) {
  134.     return XST_FAILURE;
  135.   }

  136.   // Comment
  137.   XScuGic_SetPriorityTriggerType(IntcInstancePtr, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR, 0xA0, 0x3);

  138.   // Connect interrupt handler
  139.   Result = XScuGic_Connect(IntcInstancePtr, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR, (Xil_ExceptionHandler)GpioIsr, &Gpio);
  140.   if (Result != XST_SUCCESS) {
  141.     return Result;
  142.   }

  143.   // Enable GPIO interrupt
  144.   XScuGic_Enable(IntcInstancePtr, XPAR_FABRIC_AXI_GPIO_0_IP2INTC_IRPT_INTR);

  145.   // Enable button interrupts
  146.   XGpio_InterruptEnable(&Gpio, XGPIO_IR_CH2_MASK);

  147.   // Enable GPIO interrupts
  148.   XGpio_InterruptGlobalEnable(&Gpio);

  149.   // Initialise the exception table
  150.   Xil_ExceptionInit();

  151.   // Register interrupt controller handle with exception table
  152.   Xil_ExceptionRegisterHandler(XIL_EXCEPTION_ID_INT, (Xil_ExceptionHandler)XScuGic_InterruptHandler, IntcInstancePtr);

  153.   // Enable non-critical exceptions
  154.   Xil_ExceptionEnable();

  155.   return XST_SUCCESS;
  156. }


  157. //
  158. // Main function
  159. //
  160. int main(void)
  161. {
  162.   int Status;

  163.   // Initialise GPIO driver
  164.   Status = XGpio_Initialize(&Gpio, XPAR_AXI_GPIO_0_DEVICE_ID);
  165.   if (Status != XST_SUCCESS) {
  166.     return XST_FAILURE;
  167.   }

  168.   // Clear LED's
  169.   XGpio_DiscreteWrite(&Gpio, CHANNEL_LEDS, 0);

  170.   // Setup interrupt system
  171.   Status = SetupInterruptSystem();
  172.   if (Status != XST_SUCCESS) {
  173.     return XST_FAILURE;
  174.   }

  175.   // Print header
  176.   print("--== LED & Push Buttons interrupt example ==--\n\n\r");
  177.   print("Use the buttons to control the LED's :-\n\n\r");
  178.   print("Centre - Reset LED's to 00111100\n\r");
  179.   print("Left   - Rotate LED's left\n\r");
  180.   print("Right  - Rotate LED's right\n\r");
  181.   print("Up     - Increase illuminated LED's\n\r");
  182.   print("Down   - Decrease illuminated LED's\n\n\r");
  183.   print("Press enter key to quit application\n\r");

  184.   // Wait for user input
  185.   getc(stdin);

  186.   // Clear LED's
  187.   XGpio_DiscreteWrite(&Gpio, CHANNEL_LEDS, 0);

  188.   // Print footer
  189.   print("All done!\n\n\r");

  190.   return XST_SUCCESS;
  191. }

7. Build project

Build the project by right clicking on leds_buttons under leds_buttons_system inside the Explorer tab and selecting Build Project. Missing Image!

8. Archive project

Create an archive so the project can be regenerated and revision controlled (optional). Select File » Export... from the main menu. In the Export Vitis Projects dialog set Archive File to vitis_export_archive.ide.zip, set Directory to /home/steve/projects/leds_buttons and tick System Projects & Platform Projects. Click OK to continue. Missing Image! In the Export Vitis Projects status dialog click OK to continue. Missing Image! Add the file /home/steve/projects/leds_buttons/vitis_export_archive.ide.zip to the revision control system & commit (optional).