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:
parent
860ac1e212
commit
7d141258be
|
@ -538,37 +538,43 @@ void romboot(void)
|
|||
|
||||
void sdcardboot(void)
|
||||
{
|
||||
unsigned int result;
|
||||
|
||||
printf("Booting from SDCard...\n");
|
||||
|
||||
/* Initialize SDCard */
|
||||
#ifdef CSR_SPISDCARD_BASE
|
||||
printf("Initializing SDCard in SPI-Mode...\n");
|
||||
if(spi_sdcard_goidle() == 0) {
|
||||
printf("SD Card Timeout\n");
|
||||
return;
|
||||
}
|
||||
result = spisdcard_init();
|
||||
#endif
|
||||
#ifdef CSR_SDCORE_BASE
|
||||
printf("Initializing SDCard in SD-Mode...\n");
|
||||
sdcard_init(); // FIXME : check returned value
|
||||
result = sdcard_init();
|
||||
#endif
|
||||
|
||||
if(sdcard_readMBR() == 0) {
|
||||
printf("SD Card MBR Timeout\n");
|
||||
if (result == 0) {
|
||||
printf("SDCard initialization failed.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int result;
|
||||
/* 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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
|
@ -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--;
|
||||
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();
|
||||
}
|
||||
|
||||
// printf("Done\n");
|
||||
return r;
|
||||
}
|
||||
/* SPI SDCard functions */
|
||||
|
||||
// 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;
|
||||
static uint8_t spisdcard_wait_response(void) {
|
||||
uint8_t timeout;
|
||||
uint8_t response;
|
||||
|
||||
spi_write_byte( 0xff );
|
||||
r = spisdcard_miso_read();
|
||||
|
||||
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;
|
||||
|
||||
// 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;
|
||||
|
||||
// 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
|
||||
for(i=0; i<4; i++)
|
||||
r=spi_read_byte();
|
||||
|
||||
// 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;
|
||||
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();
|
||||
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();
|
||||
|
||||
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();
|
||||
timeout--;
|
||||
} while ((timeout > 0) && (response == 0));
|
||||
|
||||
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_xfer(0xff); /* FIXME: add check? */
|
||||
|
||||
/* Send Force SD CARD READY (CMD55 + ACMD41), expects 0x00 R1 response */
|
||||
timeout = 32;
|
||||
do {
|
||||
/* 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;
|
||||
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();
|
||||
/* Do SPI Xfers on SDCard until 0xfe is received (block start) or timeout is expired */
|
||||
r = spi_xfer(0xff);
|
||||
timeout = 16384;
|
||||
while( (r!=0xfe) && (timeout>0) ) {
|
||||
r=spi_read_byte();
|
||||
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
|
||||
|
|
|
@ -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 */
|
||||
|
||||
|
|
Loading…
Reference in New Issue