software/liblitesdcard: move fat16 code to separate file to avoid duplication.
This commit is contained in:
parent
4b3c5203ed
commit
bdaf6ff2dd
|
@ -30,6 +30,7 @@
|
||||||
|
|
||||||
#include <liblitesdcard/spisdcard.h>
|
#include <liblitesdcard/spisdcard.h>
|
||||||
#include <liblitesdcard/sdcard.h>
|
#include <liblitesdcard/sdcard.h>
|
||||||
|
#include <liblitesdcard/fat16.h>
|
||||||
|
|
||||||
extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr);
|
extern void boot_helper(unsigned long r1, unsigned long r2, unsigned long r3, unsigned long addr);
|
||||||
|
|
||||||
|
@ -550,7 +551,7 @@ void sdcardboot(void)
|
||||||
sdcard_init(); // FIXME : check returned value
|
sdcard_init(); // FIXME : check returned value
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if(spi_sdcard_readMBR() == 0) {
|
if(sdcard_readMBR() == 0) {
|
||||||
printf("SD Card MBR Timeout\n");
|
printf("SD Card MBR Timeout\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -558,20 +559,16 @@ void sdcardboot(void)
|
||||||
unsigned int result;
|
unsigned int result;
|
||||||
|
|
||||||
#if defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX)
|
#if defined(CONFIG_CPU_TYPE_VEXRISCV) && defined(CONFIG_CPU_VARIANT_LINUX)
|
||||||
result = spi_sdcard_readFile("IMAGE", "",
|
result = sdcard_readFile("IMAGE", "", MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET);
|
||||||
MAIN_RAM_BASE + KERNEL_IMAGE_RAM_OFFSET);
|
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
result &= spi_sdcard_readFile("ROOTFS~1", "CPI",
|
result &= sdcard_readFile("ROOTFS~1", "CPI", MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET);
|
||||||
MAIN_RAM_BASE + ROOTFS_IMAGE_RAM_OFFSET);
|
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
result &= spi_sdcard_readFile("RV32", "DTB",
|
result &= sdcard_readFile("RV32", "DTB", MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET);
|
||||||
MAIN_RAM_BASE + DEVICE_TREE_IMAGE_RAM_OFFSET);
|
|
||||||
|
|
||||||
if(result)
|
if(result)
|
||||||
result &= spi_sdcard_readFile("EMULATOR", "BIN",
|
result &= sdcard_readFile("EMULATOR", "BIN", MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
|
||||||
MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
|
|
||||||
|
|
||||||
if(result) {
|
if(result) {
|
||||||
boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
|
boot(0, 0, 0, MAIN_RAM_BASE + EMULATOR_IMAGE_RAM_OFFSET);
|
||||||
|
@ -579,7 +576,7 @@ void sdcardboot(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
result = spi_sdcard_readFile("BOOT", "BIN", MAIN_RAM_BASE);
|
result = sdcard_readFile("BOOT", "BIN", MAIN_RAM_BASE);
|
||||||
if(result)
|
if(result)
|
||||||
boot(0, 0, 0, MAIN_RAM_BASE);
|
boot(0, 0, 0, MAIN_RAM_BASE);
|
||||||
else
|
else
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
include ../include/generated/variables.mak
|
include ../include/generated/variables.mak
|
||||||
include $(SOC_DIRECTORY)/software/common.mak
|
include $(SOC_DIRECTORY)/software/common.mak
|
||||||
|
|
||||||
OBJECTS=sdcard.o spisdcard.o
|
OBJECTS=fat16.o sdcard.o spisdcard.o
|
||||||
|
|
||||||
all: liblitesdcard.a
|
all: liblitesdcard.a
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,333 @@
|
||||||
|
// SD CARD code for loading files from a FAT16 formatted partition into memory
|
||||||
|
|
||||||
|
#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 <system.h>
|
||||||
|
|
||||||
|
#include "spisdcard.h"
|
||||||
|
#include "sdcard.h"
|
||||||
|
#include "fat16.h"
|
||||||
|
|
||||||
|
// Return values
|
||||||
|
#define SUCCESS 0x01
|
||||||
|
#define FAILURE 0x00
|
||||||
|
|
||||||
|
#if defined(CSR_SPISDCARD_BASE) || defined(CSR_SDCORE_BASE)
|
||||||
|
|
||||||
|
// FAT16 Specific code starts here
|
||||||
|
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
||||||
|
|
||||||
|
// Structure to store SD CARD partition table
|
||||||
|
typedef struct {
|
||||||
|
uint8_t first_byte;
|
||||||
|
uint8_t start_chs[3];
|
||||||
|
uint8_t partition_type;
|
||||||
|
uint8_t end_chs[3];
|
||||||
|
uint32_t start_sector;
|
||||||
|
uint32_t length_sectors;
|
||||||
|
} __attribute((packed)) PartitionTable;
|
||||||
|
|
||||||
|
PartitionTable sdCardPartition;
|
||||||
|
|
||||||
|
// Structure to store SD CARD FAT16 Boot Sector (boot code is ignored, provides layout of the FAT16 partition on the SD CARD)
|
||||||
|
typedef struct {
|
||||||
|
uint8_t jmp[3];
|
||||||
|
uint8_t oem[8];
|
||||||
|
uint16_t sector_size;
|
||||||
|
uint8_t sectors_per_cluster;
|
||||||
|
uint16_t reserved_sectors;
|
||||||
|
uint8_t number_of_fats;
|
||||||
|
uint16_t root_dir_entries;
|
||||||
|
uint16_t total_sectors_short; // if zero, later field is used
|
||||||
|
uint8_t media_descriptor;
|
||||||
|
uint16_t fat_size_sectors;
|
||||||
|
uint16_t sectors_per_track;
|
||||||
|
uint16_t number_of_heads;
|
||||||
|
uint32_t hidden_sectors;
|
||||||
|
uint32_t total_sectors_long;
|
||||||
|
|
||||||
|
uint8_t drive_number;
|
||||||
|
uint8_t current_head;
|
||||||
|
uint8_t boot_signature;
|
||||||
|
uint32_t volume_id;
|
||||||
|
uint8_t volume_label[11];
|
||||||
|
uint8_t fs_type[8];
|
||||||
|
uint8_t boot_code[448];
|
||||||
|
uint16_t boot_sector_signature;
|
||||||
|
} __attribute((packed)) Fat16BootSector;
|
||||||
|
|
||||||
|
Fat16BootSector sdCardFatBootSector;
|
||||||
|
|
||||||
|
// Structure to store SD CARD FAT16 Root Directory Entries
|
||||||
|
// Allocated to MAIN RAM - hence pointer
|
||||||
|
typedef struct {
|
||||||
|
uint8_t filename[8];
|
||||||
|
uint8_t ext[3];
|
||||||
|
uint8_t attributes;
|
||||||
|
uint8_t reserved[10];
|
||||||
|
uint16_t modify_time;
|
||||||
|
uint16_t modify_date;
|
||||||
|
uint16_t starting_cluster;
|
||||||
|
uint32_t file_size;
|
||||||
|
} __attribute((packed)) Fat16Entry;
|
||||||
|
|
||||||
|
Fat16Entry *sdCardFat16RootDir;
|
||||||
|
|
||||||
|
// Structure to store SD CARD FAT16 Entries
|
||||||
|
// Array of uint16_tS (16bit integers)
|
||||||
|
uint16_t *sdCardFatTable;
|
||||||
|
|
||||||
|
// Calculated sector numbers on the SD CARD for the FAT16 Entries and ROOT DIRECTORY
|
||||||
|
uint32_t fatSectorStart, rootDirSectorStart;
|
||||||
|
|
||||||
|
// Storage for SECTOR read from SD CARD
|
||||||
|
uint8_t sdCardSector[512];
|
||||||
|
|
||||||
|
// SPI_SDCARD_READMBR
|
||||||
|
// Function exposed to BIOS to retrieve FAT16 partition details, FAT16 Entry Table, FAT16 Root Directory
|
||||||
|
// MBR = Master Boot Record - Sector 0x00000000 on SD CARD - Contains Partition 1 details at 0x1be
|
||||||
|
//
|
||||||
|
// FIXME only checks partition 1 out of 4
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
int i, n;
|
||||||
|
|
||||||
|
// Read Sector 0x00000000
|
||||||
|
printf("Reading MBR\n");
|
||||||
|
if( readSector(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));
|
||||||
|
|
||||||
|
// Check Partition 1 is valid, FIRST_BYTE=0x00 or 0x80
|
||||||
|
// Check Partition 1 has type 4, 6 or 14 (FAT16 of various sizes)
|
||||||
|
printf("Partition 1 Information: Active=0x%02x, Type=0x%02x, LBAStart=0x%08x\n", sdCardPartition.first_byte, sdCardPartition.partition_type, sdCardPartition.start_sector);
|
||||||
|
if( (sdCardPartition.first_byte!=0x80) && (sdCardPartition.first_byte!=0x00) ) {
|
||||||
|
printf("Partition 1 Not Valid\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
if( (sdCardPartition.partition_type==4) || (sdCardPartition.partition_type==6) || (sdCardPartition.partition_type==14) ) {
|
||||||
|
printf("Partition 1 is FAT16\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Partition 1 Not FAT16\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Failed to read MBR\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read Parition 1 Boot Sector - Found from Partion Table
|
||||||
|
printf("\nRead FAT16 Boot Sector\n");
|
||||||
|
if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) {
|
||||||
|
memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
printf("Failed to read FAT16 Boot Sector\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print details of Parition 1
|
||||||
|
printf(" Jump Code: 0x%02x 0x%02x 0x%02x\n",sdCardFatBootSector.jmp[0],sdCardFatBootSector.jmp[1],sdCardFatBootSector.jmp[2]);
|
||||||
|
printf(" OEM Code: [");
|
||||||
|
for(n=0; n<8; n++)
|
||||||
|
printf("%c",sdCardFatBootSector.oem[n]);
|
||||||
|
printf("]\n");
|
||||||
|
printf(" Sector Size: %d\n",sdCardFatBootSector.sector_size);
|
||||||
|
printf(" Sectors Per Cluster: %d\n",sdCardFatBootSector.sectors_per_cluster);
|
||||||
|
printf(" Reserved Sectors: %d\n",sdCardFatBootSector.reserved_sectors);
|
||||||
|
printf(" Number of Fats: %d\n",sdCardFatBootSector.number_of_fats);
|
||||||
|
printf(" Root Dir Entries: %d\n",sdCardFatBootSector.root_dir_entries);
|
||||||
|
printf(" Total Sectors Short: %d\n",sdCardFatBootSector.total_sectors_short);
|
||||||
|
printf(" Media Descriptor: 0x%02x\n",sdCardFatBootSector.media_descriptor);
|
||||||
|
printf(" Fat Size Sectors: %d\n",sdCardFatBootSector.fat_size_sectors);
|
||||||
|
printf(" Sectors Per Track: %d\n",sdCardFatBootSector.sectors_per_track);
|
||||||
|
printf(" Number of Heads: %d\n",sdCardFatBootSector.number_of_heads);
|
||||||
|
printf(" Hidden Sectors: %d\n",sdCardFatBootSector.hidden_sectors);
|
||||||
|
printf(" Total Sectors Long: %d\n",sdCardFatBootSector.total_sectors_long);
|
||||||
|
printf(" Drive Number: 0x%02x\n",sdCardFatBootSector.drive_number);
|
||||||
|
printf(" Current Head: 0x%02x\n",sdCardFatBootSector.current_head);
|
||||||
|
printf(" Boot Signature: 0x%02x\n",sdCardFatBootSector.boot_signature);
|
||||||
|
printf(" Volume ID: 0x%08x\n",sdCardFatBootSector.volume_id);
|
||||||
|
printf(" Volume Label: [");
|
||||||
|
for(n=0; n<11; n++)
|
||||||
|
printf("%c",sdCardFatBootSector.volume_label[n]);
|
||||||
|
printf("]\n");
|
||||||
|
printf(" Volume Label: [");
|
||||||
|
for(n=0; n<8; n++)
|
||||||
|
printf("%c",sdCardFatBootSector.fs_type[n]);
|
||||||
|
printf("]\n");
|
||||||
|
printf(" Boot Sector Signature: 0x%04x\n\n",sdCardFatBootSector.boot_sector_signature);
|
||||||
|
|
||||||
|
// Check Partition 1 is valid, not 0 length
|
||||||
|
if(sdCardFatBootSector.total_sectors_long==0) {
|
||||||
|
printf("Error reading FAT16 Boot Sector\n");
|
||||||
|
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);
|
||||||
|
printf("sdCardFatTable = 0x%08x Reading Fat16 Table (%d Sectors Long)\n\n",sdCardFatTable,sdCardFatBootSector.fat_size_sectors);
|
||||||
|
|
||||||
|
// 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 ) {
|
||||||
|
printf("Error reading FAT16 table - sector %d\n",n);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read in FAT16 Root Directory
|
||||||
|
// Calculate Storage from TOP of MAIN RAM
|
||||||
|
sdCardFat16RootDir= (Fat16Entry *)(MAIN_RAM_BASE+MAIN_RAM_SIZE-sdCardFatBootSector.sector_size*sdCardFatBootSector.fat_size_sectors-sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry));
|
||||||
|
printf("sdCardFat16RootDir = 0x%08x Reading Root Directory (%d Sectors Long)\n\n",sdCardFat16RootDir,sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry)/sdCardFatBootSector.sector_size);
|
||||||
|
|
||||||
|
// 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 ) {
|
||||||
|
printf("Error reading Root Dir - sector %d\n",n);
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print out Root Directory
|
||||||
|
// Alternates between valid and invalid directory entries for SIMPLE 8+3 file names, extended filenames in other entries
|
||||||
|
// Only print valid characters
|
||||||
|
printf("\nRoot Directory\n");
|
||||||
|
for(n=0; n<sdCardFatBootSector.root_dir_entries; n++) {
|
||||||
|
if( (sdCardFat16RootDir[n].filename[0]!=0) && (sdCardFat16RootDir[n].file_size>0)) {
|
||||||
|
printf(" File %d [",n);
|
||||||
|
for( i=0; i<8; i++) {
|
||||||
|
if( (sdCardFat16RootDir[n].filename[i]>31) && (sdCardFat16RootDir[n].filename[i]<127) )
|
||||||
|
printf("%c",sdCardFat16RootDir[n].filename[i]);
|
||||||
|
else
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf(".");
|
||||||
|
for( i=0; i<3; i++) {
|
||||||
|
if( (sdCardFat16RootDir[n].ext[i]>31) && (sdCardFat16RootDir[n].ext[i]<127) )
|
||||||
|
printf("%c",sdCardFat16RootDir[n].ext[i]);
|
||||||
|
else
|
||||||
|
printf(" ");
|
||||||
|
}
|
||||||
|
printf("] @ Cluster %d for %d bytes\n",sdCardFat16RootDir[n].starting_cluster,sdCardFat16RootDir[n].file_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SPI_SDCARD_READFILE
|
||||||
|
// Function exposed to BIOS to retrieve FILENAME+EXT into ADDRESS
|
||||||
|
//
|
||||||
|
// FIXME only checks UPPERCASE 8+3 filenames
|
||||||
|
//
|
||||||
|
// 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)
|
||||||
|
{
|
||||||
|
int i, n, sector;
|
||||||
|
uint16_t fileClusterStart;
|
||||||
|
uint32_t fileLength, bytesRemaining, clusterSectorStart;
|
||||||
|
uint16_t nameMatch;
|
||||||
|
printf("Reading File [%s.%s] into 0x%08x : ",filename, ext, address);
|
||||||
|
|
||||||
|
// Find FILENAME+EXT in Root Directory
|
||||||
|
// Indicate FILE found by setting the starting cluster number
|
||||||
|
fileClusterStart=0; n=0;
|
||||||
|
while( (fileClusterStart==0) && (n<sdCardFatBootSector.root_dir_entries) ) {
|
||||||
|
nameMatch=0;
|
||||||
|
if( sdCardFat16RootDir[n].filename[0]!=0 ) {
|
||||||
|
nameMatch=1;
|
||||||
|
for(i=0; i<strlen(filename); i++)
|
||||||
|
if(sdCardFat16RootDir[n].filename[i]!=filename[i]) nameMatch=0;
|
||||||
|
for(i=0; i<strlen(ext); i++)
|
||||||
|
if(sdCardFat16RootDir[n].ext[i]!=ext[i]) nameMatch=0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(nameMatch==1) {
|
||||||
|
fileClusterStart=sdCardFat16RootDir[n].starting_cluster;
|
||||||
|
fileLength=sdCardFat16RootDir[n].file_size;
|
||||||
|
} else {
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If starting cluster number is still 0 then file not found
|
||||||
|
if(fileClusterStart==0) {
|
||||||
|
printf("File not found\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("File starts at Cluster %d length %d\n",fileClusterStart,fileLength);
|
||||||
|
|
||||||
|
// ZERO Length file are automatically assumed to have been read SUCCESS
|
||||||
|
if( fileLength==0 ) return SUCCESS;
|
||||||
|
|
||||||
|
// Read each cluster sector by sector, i being number of clusters
|
||||||
|
bytesRemaining=fileLength;
|
||||||
|
// Calculate number of clusters (always >1)
|
||||||
|
for(i=0; i<1+((fileLength/sdCardFatBootSector.sectors_per_cluster)/sdCardFatBootSector.sector_size); i++) {
|
||||||
|
printf("\rCluster: %d",fileClusterStart);
|
||||||
|
|
||||||
|
// Locate start of cluster on SD CARD and read appropraite number of sectors
|
||||||
|
clusterSectorStart=rootDirSectorStart+(fileClusterStart-1)*sdCardFatBootSector.sectors_per_cluster;
|
||||||
|
for(sector=0; sector<sdCardFatBootSector.sectors_per_cluster; sector++) {
|
||||||
|
// Read Sector from SD CARD
|
||||||
|
// 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 ) {
|
||||||
|
printf("\nRead Error\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
bytesRemaining=bytesRemaining-sdCardFatBootSector.sector_size;
|
||||||
|
address=address+sdCardFatBootSector.sector_size;
|
||||||
|
} else {
|
||||||
|
if( readSector(clusterSectorStart+sector,sdCardSector) == FAILURE ) {
|
||||||
|
printf("\nRead Error\n");
|
||||||
|
return FAILURE;
|
||||||
|
}
|
||||||
|
memcpy((uint8_t *)address, sdCardSector, bytesRemaining);
|
||||||
|
bytesRemaining=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move to next cluster
|
||||||
|
fileClusterStart=sdCardFatTable[fileClusterStart];
|
||||||
|
}
|
||||||
|
printf("\n\n");
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,7 @@
|
||||||
|
#ifndef __FAT16_H
|
||||||
|
#define __FAT16_H
|
||||||
|
|
||||||
|
uint8_t sdcard_readMBR(void);
|
||||||
|
uint8_t sdcard_readFile(char *, char *, unsigned long);
|
||||||
|
|
||||||
|
#endif /* __FAT16_H */
|
|
@ -726,7 +726,6 @@ int sdcard_test(unsigned int blocks)
|
||||||
// Return 0 success, 1 failure
|
// Return 0 success, 1 failure
|
||||||
//
|
//
|
||||||
// Details from https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ section "Read/Write SD Card"
|
// 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)
|
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage)
|
||||||
{
|
{
|
||||||
int n;
|
int n;
|
||||||
|
@ -740,302 +739,4 @@ uint8_t readSector(uint32_t sectorNumber, uint8_t *storage)
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FAT16 Specific code starts here
|
|
||||||
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
|
||||||
|
|
||||||
// Structure to store SD CARD partition table
|
|
||||||
typedef struct {
|
|
||||||
uint8_t first_byte;
|
|
||||||
uint8_t start_chs[3];
|
|
||||||
uint8_t partition_type;
|
|
||||||
uint8_t end_chs[3];
|
|
||||||
uint32_t start_sector;
|
|
||||||
uint32_t length_sectors;
|
|
||||||
} __attribute((packed)) PartitionTable;
|
|
||||||
|
|
||||||
PartitionTable sdCardPartition;
|
|
||||||
|
|
||||||
// Structure to store SD CARD FAT16 Boot Sector (boot code is ignored, provides layout of the FAT16 partition on the SD CARD)
|
|
||||||
typedef struct {
|
|
||||||
uint8_t jmp[3];
|
|
||||||
uint8_t oem[8];
|
|
||||||
uint16_t sector_size;
|
|
||||||
uint8_t sectors_per_cluster;
|
|
||||||
uint16_t reserved_sectors;
|
|
||||||
uint8_t number_of_fats;
|
|
||||||
uint16_t root_dir_entries;
|
|
||||||
uint16_t total_sectors_short; // if zero, later field is used
|
|
||||||
uint8_t media_descriptor;
|
|
||||||
uint16_t fat_size_sectors;
|
|
||||||
uint16_t sectors_per_track;
|
|
||||||
uint16_t number_of_heads;
|
|
||||||
uint32_t hidden_sectors;
|
|
||||||
uint32_t total_sectors_long;
|
|
||||||
|
|
||||||
uint8_t drive_number;
|
|
||||||
uint8_t current_head;
|
|
||||||
uint8_t boot_signature;
|
|
||||||
uint32_t volume_id;
|
|
||||||
uint8_t volume_label[11];
|
|
||||||
uint8_t fs_type[8];
|
|
||||||
uint8_t boot_code[448];
|
|
||||||
uint16_t boot_sector_signature;
|
|
||||||
} __attribute((packed)) Fat16BootSector;
|
|
||||||
|
|
||||||
Fat16BootSector sdCardFatBootSector;
|
|
||||||
|
|
||||||
// Structure to store SD CARD FAT16 Root Directory Entries
|
|
||||||
// Allocated to MAIN RAM - hence pointer
|
|
||||||
typedef struct {
|
|
||||||
uint8_t filename[8];
|
|
||||||
uint8_t ext[3];
|
|
||||||
uint8_t attributes;
|
|
||||||
uint8_t reserved[10];
|
|
||||||
uint16_t modify_time;
|
|
||||||
uint16_t modify_date;
|
|
||||||
uint16_t starting_cluster;
|
|
||||||
uint32_t file_size;
|
|
||||||
} __attribute((packed)) Fat16Entry;
|
|
||||||
|
|
||||||
Fat16Entry *sdCardFat16RootDir;
|
|
||||||
|
|
||||||
// Structure to store SD CARD FAT16 Entries
|
|
||||||
// Array of uint16_tS (16bit integers)
|
|
||||||
uint16_t *sdCardFatTable;
|
|
||||||
|
|
||||||
// Calculated sector numbers on the SD CARD for the FAT16 Entries and ROOT DIRECTORY
|
|
||||||
uint32_t fatSectorStart, rootDirSectorStart;
|
|
||||||
|
|
||||||
// Storage for SECTOR read from SD CARD
|
|
||||||
uint8_t sdCardSector[512];
|
|
||||||
|
|
||||||
// SPI_SDCARD_READMBR
|
|
||||||
// Function exposed to BIOS to retrieve FAT16 partition details, FAT16 Entry Table, FAT16 Root Directory
|
|
||||||
// MBR = Master Boot Record - Sector 0x00000000 on SD CARD - Contains Partition 1 details at 0x1be
|
|
||||||
//
|
|
||||||
// FIXME only checks partition 1 out of 4
|
|
||||||
//
|
|
||||||
// Return 0 success, 1 failure
|
|
||||||
//
|
|
||||||
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
|
||||||
uint8_t spi_sdcard_readMBR(void)
|
|
||||||
{
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
// Read Sector 0x00000000
|
|
||||||
printf("Reading MBR\n");
|
|
||||||
if( readSector(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));
|
|
||||||
|
|
||||||
// Check Partition 1 is valid, FIRST_BYTE=0x00 or 0x80
|
|
||||||
// Check Partition 1 has type 4, 6 or 14 (FAT16 of various sizes)
|
|
||||||
printf("Partition 1 Information: Active=0x%02x, Type=0x%02x, LBAStart=0x%08x\n", sdCardPartition.first_byte, sdCardPartition.partition_type, sdCardPartition.start_sector);
|
|
||||||
if( (sdCardPartition.first_byte!=0x80) && (sdCardPartition.first_byte!=0x00) ) {
|
|
||||||
printf("Partition 1 Not Valid\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
if( (sdCardPartition.partition_type==4) || (sdCardPartition.partition_type==6) || (sdCardPartition.partition_type==14) ) {
|
|
||||||
printf("Partition 1 is FAT16\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Partition 1 Not FAT16\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Failed to read MBR\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read Parition 1 Boot Sector - Found from Partion Table
|
|
||||||
printf("\nRead FAT16 Boot Sector\n");
|
|
||||||
sdCardPartition.start_sector = sdCardPartition.start_sector/512;
|
|
||||||
if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) {
|
|
||||||
memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Failed to read FAT16 Boot Sector\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print details of Parition 1
|
|
||||||
printf(" Jump Code: 0x%02x 0x%02x 0x%02x\n",sdCardFatBootSector.jmp[0],sdCardFatBootSector.jmp[1],sdCardFatBootSector.jmp[2]);
|
|
||||||
printf(" OEM Code: [");
|
|
||||||
for(n=0; n<8; n++)
|
|
||||||
printf("%c",sdCardFatBootSector.oem[n]);
|
|
||||||
printf("]\n");
|
|
||||||
printf(" Sector Size: %d\n",sdCardFatBootSector.sector_size);
|
|
||||||
printf(" Sectors Per Cluster: %d\n",sdCardFatBootSector.sectors_per_cluster);
|
|
||||||
printf(" Reserved Sectors: %d\n",sdCardFatBootSector.reserved_sectors);
|
|
||||||
printf(" Number of Fats: %d\n",sdCardFatBootSector.number_of_fats);
|
|
||||||
printf(" Root Dir Entries: %d\n",sdCardFatBootSector.root_dir_entries);
|
|
||||||
printf(" Total Sectors Short: %d\n",sdCardFatBootSector.total_sectors_short);
|
|
||||||
printf(" Media Descriptor: 0x%02x\n",sdCardFatBootSector.media_descriptor);
|
|
||||||
printf(" Fat Size Sectors: %d\n",sdCardFatBootSector.fat_size_sectors);
|
|
||||||
printf(" Sectors Per Track: %d\n",sdCardFatBootSector.sectors_per_track);
|
|
||||||
printf(" Number of Heads: %d\n",sdCardFatBootSector.number_of_heads);
|
|
||||||
printf(" Hidden Sectors: %d\n",sdCardFatBootSector.hidden_sectors);
|
|
||||||
printf(" Total Sectors Long: %d\n",sdCardFatBootSector.total_sectors_long);
|
|
||||||
printf(" Drive Number: 0x%02x\n",sdCardFatBootSector.drive_number);
|
|
||||||
printf(" Current Head: 0x%02x\n",sdCardFatBootSector.current_head);
|
|
||||||
printf(" Boot Signature: 0x%02x\n",sdCardFatBootSector.boot_signature);
|
|
||||||
printf(" Volume ID: 0x%08x\n",sdCardFatBootSector.volume_id);
|
|
||||||
printf(" Volume Label: [");
|
|
||||||
for(n=0; n<11; n++)
|
|
||||||
printf("%c",sdCardFatBootSector.volume_label[n]);
|
|
||||||
printf("]\n");
|
|
||||||
printf(" Volume Label: [");
|
|
||||||
for(n=0; n<8; n++)
|
|
||||||
printf("%c",sdCardFatBootSector.fs_type[n]);
|
|
||||||
printf("]\n");
|
|
||||||
printf(" Boot Sector Signature: 0x%04x\n\n",sdCardFatBootSector.boot_sector_signature);
|
|
||||||
|
|
||||||
// Check Partition 1 is valid, not 0 length
|
|
||||||
if(sdCardFatBootSector.total_sectors_long==0) {
|
|
||||||
printf("Error reading FAT16 Boot Sector\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
printf("sdCardFatTable = 0x%08x Reading Fat16 Table (%d Sectors Long)\n\n",sdCardFatTable,sdCardFatBootSector.fat_size_sectors);
|
|
||||||
|
|
||||||
// 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 ) {
|
|
||||||
printf("Error reading FAT16 table - sector %d\n",n);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in FAT16 Root Directory
|
|
||||||
// Calculate Storage from TOP of MAIN RAM
|
|
||||||
sdCardFat16RootDir= (Fat16Entry *)(MAIN_RAM_BASE+MAIN_RAM_SIZE-sdCardFatBootSector.sector_size*sdCardFatBootSector.fat_size_sectors-sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry));
|
|
||||||
printf("sdCardFat16RootDir = 0x%08x Reading Root Directory (%d Sectors Long)\n\n",sdCardFat16RootDir,sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry)/sdCardFatBootSector.sector_size);
|
|
||||||
|
|
||||||
// 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 ) {
|
|
||||||
printf("Error reading Root Dir - sector %d\n",n);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out Root Directory
|
|
||||||
// Alternates between valid and invalid directory entries for SIMPLE 8+3 file names, extended filenames in other entries
|
|
||||||
// Only print valid characters
|
|
||||||
printf("\nRoot Directory\n");
|
|
||||||
for(n=0; n<sdCardFatBootSector.root_dir_entries; n++) {
|
|
||||||
if( (sdCardFat16RootDir[n].filename[0]!=0) && (sdCardFat16RootDir[n].file_size>0)) {
|
|
||||||
printf(" File %d [",n);
|
|
||||||
for( i=0; i<8; i++) {
|
|
||||||
if( (sdCardFat16RootDir[n].filename[i]>31) && (sdCardFat16RootDir[n].filename[i]<127) )
|
|
||||||
printf("%c",sdCardFat16RootDir[n].filename[i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
printf(".");
|
|
||||||
for( i=0; i<3; i++) {
|
|
||||||
if( (sdCardFat16RootDir[n].ext[i]>31) && (sdCardFat16RootDir[n].ext[i]<127) )
|
|
||||||
printf("%c",sdCardFat16RootDir[n].ext[i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
printf("] @ Cluster %d for %d bytes\n",sdCardFat16RootDir[n].starting_cluster,sdCardFat16RootDir[n].file_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPI_SDCARD_READFILE
|
|
||||||
// Function exposed to BIOS to retrieve FILENAME+EXT into ADDRESS
|
|
||||||
//
|
|
||||||
// FIXME only checks UPPERCASE 8+3 filenames
|
|
||||||
//
|
|
||||||
// Return 0 success, 1 failure
|
|
||||||
//
|
|
||||||
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
|
||||||
uint8_t spi_sdcard_readFile(char *filename, char *ext, unsigned long address)
|
|
||||||
{
|
|
||||||
int i, n, sector;
|
|
||||||
uint16_t fileClusterStart;
|
|
||||||
uint32_t fileLength, bytesRemaining, clusterSectorStart;
|
|
||||||
uint16_t nameMatch;
|
|
||||||
printf("Reading File [%s.%s] into 0x%08x : ",filename, ext, address);
|
|
||||||
|
|
||||||
// Find FILENAME+EXT in Root Directory
|
|
||||||
// Indicate FILE found by setting the starting cluster number
|
|
||||||
fileClusterStart=0; n=0;
|
|
||||||
while( (fileClusterStart==0) && (n<sdCardFatBootSector.root_dir_entries) ) {
|
|
||||||
nameMatch=0;
|
|
||||||
if( sdCardFat16RootDir[n].filename[0]!=0 ) {
|
|
||||||
nameMatch=1;
|
|
||||||
for(i=0; i<strlen(filename); i++)
|
|
||||||
if(sdCardFat16RootDir[n].filename[i]!=filename[i]) nameMatch=0;
|
|
||||||
for(i=0; i<strlen(ext); i++)
|
|
||||||
if(sdCardFat16RootDir[n].ext[i]!=ext[i]) nameMatch=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nameMatch==1) {
|
|
||||||
fileClusterStart=sdCardFat16RootDir[n].starting_cluster;
|
|
||||||
fileLength=sdCardFat16RootDir[n].file_size;
|
|
||||||
} else {
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If starting cluster number is still 0 then file not found
|
|
||||||
if(fileClusterStart==0) {
|
|
||||||
printf("File not found\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("File starts at Cluster %d length %d\n",fileClusterStart,fileLength);
|
|
||||||
|
|
||||||
// ZERO Length file are automatically assumed to have been read SUCCESS
|
|
||||||
if( fileLength==0 ) return SUCCESS;
|
|
||||||
|
|
||||||
// Read each cluster sector by sector, i being number of clusters
|
|
||||||
bytesRemaining=fileLength;
|
|
||||||
// Calculate number of clusters (always >1)
|
|
||||||
for(i=0; i<1+((fileLength/sdCardFatBootSector.sectors_per_cluster)/sdCardFatBootSector.sector_size); i++) {
|
|
||||||
printf("\rCluster: %d",fileClusterStart);
|
|
||||||
|
|
||||||
// Locate start of cluster on SD CARD and read appropraite number of sectors
|
|
||||||
clusterSectorStart=rootDirSectorStart+(fileClusterStart-1)*sdCardFatBootSector.sectors_per_cluster;
|
|
||||||
for(sector=0; sector<sdCardFatBootSector.sectors_per_cluster; sector++) {
|
|
||||||
// Read Sector from SD CARD
|
|
||||||
// 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 ) {
|
|
||||||
printf("\nRead Error\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
bytesRemaining=bytesRemaining-sdCardFatBootSector.sector_size;
|
|
||||||
address=address+sdCardFatBootSector.sector_size;
|
|
||||||
} else {
|
|
||||||
if( readSector(clusterSectorStart+sector,sdCardSector) == FAILURE ) {
|
|
||||||
printf("\nRead Error\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
memcpy((uint8_t *)address, sdCardSector, bytesRemaining);
|
|
||||||
bytesRemaining=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to next cluster
|
|
||||||
fileClusterStart=sdCardFatTable[fileClusterStart];
|
|
||||||
}
|
|
||||||
printf("\n\n");
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif /* CSR_SDCORE_BASE */
|
#endif /* CSR_SDCORE_BASE */
|
||||||
|
|
|
@ -108,9 +108,7 @@ int sdcard_sddatawriter_wait(void);
|
||||||
int sdcard_sddatareader_wait(void);
|
int sdcard_sddatareader_wait(void);
|
||||||
int sdcard_test(unsigned int blocks);
|
int sdcard_test(unsigned int blocks);
|
||||||
|
|
||||||
/* FAT16 (FIXME: avoid duplication with spisdcard) */
|
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage);
|
||||||
uint8_t spi_sdcard_readMBR(void);
|
|
||||||
uint8_t spi_sdcard_readFile(char *, char *, unsigned long);
|
|
||||||
|
|
||||||
#endif /* CSR_SDCORE_BASE */
|
#endif /* CSR_SDCORE_BASE */
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,6 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <system.h>
|
#include <system.h>
|
||||||
|
|
||||||
#define USE_SPISCARD_RECLOCKING
|
|
||||||
|
|
||||||
#ifdef CSR_SPISDCARD_BASE
|
#ifdef CSR_SPISDCARD_BASE
|
||||||
// Import prototypes for the functions
|
// Import prototypes for the functions
|
||||||
#include "spisdcard.h"
|
#include "spisdcard.h"
|
||||||
|
@ -290,314 +288,4 @@ uint8_t readSector(uint32_t sectorNumber, uint8_t *storage)
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// FAT16 Specific code starts here
|
|
||||||
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
|
||||||
|
|
||||||
// Structure to store SD CARD partition table
|
|
||||||
typedef struct {
|
|
||||||
uint8_t first_byte;
|
|
||||||
uint8_t start_chs[3];
|
|
||||||
uint8_t partition_type;
|
|
||||||
uint8_t end_chs[3];
|
|
||||||
uint32_t start_sector;
|
|
||||||
uint32_t length_sectors;
|
|
||||||
} __attribute((packed)) PartitionTable;
|
|
||||||
|
|
||||||
PartitionTable sdCardPartition;
|
|
||||||
|
|
||||||
// Structure to store SD CARD FAT16 Boot Sector (boot code is ignored, provides layout of the FAT16 partition on the SD CARD)
|
|
||||||
typedef struct {
|
|
||||||
uint8_t jmp[3];
|
|
||||||
uint8_t oem[8];
|
|
||||||
uint16_t sector_size;
|
|
||||||
uint8_t sectors_per_cluster;
|
|
||||||
uint16_t reserved_sectors;
|
|
||||||
uint8_t number_of_fats;
|
|
||||||
uint16_t root_dir_entries;
|
|
||||||
uint16_t total_sectors_short; // if zero, later field is used
|
|
||||||
uint8_t media_descriptor;
|
|
||||||
uint16_t fat_size_sectors;
|
|
||||||
uint16_t sectors_per_track;
|
|
||||||
uint16_t number_of_heads;
|
|
||||||
uint32_t hidden_sectors;
|
|
||||||
uint32_t total_sectors_long;
|
|
||||||
|
|
||||||
uint8_t drive_number;
|
|
||||||
uint8_t current_head;
|
|
||||||
uint8_t boot_signature;
|
|
||||||
uint32_t volume_id;
|
|
||||||
uint8_t volume_label[11];
|
|
||||||
uint8_t fs_type[8];
|
|
||||||
uint8_t boot_code[448];
|
|
||||||
uint16_t boot_sector_signature;
|
|
||||||
} __attribute((packed)) Fat16BootSector;
|
|
||||||
|
|
||||||
Fat16BootSector sdCardFatBootSector;
|
|
||||||
|
|
||||||
// Structure to store SD CARD FAT16 Root Directory Entries
|
|
||||||
// Allocated to MAIN RAM - hence pointer
|
|
||||||
typedef struct {
|
|
||||||
uint8_t filename[8];
|
|
||||||
uint8_t ext[3];
|
|
||||||
uint8_t attributes;
|
|
||||||
uint8_t reserved[10];
|
|
||||||
uint16_t modify_time;
|
|
||||||
uint16_t modify_date;
|
|
||||||
uint16_t starting_cluster;
|
|
||||||
uint32_t file_size;
|
|
||||||
} __attribute((packed)) Fat16Entry;
|
|
||||||
|
|
||||||
Fat16Entry *sdCardFat16RootDir;
|
|
||||||
|
|
||||||
// Structure to store SD CARD FAT16 Entries
|
|
||||||
// Array of uint16_tS (16bit integers)
|
|
||||||
uint16_t *sdCardFatTable;
|
|
||||||
|
|
||||||
// Calculated sector numbers on the SD CARD for the FAT16 Entries and ROOT DIRECTORY
|
|
||||||
uint32_t fatSectorStart, rootDirSectorStart;
|
|
||||||
|
|
||||||
// Storage for SECTOR read from SD CARD
|
|
||||||
uint8_t sdCardSector[512];
|
|
||||||
|
|
||||||
// SPI_SDCARD_READMBR
|
|
||||||
// Function exposed to BIOS to retrieve FAT16 partition details, FAT16 Entry Table, FAT16 Root Directory
|
|
||||||
// MBR = Master Boot Record - Sector 0x00000000 on SD CARD - Contains Partition 1 details at 0x1be
|
|
||||||
//
|
|
||||||
// FIXME only checks partition 1 out of 4
|
|
||||||
//
|
|
||||||
// Return 0 success, 1 failure
|
|
||||||
//
|
|
||||||
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
|
||||||
uint8_t spi_sdcard_readMBR(void)
|
|
||||||
{
|
|
||||||
int i, n;
|
|
||||||
|
|
||||||
// Read Sector 0x00000000
|
|
||||||
printf("Reading MBR\n");
|
|
||||||
if( readSector(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));
|
|
||||||
|
|
||||||
// Check Partition 1 is valid, FIRST_BYTE=0x00 or 0x80
|
|
||||||
// Check Partition 1 has type 4, 6 or 14 (FAT16 of various sizes)
|
|
||||||
printf("Partition 1 Information: Active=0x%02x, Type=0x%02x, LBAStart=0x%08x\n", sdCardPartition.first_byte, sdCardPartition.partition_type, sdCardPartition.start_sector);
|
|
||||||
if( (sdCardPartition.first_byte!=0x80) && (sdCardPartition.first_byte!=0x00) ) {
|
|
||||||
printf("Partition 1 Not Valid\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
if( (sdCardPartition.partition_type==4) || (sdCardPartition.partition_type==6) || (sdCardPartition.partition_type==14) ) {
|
|
||||||
printf("Partition 1 is FAT16\n");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Partition 1 Not FAT16\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Failed to read MBR\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read Parition 1 Boot Sector - Found from Partion Table
|
|
||||||
printf("\nRead FAT16 Boot Sector\n");
|
|
||||||
if( readSector(sdCardPartition.start_sector, sdCardSector)==SUCCESS ) {
|
|
||||||
memcpy(&sdCardFatBootSector, &sdCardSector, sizeof(Fat16BootSector));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
printf("Failed to read FAT16 Boot Sector\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print details of Parition 1
|
|
||||||
printf(" Jump Code: 0x%02x 0x%02x 0x%02x\n",sdCardFatBootSector.jmp[0],sdCardFatBootSector.jmp[1],sdCardFatBootSector.jmp[2]);
|
|
||||||
printf(" OEM Code: [");
|
|
||||||
for(n=0; n<8; n++)
|
|
||||||
printf("%c",sdCardFatBootSector.oem[n]);
|
|
||||||
printf("]\n");
|
|
||||||
printf(" Sector Size: %d\n",sdCardFatBootSector.sector_size);
|
|
||||||
printf(" Sectors Per Cluster: %d\n",sdCardFatBootSector.sectors_per_cluster);
|
|
||||||
printf(" Reserved Sectors: %d\n",sdCardFatBootSector.reserved_sectors);
|
|
||||||
printf(" Number of Fats: %d\n",sdCardFatBootSector.number_of_fats);
|
|
||||||
printf(" Root Dir Entries: %d\n",sdCardFatBootSector.root_dir_entries);
|
|
||||||
printf(" Total Sectors Short: %d\n",sdCardFatBootSector.total_sectors_short);
|
|
||||||
printf(" Media Descriptor: 0x%02x\n",sdCardFatBootSector.media_descriptor);
|
|
||||||
printf(" Fat Size Sectors: %d\n",sdCardFatBootSector.fat_size_sectors);
|
|
||||||
printf(" Sectors Per Track: %d\n",sdCardFatBootSector.sectors_per_track);
|
|
||||||
printf(" Number of Heads: %d\n",sdCardFatBootSector.number_of_heads);
|
|
||||||
printf(" Hidden Sectors: %d\n",sdCardFatBootSector.hidden_sectors);
|
|
||||||
printf(" Total Sectors Long: %d\n",sdCardFatBootSector.total_sectors_long);
|
|
||||||
printf(" Drive Number: 0x%02x\n",sdCardFatBootSector.drive_number);
|
|
||||||
printf(" Current Head: 0x%02x\n",sdCardFatBootSector.current_head);
|
|
||||||
printf(" Boot Signature: 0x%02x\n",sdCardFatBootSector.boot_signature);
|
|
||||||
printf(" Volume ID: 0x%08x\n",sdCardFatBootSector.volume_id);
|
|
||||||
printf(" Volume Label: [");
|
|
||||||
for(n=0; n<11; n++)
|
|
||||||
printf("%c",sdCardFatBootSector.volume_label[n]);
|
|
||||||
printf("]\n");
|
|
||||||
printf(" Volume Label: [");
|
|
||||||
for(n=0; n<8; n++)
|
|
||||||
printf("%c",sdCardFatBootSector.fs_type[n]);
|
|
||||||
printf("]\n");
|
|
||||||
printf(" Boot Sector Signature: 0x%04x\n\n",sdCardFatBootSector.boot_sector_signature);
|
|
||||||
|
|
||||||
// Check Partition 1 is valid, not 0 length
|
|
||||||
if(sdCardFatBootSector.total_sectors_long==0) {
|
|
||||||
printf("Error reading FAT16 Boot Sector\n");
|
|
||||||
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);
|
|
||||||
printf("sdCardFatTable = 0x%08x Reading Fat16 Table (%d Sectors Long)\n\n",sdCardFatTable,sdCardFatBootSector.fat_size_sectors);
|
|
||||||
|
|
||||||
// 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 ) {
|
|
||||||
printf("Error reading FAT16 table - sector %d\n",n);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read in FAT16 Root Directory
|
|
||||||
// Calculate Storage from TOP of MAIN RAM
|
|
||||||
sdCardFat16RootDir= (Fat16Entry *)(MAIN_RAM_BASE+MAIN_RAM_SIZE-sdCardFatBootSector.sector_size*sdCardFatBootSector.fat_size_sectors-sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry));
|
|
||||||
printf("sdCardFat16RootDir = 0x%08x Reading Root Directory (%d Sectors Long)\n\n",sdCardFat16RootDir,sdCardFatBootSector.root_dir_entries*sizeof(Fat16Entry)/sdCardFatBootSector.sector_size);
|
|
||||||
|
|
||||||
// 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 ) {
|
|
||||||
printf("Error reading Root Dir - sector %d\n",n);
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Print out Root Directory
|
|
||||||
// Alternates between valid and invalid directory entries for SIMPLE 8+3 file names, extended filenames in other entries
|
|
||||||
// Only print valid characters
|
|
||||||
printf("\nRoot Directory\n");
|
|
||||||
for(n=0; n<sdCardFatBootSector.root_dir_entries; n++) {
|
|
||||||
if( (sdCardFat16RootDir[n].filename[0]!=0) && (sdCardFat16RootDir[n].file_size>0)) {
|
|
||||||
printf(" File %d [",n);
|
|
||||||
for( i=0; i<8; i++) {
|
|
||||||
if( (sdCardFat16RootDir[n].filename[i]>31) && (sdCardFat16RootDir[n].filename[i]<127) )
|
|
||||||
printf("%c",sdCardFat16RootDir[n].filename[i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
printf(".");
|
|
||||||
for( i=0; i<3; i++) {
|
|
||||||
if( (sdCardFat16RootDir[n].ext[i]>31) && (sdCardFat16RootDir[n].ext[i]<127) )
|
|
||||||
printf("%c",sdCardFat16RootDir[n].ext[i]);
|
|
||||||
else
|
|
||||||
printf(" ");
|
|
||||||
}
|
|
||||||
printf("] @ Cluster %d for %d bytes\n",sdCardFat16RootDir[n].starting_cluster,sdCardFat16RootDir[n].file_size);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("\n");
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
|
|
||||||
// SPI_SDCARD_READFILE
|
|
||||||
// Function exposed to BIOS to retrieve FILENAME+EXT into ADDRESS
|
|
||||||
//
|
|
||||||
// FIXME only checks UPPERCASE 8+3 filenames
|
|
||||||
//
|
|
||||||
// Return 0 success, 1 failure
|
|
||||||
//
|
|
||||||
// Details from https://codeandlife.com/2012/04/02/simple-fat-and-sd-tutorial-part-1/
|
|
||||||
uint8_t spi_sdcard_readFile(char *filename, char *ext, unsigned long address)
|
|
||||||
{
|
|
||||||
int i, n, sector;
|
|
||||||
uint16_t fileClusterStart;
|
|
||||||
uint32_t fileLength, bytesRemaining, clusterSectorStart;
|
|
||||||
uint16_t nameMatch;
|
|
||||||
printf("Reading File [%s.%s] into 0x%08x : ",filename, ext, address);
|
|
||||||
|
|
||||||
// Find FILENAME+EXT in Root Directory
|
|
||||||
// Indicate FILE found by setting the starting cluster number
|
|
||||||
fileClusterStart=0; n=0;
|
|
||||||
while( (fileClusterStart==0) && (n<sdCardFatBootSector.root_dir_entries) ) {
|
|
||||||
nameMatch=0;
|
|
||||||
if( sdCardFat16RootDir[n].filename[0]!=0 ) {
|
|
||||||
nameMatch=1;
|
|
||||||
for(i=0; i<strlen(filename); i++)
|
|
||||||
if(sdCardFat16RootDir[n].filename[i]!=filename[i]) nameMatch=0;
|
|
||||||
for(i=0; i<strlen(ext); i++)
|
|
||||||
if(sdCardFat16RootDir[n].ext[i]!=ext[i]) nameMatch=0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(nameMatch==1) {
|
|
||||||
fileClusterStart=sdCardFat16RootDir[n].starting_cluster;
|
|
||||||
fileLength=sdCardFat16RootDir[n].file_size;
|
|
||||||
} else {
|
|
||||||
n++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If starting cluster number is still 0 then file not found
|
|
||||||
if(fileClusterStart==0) {
|
|
||||||
printf("File not found\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
printf("File starts at Cluster %d length %d\n",fileClusterStart,fileLength);
|
|
||||||
|
|
||||||
// ZERO Length file are automatically assumed to have been read SUCCESS
|
|
||||||
if( fileLength==0 ) return SUCCESS;
|
|
||||||
|
|
||||||
// Read each cluster sector by sector, i being number of clusters
|
|
||||||
bytesRemaining=fileLength;
|
|
||||||
// Calculate number of clusters (always >1)
|
|
||||||
for(i=0; i<1+((fileLength/sdCardFatBootSector.sectors_per_cluster)/sdCardFatBootSector.sector_size); i++) {
|
|
||||||
printf("\rCluster: %d",fileClusterStart);
|
|
||||||
|
|
||||||
// Locate start of cluster on SD CARD and read appropraite number of sectors
|
|
||||||
clusterSectorStart=rootDirSectorStart+(fileClusterStart-1)*sdCardFatBootSector.sectors_per_cluster;
|
|
||||||
for(sector=0; sector<sdCardFatBootSector.sectors_per_cluster; sector++) {
|
|
||||||
// Read Sector from SD CARD
|
|
||||||
// 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 ) {
|
|
||||||
printf("\nRead Error\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
bytesRemaining=bytesRemaining-sdCardFatBootSector.sector_size;
|
|
||||||
address=address+sdCardFatBootSector.sector_size;
|
|
||||||
} else {
|
|
||||||
if( readSector(clusterSectorStart+sector,sdCardSector) == FAILURE ) {
|
|
||||||
printf("\nRead Error\n");
|
|
||||||
return FAILURE;
|
|
||||||
}
|
|
||||||
memcpy((uint8_t *)address, sdCardSector, bytesRemaining);
|
|
||||||
bytesRemaining=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Move to next cluster
|
|
||||||
fileClusterStart=sdCardFatTable[fileClusterStart];
|
|
||||||
}
|
|
||||||
printf("\n\n");
|
|
||||||
return SUCCESS;
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -1,6 +1,19 @@
|
||||||
|
#ifndef __SPISDCARD_H
|
||||||
|
#define __SPISDCARD_H
|
||||||
|
|
||||||
|
#include <generated/csr.h>
|
||||||
|
|
||||||
|
#ifdef CSR_SPISDCARD_BASE
|
||||||
|
|
||||||
|
#define USE_SPISCARD_RECLOCKING
|
||||||
|
|
||||||
int spi_sdcard_init(uint32_t device);
|
int spi_sdcard_init(uint32_t device);
|
||||||
int spi_sdcard_read_sector(uint32_t device, uint32_t lba,uint_least8_t *buf);
|
int spi_sdcard_read_sector(uint32_t device, uint32_t lba,uint_least8_t *buf);
|
||||||
|
|
||||||
uint8_t spi_sdcard_goidle(void);
|
uint8_t spi_sdcard_goidle(void);
|
||||||
uint8_t spi_sdcard_readMBR(void);
|
|
||||||
uint8_t spi_sdcard_readFile(char *, char *, unsigned long);
|
uint8_t readSector(uint32_t sectorNumber, uint8_t *storage);
|
||||||
|
|
||||||
|
#endif /* CSR_SPISDCARD_BASE */
|
||||||
|
|
||||||
|
#endif /* __SPISDCARD_H */
|
||||||
|
|
Loading…
Reference in New Issue