SD Card

7/29/09

A couple of my projects have a need for SD card interfaces to log data. I have now obtained an SD card connector on a breakout board, with it's own voltage regulator (see adapter). It was pricey (about $20). Unfortunately, I could not find an SD card connector as a through-the-hole part without buying them in bulk (with the JST SD card connector, which is a through the hole part, you have to buy a minimum of 60 parts). I have come across a SD card connector that is a surface mounted part, and that has pads connecting at the edge, and not under the part (see Digikey part). I'm going to try to do the next SD card connector I put together with an SMT part.

I have now soldered my SD card connector on its breakout board adapter to a header, and have soldered that to connections on one of my perf boards. See these pictures:

From the adapter web page, here is the pin out for this adapter:

VIN: Input power to the SD card (3.3V to 6.0V)
GND: Common (Connects to the housing of the SD socket)
3V3: Output voltage from the on-board 3.3V regulator (250mA)
NC: Connect to pin 9 on the SD card (not used in SPI mode)
CS: Chip select
DI: Serial input data
SCK: Serial clock
DO: Serial output data
IRQ: Interrupt request, connect to pin 8 on the SD card (not used in SPI mode)
CD: Card detect (active low)
WP: Write protect

I have established the following connections:

VIN: Connected to my +5V supply rail

GND

CS: Connected to pin 4 (CS, RA2) on my 18f4550

DI: Connected to pin 26 (SDO, RC7) on my 18f4550

SCK: Connected to pin 34 (SCK, RB1) on my 18f4550

DO: Connected to pin 33 (SDI, RB0) on my 18f4550

CD: Connected to pin 6 (RA4) on my 18f4550

WP: Connected to pin 5 (RA3) on my 18f4550

Now, to see if I can get some software working! Microchip supplies a software interface ("stack") to SD cards as a file system interface. Here is the link to AN1045-- File I/O Functions Using Microchip's Memory Disk Drive File System Library.

I have also downloaded previously with Microchip's current USB support code which installed under "C:\Microchip Solutions\MDD File System-SD Card", and which seems to be the same as AN1045. I'm going to try to flash my firmware with that code, put a SD card in place on my adapter, and see how joyful that is ;).

Trying to build this code, I'm getting errors like "configuration setting 'OSC' not recognized". It would seem some standard header is missing. Lovely! Here are the full set of errors I'm getting here.

If I comment out these configuration settings in the C code, I get another set of errors!

I am now downloading the most current version of the support libraries from Microchip (Memory Disk Drive (MDD) Library v1.2.2) which is contained in MCHPFSUSB Framework2.5a from here. Shall see if that generates the same errors. (I was trying v1.2.1 previously).

7/30/09

OK. I'm now looking at "C:\Microchip Solutions\MDD File System-SD Card\Pic18f\HardwareProfile.h", line 122, which starts with:

#ifdef USE_SD_INTERFACE_WITH_SPI

#ifdef __18CXX

And it appears I need to make changes in this code corresponding to my pins & 18f4550. I'm changing definitions for: SD_CS, SD_CS_TRIS, SD_CD, SD_CD_TRIS, SD_WE, SD_WE_TRIS, SPICON1, etc. until the start of "#elif defined __PIC24F__".

Commenting out the configuration settings, cleaning, and recompiling, I get all files compiling (YEAH!!!!), but an error: "Error - processor types do not agree across all input files". I'm thinking this may be because of the linker script. I'm going to try to change this to reflect the 18f4550 processor. From "C:\Program Files\Microchip\MPASM Suite\LKR", I've selected 18f4550i.lkr

Now, the linker is complaining that it can't find "tolower"-- a standard C library function.

I've selected the wrong linker script. I seem to need the one at "C:\MCC18\bin\LKR". I've selected 18f4550_g.lkr at that location. (There was no "i" file).

Hmmm. This fails on linking with an error "section '.code_FSIO.o' can not fit the section." Lovely. Not!

Hmmm. I thought this had to do with data definitions in the linker script, but the error is for a code section, so this doesn't seem right.

The linker is saying that the code size is e4ca (hex), which is 58,570 (base 10). I'm assuming the units are bytes. Does my processor have enough code space to fit this?

I was just reading in the C18 compiler docs. I tried turning on all optimizations: "To reduce the amount of program memory used by the code sections, enable all optimizations. To enable in the MPLAB IDE, select Project>Build options…>Project, click
the MPLAB C18 tab and set Categories: Optimization to enable all."

That reduced the code length to d5fc in length (54,780 bytes). Still getting compiler error! If I change the compiler options to the small memory model, I get length = d422 (54,306 bytes).

I downloaded the C18 C compiler I'm using on 7/15/09. So, it still has the full set of optimizations. My inference at this point is that, the 18f4550 microcontroller just doesn't have enough program memory space to support this SD card application.

7/31/09

In the MPLAB IDE with C18, I have now found that the PIC18f4610 part will compile without linker errors, as will the 18f26J50. Both of these MCU's have at least 64K bytes of program memory. The 18f26J50 has a USB interface.

I also just a response back from a Microchip forum posting. The AN 1045 document from Microchip (p. 11, Table 10) gives memory usage for the library. Table 9 in this same document gives library options, to vary memory usage. The current MDD library (see C:\Microchip Solutions\Microchip\MDD File System\Documentation\Readme.pdf) in section 5 also gives updated memory size requirements for the library. The file FSconfig.h has options to vary the memory usage.

I have now turned off all options except for ALLOW_WRITES, commented out most of the example code in Demonstration.c, and building for the 18f4550 still says .code_FSIO.o cannot fit the section. The length given is 0x802c which is 32,812 bytes, which is smaller than given in Table 1 of the current Readme.pdf file (because I have optimization on, presumably). The memory size of the PIC 18f4550 is 32K (32,768) bytes, so seemingly, we are just over max size!

If I disable write functionality, and comment out relevant code for writes in Demonstration.c, this enables the code to be small enough for the 18f4550. However, of course, this makes the code now useless for our purpose! We need to log data to the SD card!

If I re-enable write functionality, and turn OFF optimizations, this makes a code size of: 0x874a, which is 34,634 bytes. So, the optimizations only reduce the program code by about 2K. I have done this to get an idea of what the code size will be when the "demo" time of the C18 compiler expires. A 64K or 48K program memory size MCU should be sufficient. One question here is: Are there 48K MCU's that have the same pin layout as the 18f4550? (I'm trying to reduce change in my circuits).

Other possible MCU's include (amount of program memory in brackets): PIC18F2515 (48K, 5V, 28 pin DIP, no USB), PIC18F2525 (48K, 5V, no USB, 28 pin DIP), 18F2585 (48K, 28 pin DIP, 5V), 18F26J11 (64K, 28 pin DIP, 3V, no USB), 18F46K20 (64K, 40 pin; 3V part), PIC18LF4525 (48K, 40pin, 5V), PIC18F4610 (64K, 40pin, 5V, no USB), and 18f26J50 (64K, 28 pin DIP, 3V).

How much data RAM does the 18f4550 have? It has 2K bytes of data RAM.

It seems there is no PIC18 part with: USB, >= 64K program RAM, and 5V.

I am going to go with the PIC18f4610 part (see microchip page) because it has 64K program memory, 40pin, and 5V (but no USB interface). The 18f26J50 part also has USB, but is a 3V part. Since it seems for our logger projects we don't need USB very much (debugging may be done with LED's), I am going to get a part that does not have USB.

8/7/09

Here is the Eagle schematic I'm using for the circuit with this SD card. The MCU in the circuit still has the pin labels for the 18f4550 because I can't find an Eagle part for the 18f4610. The pin numbers are correct, however. Here's the pin out for the 18f4610:

And here are pictures of my wired circuit:

I'm using the MDD File System provided by Microchip.

Parameters in FSconfig.h are set up to ALLOW_WRITES in the file system (and not much else).

I have changed HardwareProfile.h for the specific SPI pins we're using on the 18f4610:

Port/Pin Function
RA1 WP
RA2 CD
RA0 CS
RC3 SCK
RC4 SDI
RC5 SDO

I am using a modified version of the 18f4610_g.lkr script.

Right now, the config #pragma statments are commented out int the Demonstration.c file.

First, before I go all wild and crazy, I need to flash a basic test program onto the PIC to make sure all is well. I just want to turn on the LED I've attached to RD1. I'm going to flash the PIC with this firmware. I was successful in flashing the firmware! But, when I power on the circuit, the LED is not turning on. Why not? I've made changes to the LED flashing example code (CONFIG changes) to get example working with the new PIC. It's also possible the hardware isn't wire correctly too.

I just tried removing all the CONFIG's and letting the MPLAB IDE set all the CONFIG's. That doesn't have the LED turning on. Other possible debugging steps: 1) swap the 18f4610 for a 18f4550, temporarily. I know it can work to drive the LED with this same circuit. 2) Find a C code example that works to drive the LED.

OK! I swapped a 18f4550 into this circuit, and the LED flashes with the version of the firmware for the 18f4550 (see here). Good deal! So, the hardware, at least as far as flashing an LED is concerned, works! So, my problem would appear to be in the firmware for the new (18f4610) MCU.

My best guess as to the problem is that the CONFIG's need to be set up for the 18f4610. Using the C18 compiler at the command line on Windows, mcc18 --help-config displays the configuration settings available for the device. I tried installing a full set of configuration settings in my assembly language program that turns on an LED, but this is not working.

So, what could be the problem? Perhaps the 18f4610 interacting negatively with the circuit? (e.g., the SD card interface). Perhaps the specific software configuration settings I have selected?

One thing I can do is to (a) program the MCU with the firmware I want, and (b) put the MCU on a breadboard, to eliminate all of the extra circuitry. [[I just doubt this is going to show anything new. The current circuit is just connected to pins that haven't yet been configured in software, so it seems unlikely that the extra circuitry could cause problems]].

OK. I flashed the 18f4610, and then connected it into a breadboarded circuit. It has MCLRE = OFF to disable MCLR. I applied power to both sides, and connected a LED in to RD1. No go. No flashing LED. It seems to point the way to: (a) either bad configuration settings, or (b) a faulty MCU. I'll try my other 18f4610 MCU and see if I get the same issues. Here's the breadboarded circuit:

I tried my other 18f4610. Same issue-- No LED turning on.

I am back to bad configuration settings. Here's my current (non-working) code. Here's a link to just the assembly code.

8/9/09

The guys at Microchip Forums came to my rescue on this one! Thanks Guys! The problem was the setting of the OSC. I had

OSC = LP

but, this means that I should have a clock or oscillator external to the circuit! (Which I did not!). Now, I have

OSC = INTIO67

and the LED turns on! Great!!!! :) :) :). As a secondary win, I've now learned that if you turn off MCLR in the configuration settings, once the MCU is programmed by the PICKit2, it starts running off the power provided by the PICKit2.

Here's the working program and here's a picture of everything running:

Happiness is an LED that turns on! :) :).

8/10/09

Before I proceed to testing the MDD library, I'm going to see if I can get an LED to turn on using C program code. OK! So, here's a C program, with the full set of config statements for the PIC18f4610, that turns on a LED.

Now, on to the MDD library example code!

Initially, the code didn't work. I've reformatted the SD card I'm using to have an "allocation unit size" (hopefully, block size) to 512 bytes because that's what it says currently in the FSConfig.h file.

I'm still not getting by the FSInit() line in the code. One possibility is that the SD card I'm using isn't "right". I have a micro-SD card in an adapter. Perhaps this isn't recognized by this hardware/software combination? Inserting the SD card from my camera doesn't help matters. However, the SD card from the camera probably isn't formatted with 512 byte blocks. My camera SD card is certainly formatted with FAT 32, and my MDD library settings are not allowing for FAT32 right now. I just rebuilt the library with FAT32 support.

Still not getting by the FSInit() line of the code. Block size could be an issue. I'm trying to reformat my camera SD card with 512 byte blocks. The first time through Windows Vista said it couldn't reformat the card. I'm giving it a 2nd try now. Also fails. Hmmm. I'm going to increase the block size to 1K. OK. That worked! However, now I'm running into data memory issues on the the MCU. The FAT buffers are not big enough and my knowledge is running out on how to adjust the buffer sizes.

I'm assuming that the FSInit() is taking responsibility for the Chip Select or Slave Select of the SPI interface.

I've found another SD card. It's a 1GB card. I'm reformatting it to 512 byte blocks, with FAT (16?) file system. Windows Vista complains that it was "unable to complete the format". Lovely. I'm now trying FAT32 with 512 byte blocks. That worked! (For formatting). However, it's still not getting past the FSInit() line of the code.

I just tried setting up ADCON1 so that RA1, RA2, and RA0 are digital. No change in behavior.

I just tried adding code to configure RA0, RA1, RA2 as inputs or outputs as appropriate. No change in behavior.

I just tried, in SD-SPI.h, commenting out SYNCH_MODE_FAST and SYNCH_MODE_MED because I was using the 64x prescale divider in my previous example code. However, this doesn't control the usage of these. It causes the code to not build. Had to take out these comments.

OK. I've changed my strategy. I've put an LED output into the guts of the FSInit() code. The LED is lighting after the first conditional in DISKmount in FSIO.c. This is indicating that MDD_MediaInitialize is returning an error code that is not MEDIA_NO_ERROR. The next place to continue looking is: MDD_SDSPI_MediaInitialize in SD-SPI.c

8/11/09

OK. We are getting by point [1] in MDD_SDSPI_MediaInitialize (see my "CGP [1]" comment in the code that I will link in below). This is immediately after the call to SendMMCCmd. It would appear then that the SPI interface may actually be working correctly, given that we are not failing on this command going to the SD card through the SPI interface.

Hmmm. Not sure if point [1] is actually in the conditional code. The conditional code is complicated. Point [2] is not in the conditional code, so we're not able to get to point [1].

Aha! We are getting to point [3] though!

OK. We've found the failure point. It's failing in MDD_SDSPI_MediaInitialize at point [4].

So, in reality, we don't know if the SPI interface is working correctly. The failure is happening in the response to the call to SendMMCCmdManual.

This may be failing for reasons including: (a) I've not initialized pins correctly, and (b) the SPI is not wired correctly to the SD card adapter.

Let's look at the wiring first. I was a little concerned about the labeling on the SD card adapter pins. I've gone from DO on the SD card adapter to SDI on the MCU. That is, the Data Output of the car goes to Data Input of the microcontroller. SDI on the MCU stands for Serial Data Input, and so it should go to the DO (Data Output) of the slave (SD card).

The function MDD_SDSPI_InitIO is being called by the MDD code, and that programs pins: CD (Card Detect) as input, CS (Chip Select) as output and WE (Write Protect) as input.

I'm wondering why, in the code sequence around point [3], there is no Open call to initialize the SPI interface (e.g., no call to OpenSPIM). The first SPI interaction, after initializing pins in MDD_SDSPI_InitIO, seems to be the line:

SPICON1 = 0x00;

and then the loop that calls

WriteSPIManual

Why is GetSystemClock(), immediately after point [0], giving a value less than 25,600,000? It should be 40,000,000 from the HardwareProfile.h

At point [5] in Demonstration.c, __18CXX is defined.

At point [6], __18CXX is defined.

OK. I understand. The conditional code around [2] is for the system clock LESS than 25,600,000. Our system clock is 40,000,000. Thus, the conditional code around [2] is skipped.

Hmmm. The code after point [3] is being executed. This does "bit banged" SPI. That is, the SPI module of the MCU is not being used to control the SPI bus. Thus, the SPI pins (RC3, RC4, RC5) should be initialized. But, I think they have not been initialized.

Hmm. In WriteSPIManual, it has two lines:

SPICLOCK = OUTPUT;
SPIOUT = OUTPUT;

(I wonder if I was using some other kind of clock scheme for SPI previously with the PIC18f4550. Because I don't recall anything about manual SPI bit banging).

I've just found a bug in HardwareProfile.h. SPIOUT was misdefined as pin RC7. Ooops. And another error defining the clock as RB1. Double ooops. And a triple ooops.

Holy #&@^@%@!&!!!!!! Yeah! I have my first working SD card writing test!!

Here's the file & output on the SD card:

Here's the code I've been working with.

One interesting outcome of this debugging process is the fact that SPI isn't being used in the normal way with the 18f4610, and the MDD library. It seems that in order to use other SPI devices and this MDD library with the 18f4610, we may need to do some rethinking. According to the strategy used by the MDD library, the clock speed of the 18f4610 is too high. Was the clock speed of the 18f4550 slower, or was I relying on an external clock for SPI? Hmmm. Or perhaps the clock speed issue with the SPI just relates to the specific SD card/MMC devices. We should find out what the max SPI clock rate is for our sensors.

8/12/09

I've just put a loop in my code and in the loop, I'm calling MDD_MediaDetect, initializing the SD card (FSInit), opening a file, writing (appending) to the file, and closing the file. It takes approx. 3 seconds per iteration in this code.

Another way to resolve the issue of keeping a SD card file open while reading SPI sensors is to get a MCU that (a) has enough program memory for the MMD library and (b) has two SPI modules-- one could be used for the MMD library and the other could be used for accessing sensors.