Close

SD Card Library Examples

A project log for 3-Chip Z80 Design

Combining a Z80 retro design with a modern PSoC CPU.

land-boardscomland-boards.com 10/23/2019 at 14:230 Comments

There is a PSoC library (emFile) for SD cards but it's more oriented towards supporting FATxx (DOS) file systems. Grant's code already takes care of the CP/M file system details so those examples would be painful to adapt. The Arduino library, also, centers around DOS.

The lower level connection is the SPI and that's easy for the PSoC since it has SPI interfaces built in. PSoC Creator makes the API code to talk to the SPI.

We've already done the Z80 to SD card interface. It's a series of I/O space addresses which set the block number, write a command, read the status and read/write data from/to the SD card.

Next, we need to fill in the functions to map Grant's calls into PSoC functions to map between the Z80 I/O and SPI interfaces (Grant''s details are here).

Links

The following series of BLOG posts is really good and actually gives the C code for a Microcontroller. The author helps quite a bit by working the examples in detail. If you really want to understand SD card access it's a great place to read. 

Best part is he provides his source code. I can't use the code, as-is, since he's made some trade-offs I don't need and my hardware has different API calls to his ATMega SPI interface but it gets me close.

One of the trade-offs is that he's written the code to read from the SD card in small chunks to support Microcontrollers with very little SRAM. That's not necessary in this case since we've got a PSoC with 32KB of SRAM. Having 2 dedicated buffers of 512-bytes each barely makes a dent in our internal SRAM. I think the right approach is to read an entire block into the SRAM of the PSoC and have the PSoC feed the data out to the Z80.

Here's the helpful series:

SD_init code from Part 4

Here is the code from part 4 of the series above. The comments show what the command would be if typed into a Bus Pirate.

unsigned long sd_sector;
unsigned short sd_pos;

char SD_init() {
    char i;
    
    // ]r:10
    CS_DISABLE();
    for(i=0; i<10; i++) // idle for 1 bytes / 80 clocks
        SPI_write(0xFF);
        
    // [0x40 0x00 0x00 0x00 0x00 0x95 r:8] until we get "1"
    for(i=0; i<10 && SD_command(0x40, 0x00000000, 0x95, 8) != 1; i++)
        _delay_ms(100);
            
    if(i == 10) // card did not respond to initialization
        return -1;
        
    // CMD1 until card comes out of idle, 
    // but maximum of 10 times
    for(i=0; i<10 && SD_command(0x41, 0x00000000, 0xFF, 8) != 0; i++)
        _delay_ms(100);

    if(i == 10) // card did not come out of idle
        return -2;
        
    // SET_BLOCKLEN to 512
    SD_command(0x50, 0x00000200, 0xFF, 8);
    
    sd_sector = sd_pos = 0;
    
    return 0;
}

Makes Sense of a Past Mystery

The initialization part of this makes sense of something I saw when I wrote another SD card driver before (for my 32-bit RISC design in an FPGA). I don't think it did the initialization right and when it ran it would sometimes not work for the first SD card access. Later accesses worked just fine. I think it might have been lacking the initialization sequence.

In a later log I will take this example code and adapt it to the PSoC.

Discussions