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?
Internal Subsystem
We will be relying heavily on the MSSP subsystem, configured to run in SPI
mode, to send and received bits from the SD card. We will talk more about
the SPI subsystem in coming lectures. To get an overview of the nature of
the serial communication between the PIC and the SD Card, consult Figure
15-5 of the PIC 18F26K22 Technical documents posted on the class web page.
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.
- In the INTERNAL OSCILLATOR area of the System Module window
- Oscillator Select: Internal oscillator block
- System Clock Select: FOSC
- Internal Clock: 16MHz_HFINTOSC
- Software PLL Enabled: Check
The Current System clock should be 64MHz (4x PLL)
- In the Device Resources area of the project window, expand the Timer
option. Double click TMR0,
- In the Device Resources area of the project window, expand the EUSART
option. Double click EUSART1 [PIC10/PIC12/…],
- In the Device Resources area of the project window, expand the MSSP
option. Double click MSSP2 [PIC10/PIC12/…].
- In the Project Resources area of the project window click on TMR0.
- Enable Timer: ✓
- Enable Prescaler: □
- Prescaler: 1:2 <Doesn't matter>
- Timer mode: 16-bit
- Clock Source: FOSC/4
- Enable Timer Interrupt ✓
- Still in the TMR0 configuration, click on the "Registers" tab
- Change the "TMR0H" text box to 0x0
- Change the "TMR0L" text box to 0x0
- Do not try and modify the Requested Period value in the "Easy Setup" tab.
- In the Project Resources area of the project window click on EUSART1.
- Enable EUSART: ✓
- Enable Transmit: ✓
- Enable Wake-up: □
- Auto-Baud Detection: □
- Enable Address Detect: □
- Baud Rate: 9600
- Transmission Bits: 8-bit
- Reception Bits: 8-bit
- Data Polarity: async_noninverted_sync_fallingedge
- Enable Continuous Receive: ✓
- Enable EUSART Interrupts: □
- Redirect STDIO to USART ✓
- In the Project Resources area of the project window click on MSSP2
- Mode: SPI Master
- Input Data Sampled at: Middle
- SPI Mode: 0
- Clock Source: FOSC/16
- SPI Clock <will change to 4000kHz>
- In the Project Resources area of the project window, click
"Pin Module". The editor window will change from the System Module to
Pin Module. Click on the Pin Manager tab in the console area. Click
on Port A bit 6 in the GPIO output row . The blue open
lock should change to a green closed lock. Now in the Pin Module area,
click on the Custom Name text box in the RA6 Pin Module row and change
the name to "TEST_PIN" and hit enter.
- In the Pin Manager tab in the console area:
- Click on Port B bit 4 in the GPIO output row . The blue open
lock should change to a green closed lock. Now in the Pin Module area,
click on the Custom Name text box in the RB4 Pin Module row and change
the name to "CS" and hit enter.
- Click on Port C bit 4 in the GPIO output row . The blue open
lock should change to a green closed lock. Now in the Pin Module area,
click on the Custom Name text box in the RC4 Pin Module row and change
the name to "WRITE_TIME_PIN", unselect the Analog check box then hit enter.
- Click on Port C bit 5 in the GPIO output row . The blue open
lock should change to a green closed lock. Now in the Pin Module area,
click on the Custom Name text box in the RC5 Pin Module row and change
the name to "READ_TIME_PIN", unselect the Analog check box then hit enter.
- Click File → Save All
- Go back and check the TMR0L and TMR0H registers after generating
the MCC configuration! The code configurator has a bad habbit of not
storing these timer values.
- Leave the configuration file name as "MyConfig.mc3"
- Click on the "Generate" button in the Project Resources area of the
project manager window.
In the MCC Save Configuration File, keep the defaults and Save.
Remember that anytime that you make a change to
the configuration you must re-generate the supporting files by clicking
on the generate button,
- 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.
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? I found the answer to this question
on the first page of the data sheet.
- 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. Next make the following changes:
- In main.c - comment out TMR0_WriteTimer(0x10000 - RATE);
- In main.c - remove comment TMR0_WriteTimer(TMR0_ReadTimer() + (0x10000 - RATE));
Now measure the interrupt period again. Put your finding in the table
below.
ISR timer adjustment | Interrupt period
|
TMR0_WriteTimer(0x10000 - RATE); |
|
TMR0_WriteTimer(TMR0_ReadTimer() + (0x10000 - RATE)); |
|
- Explain in your own words what causes the second form to be so
much more accurate.
An important note, you MUST configure timer 0
in MCC so that the TMR0H:TMR0L is 0 when you use the
TMR0_WriteTimer(TMR0_ReadTimer() + (0x10000 - RATE));
form to set the duration to the next timer. This is because the timer
is set to the Requested Period (from MCC) before your myTMR0ISR is called.
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.