software/liblitesdcard/spisdcard: simplify/rewrite for consistency with the others parts of the project.

- Improve code readability, remove un-needed or duplicate comments.
- Only use a spi_xfer function for both write/read.
- Set the SDCard to low clk freq before init and increase it when initialized.
This commit is contained in:
Florent Kermarrec 2020-06-05 09:07:19 +02:00
parent 860ac1e212
commit 7d141258be
7 changed files with 267 additions and 321 deletions

View File

@ -538,37 +538,43 @@ void romboot(void)
void sdcardboot(void)
{
printf("Booting from SDCard...\n");
#ifdef CSR_SPISDCARD_BASE
printf("Initializing SDCard in SPI-Mode...\n");
if(spi_sdcard_goidle() == 0) {
printf("SD Card Timeout\n");
return;
}
#endif
#ifdef CSR_SDCORE_BASE
printf("Initializing SDCard in SD-Mode...\n");
sdcard_init(); // FIXME : check returned value
#endif
if(sdcard_readMBR() == 0) {
printf("SD Card MBR Timeout\n");
return;
}
unsigned int result;
printf("Booting from SDCard...\n");
/* Initialize SDCard */
#ifdef CSR_SPISDCARD_BASE
printf("Initializing SDCard in SPI-Mode...\n");
result = spisdcard_init();
#endif
#ifdef CSR_SDCORE_BASE
printf("Initializing SDCard in SD-Mode...\n");
result = sdcard_init();
#endif
if (result == 0) {
printf("SDCard initialization failed.\n");
return;
}
/* Read MBR */
result = fat16_read_mbr();
if (result == 0) {
printf("SDCard MBR read failed.\n");
return;
}
/* Copy files to RAM */
#if defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX)
result = sdcard_readFile("IMAGE", "", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET);
result = fat16_read_file("IMAGE", "", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET);
if(result)
result &= sdcard_readFile("ROOTFS~1", "CPI", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET);
result &= fat16_read_file("ROOTFS~1", "CPI", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET);
if(result)
result &= sdcard_readFile("RV32", "DTB", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET);
result &= fat16_read_file("RV32", "DTB", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET);
if(result)
result &= sdcard_readFile("EMULATOR", "BIN", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
result &= fat16_read_file("EMULATOR", "BIN", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
if(result) {
boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
@ -576,10 +582,10 @@ void sdcardboot(void)
}
#endif
result = sdcard_readFile("BOOT", "BIN", MAIN_RAM_BASE);
result = fat16_read_file("BOOT", "BIN", MAIN_RAM_BASE);
if(result)
boot(0, 0, 0, MAIN_RAM_BASE);
else
printf("SD Card SPI boot failed\n");
printf("SDCard boot failed\n");
}
#endif

View File

@ -24,6 +24,14 @@
#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE)
#if defined(CSR_SPISDCARD_BASE)
#define read_block spisdcard_read_block
#endif
#if defined(CSR_SDCORE_BASE)
#define read_block sdcard_read_block
#endif
// FAT16 Specific code starts here
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
@ -102,13 +110,13 @@ uint8_t sdCardSector[512];
// Return 0 success, 1 failure
//
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
uint8_t sdcard_readMBR(void)
uint8_t fat16_read_mbr(void)
{
int i, n;
// Read Sector 0x00000000
printf("Reading MBR\n");
if( readSector(0x00000000, sdCardSector)==SUCCESS ) {
if( read_block(0x00000000, sdCardSector)==SUCCESS ) {
// Copy Partition 1 Entry from byte 0x1be
// FIXME should check 0x55 0xaa at end of sector
memcpy(&sdCardPartition, &sdCardSector[0x1be], sizeof(PartitionTable));
@ -135,7 +143,7 @@ uint8_t sdcard_readMBR(void)
// Read Parition 1 Boot Sector - Found from Partion Table
printf("\nRead FAT16 Boot Sector\n");
if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) {
if( read_block(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) {
memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector));
}
else {
@ -181,19 +189,6 @@ uint8_t sdcard_readMBR(void)
return FAILURE;
}
#ifdef USE_SPISCARD_RECLOCKING
// Reclock the card
// Calculate 16MHz as an integer divider from the CONFIG_CLOCK_FREQUENCY
// Add 1 as will be rounded down
// Always ensure divider is at least 2 - half the processor speed
int divider;
divider = (int)(CONFIG_CLOCK_FREQUENCY/(16e6)) + 1;
if( divider<2 )
divider=2;
printf("Reclocking from %dKHz to %dKHz\n\n", CONFIG_CLOCK_FREQUENCY/(int)spisdcard_clk_divider_read()/1000, CONFIG_CLOCK_FREQUENCY/divider/1000);
spisdcard_clk_divider_write(divider);
#endif
// Read in FAT16 File Allocation Table, array of 16bit unsinged integers
// Calculate Storage from TOP of MAIN RAM
sdCardFatTable = (uint16_t *)(MAIN_RAM_BASE+MAIN_RAM_SIZE-sdCardFatBootSector.sector_size*sdCardFatBootSector.fat_size_sectors);
@ -202,7 +197,7 @@ uint8_t sdcard_readMBR(void)
// Calculate Start of FAT16 File Allocation Table (start of partition plus reserved sectors)
fatSectorStart=sdCardPartition.start_sector+sdCardFatBootSector.reserved_sectors;
for(n=0; n<sdCardFatBootSector.fat_size_sectors; n++) {
if( readSector(fatSectorStart+n, (uint8_t *)((uint8_t*)sdCardFatTable)+sdCardFatBootSector.sector_size*n)==FAILURE ) {
if( read_block(fatSectorStart+n, (uint8_t *)((uint8_t*)sdCardFatTable)+sdCardFatBootSector.sector_size*n)==FAILURE ) {
printf("Error reading FAT16 table - sector %d\n",n);
return FAILURE;
}
@ -216,7 +211,7 @@ uint8_t sdcard_readMBR(void)
// Calculate Start of FAT ROOT DIRECTORY (start of partition plues reserved sectors plus size of File Allocation Table(s))
rootDirSectorStart=sdCardPartition.start_sector+sdCardFatBootSector.reserved_sectors+sdCardFatBootSector.number_of_fats*sdCardFatBootSector.fat_size_sectors;
for(n=0; n<sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry)/sdCardFatBootSector.sector_size; n++) {
if( readSector(rootDirSectorStart+n, (uint8_t *)(sdCardFatBootSector.sector_size*n+(uint8_t *)(sdCardFat16RootDir)))==FAILURE ) {
if( read_block(rootDirSectorStart+n, (uint8_t *)(sdCardFatBootSector.sector_size*n+(uint8_t *)(sdCardFat16RootDir)))==FAILURE ) {
printf("Error reading Root Dir - sector %d\n",n);
return FAILURE;
}
@ -258,7 +253,7 @@ uint8_t sdcard_readMBR(void)
// Return 0 success, 1 failure
//
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
uint8_t sdcard_readFile(char *filename, char *ext, unsigned long address)
uint8_t fat16_read_file(char *filename, char *ext, unsigned long address)
{
int i, n, sector;
uint16_t fileClusterStart;
@ -311,14 +306,14 @@ uint8_t sdcard_readFile(char *filename, char *ext, unsigned long address)
// If whole sector to be read, read directly into memory
// Otherwise, read to sdCardSector buffer and transfer appropriate number of bytes
if(bytesRemaining>sdCardFatBootSector.sector_size) {
if( readSector(clusterSectorStart+sector,(uint8_t *)address) == FAILURE ) {
if( read_block(clusterSectorStart+sector,(uint8_t *)address) == FAILURE ) {
printf("\nRead Error\n");
return FAILURE;
}
bytesRemaining=bytesRemaining-sdCardFatBootSector.sector_size;
address=address+sdCardFatBootSector.sector_size;
} else {
if( readSector(clusterSectorStart+sector,sdCardSector) == FAILURE ) {
if( read_block(clusterSectorStart+sector,sdCardSector) == FAILURE ) {
printf("\nRead Error\n");
return FAILURE;
}

View File

@ -4,7 +4,7 @@
#ifndef __FAT16_H
#define __FAT16_H
uint8_t sdcard_readMBR(void);
uint8_t sdcard_readFile(char *, char *, unsigned long);
uint8_t fat16_read_mbr(void);
uint8_t fat16_read_file(char *, char *, unsigned long);
#endif /* __FAT16_H */

View File

@ -622,7 +622,7 @@ int sdcard_init(void) {
/* set block length */
sdcard_app_set_blocklen(SD_BLOCK_SIZE);
return 0;
return 1;
}
extern void dump_bytes(unsigned int *ptr, int count, unsigned long addr);
@ -713,15 +713,14 @@ int sdcard_test(unsigned int blocks)
return 0;
}
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage)
{
uint8_t sdcard_read_block(uint32_t addr, uint8_t *buf) {
int n;
// FIXME: handle errors, avoid recopy.
sdcard_read(sectorNumber, 1);
sdcard_read(addr, 1);
for(n=0; n<SD_BLOCK_SIZE; n++)
storage[n] = sdread_buf[n];
buf[n] = sdread_buf[n];
return 1;
}

View File

@ -108,7 +108,7 @@ int sdcard_sddatawriter_wait(void);
int sdcard_sddatareader_wait(void);
int sdcard_test(unsigned int blocks);
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage);
uint8_t sdcard_read_block(uint32_t addr, uint8_t *buf);
#endif /* CSR_SDCORE_BASE */

View File

@ -1,294 +1,245 @@
// This file is Copyright (c) 2020 Rob Shelton <rob.s.ng15@googlemail.com>
// This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
// License: BSD
//
// SD CARD bitbanging code for loading files from a FAT16 forrmatted partition into memory
//
// Code is known to work on a de10nano with MiSTer SDRAM and IO Boards - IO Board has a secondary SD CARD interface connected to GPIO pins
// SPI signals CLK, CS and MOSI are configured as GPIO output pins, and MISO is configued as GPIO input pins
//
// Protocol details developed from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/
//
// FAT16 details developed from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/ and https://codeandlife.com/2012/04/07/simple-fat-and-sd-tutorial-part-2/
// SDCard SPI-Mode support for LiteX's SPIMaster.
// Import LiteX SoC details that are generated each time the SoC is compiled for the FPGA
// csr defines the SPI Control registers
// soc defines the clock CONFIG_CLOCK_FREQUENCY (50MHz for the VexRiscV processor on the MiSTer FPGA
// mem defines the addresses for the SDRAM MAIN_RAM_BASE and MAIN_RAM_SIZE
#include <generated/csr.h>
#include <generated/soc.h>
#include <generated/mem.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <generated/csr.h>
#include <generated/mem.h>
#include <system.h>
#ifdef CSR_SPISDCARD_BASE
// Import prototypes for the functions
#include "spisdcard.h"
// SPI
// cs line - high to indicate DESELECT
// - low to indicate SELECT
#define CS_HIGH 0x00
#define CS_LOW 0x01
#ifdef CSR_SPISDCARD_BASE
// control register values
// onebyte to indicate 1 byte being transferred
// spi_start to indicate START of transfer
// spi_done to indicate transfer DONE
#define ONEBYTE 0x0800
#define SPI_START 0x01
#define SPI_DONE 0x01
/* SPI Master flags */
// Return values
#define SUCCESS 0x01
#define FAILURE 0x00
#define SPI_CS_HIGH (0 << 0)
#define SPI_CS_LOW (1 << 0)
#define SPI_START (1 << 0)
#define SPI_DONE (1 << 0)
#define SPI_LENGTH (1 << 8)
// spi_write_byte
// Send a BYTE (8bits) to the SD CARD
// Seqeunce
// Set MOSI
// Set START bit and LENGTH=8
// Await DONE
//
// No return values
//
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands"
void spi_write_byte(uint8_t char_to_send);
void spi_write_byte(uint8_t char_to_send)
{
// Place data into MOSI register
// Pulse the START bit and set LENGTH=8
spisdcard_mosi_write(char_to_send);
spisdcard_control_write(ONEBYTE | SPI_START);
/* SPI Master low-level functions */
// Wait for DONE
while( (spisdcard_status_read() != SPI_DONE)) {}
// Signal end of transfer
spisdcard_control_write( 0x00 );
static void spi_set_clk_freq(uint32_t clk_freq) {
uint32_t divider;
divider = CONFIG_CLOCK_FREQUENCY/clk_freq + 1;
printf("divider: %d\n", divider);
if (divider >= 65535) /* 16-bit hardware divider */
divider = 65535;
if (divider <= 2) /* At least half CPU speed */
divider = 2;
printf("Setting SDCard clk freq to ");
if (clk_freq > 1000000)
printf("%d MHz\n", (CONFIG_CLOCK_FREQUENCY/divider)/1000000);
else
printf("%d KHz\n", (CONFIG_CLOCK_FREQUENCY/divider)/1000);
spisdcard_clk_divider_write(divider);
}
// spi_read_rbyte
// Read a command response from the SD CARD - Equivalent to and R1 response or first byte of an R7 response
// Sequence
// Read MISO
// If MSB != 0 then send dsummy byte and re-read MISO
//
// Return value is the response from the SD CARD
// If the MSB is not 0, this would represent an ERROR
// Calling function to determine if the correct response has been received
//
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands"
uint8_t spi_read_rbyte(void);
uint8_t spi_read_rbyte(void)
{
int timeout=32;
uint8_t r=0;
// Check if MISO is 0x0xxxxxxx as MSB=0 indicates valid response
r = spisdcard_miso_read();
while( ((r&0x80)!=0) && timeout>0) {
spisdcard_mosi_write( 0xff );
spisdcard_control_write(ONEBYTE | SPI_START);
while( (spisdcard_status_read() != SPI_DONE)) {}
r = spisdcard_miso_read();
spisdcard_control_write( 0x00 );
timeout--;
}
// printf("Done\n");
return r;
static uint8_t spi_xfer(uint8_t byte) {
/* Write byte on MOSI */
spisdcard_mosi_write(byte);
/* Initiate SPI Xfer */
spisdcard_control_write(8*SPI_LENGTH | SPI_START);
/* Wait SPI Xfer to be done */
while(spisdcard_status_read() != SPI_DONE);
/* Read MISO and return it */
return spisdcard_miso_read();
}
// spi_read_byte
// Sequence
// Send dummy byte
// Read MISO
//
// Read subsequenct bytes from the SD CARD - MSB first
// NOTE different from the spi_read_rbyte as no need to await an intial 0 bit as card is already responsing
// Used to read additional response bytes, or data bytes from the SD CARD
//
// Return value is the byte read
// NOTE no error status as assumed bytes are read via CLK pulses
//
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "SD Commands"
uint8_t spi_read_byte(void);
uint8_t spi_read_byte(void)
{
uint8_t r=0;
/* SPI SDCard functions */
spi_write_byte( 0xff );
r = spisdcard_miso_read();
static uint8_t spisdcard_wait_response(void) {
uint8_t timeout;
uint8_t response;
return r;
}
// SETSPIMODE
// Signal the SD CARD to switch to SPI mode
// Pulse the CLK line HIGH/LOW repeatedly with MOSI and CS_N HIGH
// Drop CS_N LOW and pulse the CLK
// Check MISO for HIGH
// Return 0 success, 1 failure
//
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Initializing the SD Card"
uint8_t spi_setspimode(void);
uint8_t spi_setspimode(void)
{
uint32_t r;
int i, timeout=32;
// Initialise SPI mode
// set CS to HIGH
// Send pulses
timeout = 32;
/* Do SPI Xfers on SDCard until MISO MSB's is 0 (valid response) or timeout is expired */
do {
// set CS HIGH and send pulses
spisdcard_cs_write(CS_HIGH);
for (i=0; i<10; i++) {
spi_write_byte( 0xff );
}
// set CS LOW and send pulses
spisdcard_cs_write(CS_LOW);
r = spi_read_rbyte();
response = spi_xfer(0xff);
timeout--;
} while ( (timeout>0) && (r==0) );
if(timeout==0) return FAILURE;
return SUCCESS;
} while(((response & 0x80) !=0) && timeout > 0);
return response;
}
// SPI_SDCARD_GOIDLE
// Function exposed to BIOS to initialise SPI mode
//
// Sequence
// Set 100KHz timer mode
// Send CLK pulses to set SD CARD to SPI mode
// Send CMD0 - Software RESET - force SD CARD IDLE
// Send CMD8 - Check SD CARD type
// Send CMD55+ACMD41 - Force SD CARD READY
// Send CMD58 - Read SD CARD OCR (status register)
// Send CMD16 - Set SD CARD block size to 512 - Sector Size for the SD CARD
// NOTE - Each command is prefixed with a dummy set of CLK pulses to prepare SD CARD to receive a command
// Return 0 success, 1 failure
//
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Initializing the SD Card"
uint8_t spi_sdcard_goidle(void)
{
uint8_t r; // Response from SD CARD
int i, timeout; // TIMEOUT loop to send CMD55+ACMD41 repeatedly
static uint8_t spisdcard_set_mode(void) {
uint8_t timeout;
uint8_t response;
r = spi_setspimode(); // Set SD CARD to SPI mode
if( r != 0x01 ) return FAILURE;
timeout = 32;
do {
int i;
/* Set CS and send 80 clock pulses to set the SDCard in SPI Mode */
spisdcard_cs_write(SPI_CS_HIGH);
for (i=0; i<10; i++)
spi_xfer(0xff);
/* Clear CS and read response, if 0 the SDCard has been initialized to SPI Mode */
spisdcard_cs_write(SPI_CS_LOW);
response = spisdcard_wait_response();
// CMD0 - Software reset - SD CARD IDLE
// Command Sequence is DUMMY=0xff CMD0=0x40 0x00 0x00 0x00 0x00 CRC=0x95
// Expected R1 response is 0x01 indicating SD CARD is IDLE
spi_write_byte( 0xff ); spi_write_byte( 0x40 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x95 );
r = spi_read_rbyte();
if(r!=0x01) return FAILURE;
timeout--;
} while ((timeout > 0) && (response == 0));
// CMD8 - Check SD CARD type
// Command sequence is DUMMY=0xff CMD8=0x48 0x00 0x00 0x01 0xaa CRC=0x87
// Expected R7 response is 0x01 followed by 0x00 0x00 0x01 0xaa (these trailing 4 bytes not currently checked)
spi_write_byte( 0xff ); spi_write_byte( 0x48 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x01 ); spi_write_byte( 0xaa ); spi_write_byte( 0x87 );
r = spi_read_rbyte();
if(r!=0x01) return FAILURE;
// Receive the trailing 4 bytes for R7 response - FIXME should check for 0x00 0x00 0x01 0xaa
if(timeout == 0)
return 0;
return 1;
}
uint8_t spisdcard_init(void) {
uint8_t i;
uint8_t r;
uint8_t timeout;
/* Set SPI clk freq to 400KHz */
spi_set_clk_freq(400000);
/* Set SDCard in SPI Mode */
r = spisdcard_set_mode();
if(r != 0x01)
return 0;
/* Send SD CARD IDLE */
/* CMD0 */
spi_xfer(0xff);
spi_xfer(0x40);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x95);
/* R1 response, expects 0x1 */
r = spisdcard_wait_response();
if(r != 0x01)
return 0;
/* Send Check SD CARD type */
/* CMD8 */
spi_xfer(0xff);
spi_xfer(0x48);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x01);
spi_xfer(0xaa);
spi_xfer(0x87);
/* R7, expects 0x1 */
r = spisdcard_wait_response();
if(r != 0x01)
return 0;
/* Reveice the 4 trailing bytes */
for(i=0; i<4; i++)
r=spi_read_byte();
r = spi_xfer(0xff); /* FIXME: add check? */
// CMD55+ACMD41 - Force SD CARD READY - prepare card for reading/writing
// Command sequence is CMD55 followed by ACMD41
// Send commands repeatedly until SD CARD indicates READY 0x00
// CMD55 Sequence is DUMMY=0xff CMD55=0x77 0x00 0x00 0x00 0x00 CRC=0x00
// ACMD41 Sequence is DUMMY=0xff ACMD41=0x69 0x40 0x00 0x00 0x00 CRC=0x00
// Expected R1 response is 0x00 indicating SD CARD is READY
timeout=32;
/* Send Force SD CARD READY (CMD55 + ACMD41), expects 0x00 R1 response */
timeout = 32;
do {
spi_write_byte( 0xff ); spi_write_byte( 0x77 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 );
r = spi_read_rbyte();
spi_write_byte( 0xff ); spi_write_byte( 0x69 ); spi_write_byte( 0x40 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 );
r = spi_read_rbyte();
/* CMD55 */
spi_xfer(0xff);
spi_xfer(0x77);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
r = spisdcard_wait_response();
/* ACMD41 */
spi_xfer(0xff);
spi_xfer(0x69);
spi_xfer(0x40);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
/* R1 */
r = spisdcard_wait_response();
timeout--;
/* 20ms delay */
busy_wait(20);
} while ((r != 0x00) && (timeout>0));
if(r!=0x00) return FAILURE;
} while ((r != 0x00) && (timeout > 0));
if(r != 0x00)
return 0;
// CMD58 - Read SD CARD OCR (status register)
// FIXME - Find details on expected response from CMD58 to allow accurate checking of SD CARD R3 response
// Command sequence is DUMMY=0xff CMD58=0x7a 0x00 0x00 0x01 0xaa CRC=0xff
// Expected R3 response is 0x00 OR 0x01 followed by 4 (unchecked) trailing bytes
spi_write_byte( 0xff ); spi_write_byte( 0x7a ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0xff );
r = spi_read_rbyte();
if(r>0x01) return FAILURE;
// // Receive the trailing 4 bytes for R3 response
/* Send Read SD CARD OCR (status register) */
/* CMD58 */
spi_xfer(0xff);
spi_xfer(0x7a);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0xff);
/* R3, expects 0x1 */
r = spisdcard_wait_response();
if(r > 0x01)
return 0;
/* Reveice the 4 trailing bytes */
for(i=0; i<4; i++)
r=spi_read_byte();
r = spi_xfer(0xff); /* FIXME: add check? */
// CMD16 - Set SD CARD block size to 512 - Sector Size for the SD CARD
// Command Sequence is DUMMY=0xff CMD16=0x50 (512 as unsigned 32bit = 0x00000200) 0x00 0x00 0x02 0x00 CRC=0xff
// Expected R1 response is 0x00 indicating SD CARD is READY
spi_write_byte( 0xff ); spi_write_byte( 0x50 ); spi_write_byte( 0x00 ); spi_write_byte( 0x00 ); spi_write_byte( 0x02 ); spi_write_byte( 0x00 ); spi_write_byte( 0xff );
r=spi_read_rbyte();
if(r!=0x00) return FAILURE;
/* Send Set SD CARD block size */
/* CMD16 */
spi_xfer(0xff);
spi_xfer(0x50);
spi_xfer(0x00);
spi_xfer(0x00);
spi_xfer(0x02);
spi_xfer(0x00);
spi_xfer(0xff);
/* RI, expects 0x00 */
r = spisdcard_wait_response();
if(r != 0x00)
return 0;
return SUCCESS;
/* Set SPI clk freq to 16MHz */
spi_set_clk_freq(16000000);
return 1;
}
// READSECTOR
// Read a 512 byte sector from the SD CARD
// Given SECTORNUMBER and memory STORAGE
//
// Sequence
// Send CMD17 - Read Block
// Command Sequence is DUMMY=0xff CMD17=0x51 SECTORNUMBER (32bit UNSIGNED as bits 32-25,24-17, 16-9, 8-1) CRC=0xff
// Wait for SD CARD to send 0x00 indicating SD CARD is processing
// Wait for SD CARD to send 0xfe indicating SD CARD BLOCK START
// Read 512 bytes
// Read 8 DUMMY bytes
// Return 0 success, 1 failure
//
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Read/Write SD Card"
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage);
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage)
{
int n, timeout; // Number of bytes loop, timeout loop awaiting response bytes
uint8_t r; // Response bytes from SD CARD
uint8_t spisdcard_read_block(uint32_t addr, uint8_t *buf) {
int i;
uint32_t timeout;
uint8_t r;
// CMD17 - Read Block
// Command Sequence is DUMMY=0xff CMD17=0x51 SECTORNUMBER (32bit UNSIGNED as bits 32-25,24-17, 16-9, 8-1) CRC=0xff
// Expected R1 response is 0x00 indicating SD CARD is processing
spi_write_byte( 0xff ); spi_write_byte( 0x51 ); spi_write_byte( (sectorNumber>>24)&0xff ); spi_write_byte( (sectorNumber>>16)&0xff ); spi_write_byte( (sectorNumber>>8)&0xff ); spi_write_byte( (sectorNumber)&0xff ); spi_write_byte( 0xff );
r=spi_read_rbyte();
if( r!=0x00 ) return FAILURE;
/* Send Read Block */
/* CMD17 */
spi_xfer(0xff);
spi_xfer(0x51);
spi_xfer((addr >> 24) & 0xff);
spi_xfer((addr >> 16) & 0xff);
spi_xfer((addr >> 8) & 0xff);
spi_xfer((addr >> 0) & 0xff);
spi_xfer(0xff);
/* R1, expects 0x00 that indicates the SDCard is processing */
r = spisdcard_wait_response();
if(r != 0x00)
return 0;
// Await 0xfe to indicate BLOCK START
r=spi_read_byte();
timeout=16384;
while( (r!=0xfe) && (timeout>0) ) {
r=spi_read_byte();
/* Do SPI Xfers on SDCard until 0xfe is received (block start) or timeout is expired */
r = spi_xfer(0xff);
timeout = 16384;
do {
r = spi_xfer(0xff);
timeout--;
}
if( r!=0xfe ) return FAILURE;
} while((r != 0xfe) && (timeout>0));
if(r != 0xfe)
return 0;
// Read 512 bytes into storage
for(n=0; n<512; n++)
storage[n]=spi_read_byte();
/* Read the block from the SDCard and copy it to the buffer */
for(i=0; i<512; i++)
buf[i] = spi_xfer(0xff);
// Read 8 dummy bytes
for(n=0; n<8; n++)
r=spi_read_byte();
/* Read the 8 dummy bytes */
for(i=0; i<8; i++)
r = spi_xfer(0xff);
return SUCCESS;
return 1;
}
#endif

View File

@ -1,4 +1,5 @@
// This file is Copyright (c) 2020 Rob Shelton <rob.s.ng15@googlemail.com>
// This file is Copyright (c) 2020 Florent Kermarrec <florent@enjoy-digital.fr>
// License: BSD
#ifndef __SPISDCARD_H
@ -8,14 +9,8 @@
#ifdef CSR_SPISDCARD_BASE
#define USE_SPISCARD_RECLOCKING
int spi_sdcard_init(uint32_t device);
int spi_sdcard_read_sector(uint32_t device, uint32_t lba,uint_least8_t *buf);
uint8_t spi_sdcard_goidle(void);
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage);
uint8_t spisdcard_init(void);
uint8_t spisdcard_read_block(uint32_t addr, uint8_t *buf);
#endif /* CSR_SPISDCARD_BASE */