Close

SD Card Block Writes from the PSoC monitor

A project log for 3-Chip Z80 Design

Combining a Z80 retro design with a modern PSoC CPU.

land-boardscomland-boards.com 10/26/2019 at 18:400 Comments

Example Code Out There?

Unfortunately, the code example that I used to develop the read block routine doesn't have a write block example so I don't have that as reference code to compare with my code. 

I used the same code for the write that I have for the read and changed the CMD to the proper code for single block writes. I did leave in the same two dummy writes at the end but I wonder if there's some difference that I did not account for there? I see the two dummy writes for the CRC after the transfer in the SdCard.cpp file that is used for the Arduino. After the dummy bytes they pull the SD card status. They do that with a send of 0xff and read the result. I wonder if I need to do that with this card?

The SD card spec for SPI has:

"...every data block sent to the card during write operations will be responded with a data response token"

I tried an extra read at the end and got 0xFF. Can't tell if it's from the SD card.

Checking the Sector Number

The sector number I want to write to is 1GB / 512-bytes. The sector number for the block at the 1GB location is 0x20,0000,

To run the monitor I press the EXFP button on the Front Panel. If I didn't have the front panel I could just jump into the monitor but this way is flexible. Adding a function to write to the SD card when "W" is entered is relatively easy since I already have the command interface works.

Tried it and the reads don't match the writes. I don't know what's in the upper card contents. Is there a problem with having block numbers so high? The sector number is an unsigned long (32-bits) so the value 0x200000 fits. This translates into:

// S  0000 0000 0000 0010 0000 0000 0000 0000     - Sector Number
// AD 0000 0100 0000 0000 0000 0000 0000 0000     - Sector shifted left by 9 
// UP 0000 0100                                   - Upper byte
//                                                - >> 24 bits + << 9 bits = >> 15 bits
// UM           0000 0000                         - Upper middle byte
//                                                - >> 16 bits + << 9 bits = >> 7 bits
// LM                     0000 0000               - Lower middle byte
//                                                - >> 8 bits + << 9 bits = << 1 bit
// LO                               0000 0000     - Bottom byte

This actually does make sense. The address sent to the SD card is the absolute address where the bottom 9 bits are 0x's to match the 512 byte sectors. The bottom bits of the sector count get shifted left by 9 bits Since it's being written into the second address byte from the bottom it only gets shifted up by 1 bit. 

LBA mapping to the Disk

This probably doesn't matter for this, but Grant's docs has: 

Write Code

The write code looks like:

void SD_WriteSector(uint32 sector, uint8 * buffPtr)
{
    uint16 loopCount = 0;
    uint8 junk;
    SPI_write_byte(CMD24);            // CMD24
    SPI_write_byte(sector>>15);       // >>24 + <<9 = >> 15
    SPI_write_byte(sector>>7);        // >>16 + <<9 = >> 7
    SPI_write_byte(sector<<1);        // >>8 + <<9 = << 1
    SPI_write_byte(0);
    SPI_write_byte(0xFF);
    while((SPI_Master_ReadTxStatus() & SPI_Master_STS_TX_FIFO_EMPTY) != SPI_Master_STS_TX_FIFO_EMPTY);

The top byte of the sector number is in d15..d22. The read is attempting to happen with:

readSDCard(0x200000);

One problem was that I bumped up the SPI bus speed to 400 KHz but had the sample rate at 500 KHz so there was possibly some data dropped. After changing the sample rate to 500 KH this is what I see for the write:

So, I can see the writes and I know reads work when I read sector 0 because I see the CP/M code.

Read from the SD Card
0000  c3 5c d3 c3 58 d3 7f 00 43 6f 70 79 72 69 67 68  .\..X...Copyrigh
0010  74 20 31 39 37 39 20 28 63 29 20 62 79 20 44 69  t.1979.(c).by.Di
0020  67 69 74 61 6c 20 52 65 73 65 61 72 63 68 20 20  gital.Research..
0030  20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00  ................
0040  00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................

But my code does the write, then does a read and it gets back something other than the expected pattern (0xff, 0xfe, 0xfd...). 

Write to the SD Card
0000  00 00 00 00 00 00 00 00 00 ff ff ff ff ff ff ff  ................
0010  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
0020  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................
0030  ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff  ................

So it appears that the SD Block Write didn't work correctly, I don't see a wait after the write before the read starts. Is there a need to wait after writes before starting the read cycle? Adding a time delay between the write and read to see if this is the reason.

void writeSDCard(uint32 sectorNumber)
{
    SD_WriteSector(sectorNumber, writeSDBuffer);
    CyDelay(1000);
    SD_ReadSector(sectorNumber, readSDBuffer);
    dumpBuffer(readSDBuffer);
    return;
}

 Tried the delay and it didn't change the results. Here's the start of the SD Read.

And here's the start of the SD Write:

The commands are defined as:

#define CMD12   0x4C
#define CMD13   0x4D
#define CMD17   0x51    // Read a single block
#define CMD24   0x58    // Write a single block

I see the 0x58 (CMD24) at the start of the write sequence followed by the address 0x40 (for both reads and writes).

One Problem

The code has a timeout when it is looking for 0xFE and it never got the 0xFE. I made the loop 1000 checks and it still didn't get the 0xFE. The card returns the 0x00 status after the initial command.

I increased the number of tries to 10,000 and it still didn't respond. Makes me wonder if this response is specific to reads? It would make sense since there may be an extra delay in the card to set up reads. I could see the card transferring the read buffer.

Got writes to work after a very long slog. And right now, they only work because I initialize the card after each write. But they do work. And I'm going to figure out how to clean up the write so it ends properly.

Discussions