Lab 2: MPLAB Introduction
Effective 9/30/24: This lab is being revised for Spring 2025 and may differ slightly from the lab you performed. Contact Peter Loux (prl83@msstate.edu) if you have questions.
TODO:
waive calculations from Task 1
emphasize that u16_studentid and u16_netid should not be 0000
make netid.s for students
make a second file, mplab_test, for task1, leaving mptst_word and mptst_byte as sample files only
add underscores
This lab introduces you to the Microchip MPLAB X Integrated Design Environment. The objectives of this lab are:
Become familiar with the MPLAB X environment.
Do some simple programming tasks using PIC24 assembly language.
As always, read/scan through the entire lab before starting to work.
Basics
If you've not already done so, download the pic24_code_examples.zip archive from Canvas > Files > Labs S2025 > Lab 0. Extract it into C:\ece3724\pic24_code_examples . This lab requires files from the chap03 directory.
Download lab2.zip from Canvas > Files > Labs S2025 > Lab 2. Extract it into C:\ece3724\pic24_code_examples\chap03\. This archive contains two assembly files you'll be working with in the lab:
mplab_test.s - This is a very simple program you'll be using for the prelab and Task 1 to get used to MPLAB.
netid.s - You'll be using this program in Task 2. It does some calculations with your netID and student ID number. You'll be submitting this file.
The following sections will cover basic usage of MPLAB X IDE 6.20:
Opening a project
To open a project, go to File > Open Project...
For these examples, I will be using the project C:\ece3724\pic24_code_examples\chap03\mptst_byte.X. Feel free to open it and follow along.
Closing a project
To close a project, choose the appropriate option from the File menu. To close a file, just click the X in the editor tab. Closing a file does not close a project and vice versa. A common error is to be working on a file that is not part of the project you are compiling. No matter what you do to the file, it won't fix your program! To avoid this frustrating problem, it is highly recommended that you only keep one project open at a time. If you need to look at other files that aren't in the project, just open them separately. If you absolutely must have multiple projects open, be sure to set the one you're trying to compile as the main project.
Opening an assembly source file
The assembly source files (the code) will be in the Source Files folder of the project. Doubleclick to open them in the editor:
Adding a file to a project
It is a pain in the neck to create a new MPLAB project. You have to be sure that all the header files and libraries from pic24_code_examples are included and that the makefile is configured correctly. Copying an existing project is somewhat easier, but you can run into trouble doing this as well. So in lab, follow these steps when you want to begin something new:
1. Open an existing project.
2. Then either:
a. Add a provided file (like lab code you've downloaded from Canvas) or
b. Create a new file.
Do not open up an existing file from pic24_code_examples or one of your completed labs and start modifying it. Why not? Because if you change it and suddenly start getting a bunch of errors, you don't know whether the problem is buggy code, your computer, MPLAB, the PIC, etc. (Instead, when you're writing code and get completely stuck, go back to one of these known good files and make sure it still runs. If it doesn't, then you've got bigger issues.
Running (debugging) a project
To debug (run in the MPLAB simulator) the project, click the button that looks like a piece of paper with a play button on the lower right corner.
The red square next to it - you guessed it - stops the debugger. You can also go to Debug > Debug Main Project or Debug > Finish Debugger Session through the menu.
I've set F5 as my Debug Main Project shortcut key. To do this, go to Tools > Options > Keymap
Viewing program memory
To view program memory, Window -> Target Memory Views -> Program Memory.
This opens up a tab at the bottom where you can view the (virtual) PIC's program memory.
Try switching the Format from Code to Hex (and then back, unless you're a computer). Right-click somewhere in the program memory, and make sure Symbolic Mode and Verbose Labels are checked. They also make it a lot easier to read. Uncheck/recheck them and try to figure out why.
Viewing data memory (file registers)
Data memory is called "File Registers" in MPLAB. If you click Memory on the bottom right of the Program Memory tab, it opens up a dropdown. If you select File Registers, this will show data memory in that tab instead. If you want to have both open at the same time, then Window > Target Memory Views > File Registers.
Format: Symbol makes this easier to read. For example, you can see the registers, starting at 0x0000, and below, starting at 0x1000, the variables in the program. Instead of scrolling through, you can click the magnifying glass below the output tab and search for line 1000.
Notice that it doesn't show u8_j, because that's at 0x1001.
Viewing registers
In MPLAB, instead of W0-W15, the working registers are called WREG0 - WREG15. All the registers with names are referred to as SFRs, or Special Function Registers. There's a number of ways to view their contents. One is by going to address 0x0000 of data memory, as mentioned above:
You can also Window -> Target Memory Views -> SFRs:
However, generally we're interested in only a few of the working registers. Also we might want to look at the values of some variables as well, and we'd like to do all this without scrolling back and forth through memory locations. Fortunately, there's a way to do this - setting Watches!
Setting Watches
To get the Watches tab to show up, you Window -> Debugging -> Watches (or just Alt-Shift-2).
The Variables tab is very similar to the Watches tab, but it also lets you view local variables i.e. variables that are created inside a function and then vanish when the function exits. (https://developerhelp.microchip.com/xwiki/bin/view/software-tools/ides/x/debugging/accessing-data/watches-vs-variables/)
To add a variable or register you want to watch, right click in the Watches tab. Another way to add expressions to the Watch window is to right-click in the source code and select "New Watch..."
You can also highlight variables to save typing, or select multiple expressions at the same time:
Variables are found in Global Symbols. Registers are found in SFR's (Special Function Registers). Important: To watch a working register, add WREG#. For example, to watch W2, select WREG2. If you're not able to add variables to the Global Symbols list, debug the program once first and try again.
If we look through mptst_byte, we can see it uses 3 variables (u8_i, u8_j, and u8_k), and 2 registers (W0 & W1 aka WREG0 & WREG1). So, if you're following along, add those to your watches:
To get the extra columns to show up, right click in the bar atop the watches that says "Name Type Address ..." and check the ones you want to see.
The last two lines of this program (visible in the above picture) just loop endlessly, doing nothing. So the watches are showing the final values in the registers and variables at the very end of the program. But what if our program screws up somewhere along the way and we want to find out where we went wrong? That is what breakpoints are for, and it's the last thing you need to know about in MPLAB, at least in order to do the prelab.
Breakpoints
A breakpoint is a place we want our program to pause its execution so we can examine memory and register contents in midstream. Setting a breakpoint is easy - just click on the line number in the left margin. Click again to make the breakpoint go away. Stop your debugger if it's running, and set a breakpoint on line 60:
Windows > Debugging > Breakpoints, or Alt-Shift-5 if your Breakpoints tab doesn't show up.
Some important things to know about breakpoints:
They pause execution of the program right before the line runs.
You can't set a breakpoint on a line without valid assembly (or later, C) code on it. Well you can, but you'll just get a warning message when you debug. Labels, comments, and compiler directives don't count as code.
You also may get warning messages if you have breakpoints in random files that aren't open anymore. Right-click in the breakpoint tab and select Delete All to make them go away.
Now start the debugger. The program should halt, the output tab should say:
Launching
Initializing simulator
User program running
Breakpoint hit at line 60 in file C:/ece3724/pic24_code_examples/chap03/mptst_byte.s.
User program stopped
And if we look at the Watches window, you should see...
The green arrow (currently on top of the breakpoint) shows the location of the program counter.
...a bunch of nothing. That's because this is the first line of code, and as mentioned earlier, it hasn't executed yet. If you click on File Registers to view the contents of data memory, you can see that, indeed, the registers (at 0x0000) and the variables (at 0x1000) are all zeroes. (Except for W15, which is the stack pointer - don't mess with this). Slightly more interestingly, if you click on Program Memory, you can see the line of assembly that's about to execute:
Remember, right-click and select Symbolic Mode and Verbose Labels.
The program counter (green arrow) indicates the location in program memory that is about to execute, and as might be expected, it's the same assembly instruction as the line in the program (0x64 = 100). Notice the __reset label. Scroll up to the top of program memory and you will see a GOTO __reset, which is how we got here, as program execution always begins at 0x0000
After we've paused at a breakpoint, we can step through the program line-by-line and examine:
Where in the program we are (Program Memory)
The contents of variables and registers (Watches)
The current contents of every location in data memory (File Registers)
To do this, we use the debugger commands:
These commands can also be accessed through the Debug menu, but you never will. In fact, you also probably will not want to click the icons dozens of times, so you need to learn the hotkeys, or at least the most important one (especially if you want to get all your prelab points).
F7 - Step Into - executes a single line of the program
F8 - Step Over - executes a single line of the program, but skips past whole functions (does the same thing as Step Into here since there are no functions to get into, and will also get you prelab credit).
F5 (unless you messed around with your shortcut keys like I did) - Continue - This is the green play button. It resumes execution of the program and goes on to the end (or until you hit another breakpoint).
You can learn about all the debug commands here if you're curious, but you'll probably never use the other ones. Just take a moment to play around with these three and marvel at how the contents of the registers and variables change as each line of code executes.
PIC24 Assembly
In order to complete this lab, you'll need to know some assembly. Besides the ebook and lecture slides, the required information can be found in the PIC24 Assembly Primer. (Just the first half, up to where it says "YOU NEED TO KNOW THIS MUCH ASSEMBLY TO DO LAB 2" in bright red)
Code commenting and neatness
Proper commenting and neat, organized code is more important than writing correct assembly code (except on the exams). You may never program assembly again in your life after you take this class, but you will almost certainly be required to write code that your employers, coworkers, and/or subordinates can understand. For the assembly labs (2-5), since most of what you are translating is just random math code in C, you are not expected to write "traditional" comments like:
; move register contents to variables and increment counter
or
; this shifts W2 left by 3 bits, then adds #0x3423 to W1
(Though you can if you want to and won't be penalized - use whatever additional comments you want that help you write the program.)
You are expected to:
write the C code you are translating as a comment and write the assembly code below it
write register assignments as comments
not have incorrect comments (usually left from a previous program when copying a file)
remove "junk" from the files you turn in
put a proper header on top
indent and use blank lines reasonably
in general, submit professional-looking work
Prelab (20 points)
Before the TA arrives:
Start MPLAB X, close other projects, open the mptst_word project from chap03, and debug it. Stop the debugger session.
Open the program memory tab to view your program.
Open the file registers tab to view your program's data.
Open the watch tab, then add u16_i, u16_j, u16_k, and WREG0, WREG1, WREG2.
Set a breakpoint in the program on the first line of assembly code (mov #2047, W0). Debug the project again.
TA checkoff
With the TA watching:
Show the TA that you can single-step through instructions.
You can do this with a keyboard shortcut (10).
You can only do it with the mouse (5).
You cannot (0).
Show the TA the requested variable in data memory.
You show it to the TA (10).
You show the TA the tab labeled "program memory" (0).
You frantically look for the "data memory" tab (0).
You tell the TA it's in the Watches/Variable window so you don't need to know how to find it in data memory (0).
Task 1: mptst_word.s (20)
For this task, you perform some simple calculations with the last four digits of your student ID number, then observe that the proper result is stored in data memory.
Be sure that only the mptst_word project is open. Stop the debugger. Open mptst_word.s.
Delete the massive header on top of the file. Do this now, because if you leave this on your code, your lab will not be accepted for grading:
DELETE THIS.
2. Put the proper header in its place:
+1 to your lab grade if you fix the spelling error from 2013.
3. Also erase these two lines, which are relics from the ebook:
4. Modify the i = 2047 assignment to be the last four digits of your student ID (the one on your student ID card, not your NetID from your email address). This is the only line of code you have to change for this task. Literally four numbers. Note: In all tasks, if your number begins with a 0, omit it, or the program will give odd results, as a prefix of 0 indicates an octal number. So if your number is #0123, just use #123.
On this and all other labs, including the practicum, do not use the wrong number or you will not get credit for the task.
For example if my student ID ended in 7777, I would do this.
5. Debug project.
6. Read the section entitled "Screenshots" at the bottom of the page. Then, take a screenshot of the Watch window contents (showing u16_i, u16_j, u16_k, and WREG0, WREG1, WREG2).
7. Take a screenshot of the data memory (File Registers window contents showing the variables). Be sure that u16_k is showing, as this is the "answer" variable that we care about.
8. Fix the comment above the line you changed to have your student ID in it.
9. Fix the comments for the C code at the top of the file.
Checkoff:
You've changed the number in the code.
You have changed the comments in both places.
You have the correct screenshots. It's on you to check that you have the correct number - the TA is not going to do math for you.
You've taken the default header off your file and have the correct one on top.
Task 2: netid.s (40 points)
In this task, you'll write a program in PIC24 assembly to perform some calculations, then use MPLAB to observe data memory and verify that your answer is correct.
Right-click "Source Files" in the Projects window, then select New > AssemblyFile.s...
2. Name the file netid and click Finish.
3. Go back to your mptst_word.s file, hit Ctrl-A to select everything. Hit Ctrl-C to copy, go back to the blank netid.s file you just created, and hit Ctrl-V to paste everything in.
4. Close your mptst_word.s file. Right click on mptst_word.s (the file not the project) in the Projects window, and select "Exclude file(s) from current configuration".
5. Debug the project again, just to check that it's working.
6. Fix the header, changing the filename in two (2) places to netid.s.
7. Here's the C code you're going to translate:
uint16_t u16_netid;
uint16_t u16_studentid;
uint16_t u16_answer;
u16_netid = __; // numbers from net ID (decimal)
u16_studentid = ____; // last four of student ID (decimal)
u16_studentid -= u16_netid;
u16_studentid = u16_studentid & 0xB0B0;
u16_studentid = u16_studentid | 0xC0C0;
u16_studentid = u16_studentid ^ u16_netid;
u16_studentid = ~u16_studentid;
u16_netid = u16_studentid << 3;
u16_studentid = u16_netid >> 2;
u16_answer = u16_studentid + u16_netid;
Copy-paste it into netid.s, overwriting the old C code at the top of the file. Make each line a comment by preceding it with a semicolon:
8. Type the the last 4 of your student ID and the numbers from your net ID (email address) into the blanks.
9. Declare your variables. Luckily, there were three 16-bit variables in mptst_word, so all you have to do is change their names. Leave the fourth variable, u16_bug alone. MPLAB has a bug where it shows the wrong size for the last variable you declare. Microchip will probably fix this bug by 2014, but for now a workaround is to declare a dummy variable that we don't care about:
I changed the first variable. +1 to your Lab 2 grade if you correct the comment over u16_bug like I did here.
10. Now the actual task: You must translate each line of the C program to assembly instruction(s). Some hints/guidelines:
You MUST include, in comments, a register assignment and the line of C code you're translating, followed by your translation to assembly.
You don't need to divide your code and write Input, Process, and Output, but if you do use those labels, use them correctly. Delete them if you're not using them:
Fine.
Also fine.
Not fine.
mptst_word moves the variables into registers for each instruction. This is something you'll have to do for Labs 3 and 4 or your program won't run. However, you are not required to do this for this task, e.g. if u16_netid is in W1 after one instruction and you need to do something with it in the next instruction, you don't need to move it into W1 again. Either way is fine, it's up to you.
Use only registers W0-W7. Do not use registers W8-W15.
Put a blank line between instructions but not in the middle of instructions: For example:
; W0---------W1
; u16_j += u16_k;
add u16j, w1, whatever
; W2 -------- W3 --- W4
; u16_sum + etc...
11. Use the Watches window to watch variables u16_netid, u16_studentid, and u16_answer as well as the registers you use. Delete the watches of variables you were watching before and any registers you're not using. Also, use the File Registers window to monitor the memory locations corresponding to these variables.
12. Debug your program. Take a screenshot of the Watch window contents. Take a screenshot of the the data memory showing u16_answer (File Registers window).
Checkoff: You have the correct value in u16_answer.
Report
See Lab Policy Summary for formatting guidance and a sample report.
The title page should contain the following: Lab name & number, your name & NetID, and course & lab section on successive lines.
Second page should begin with a brief description of the overall lab activity, intelligible to an outside reader.
Task 1 (write "Task 1" or "Task 1 - mptst_word" in your report, do the same for every Task so the grader can tell them apart)
Write a brief description of Task 1, intelligible to an outside reader, e.g. "I translated the following C code into PIC24 assembly..." not "I did mptst_word"
Copy/paste the C code you translated (using a monospace font) or include a screenshot of it in the report.
Include your two screenshots.
Verify that the value of u16_k in your screenshots is correct. See below for an example of how to do this.
Task 2
Write a brief description of Task 2, intelligible to an outside reader.
Copy/paste the C code you translated (using a monospace font) or include a screenshot of it in the report.
Include your two screenshots.
Verify that the value of u16_answer in your screenshots is correct.
Include the source code of mptst_word.s and netid.s as attachments to your submission. Check that the header and comments are correct. Remove comments/code that don't apply. If you make changes after being checked off, it's up to you to check that your code still runs.
How to Verify
You need to do the calculations by hand to show the grader that the answer in your screenshots are correct.
You don't need to show how you convert between bases or perform elementary math operations. Just don't do them wrong.
If you get a weird answer (hint: 0xFFFF + 1 = 0??) you need to explain it.
Do not handwrite on lab reports, ever. This includes MS Paint, using a stylus, or writing very neatly on graph paper and scanning it.
For example, let's say the C code you were translating was:
u16_studentid = 2047;
u16_studentid++;
u16_studentid = u16_studentid << 1;
Satisfactory verification
u16_studentid is the last four digits of my student ID, 2047. First, we increment by 1, giving 2048. Then left shift by 1 bit.
2048 = 0x800 = 0000 1000 0000 0000
Left shift 1 gives 0001 0000 0000 0000 or 0x1000
The screenshots below of the data memory and the Watches window show that u16_studentid contains 0x1000
Unsatisfactory verification
2047+1=0x8000
left shift 1 =4096 see screenshots
Grading
If you do not successfully complete a task and your report fails to mention or glosses over this fact, you will receive a zero for the report portion of your grade as well as for the task. If you attempt to deceive the grader, e.g. by including screenshots not generated by the code you submitted, your instructor will be notified and you will be recommended for an Honor Code violation.
The report is worth 20 points for neatly and coherently presenting your information to a reader. The following non-exhaustive list of errors will result in losing credit from the report portion of the lab grade:
bad screenshots (not cropped properly, blurry, too small)
text is "lab jargon" unintelligible to an outside reader ("u16_studentid declared and watch set 0x1000.")
text is phrased as instructions to a second party ("Increment variable.")
text is copy-pasted from the lab directions rather than using your own words.
text is a literal recap of the activities you performed rather than communicating your results and understanding ("First, I set a breakpoint. Then I added the following variables to the Watches window...")
blatantly erroneous text ("The program adds the first four digits of my student ID to the last four digits")
garbled / confusing / gibberish text ("Sure, I can help you with that! In assembly language written for the PIC24 microprocessor, a MOV command typically...")
using vague or incorrect terminology ("We wrote C code and ran it in MatLab")
excessive text
careless use of pagebreaks that leave blank pages, 1-2 lines of text on a page, etc.
general unprofessional appearance
code is untidy
code is missing header, has wrong header, and/or contains default header
The tasks are worth 60 points. If your report indicates that you did not successfully complete or do not understand a task, you will lose credit, even if you performed it during the lab. The same is true for tasks performed during the prelab. There are two tasks. The first task is worth 20 points. The second task is worth 40 points. The following non-exhaustive list of errors will result in losing credit from a task:
missing screenshot
screenshot of the wrong thing
screenshots show wrong values
cannot read screenshot
code won't run
code performs incorrectly
code is convoluted
code doesn't follow lab directions - no/missing/wrong register assignments, no/missing/wrong C code, etc.
didn't do calculations / calculations are incorrect/incomplete
Lab reports that flagrantly violate submission policy (wrong lab, no screenshots, no title page, no text besides headings/labels, mostly blank, assembly code pasted into pdf, paragraphs of lab text pasted in, extremely sloppy/unprofessional, missing code etc.) will not be accepted. You will receive a zero for the lab and may resubmit with late penalty.
Screenshots
When taking screenshots, use a snipping tool for screen capture. Don't select the entire screen or most of it.
Too much screen.
But don't zoom in so much that you're missing important information. Leave some surroundings, such as labels, headings, addresses, to give your image meaning.
Not enough screen.
Good.
Good.
If you resize the image in your report, be sure to preserve aspect ratio. (In Word, hold down the Shift key)
Hard to read.
If you're taking screenshots of the Watches Window, adjust the size of the columns to make them fit nicely. Also, do not highlight one of the watches as the dark blue makes them hard to read:
I found this article, How to Change Default Action on PrtScrn Button in Windows 11 from askdavetaylor.com to be helpful.