This lab has you explore asynchronous serial I/O and interface the PIC with a serial EEPROM using the I2C protocol.
Download the file lab9.zip from Canvas > Labs S2025 > Lab 9. It contains three projects: uart_test.X, uart_test_interrupt.X, and i2c_eeprom.X.
Make a new folder in C:\ece3724\pic24_code_examples called lab9. Extract the contents of lab9.zip into this folder.
Download the datasheet for the Microchip 24LC512 EEPROM.
Answer the following questions. Your answers must be on paper. If you are an in-person student, your name must be on the paper. Your letter waveform may be handdrawn but it should be reasonably neat. You may handwrite the other answers. You may either rephrase the questions, copy them, or jot down relevant portions, however you must give an indication of what you are answering. For example :
Inadequate:
3. 42
Inadequate:
3. 42 us
Adequate:
3. one bit time: 42 us
(Note: the answer to #3 is not 42)
Take the first letter of your name (capitalize it), and draw the asynchronous serial waveform used to transmit it. Assume data is sent LSB to MSB as 8 data bits + 1 start bit + 1 stop bit. Label your waveform the same way as the below diagram (i.e. it should have 1s and 0s, and all the words, but use the ASCII code for your letter).
Y. Luo, ECE3724 Lecture Slides, Chapter 9 - Asynchronous Communications, p8, Example 3
2. What is the baud rate that you commonly use for your BullyCPP connection?
Give the answers to #3-5 in microseconds. For all of them, assume the baud rate from #2.
3. How long does it take to transmit one bit?
4. How long does it take to send on ASCII character assuming 8 data bits + 1 start bit + 1 stop bit?
5. How long does it take to overflow the dsPIC33EP128GP502 UART, assuming that it takes five complete characters, overflow occurs when the 5th character is fully received, and characters are sent with no dead time between them?
6. What is the amount of dsPIC33E timer ticks equivalent to answer #5, assuming the processor is running at a frequency of 60 MHz, and the prescaler is 8? (Solve for PR2)
Wire the 24LC512 EEPROM from the parts kit wired up on your board. You must look at the datasheet to figure out how to do this.
Connect SDA to the ASDA1 pin on your PIC
Connect SCL to the ASCL1 pin.
SDA and SCL must also be connected to the Vcc rail, via external pullups - the 2.2 K resistors from your parts kit will work.
Take the last digit of your student ID, convert it to binary, then use the last three bits for the A2/A1/A0 pins. So, if your last student digit is 5, this is 0b0101, the last three bits are 101, so A2=1 (VDD), A1=0 (GND), and A0 =1 (VDD).
All of the pins of the EEPROM must be connected to something, even pin 7 and pin 8. Read the datasheet to find out what.
Turn your paper into the TA upon arrival to the lab. (15: 5 for waveform, 2 each for other 5 questions)
Your EEPROM is wired correctly and neatly. (5)
Open the uart_test project, build it, and program your PIC with it. This program measures the UART overflow time by having the user input a character string, followed by a loop that only reads the first character and ignores the rest of them. The PIC Timer3 is started after the first character is read, and the loop is exited if either UART1 overflows or the timer overflows (the timer overflow period is much greater than the UART overflow time). The UART1 overflows when its internal buffer is full and the next character is fully received.
Test the program by typing the number "1" into the BullyCPP window. You should get a message saying that "UART overflow did not occur". Next, copy (Ctrl-C) and paste (Ctrl-V) progressively larger strings into the BullyCPP window ("12", "123", etc) until you find the first one that overflows. Call this the "overflow string". Take a screenshot of BullyCPP showing the overflow.
When the UART overflows, a timer tick value is printed out corresponds to the number of timer ticks after the arrival of the first character (which is read by the program) and UART overflow. Test the program with a few times with your overflow string and take an average of the last three timer tick values you see. The program also uses a GPIO pin to measure UART overflow time by setting RB14 high after receipt of the first character, and then back low when UART overflow occurs. Convert the timer ticks into a time in microseconds (the reverse of prelab question #6).
Find the top left wire of the VirtualBench logic analyzer connector (it has 40 wires, colored black, red, green, yellow, blue, and white). It is labeled GND. Stick a small wire from your wiring kit into this wire socket, and plug this into your breadboard on the ground rail.
Connect the VirtualBench logic analyzer red wire labeled D0 into the RX pin of your PIC (will be the RB10 pin).
Connect the VirtualBench logic analyzer red wire labeled D1 into the RB14 pin of your PIC.
Remove the analog input from Channel 1 so the red line goes away.
Configure the VirtualBench logic analyzer, enabling D0 and labeling it UART RX, and enabling D1 and labeling it RB14.
Set the trigger for a rising edge on RB14.
Type in the first capital letter of your name and measure the width of one bit. Take a screenshot.
Change trigger to falling edge.
Type in your overflow string. Measure the high pulse width (from where it first goes high to where it dips back low) of the RB14 trace using cursors in VirtualBench and compare this time to the time that you computed in step 1 and in the prelab. This is the measured overflow time of the UART.
Capture a VirtualBench screenshot showing all of the characters that were sent on the UART RX trace as well as your measurement of the RB14 high pulse time:
You have:
screenshot of BullyCPP, showing number of ticks for overflow
conversion of this overflow time into microseconds
VirtualBench screenshot of your letter
measurement of one bit time
VirtualBench screenshot of overflow
measurement of overflow time
Keep the VirtualBench connections from Task 1
Open the uart_test_interrupt project. This project is the same as uart_test except that it has the compiler flag -DUART1_RX_INTERRUPT defined during compilation, which enables interrupt-driven UART code in the my_pic24_uart.c file Interrupt-driven I/O uses a software FIFO to store incoming UART receive bytes in order to give a larger number of characters before receive overflow.
How the compiler flag -DUART1_RX_INTERRUPTis turned on in the project; to reach this, right-click on uart_test_interrupt in the Project panel and select Properties from the pop-up menu. You shouldn't need to adjust it - it's just for reference.
Open the file my_pic24_uart.c, and find the define UART1_RX_FIFO_SIZE statement; note that this size is set to 32.
Find the UART1 RX interrupt service routine (_U1RXInterrupt) in the my_pic24_uart.c file, and in the blank line near the beginning of the function, add the line _LATB2 = ~_LATB2; This toggles the RB2 pin each time the interrupt is called and a serial character is stored in the software buffer.
Build the project and download it to your PIC. Send the overflow string found for Task 1, and you will find that the UART software buffer does not overflow.
Keep sending successively larger strings until you find the first one that causes overflow (you will get a software reset, and a report of 'UART1 RX Interrupt FIFO overrun' in BullyCPP). Capture a screenshot of the overflow in BullyCPP.
Locate the wire D2 on the logic analyzer connector and plug this wire into the RB2 pin of your PIC. Label this RB2 in the VirtualBench logic analyzer setup.
Configure the VirtualBench for single shot trigger, falling edge.
Send the same string you found that caused overflow.
Zoom out on the VirtualBench display until you see all of the characters that were sent, and verify that the RB2 trace toggled for each character that was received. Take a screenshot.
You don't need to measure anything.
BullyCPP screenshot showing overflow. You know how many characters it took to overflow.
VirtualBench screenshot showing your overflow string.
Open the project i2c_eeprom.
Include the source file lab9.c and exclude i2c_eeprom.c .
The control bytes are defined near the top of the file:
// control bytes
#define READ 0x00
#define WRITE 0x00
Replace the 00s with two hexadecimal digits. Information on how to do this can be found in the datasheet (in Device Addressing).
Build the program and download it to your PIC. When run, this program displays three menu options:
Option #1 reads a byte from the current address location in the EEPROM
Option #2 reads a byte from a specific address
Option #3 writes a byte to a specific address and reads that byte back to verify that the write operation was performed correctly.
Option #1 has been implemented for you, while options 2 and 3 need to be completed for this task.
Execute menu option #1, readOneByteCurrentAddress. You should get a string back indicating that some byte was read from your EEPROM (we don't care what the byte value is). If you get a Watchdog timer timeout with an I2C error message, this means that either your #define READ address is incorrect, or your EEPROM is wired incorrectly (A0-A2 wrong, SDA/SCLK lines reversed, write protect pin not grounded, SDA/SCLK pins not connected to PIC, no pullup resistors on I2C lines, etc), or both.
By default, the entire EEPROM is full of 0xFF, so you won't get very interesting results even if it does work.
Remove the RB14, RB2, and UART RX wires, and clear them from the VirtualBench setup.
Connect the red logic analyzer wire, D3, to the SCL pin on the LC512 EEPROM. Label this SCLK in the VirtualBench setup.
Connect the red logic analyzer wire, D4, to the SDA pin on the LC512 EEPROM. Label this SDA in the VirtualBench setup.
Add an I2C interpreter using these two pins to the VirtualBench logic analyzer setup:
Set up the VirtualBench software for single shot execution, with trigger on the falling edge of the SDA trace.
Run option 1 and take a VirtualBench screenshot:
You don't need to measure anything.
Menu option #2 calls a function named readOneByteSpecificAddress that reads one byte from location u16_address and returns it. Currently it does nothing, since the function is nearly empty. You need to write it.
Consult the datasheet (READ OPERATION : Current Address Read).
Use the primitive functions listed below (all of them may not be needed):
void startI2C1(void);
void rstartI2C1(void);
void stopI2C1(void);
void putI2C1(uint8_t u8_val);
uint8_t getI2C1(uint8_t u8_ack2Send);
To extract the most significant byte of a 16-bit number into an 8-bit variable, you can do:
u8_msb = (u16_address >> 8);
To extract the least significant byte of a 16-bit number into an 8-bit variable, you can do:
u8_lsb = u16_address & 0xFF;
The function needs to return the byte read, so remember to fix the return 0; line.
You need comments on every line, like in readOneByteCurrentAddress. Might as well do it now.
Test option #2 with a few addresses. However, since the entire EEPROM is 0xFF, you won't be able to tell if it's working correctly yet.
Take a VirtualBench screenshot of readOneByteSpecificAddress in action:
You don't need the gray lines, since they're just duplicates. No measurements either. Make sure the ASCII values are readable.
Menu option #3 calls a function named writeOneByteSpecificAddress that writes the u8_byte byte value to location u16_address. Currently it does nothing, since the function is empty. Complete it. Use the datasheet (WRITE OPERATION : Byte Write).
After running writeOneByteSpecificAddress, Option #3 also calls readOneByteSpecificAddress to check that the byte written is correct. So if you're having difficulties, it's possible that your writeOneByteSpecificAddress is fine but that your readOneByteSpecificAddress is jacked up, causing it to check the wrong byte.
Test your implementation with the address of the last four digits of your student ID number. Write the ASCII code of the first (capital) letter of your name. Use option #2 to read that address. Take a screenshot of this in BullyCPP.
Take a VirtualBench screenshot of writeOneByteSpecificAddress in action.
This was at 10 us. Make sure you can read the ASCII values
The TA uses option #3 to write something into some address, then reads it back with option #2.
There are four screenshots (one of BullyCPP and three of VirtualBench) for this task.
Your report must have a title page.
You must textually describe what all your images are showing the reader.
Do not invite the grader to inspect values in screenshots, e.g. "Rise time shown below:" Rather, state the value in your report. "The rise time was 280 ns as seen below."
Write a few sentences describing the overall activities of the lab.
Distance students only: Label the first section Prelab. Include your response to the five questions. Your letter waveform may be handdrawn but it should be reasonably neat. Your other answers must be typed, not handwritten and scaneed. You may either rephrase the questions or copy them, however you must give an indication of what you are answering (not just: 1. True 2. 42 etc). Include a photo showing you have wired your EEPROM on your board.
Label the first section Task 1. Describe Task 1 so that an outside reader could understand what you measured. Compare your prelab answers to your actual results. Present your data in a coherent and organized fashion. Be sure to include:
screenshot of BullyCPP, showing number of ticks for overflow
conversion of this overflow time into microseconds
VirtualBench screenshot of your letter
measurement of one bit time
VirtualBench screenshot of overflow
measurement of overflow time
Label the next section Task 2. Describe Task 2 so that an outside reader could understand what you measured. Present your data in a coherent and organized fashion. Be sure to include:
BullyCPP screenshot showing overflow.
How many characters it took to overflow.
VirtualBench screenshot showing your overflow string.
Label the third section Task 3. Describe Task 3 so that an outside reader could understand what you did. Be sure to include:
your one BullyCPP screenshot.
your three Virtual Bench screenshots.
Submit your lab.c file
Be sure your name and etc. is at the top
Comment each line you added
Check that it is neat and indented right.
If you've made any changes, since leaving lab, debug your program in MPLAB to make sure it stil runs.
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 ("I got my PIC to overflow." "Here is the screenshots of my I2C.")
text is phrased as instructions to a second party
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 ("First I opened an MPLab project. Then I saved the file as...")
blatantly erroneous text
garbled / confusing / gibberish text ("The length of one bit is one bit, also known as a byte.")
using vague or incorrect terminology
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 and/or contains default header
code has inaccurate/inadequate comments
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 three tasks. The first task is worth 10 points. The second task is worth 10 points. The third task is worth 40 points. (Task 3a is worth 10, and 3b and 3c are each worth 15 points.) The following non-exhaustive list of errors will result in losing credit from a task:
missing screenshot/diagram/text
screenshot of the wrong thing
screenshot shows incorrect results
cannot read screenshot
code won't build
code performs incorrectly
code is convoluted
code uses incorrect methodology; doesn't follow lab directions
Lab reports that flagrantly violate submission policy (wrong lab, no screenshots, no title page, no text besides headings/labels, mostly blank, code pasted into pdf, paragraphs of lab text pasted in, extremely sloppy/unprofessional, missing code etc.) will not be accepted. The student will receive a zero for the lab and may resubmit with late penalty.