Lab 5: Meet the PIC32

Starting in this week’s lab, we will be working with the PIC32 processor and the Microstick development board. The PIC32 is a popular line of microcontrollers that implements the MIPS32 instruction set, the same instruction set covered in our textbook. In this lab we will learn to use the MPLAB IDE to assemble code and download it to the Microstick, how to step through a program’s execution using the MPLAB Debugger, and how to use the PIC32’s port I/O to interact with circuits on your protoboard.

Groups

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

Background

We will be programming an inexpensive, low-power PIC32 microprocessor, the PIC32 MX110F016B. To power and program the microprocessor, we wil be using the Microstick II development board. The Microstick II, with a processor installed, looks like this:

Photograph of the Microstick II development board

The microprocessor is the large component on the right. While there are many standard layouts (or “packages”) used for microprocessors, observe that the processor shown is in an SPDIP package, with two parallel rows of pins, similar to the TTL logic chips you have already used in lab. The physical form of the Microstick II development board means it can be easily plugged into our protobards and connected to other electronic components.

The devices used in this lab are based on CMOS technology, and as such, they are more sensitive to small static shocks than are the TTL logic chips we used previously. Even a shock that you don’t feel can damage the chip, so it is advisable to avoid touching the microprocessor with your fingers. Please also be careful not to drop anything metal (e.g., wires, rings, or paperclips) onto the development board as this could also damage the board or the chip by causing a short circuit.

Resources

As you work through this lab, you may want to refer to the following references:

Preparation

Program add.s

Before you start working with hardware, study the following small assembly program and make sure you understand how it works.

# add.s
# Written by Jan Erik Larsson, 27 October 1998
# Adapted by Janet Davis, 6 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:	li	$s0, 0x1	# Load the value 1
  li 	$s1, 0x1	# Load the value 1
  add	$s2, $s0, $s1	# Add the values
  nop			# Do nothing
  .end main		# Marks the end of the program

Commentary:

  • The .s filename extension indicates that this is an assembly language program.
  • The first four lines are directives that tell how the program should be translated by the assembly. You can ignore them for now.
  • The three lines starting with the label main produce actual machine instructions. You should be able to explain what these instructions mean and what the program does when executed.
  • The instruction li $s0, 0x1 is a pseudo-instruction that is translated to the actual instruction addiu $s0, $zero, 0x1 before it is translated to machine code.
  • Comments are preceded by #. From now on, all the programs that you write for this course should include informative comments.

Program blinkonce.S

The following assembly program uses PORT A, pin 0 to blink an LED on, and then off again. Study this program and be able to explain how it works.

	# blinkonce.S
	# Written by Janet Davis, 6 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

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

	li	$t0, ON		
	sw	$t0, 0($s0)	# Write to LATA, turning the LED on

	li	$t0, OFF	
	sw	$t0, 0($s0)	# Write to LATA, turning the LED off

	nop			# Do nothing
	.end main		# Marks the end of the program

Commentary:

  • The .S filename extension indicates that this is an assembly language program which incudes C preprocessor directives (e.g., #define). Note that .S must be capitalized so that the assembler knows knows to run the C preprocessor on the file.
  • The la pseudo-instruction is similar to the li pseudo-instruction, but loads a memory address (known at link time) rather than a constant. See John Loomis’s notes on load immediate, add/subtract, and logic operations for further discussion and examples.
  • The TRISA register controls the state (input or output) of the Port A I/O pins. Output is indicated by 0; input by 1. The TRISA register is mapped to a memory address and is accessed using the sw and lw instructions.
  • We write to the Port A I/O pins using the LATA register, which is also mapped into memory.

Part A: Creating a project and programming the device

This part of the lab walks you through the basic procedures you will use to create projects and program the device. You’ll follow these steps every time you write a new program, so they will become routine.

  1. When you arrive in lab, take a good look at the Microstick II development board, which is plugged into your protoboard. Identify the PIC32 microprocessor. Moving upward, you should also see a round button, which is the reset (or “RST”) button, which is used to restart the microprocessor from its initial state. Above this is a toggle switch which should be set in the up position. Above the toggle switch is a small green LED which indicates whether the board has power. Above the LED is a USB connector, which is used to power, program, and debug the board.
    Verify that the USB cable is plugged into the workstation and that the power LED is lit. Do not touch the power switch on the protoboard. The Microstick II is powered through the USB connection and will provide power to any peripherals (e.g., LEDs).
  2. Log in to the workstation if you haven’t already. Open a terminal and type /home/curtsinger/bin/mplab_ide & to start the MPLAB X IDE.
  3. Follow these steps to create a new development project.
    • Under the File menu, select New Project…
    • Accept the default project type (Microchip Embedded, Standalone Project) and click Next.
    • When you are asked to select a device, choose the family of 32-bit MCUs (PIC32) and then our device, the PIC32MX110F016B. Click Next.
    • When you are asked to select development tools, look under Microchip Starter Kits and verify that a starter kit is selected, reporting the serial number of the connected device. It should look something like this: “SN: BUR131420426”. Click Next.
    • When you are asked to select a compiler, choose the XC32 compiler. Click Next.
    • For the project name, type “Add”. Click the checkbox to set this as the main project. Click Finish.
  4. You should see the new project appear in the IDE’s project browser. Next, you will add a source file to the project.
    • Right-cick on Source Files and select New, Other.
    • Select the “Other” category and choose “Empty File”.
    • For the filename, type add.s.
    • Then click Finish. You will see the file appear in the project browser under Source Files, and you will have a new, blank file to edit.
    • Copy and paste the add.s program into the IDE. Format your program for readability: It is customary to use tab characters to vertically align the operations, the operands, and the comments. Be sure to save the file.
  5. Assemble the program using the Build Main Project command in the Run menu, or by clicking the toolbar button that looks like a hammer. If the assembler finds any syntactic errors, it will tell you on which line the first error is located. Correct all errors and rebuild the program.
  6. To program the device, click the toolbar button that looks like a green arrow pointing down. If this is the first time the microprocessor has been used, the IDE will go through several steps to not only download your code to the device, but also to download appropriate firmware. This process is complete when you see the text “Programming/Verify complete”. (If you don’t see this text, ask for help.)

Believe it or not, the microprocessor is now running your code. But unfortunately, our simple addition program has no visible effects (such as blinking an LED). Therefore, we will use MPLAB X with the Microstick II’s onboard debugging unit to see what our program is doing.

Part B: Stepping through instructions and inspecting register values

We will use the debugger to step through our program line by line and view the corresponding changes to the values stored in the microprocessor’s general purpose registers.

  1. Click the line number next to the first li instruction to set a breakpoint. A breakpoint tells the debugger to stop before executing the indicated instruction.
  2. Let’s also view the contents of all the registers:
    • Under the Window menu, choose PIC Memory Views, then CPU Registers. You will see a new tab pop up showing the CPU Registers.
    • Click on the heading of the leftmost column to sort the registers by Address. At the top, you will see a number of special purpose registers used to manage the processor’s current configuration and status, starting with BadVAddr. Note that these registers do not have addresses; they are not accessible through typical assembly language instructions.
    • Scroll down until you find the general purpose registers, starting with r00, otherwise known as zero. Keep scrolling until you find r16, r17, and r18, otherwise known as s0, s1, and s2. What values are stored in these registers?
  3. Under the “Debug” menu, click “Debug Main Project”. This will rebuild your program for use with the debugger and also configure the microprocessor appropriately. If you are presented with any questions as part of this process, answer Yes.
  4. At the end of the build process, you should see the words “Target Halted,” which indicates that the microprocessor is halted and waiting for you to tell it what to do next. You should also see that the first line of your program is highlighted in green, and there is a green arrow over the red breakpoint square to the left of the program. The green arrow and highlight indicate the instruction that will be executed next.
  5. Click on the CPU Registers tab to go back to inspecting the values stored in the registers. Make sure you can see the registers used by your program.
  6. Step into the current instruction by clicking the toolbar button with an orange arrow pointing down, or by touching the F7 key. You should see the green highlight move down to the next line of your program. How do the register values change?
  7. Step through the next two instructions and observe how the register values change.
  8. Now, the nop instruction should be highlighted. What do you think will happen when you reach the end of the program? Step once more and find out.
  9. Click the stop button to halt the program execution and exit the debugger.
  10. Add a jump instruction that will cause an endless loop. After the add instruction, add the instruction j main to jump back to the first instruction. Leave the nop as the last instruction. (Jump instructions take two cycles to execute on the PIC32; therefore we use the nop to fill in the extra cycle.) Re-assemble and debug your program. What happens when you step through the program line by line? How can you stop it?
  11. Modify the program so that it does something a bit more interesting. Instead of performing the same addition over and over, have the program continually add 1 to the same register, so that it counts up as the program executes. Debug your program and verify that the value of the register increases on each pass through the loop. After how many loop iterations will overflow occur?
  12. Modify your program so that it counts by 2, 5, or another small integer, instead of counting by 1.

Part C: Getting started with Port I/O

The first program uses only internal registers. However, the second program writes on ports connected to “real world” devices.

  1. Create a new project named blinkonce. Be sure to set it as the main project. Create a new source file named blinkonce.S and copy the contents of the second program into this file.
  2. Assemble the program
  3. Debug the program, executing it step by step. Investigate what happens to the register values. (You may need to make the status pane a bit bigger to see all the registers at once.) Also observe that the Microstick II’s onboard user LED, which is red, blinks on and then off. The development board connects pin 0 of Port A to this red LED.
  4. In the CPU Memory pane, choose to inspect the Peripheral Memory instead of the CPU Registers. Sort by name and find the LATA register. What is the address corresponding to LATA? What value is stored there? Step through your program again and see how the value changes.
  5. Let’s try connecting an external LED to pin 0 of Port A.
    • 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.
    • In the pin diagram, find pins labeled for pin 0 of Port A (RA0) and for ground (VSS). Make note of the pin numbers.
    • Grab a green LED and a 150Ω resistor. Build a circuit connecting the power lead of the LED to RA0, the ground lead of the LED to the resistor, and the resistor to VSS.
    • Use the debugger to step through your program again. Verify that the green LED turns on and then off again, along with the red LED on the Microstick II, as you step through the appropriate instructions.
  6. Now, let’s add a loop to make our program blink the LEDs on and off repeatedly. Add the label loop: to your program where you want the loop to begin. Add a jump instruction where you want the loop to end. Assemble and debug your program. Step through the program, instruction by instruction, and verify that the loop controls the LED as you expected.
  7. When you are done, stop the debugger. To program the device without using the debugger, click the toolbar button that looks like a green arrow pointing down. What happens?

The problem is that the microprocessor is turning the LED on and off too fast for us to see. To slow the blinking down so that we can see it, we will need to add a delay loop (busy waiting, to those who have taken CSC 213). And to do that, we will need conditional branch instructions, which we will learn about in class on Friday.

Part D: Execution memory (if you have time)

Now, we’ll look at the representation of your program as data in memory.

  1. Choose “Execution Memory” from the dropdown at the bottom of the CPU Registers tab, then select “Code” as the format. This will show you the disassembled machine code for the program loaded on the PIC32.
  2. Find your program as it is stored in memory. Jump to the memory address corresponding to the PC (Program Counter), or scroll down until you see red boxes corresponding to your breakpoints. How do the instructions disassembled from execution memory correspond with the instructions you wrote in your program? What differences do you see?
  3. Use the debugger to step through your program again, instruction by instruction, watching the green arrow corresponding to the PC as it steps through execution memory. Pay special attention to what happens at the jump instruction. When you are done, do not stop the debugger; stay in debug mode.
  4. Note the addresses of your program instructions. Switch back to the Data view of execution memory and find your program. How does it look in hexidecimal? In ASCII?

Acknowledgements

This lab was developed by Janet Davis, and inspired by exercises written by Marge Coahran and by Mats Brorsson and Jan Eric Larsson.

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