Lab 6: Blinking Lights

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.

Groups

  • Bea, Matt, and Linda
  • Jerry and Charlie
  • Kamal and Hattie
  • Sara and Giang
  • Fengyuan and Devin
  • Adam H. and Jacob
  • Ryan and Sophie
  • Eli and Blake
  • Tanner and Hamza
  • Maddie and Theo
  • Ana and Adam W.

Resources

Preparation

Before starting the lab, study the following assembly procedure and be able to explain how it works.

delayloop:
  beq $a0, $zero, delayloopend
  nop
  addi $a0, $a0, -1
  j delayloop
  nop
delayloopend:
  jr $ra
  nop

Questions to ask yourself:

  • What does the procedure do?
  • How many arguments does this procedure take? What is their use?
  • Is there a return value from this procedure? If so, what is it? If not, why not?
  • This procedure doesn’t need to use the stack. Why not?

Part A: Blinking slowly

Our first task is to write a program that will blink the LEDs slowly enough for us to see. Start by launching MPLAB:

$ /home/curtsinger/bin/mplab_ide &

Create a new project named blinky. In that project, create a file named blinky.S (note capitalization) and copy the following code:

  # blinky.S
  # Written by Janet Davis, 13 October 2013

.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

#define ON  0x1
#define OFF 0x0

delayloop:
  beq    $a0, $zero, delayloopend
  nop
  addi    $a0, $a0, -1
  j     delayloop
  nop
delayloopend:
  jr    $ra
  nop

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
  ##################
  # YOUR CODE HERE #
  ##################
  li $t0, OFF    
  sw $t0, 0($s0)  # Write to LATA, turning the LED off
  ##################
  # YOUR CODE HERE #
  ##################
  j loop          # Infinite loop
  nop             # Do nothing
.end main         # Marks the end of the program

This should be similar to a program you wrote in the previous lab. Verify that stepping through the code with the debugger blinks the onboard LED on and off. Where the program says # YOUR CODE HERE #, add instructions to call the given delayloop procedure.

You will need to decide what number to pass as an argument to delayloop. My advice is to blink the LED at a rate of about 1Hz, or once per second - not too fast and not too slow. By default, the PIC32 MX110F016B runs at 4MHz, executing one instruction per cycle. Given this information, the code for the delay loop, and the classic CPU perfomance equation, you should be able to estimate an appropriate number of loop iterations. If you are not sure of your calculation, check with me.

Next, we will use a protoboard switch to control the blink rate of the LED. Our goal: If the switch is off, the LED will continue to blink at a slow rate of 1Hz. If the switch is on, it will blink faster.

Hardware setup

In the PIC32MX1XX/2XX Family Data Sheet, find the pin diagram for the 28-pin SPDIP package on page 4. Focus at the diagram on the top of the page, which is for the PIC32MX1XX product series. Observe that pin 14, which corresponds to RB5, is 5V-tolerant (meaning it can accept a 5V input from the protoboard).

Wire one of the protoboard logic switches to pin 14. Turn the protoboard on.

Assembly code

Before the loop, add code to configure Port B as input (at least the lower 8 bits). Store the address of PORTB in a register.

At the start of the loop, read the value of PORTB into an unused register. Use logic operations to isolate bit 5 of the register value, so that the register contains 1 (true) if the switch is on and 0 (false) if the switch is off. You may find it helpful to use the debugger and its view of CPU register values to make sure you are doing this correctly.

Then, add a conditional to choose between two different delay values: the one you computed before, and one that is somewhat smaller. Pass the chosen value as an argument to the delayloop procedure.

Finally, test your code. Have you met your goal? Show me when you are done with this part!

Part C: More choices

If you have time, wire a second protoboard switch to pin 15 (also 5V-tolerant, and wired to RB6). With two input switches, you should be able to choose from four different blink patterns by using more complex conditionals. Here are some suggestions:

  • Blink the LEDs at four different speeds.
  • Independently vary the amount of time the LED is on and the amount of time it is off, to create different rhythms.
  • Wire up four LEDS to RA0, RA1, RA2, and RA3. Create different combinations of which LEDs are on and which are off. For example, each of the four LEDs could light up in sequence. Or the odd ones could turn on together, then the even ones.

Use your imagination and have fun!

Clean up

Before you leave, please stop the blinking. Reprogram your device with the add.s program from last time or a simple program such as the following:

  # donothing.s
  # Written by Janet Davis, 15 October 2013

.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

main:
  j main
  nop
.end main

Also, remove any additional components you’ve wired on the protoboard and put them away.

Acknowledgements

This lab was developed by Janet Davis for CSC 211L in 2013. Parts of the lab were inspired by exercises written by Marge Coahran.

license This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.