Due: 5 pm Friday 28 March 2025
Summary: You will write MIPS assembly to blink LEDs programmatically.
Collaboration: You will work during lab in randomly assigned pairs. You must complete the work together in these groups, whether during or after the scheduled lab time.
Submitting: After completing each exercise, show your completed work to the instructor or a course mentor. If you are unable to complete the lab during class time, schedule a time during office hours to demonstrate each of your solutions.
In this lab, you will use the protoboard’s switches to blink LEDs in two or more different patterns. Along the way, you will write assembly code to call functions, read input, isolate bit fields, and perform conditional execution.
Note that you are expected to produce instruction-efficient, nicely-aligned, well-commented assembly code. Code that does not meet these standards will not be checked off.
Our first task is to write a program that will blink the LEDs slowly enough for us to see. We’ll control the LED on the microstick the same way we did in the previous lab, but we’ll add a pause by asking the PIC32 to loop for a while before changing the state of the LED. Specifically, we’re going to use a MIPS version of the following C procedure:
// Precondition: iterations > 0
void delayloop(int iterations) {
do {
iterations--;
} while (iterations != 0);
return;
} // delayloopTranslate the above C procedure to MIPS assembly with pencil and paper. Make sure you follow all the MIPS calling conventions in your translated version. When you have completed your translation, have the instructor or a mentor sign off on this part of the lab.
Now that we have our delayloop procedure we can use it
to make the LED on the microstick blink slowly enough when running at
full speed. You will need to calculate the number of iterations your
delayloop procedure should run to pause for about half a
second, then call this procedure with the appropriate value of
iterations.
First, you’ll need to launch MPLAB.
mplab_ide &
Create a new project named blinky (if the software
complains about an invalid folder, you will need to reboot your
machine); select the appropriate chip number (PIC32MX250F128B) when you
create your project. In your new project, create a file named
blinky.S (note capitalization) and copy the following
code:
# blinky.S
# Written by Janet Davis, 13 October 2013
# Edited by Charlie Curtsinger, 9 October 2018
.set noreorder # Avoid reordering instructions
.text # Start generating instructions
.globl main # The label should be globally known
.ent main # The label marks an entry point
# Preprocessor defines for output port control
#define ON 0x1
#define OFF 0x0
# The beginning of the delayloop procedure.
# Signature: void delayloop(int interations)
delayloop:
##########################################
# Transfer your delayloop procedure here #
##########################################
# The main entry point for the program
main:
la $s0, TRISA # Load the address mapped to the TRISA control register
li $t0, 0
sw $t0, 0($s0) # Store the value 0 to all bits of the TRISA register,
# setting all bits of Port A as output
la $s0, LATA # Load the address mapped to the LATA control register
loop:
li $t0, ON
sw $t0, 0($s0) # Write to LATA, turning the LED on
#####################################
# Call the delayloop procedure here #
#####################################
li $t0, OFF
sw $t0, 0($s0) # Write to LATA, turning the LED off
#####################################
# Call the delayloop procedure here #
#####################################
j loop # Infinite loop
nop # Delay slot
.end main # Marks the end of the programThis program is very similar to the one you used in the previous lab. Verify that stepping through
the code with the debugger blinks the onboard LED on and off. Transcribe
the body of the delayloop procedure you translated in part
A, and call that procedure in both spaces indicated in the above
assembly code. Call delayloop with a parameter of at least
100,000 to start; this will allow you to test the implementation before
you derive an appropriate parameter to pause for half a second. Move on
once you have your LED blinking slowly enough that you can see it
blinking when the program is running at full speed (not in debug
mode).
I would like you to blink your LED so a full period takes one second;
that means the LED will be on for half a second, then off for half a
second. The first step in controlling pause time is to calculate how
many instructions your delayloop procedure executes for a
given value of iterations. Remember that the PIC32 will run
one instruction immediately after all branch and jump instructions. Our
PIC32 has a clock speed of 4MHz, and it executes one instruction on each
clock cycle. That means one instruction takes .00000025s, or 250
nanoseconds. Using this information, find a reasonable value of
iterations that will cause delayloop to run
for about half a second; it is okay if you are off by a few cycles. Once
you have an iteration count, update your code and demonstrate your
program for the instructor or a mentor before moving on to the next
part.
Now that we have a program that blinks an LED at a steady rate, you will need to make it respond to switch input. Our goal is for the LED to blink at 1Hz when the switch is off and 2Hz when the switch is on. Working with input pins isn’t too difficult, but you have to get a few details right so please read the instructions carefully.
So far we have used the pin RA0 as an output to turn a
single LED on and off. This pin is part of a collection of pins referred
to Port A. The control register TRISA sets each pin up to
work as either an input or output; for example, storing a 0
into bit 3 of TRISA will make RA3 an output,
and storing a 1 into bit 2 of TRISA will make
RA2 an input.
There is another collection of pins on the PIC32—with corresponding
pins on the microstick—called Port B, which is controlled by the
memory-mapped register TRISB. We are going to use the pin
RB5, so you’ll need to store a 1 in bit 5 of
TRISB; remember that we count bits from the right starting
at zero. Update your MIPS program to do this now.
Now that we have pin RB5 set up as an input we need to
read from it. So far we have only dealt with outputs, which we control
by storing values to the LATA memory-mapped register.
Storing values to LATA will control the state of any output
pins in port A. There is an equivalent LATB memory-mapped
register for port B, but these LAT registers are only
suitable for use with outputs. To read from inputs we
instead load from the locations PORTA and
PORTB. If the input pin RB5 is high, the value
loaded from PORTB will have a 1 in bit 5 of the result.
Update your code to load from PORTB at the start of each
iteration of the main loop.
Now that we have code that can read from input pins we need to connect some sort of input. While we were able to use logic switches with the protoboard in previous labs, this would be a bad idea with the Microstick. Remember that voltages are not absolute values, but rather the potential energy difference between two levels. There is no guarantee that ground for the protoboard will be the same as the ground for the microstick, so we have to use the microstick’s onboard voltage source and ground rather than the protoboard’s. To do this, we will use the single-pole, double-throw (SPDT) switches on the protoboard.
An SPDT switch connects a common output wire to one of two inputs. When the switch is up, it connects the common output wire in the middle to the top input. When the switch is down, it connects the common output wire to the bottom input. A logic switch uses the common wire for output with the top input connected to positive voltage and the bottom input connected to ground, as illustrated in the figure below.
Look at the PIC32MX1XX/2XX Family Data Sheet (in the Resources above)
to find the RB5 pin, VDD (a positive voltage
source), and VSS (ground). Make sure you’re looking
at the diagram for the correct chip. Connect these pins to an
SPDT switch on the protoboard so RB5 connects to
VDD when the switch is up and VSS when the
switch is down.
Important: Make sure you do NOT use AVSS or AVDD. (Those are for analog inputs and outputs.)
Now that you have your switch wired up to the microstick, use the
debugger to look at the value loaded from PORTB when the
switch is up or down. Verify that bit 5 (counting from zero) is set when
the switch is up and cleared when the switch is down. You will likely
notice that unconnected pins have an unpredictable effect on the bits of
PORTB; this is expected.
Now that you have all the new pieces in place, you’ll need to use the
switch to control the blink rate. Your program should already configure
port B as an input and read from PORTB at the top of the
program’s main loop. Now add code to isolate bit 5 of the value loaded
from PORTB and change the parameter passed to
delayloop based on the switch setting. Remember to follow
MIPS calling conventions with your register use; that means you may not
assume that any $t_ register will be preserved across a
call to delayloop. Once your program is working,
demonstrate it to the instructor or a mentor before moving on.
In the final part of this lab you will use a second switch to add
additional control to the blinking LED. You will need to wire a second
SPDT switch to RB7, connected to either VDD or
VSS in the same way as the first switch. Once you have the
second switch connected, implement one of the following features:
RA0, RA1,
RA2, and RA3. Changing the switches should
control which combinations of LEDs turn on and off together; there are
many possibilities, so you are free to choose whatever scheme you
like.Note: Remember that the pins are numbered to form a “U” around
the bottom of the chip, while the table in the pinout diagram is not.
Make sure you wire the location of RB7 correctly!
Have the instructor or a mentor sign off on your implementation once you have finished one of the above features.
Copyright © 2018–2025 Charlie Curtsinger, Janet Davis, and Jerod Weinman
This work is
licensed under a Creative Commons Attribution NonCommercial ShareAlike
4.0 International License. To view a copy of this license, visit http://creativecommons.org/licenses/by-nc-sa/4.0/
or send a letter to Creative Commons, 543 Howard Street, 5th Floor, San
Francisco, California, 94105, USA.