EENG 383
Lab 9 - Data acquisition
Requirements
Working in teams of two, read through the following lab activity and perform all the actions prescribed. You do not need to document bullet items. Make a record of your response to numbered items and turn them in a single copy as your teams solution on Canvas using the instructions posted there.
Include the names of both team members at the top of your solutions. Use complete English sentences when answering questions. If the answer to a question is a table or other piece of art (like an oscilloscope trace or a figure), then include a sentence explaining the piece of art. Only include your answers, do not include the question-text unless it is absolutely needed.
Objective
To familiarize you with the SD Card and its SPI interface. To use
the test and measurement equipment to measure the time required to
complete read/write operations to the SD Card.
External Hardware
Kingston Technology is a large technology company that manufactures
mainly storage products. Their
microSDXC memory card Flash Storage Media document provides one of
the best overviews of micro SD Cards and the associated SPI interface
that I have found on the Internet. Download this PDF and use it to
help you answer the following questions.
- Use Figure 1 from the Kingston PDF and the schematic of the development
board to answer the following question.
- The SD Card pin# column refers to Figure 1 of the Kingston
PDF. The SPI Mode Name referrers to the SPI Mode Name column
from Table 2 of the Kingston PDF.
- The PIC pin column referrers to PIC pin (shown on the
development board schematic) attached to the SD Card Holder
pin in that row. If the pin in this row is not connected
to the SD card holder, write "Not connected".
- The PIC MCCP column refers to the MSSP function of the
PIC pin in that row. You can get the MSSP function by looking
in Table 2 of
the PIC18(L)F2X/4XK22 Data Sheet posted on the class web page.
| SD Card pin # | SPI Mode Name | PIC pin | PIC MCCP
|
| 1 | RSV | Not connected |
|
| 2 | | |
|
| 3 | | | SDO2
|
| 4 | | |
|
| 5 | SCLK | |
|
| 6 | | | Power supply
|
| 7 |   | RB2 |
|
| 8 | | | Not connected
|
- How many Bytes of memory does our 128MByte SD Card hold, represented
as a decimal number? The "Mega" in MB means 220. How many bits
of address does the SD Card need to give each Byte a unique address?
Firmware Organization
Let's start by creating, configuring and including all the code that
you will need for this week's lab. To do this, complete the following
steps. Note, this week's lab has two .c files and a .h file, so pay
close attention to the instructions at the end.
- Click on "Clock Control" in the Project Resources section of the Resource
Management tab (left side of the screen). Then, in the Clock Control tab
- System Clock Select: FOSC
- Internal Clock: 16MHz_HFINTOSC
- Software PLL Enabled: ✓
The current System Clock should be 64000000.
- In the Device Resources section of the Resource Management tab, scroll down
and expand the "Timer" list. Double click TMR0.
- In the Device Resources section of the Resource Management tab, scroll down
and expand the "UART" list. Double click UART.
- In the UART(None) menu that pops up, set the following:
- UART PLIB Selector: EUSART1
- In the Device Resources section of the Resource Management tab, scroll down
and expand the "SPI" list. Double click SPI_Host.
- In the SPI_Host(None) menu that pops up, set the following:
- SPI Host PLIB Selector: MSSP2 (SPI)
- In the Project Resources section of the the Resource Management tab, expand
the Drivers → Timer options if not already expanded, and click on TMR0.
- Timer Enable: ✓
- Timer Mode: 16-bit
- Clock Source: FOSC/4
- Prescaler Assignment: not_assigned
- Requested Period: 4.096ms
- TMR Interrupt Enable: ✓
- Generate TMR ISR: ✓
- In the Project Resources section of the the Resource Management tab, expand
the UART option and click on UART1.
- Requested Baudrate: 9600
- Data Size: 8
- Flow Control Mode: None
- Redirect Printf to UART: ✓
- Interrupt Driven: □
- In the Project Resources section of the the Resource Management tab, expand
the SPI option and click on SPI2_Host.
- Click the "Add Row" button and make the following table:
| Config Name | Requested Speed (kHz) | Calculated Speed (kHz) | Mode | Data Input Sample At
|
| HOST_CONFIG | 125 | 125 | Mode 1 | Middle
|
| CLASSIC_FWPORT | 4000 | 4000 | Mode 0 | Middle
|
- Interrupt Driven: □
- Click on "Pins" in Project Resources. In the Pin Grid View tab
(bottom of the screen) click on the blue open lock in the Port A 6
column of the "output" subrow in the "Pins" group of rows.
This space will change to a green closed lock.
- In the Pin Grid View tab click on the blue open lock in the Port
B 4 column of the "output" subrow in the "Pins" group of rows.
This space will change to a green closed lock.
- In the Pin Grid View tab click on the blue open lock in the Port
C 4 column of the "output" subrow in the "Pins" group of rows.
This space will change to a green closed lock.
- In the Pin Grid View tab click on the blue open lock in the Port
C 5 column of the "output" subrow in the "Pins" group of rows.
This space will change to a green closed lock.
- Open the Pins tab (right side of the screen).
Click on the Custom Name text box in the RA6 row and change
the name of RA6 to "TEST_PIN"
- In the Pins tab, change the name of the RB4 pin to "CS"
- In the Pins tab, change the name of the RC4 pin to "WRITE_TIME_PIN"
- In the Pins tab, change the name of the RC5 pin to "READ_TIME_PIN"
- Click on the "Generate" button in the Project Resources area of the
project manager window. If you get a MCC pop-up asking you to confirm
that the configuration has warnings, click Yes.
In the MCC Save Configuration File, keep the
defaults and Save. Anytime that you make a change to the configuration
you must re-generate the supporting files by clicking on the generate
button,
- If you are using MCC Melody, once you generate the MCC files, follow the directions here to patch you MCC files to work properly.
If you do not do this, your timer period will be wrong
and you will get incorrect answers later in your lab.
- Click on the Project tab in the project manager window,
expand the Source Files folder and double click main.c to open
it in the editor window.
- Replace the contents of main.c with inlab09.c
- Download sdCard.c and
sdCard.h into the same directory as main.c
- In the Project navigation pane, select the Projects tab.
- Right mouse click on "Header Files" folder
- Select "Add Existing Item…"
- In the Select Item pop-up navigate and select sdCard.h. Since
you have two files called "sdCard", be careful which you select.
- Add sdCard.c to the "Source Files" folder in the Project tab
using the same process.
- Compile and download the code to the PIC,
- Launch PuTTY and connect to the virtual communication port
associated with your development board.
Experiment with the code as you read through the following text.
The firmware provided in today's lab allows you to perform
some basic operations. Let's look at these by first pressing
"?" to get the menu.
-------------------------------------------------
SD card address: 0000:0000
-------------------------------------------------
?: help menu
o: k
Z: Reset processor
z: Clear the terminal
----------------SPI TEST-------------------------
t: send a Test character over SPI
--------------SD CARD TESTS----------------------
i: Initialize SD card
a/A decrease/increase read address
r: read a block of 512 bytes from SD card
w: write a block of 512 bytes to SD card
-------------------------------------------------
- i
Before you use the SD card, you must first initialize it to operate in
SPI mode. Try hitting the "i" key now. The firmware you programmed
will call the
SDCARD_Initialize(true); function which
establishes that the PIC wants to talk to the SD Card using SPI. You
will get three pieces of feeback from this function; CMD0, CMD1 and
the block length command. When everything is working normally, you
should get the following response.
CMD0, Reset Response: 1
CMD1, Init Response: 0
Block Length Response: 0
If you do not get this sequence (or if your PIC hangs), then you should
make sure that your SD card is inserted. Then reset the PIC and try
several more times. If this does not work, make sure that your
firmware is configured correctly. Then try an SD card that works in
another computer.
- a/A
The example program allows you to read/write blocks of 512 bytes
to/from the SD card respectively. These 512 byte blocks are located
at some starting address inside the SD card. The SD card address currently
used as the starting address for these blocks is printed at the top of the
menu as: SD card address: 0000:0000. The
'A' command increase the current SD card address by 512, and the 'a' command
decrease the current SD card address by 512. Be careful when decrementing
the address that you do not underflow to a really high address.
- w
Writes a block of 512 bytes to the SD card starting at the current
SD card address. The 512 bytes written are two sets of decreasing
values from 0xFF to 0x00.
- r
Reads a block of 512 bytes to the SD card at the current SD card address.
The values in this 512 byte block are printed out in 32 rows of 16 bytes
each. Each byte is printed out in two different formats in raw hex and
in ASCII. For example, when I read a block that has just been written,
I get the following three rows.
7f 7e 7d 7c 7b 7a 79 78 77 76 75 74 73 72 71 70 ~}|{zyxwvutsrqp
6f 6e 6d 6c 6b 6a 69 68 67 66 65 64 63 62 61 60 onmlkjihgfedcba`
5f 5e 5d 5c 5b 5a 59 58 57 56 55 54 53 52 51 50 _^]\[ZYXWVUTSRQP
You should consult an online ASCII table to verify some to these
characters. Note unprintable ASCII character my be displayed
as '▒' or as '.'.
- t
Sends one character over SPI. This function will not be used in
today's lab.
Now let's look at the code which does all this to understand better
how the code operated and how you may use this code template to
write your program for this week's lab.
- Look for the call to SDCARD_Initialize in main. What two
functions are called just prior? It's important that you call
these two function prior to calling SDCARD_Initialize.
- Look for the definition of SDCARD_Initialize in sdcard.c
Using the comments in this function, what are the four main
things that this function does?
- Look in main and find the name of the function that prints
out the contents of the SD card buffer when you use the "r"
function. What is the name of this function and what is the data
type of the argument that main passes to this function (sdCardBuffer)?
- For this lab, you will write out a function to spool the
contents to the terminal, one decimal value per line.
For example, the first 16 entries of my SD Card, when
spooled out to the terminal, look like:
128
159
187
213
233
248
255
255
248
233
213
187
159
128
97
69
This question asks you to estimate the time required to
print out a block and the entire 128MB SD Card contents.
- How many character per line are printed out
if a line
contains a single byte value (represented as a decimal value)
terminated with a carriage return and line feed. Make a
reasonable assumption - only a single answer will be accepted.
- How many total characters are printed out to display
an entire block of 512 bytes, one decimal value per row?
How many bits does this correspond to?
- Baud rate tells you how many bits per second are transferred.
At 9600 Baud, how long will it take to display an entire
block of 512 bytes, one decimal value per row?
- How long would it take to display the entire 128MB of the
SD Card, one decimal value per row at 9600 Baud? Represent your
answer in hours (3-significant figures).
- I made the sdCardBuffer array a global variable even though
its only used in main. Let's explore why using section 5.5.2 of the
XC8 Compiler User's Guide posted on the class web page.
- What is the difference between an auto and non-auto
variable? You should probably search the Internet for help
with this question.
- What is the size of a memory bank in the PIC? Look at
section 5.4 in the PIC18(L)F2X/4XK22 Data Sheet posted
on the class web page. What is the size of the available
data memory on the PIC? Use the addresses in Table 5-7
to help you find the answer.
- Auto variables must fit into one data bank and non-auto
variables can be as large as the available data memory in
the PIC. Assume that your program has a declaration of a
array that looks like:
uint8_t array[SIZE];
What is the largest value of SIZE if array is a local variable?
What is the largest value of SIZE if array is a global variable?
- Look at the code in main.c and provide the names of the functions
that read and write blocks from/to the SD card respectively.
Firmware Experiments
There are a variety of reasons that the timer 0 interrupt service
routine might get delayed from running, or accumulate
unanticipated delays while executing. In the example code provided,
I forced the ISR to have a big-ole-waste-of-time inside the ISR. As
designed, the intention of the ISR was to have it called once every
100µs and set RA6 high while the CPU is in the TMR0 ISR. To check
how well this is happening, measure the frequency of ISR calls using
an oscilloscope configured as follows.
| Ch1 probe | RA6
|
| Ch1 ground clip | Dev board ground loop
|
| Horizontal (scale) | 25 us
|
| Ch1 (scale) | 1V
|
| Trigger mode | Auto
|
| Trigger source | 1
|
| Trigger slope | ↑
|
| Trigger level | 1.5V
|
Make sure to:
- Align Ch 1 on the second lowest reticule,
- Align the horizontal position at the second left-most reticule,
- Measure the period between consecutive interrupts using the
ISR as configured and record it in the table. Next make the following changes:
- In main.c - comment out TMR0_CounterSet(0x10000 - RATE);
- In main.c - remove comment TMR0_CounterSet(TMR0_CounterGet() + (0x10000 - RATE));
Now measure the interrupt period again. Put your finding in the table
below.
| ISR timer adjustment | Interrupt period
|
| TMR0_CounterSet(0x10000 - RATE); |
|
| TMR0_CounterSet(TMR0_CounterGet() + (0x10000 - RATE)); |
|
- Explain in your own words what causes the second form to be so
much more accurate.
SD Card Read Block Interface
Let's look at how long it takes to read a block of 512 bytes from the
SD card using the oscilloscope configured as follows.
| Ch1 probe | RC5
|
| Ch1 ground clip | Dev board ground loop
|
| Horizontal (scale) | 500us
|
| Ch1 (scale) | 1V
|
| Trigger mode | Auto
|
| Trigger source | 1
|
| Trigger slope | ↑
|
| Trigger level | 1.5V
|
- How long does it take SDCARD_ReadBlock to read 512 bytes from the SD card?
Divide this time by 512 to determine the effective read time per Byte.
Represent your answer in microseconds.
SD Card Block Write
Let's look at how long it takes to write a block of 512 bytes to the
SD card using the oscilloscope configured as follows.
| Ch1 probe | RC4
|
| Ch1 ground clip | Dev board ground loop
|
| Horizontal (scale) | 500us
|
| Ch1 (scale) | 1V
|
| Trigger mode | Auto
|
| Trigger source | 1
|
| Trigger slope | ↑
|
| Trigger level | 1.5V
|
- How long does it take SDCARD_ReadBlock to write 512 bytes to the SD card?
Divide this time by 512 to determine the effective write time per byte.
Represent your answer in microseconds.