Teach lesson
Nios V on DE1-SoC (2/5): C memory-mapped I/O
Students edit C memory-mapped I/O on a Nios V system, read switches, control LEDs, and explain how addresses connect code to hardware.
Learning Outcomes
Use volatile C pointers to access memory-mapped I/O.
Read LabsLand Nios V logical switches through the JP1 GPIO path.
Use masking and shifting to map input bits to LED output bits.
Validate hardware behavior using the live board camera.
Student activity preview
Activity Content
Preview only. In a class session, students can fill in responses and submit their work to the teacher.
The I/O map
8 min
The Nios V processor sees hardware peripherals as memory addresses. In this lab, the starter program uses these addresses:
- LEDR at 0xFF200000: red LED output register.
- JP1 data at 0xFF200060: LabsLand logical switch input path.
- JP1 direction at 0xFF200064: GPIO direction register.
- JTAG UART at 0xFF201000: terminal output through printf.
The CPU reads and writes these addresses like normal memory, but the FPGA fabric routes each access to a peripheral instead of ordinary RAM. That is memory-mapped I/O.
The browser controls are labelled NSW0..NSW9. They are not the physical SW0..SW9 port at 0xFF200040 in this current remote workflow. The logical NSW controls enter through JP1 GPIO bits, then the starter shifts those bits down before writing the LED register.
Reference boundary: the FPGAcademy DE1-SoC Computer with Nios V manual is the correct reference for the fixed Nios V computer and its memory-mapped peripheral map. This lesson deliberately uses the LabsLand-validated JP1 route for browser NSW controls rather than asking you to use the FPGAcademy physical switch register directly.
The browser NSW controls are read from JP1 data bits 5 through 14. The program shifts right by 5 so NSW0 becomes bit 0, then writes the ten-bit value to LEDR0..LEDR9.
Key bit positions:
- NSW0 is read as JP1 data bit 5 and becomes LEDR0.
- NSW1 is read as JP1 data bit 6 and becomes LEDR1.
- NSW2 is read as JP1 data bit 7 and becomes LEDR2.
- The same pattern continues through NSW9, which is read as JP1 data bit 14 and becomes LEDR9.
For this lab profile, writing 0 to the JP1 direction register configures the
JP1 lines used by NSW0..NSW9 as inputs. That is why the program writes
*JP1_DIR = 0; before it reads the JP1 data register.
Why does the program write to 0xFF200064 before reading switch input from 0xFF200060?
Build the C starter
14 min
Open
Nios V C IDE for DE1-SoC.Inspect
main.c.Click
Build ELF.Upload to the FPGA.
Confirm that the terminal prints
Hello from Nios V.Toggle
NSW0,NSW3, andNSW9; observe the matchingLEDRoutputs.
Use the table to record three quick tests from the lab. Fill one row per switch pattern: predict the LEDR output first, then toggle the NSW control in the board view and write what you observed.
Record three lab tests. For each row, predict the LEDR output before testing, then enter the LEDR output you actually saw on the board.
| Input tested | Expected LEDR before testing | Observed LEDR on board | Matched prediction? |
|---|---|---|---|
Read the code path
15 min
Keep the C IDE lab tab open. You can answer this section from the code below, but it is the same main.c file you just built and tested in the lab.
Focus on the loop:
*JP1_DIR = 0;
while (1) {
*LEDS = (*JP1 >> 5) & 0x3FF;
}
The shift moves the JP1 bits used by LabsLand NSW0..NSW9 down to bit positions 0 through 9. The mask keeps only those ten bits before writing them to the LED register.
For example, when only NSW0 is on, JP1 bit 5 is 1. After >> 5, that value becomes bit 0, so LEDR0 turns on. The volatile qualifiers matter because the value behind JP1 can change because of hardware, not because of a C assignment. Without volatile, a compiler optimization could reuse an old value or remove a repeated register access that looks redundant in ordinary memory code.
If NSW0 reaches JP1 data bit 5, why does the code shift the JP1 value right by 5?
What would be the risk of writing the raw JP1 value directly to the LED register without & 0x3FF?
Why should these pointers be volatile? Explain in terms of compiler optimization and hardware registers.
Modify the mapping
13 min
Use the C IDE lab tab again. If the first board session is still open, you can
reuse it; if it has timed out, build the modified ELF and upload it again to
start a fresh board session. Change the program so the LEDs show a transformed
switch pattern, then click Build ELF, upload it, and test the transformed
behavior on the board.
Choose one transformation:
- Invert the ten switch bits before writing LEDs.
- Show only the lower five NSW controls on LEDR0..LEDR4.
- Shift the NSW pattern left by one LED position and explain what happens to NSW9.
Submit the modified C loop and a one-paragraph explanation of the transformation.
The observable result must match your explanation. For example, if you choose an inverted pattern, NSW0 off should make LEDR0 on, and NSW0 on should make LEDR0 off.
Describe one switch pattern you tested, the LED result you expected, and what the board showed.
Wrap-up
5 min
Summarize the complete data path from clicking NSW4 in the browser to seeing LEDR4 change on the board.