This initial project is intended to familiarize you with Xilinx’s Vitis design tool, the ARM Assembly language, and programming your Blackboard. Vitis is a full-featured integrated design environment (IDE) tool that contains an editor, assembler/compiler, linker, loader, debugger, and programmer – everything needed to create, process, download and analyze software for ZYNQ’s ARM processor. In the project requirements, you will write several small assembly programs that access some of Blackboard’s I/O devices, like switches and LEDs. Then in the challenges, you can test your knowledge, and solve some related problems.
After completing the project requirements and challenges, you must demonstrate your work to the lab assistant to receive credit. The assistant will assign points during your demo using the project submission form, and then the submission form must be turned in for credit. Take a few moments to familiarize yourself with the submissions policy, and print out the submission form before demonstrating your work to the assistant.
Before you begin, you should:
- Have the Blackboard;
- Have a recent PC with internet access;
- Have an hour or two to get your design environment up and running.
After you’re done, you should:
- Have the Xilinx Vitis tool installed and running;
- Know how to set up a program in Vitis;
- Know how to create an ARM aseembly language program;
- Have a basic understanding of the ARM microprocessor.
This project introduces the ARM processing environment, the tools you will use to create ARM programs, and assembly language programming.
The ARM processor core used on the ZYNQ is produced by the ARM Corporation. ARM does not produce chips – rather, they design and sell the “Intellection Property” (IP) that specifies the exact structural design of the processor. Manufacturing companies that actually make chips, like Apple, TI, Cypress, NXP, Xilinx, and many others purchase the IP, and then include the processor in their chip along with other IP blocks. ARM sells many different processor circuits – Xilinx uses the ARMv7-A processor on the ZYNQ device used on the Blackboard.
The ZYNQ device also includes an FPGA, and it is directly connected to the ARM using a high-speed AXI bus (more on the AXI bus later). In the Digital Logic course, we ignored the ARM and used Xilinx’s Vivado tool to design custom logic circuits for the FPGA; in this microprocessors course, we will use Xilinx’s VITIS tool to create custom software for the ARM. Ideally, we’d like to ignore the FPGA in this class and only use the ARM. But many of the devices on the Blackboard are connected to FPGA I/O pins (and not to the ARM directly). For the ARM to access those devices, their signals must be passed through the FPGA. So, if the ARM is to access the FPGA-connected I/O, the FPGA must be configured every time the board is powered on.
Further, the ARM must support a wide range of external physical devices (like memory chips) that might be used in any given design. Board/system designers can choose from a long list of different memory technologies and speeds, different clocking sources, different peripheral drivers and devices, etc., and the ARM must be in-field configurable so that it can work with any of them. Chip manufacturers (like Xilinx) include mechanisms to allow board designers (like Real Digital) to configure/program the ARM to work with the devices they choose. This ARM setup information is typically written into internal registers each time the device is powered on.
Further still, many design tools and software environments are available for the ARM, and chip/design tool manufacturers must allow customers the flexibility to specify which software libraries, compilers, assemblers, and other related software they want to use. In the Xilinx tool set, this information is included in a “board support package” (BSP) file.
Real Digital has created an “.xsa” file to configure the FPGA and program all setup registers, and a BSP to define the tool environment. VITIS must apply both of these files every time the Blackboard is powered on. To make this as easy as possible, Real Digital has created an empty project that contains the .xsa and BSP – everything needed to properly configure the ZYNQ device. If you routinely import this project at the start of a new lab project, it will take care of all system setup details. The first tutorial will walk you through setting up a project. Note that at any time, you can look inside the .xsa and BSP to see what’s going on, but if you change anything, the system may hang.
The ARM assembler defines a large number of instructions, but most of them are variations of a relatively small number of “core” instructions. The topic documents provide some background on commonly used instructions and the ARM architecture. After working with these basic instructions, you can extend your knowledge by working directly with the ARM Architecture Reference Manual. Section A-8 provides detailed information for all possible ARM instructions. You will note that for every “core” instruction (for example, “ADD”), there are many sub-instructions (12 for ADD) that define different instruction encodings or other options. And further, each of these 12 sub-instructions have many conditional and addressing mode variations, so that many dozens of ADD instructions can be encoded. But they are all related, and once you understand a little about how the instructions are formed, you will come to realize the instruction set is actually straight-forward.
Setup VITIS and create a project
Create a VITIS project by following the tutorial: TUTORIAL: Creating a VITIS project
To create a Vitis 2020 project, use this tutorial instead: TUTORIAL: Creating a VITIS 2020 project
Add code to your file
Now, open up your source file and copy the following code into the file.
.text .global main @define constants, these can be used as symbols in your code .equ LED_CTL, 0x41210000 .set SW_DATA, 0x41220000 @the set and equ directives are equivalent and can be used interchangeably main: ldr r1,=SW_DATA @load switch address from constant ldr r2,=LED_CTL @load LED address from constant loop: ldr r0,[r1] @load switch value *r1 ->r0 str r0,[r2] @store value to led register *r2 <-r0 b loop @go back to "loop" .end
After copy and pasting the source code, your editor window should look like the picture below. To run the program, you must first build the software project, and then choose a Run Configuration. To build the software project, make sure the scr folder is selected in the explorer window, and then click Project -> Build Project. Since you already built the hardware part of the project, this should go fairly quickly.
To choose a Run Configuration, open the pull-down menu next to the run icon (the white arrow in the green circle), and choose Run Configurations. In the window that opens, select the Single Application Debug (GDB) option, and then click Run. That will transfer the program to the Blackboard, and start it running.
After a Run Configuration has been selected, you can just click the arrow icon for future runs. Note that the Run Configuration programs the FPGA by default. If you don’t power-cycle your board, there’s no need to reprogram the FPGA every time you reload software. To turn off automatic FPGA programming, select the “Target Setup” tab in the Run Configuration, and uncheck “Reset entire system” and “Program FPGA”.
That’s it! Now, on to your own programs.
1. Verify the Demo Project
Try moving the first four switches to check if your demo project was launched on the board successfully.
2. Negate the Signal from the Switches
Modify your program to turn the LEDs off when the switches are a 1, and on when they are a 0.
After loading the data from the switches, you will need to modify it (invert it) before writing the LED register. Examine the ARM instructions, and see if you can find an efficient instruction to do the inversion (there are several ways it can be done). Experiment a little, and try to find the best way!
3. Use Pushbuttons to Illuminate LEDs
Create a program to turn on the LEDs when pushbuttons are pressed.
Like the slide switches, the pushbuttons are also connected to the ARM through the FPGA, but they are accessed at a different address. Refer to the GPIO reference manual section to find the address of the correct register, and the bits within that register that must be modified. GPIO Programmers Reference
4.Use comparisons and branches to light an LED
By using branch and compare instructions, you can write programs that act differently under different conditions. The following program illuminates one of Blackboard’s LEDs if the value of the switches is less then 4. If the value is greater or equal to 4, the LED is turned off.
.text .global main .equ LED_CTL, 0x41210000 .set SW_DATA, 0x41220000 main: ldr r1,=SW_DATA ldr r2,=LED_CTL loop: ldr r0,[r1] @load switch value, (*r1) ->r0 cmp r0,#4 @compare switch value with 4 blt led_light @branch to 'led_light' if sw val is less than 4 led_dim: mov r0,#0 str r0,[r2] b loop @go back to start of loop led_light: mov r0,#1 str r0,[r2] b loop .end
Write a program that will illuminate the first LED if the value of the switches is equal to your age, and the second LED if all switches are ‘1’.
5.Use comparisons to control multiple LEDs
Treat the values from the first 4 switches as a binary number, and light up the first 4 LED’s individually if the number falls in a certain range: Light LED0 if the value of the switches is from 0 to 3; LED 1 if the value is between 4 and 7; LED 2 if the value is between 8 and 11; and LED 3 if the value is between 12 and 15. Only one LED should be lit at any time.
Hint: Reading the switch register returns the value of all 12 switches, but you are only interested in the first four switches. You need a way to check the binary value of only the first four switches. You could simply require that the upper eight switches are all set to 0, but requiring certain input states like this is generally considered bad practice, particularly when you can remove that requirment with some simple processing. In this case, you can simply “mask out” the higher switch values by ANDing the value in the switch regsiter with 0x0000000F. Is it clear why this works?
1. Control LED’s using both switches and buttons.
Treat the first four LED’s as a function of the first 4 switches and the four buttons, and light an LEDs when its corresponding switch or button is activated, but not when both are activated.
2. Use buttons to latch a binary value
Treat the first 8 switches as an 8-bit binary value, and ‘latch’ the value of the switches to an internal memory location when one of the buttons is pressed. Show the latched value on the first eight LEDs, and demonstrate that changing the switches does not change the LED value until the latch button is pressed again. Clear the value (set the value to zero) when a different button is pressed.
3. Have an LED toggle with a button press.
Make the first green LED turn on when the first button is pressed and turn off when the button is pressed again. The LED should not change state when the button is released or if the button is held down.
All done with the first module!
Print the submission form and demonstrate your work to the TA.