SD cardgit status FAT32git status Beautiful!
parent
8e11f269ce
commit
1a11ab00d8
@ -0,0 +1,31 @@
|
||||
#ifndef FAT32_H_
|
||||
#define FAT32_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct {
|
||||
uint32_t size;
|
||||
uint32_t start;
|
||||
} file_t;
|
||||
|
||||
/**
|
||||
* Finds a FAT partition on the SD card.
|
||||
* @return non-zero if partition found
|
||||
*/
|
||||
int fat_find(void);
|
||||
|
||||
/**
|
||||
* Searches for the given file, returning necessary information to use it.
|
||||
* @param name the file's name
|
||||
* @return a file data structure, null if not found
|
||||
*/
|
||||
file_t *fat_findfile(const char *name);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char *fat_readfile(file_t *file);
|
||||
|
||||
char *fat_getname(uint32_t index);
|
||||
|
||||
#endif // FAT32_H_
|
@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @file sdcard.c
|
||||
* Provides a basic library for accessing an SD card
|
||||
*
|
||||
* Copyright (C) 2018 Clyne Sullivan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SDCARD_H_
|
||||
#define SDCARD_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/**
|
||||
* Attempts to initialize the SD card.
|
||||
* Warning: Little to no error checking is done/handled properly.
|
||||
*/
|
||||
void sd_init(void);
|
||||
|
||||
/**
|
||||
* Reads in data from the SD card.
|
||||
* LBAs are 512 bytes long.
|
||||
* @param buf the pre-allocated buffer to store data in
|
||||
* @param lba the lba to read from
|
||||
* @param count the number of bytes to read
|
||||
* @return the buffer
|
||||
*/
|
||||
uint8_t *sd_read(uint8_t *buf, uint32_t lba, uint32_t count);
|
||||
|
||||
#endif // SDCARD_H_
|
@ -0,0 +1,85 @@
|
||||
ppos(0, 0)
|
||||
array(table, 1)
|
||||
|
||||
index = 0
|
||||
while (1) {
|
||||
c = getkey()
|
||||
# down
|
||||
if (c == 25) {
|
||||
rpos(0, 1)
|
||||
index = index + 1
|
||||
}
|
||||
# up
|
||||
if (c == 24) {
|
||||
rpos(0, -1)
|
||||
if (index > 0) {
|
||||
index = index - 1
|
||||
}
|
||||
}
|
||||
# right - insert
|
||||
if (c == 26) {
|
||||
print(" ")
|
||||
rpos(-10, 0)
|
||||
print("> ")
|
||||
table.index = getf()
|
||||
ppos(0, index)
|
||||
print(index)
|
||||
print(": ")
|
||||
print(table.index)
|
||||
print(" ")
|
||||
index = index + 1
|
||||
ppos(0, index)
|
||||
}
|
||||
# plus - sum
|
||||
if (c == 43) {
|
||||
s = size(table)
|
||||
j = 0
|
||||
sum = 0
|
||||
while (j < s) {
|
||||
sum = sum + table.j
|
||||
j = j + 1
|
||||
}
|
||||
ppos(0, 17)
|
||||
print(" ")
|
||||
ppos(0, 17)
|
||||
print("sum: ")
|
||||
print(sum)
|
||||
ppos(0, 0)
|
||||
index = 0
|
||||
}
|
||||
# * - product
|
||||
if (c == 42) {
|
||||
s = size(table)
|
||||
j = 0
|
||||
product = 1
|
||||
while (j < s) {
|
||||
product = product * table.j
|
||||
j = j + 1
|
||||
}
|
||||
ppos(0, 17)
|
||||
print(" ")
|
||||
ppos(0, 17)
|
||||
print("product: ")
|
||||
print(product)
|
||||
ppos(0, 0)
|
||||
index = 0
|
||||
}
|
||||
# / - average
|
||||
if (c == 47) {
|
||||
s = size(table)
|
||||
j = 0
|
||||
sum = 0
|
||||
while (j < s) {
|
||||
sum = sum + table.j
|
||||
j = j + 1
|
||||
}
|
||||
average = sum / size(table)
|
||||
ppos(0, 17)
|
||||
print(" ")
|
||||
ppos(0, 17)
|
||||
print("average: ")
|
||||
print(average)
|
||||
ppos(0, 0)
|
||||
index = 0
|
||||
}
|
||||
}
|
Binary file not shown.
@ -0,0 +1,145 @@
|
||||
/**
|
||||
* Implementation of a driver to read a FAT32 filesystem.
|
||||
*/
|
||||
|
||||
#include <ctype.h>
|
||||
#include <fat32.h>
|
||||
#include <heap.h>
|
||||
#include <sdcard.h>
|
||||
#include <string.h>
|
||||
|
||||
static uint32_t partition_lba = 0;
|
||||
|
||||
static uint8_t SectorsPerCluster;
|
||||
static uint32_t RootDirCluster;
|
||||
static uint32_t ClustersLBA;
|
||||
static uint32_t FATStartLBA;
|
||||
|
||||
int fat_find(void)
|
||||
{
|
||||
uint8_t *block = malloc(512);
|
||||
|
||||
// find FAT partition
|
||||
sd_read(block, 0, 512);
|
||||
for (unsigned int i = 450; i < 450 + 64; i += 16) {
|
||||
if (block[i] == 0x0B || block[i] == 0x0C) {
|
||||
partition_lba = *((uint32_t *)(block + i + 4));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (partition_lba == 0)
|
||||
return 0;
|
||||
|
||||
// read FAT volume id
|
||||
sd_read(block, partition_lba, 512);
|
||||
SectorsPerCluster = block[0x0D];
|
||||
uint16_t ReservedSectors = *((uint16_t *)(block + 0x0E));
|
||||
uint32_t SectorsPerFAT = *((uint32_t *)(block + 0x24));
|
||||
RootDirCluster = *((uint32_t *)(block + 0x2C));
|
||||
|
||||
FATStartLBA = partition_lba + ReservedSectors;
|
||||
ClustersLBA = FATStartLBA + 2 * SectorsPerFAT;
|
||||
|
||||
free(block);
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32_t fat_cluster2lba(uint32_t cluster)
|
||||
{
|
||||
return ClustersLBA + (cluster - 2) * SectorsPerCluster;
|
||||
}
|
||||
|
||||
int fat_namecmp(const char *fatname, const char *name)
|
||||
{
|
||||
for (unsigned int i = 0; i < 8; i++) {
|
||||
if (name[i] == '.' || name[i] == '\0')
|
||||
break;
|
||||
|
||||
if (toupper(fatname[i]) != toupper(name[i]))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
file_t *fat_findfile(const char *name)
|
||||
{
|
||||
uint8_t *block = malloc(512 * SectorsPerCluster);
|
||||
sd_read(block, fat_cluster2lba(RootDirCluster), 512 * SectorsPerCluster);
|
||||
|
||||
for (unsigned int i = 0; block[i * 32] != 0; i++) {
|
||||
if (block[i * 32] == 0xE5 || (block[i * 32 + 11] & 0x0F) == 0x0F)
|
||||
continue;
|
||||
|
||||
if (fat_namecmp((char *)(block + i * 32), name)) {
|
||||
uint32_t size = *((uint32_t *)(block + i * 32 + 28));
|
||||
uint32_t start = *((uint16_t *)(block + i * 32 + 20))
|
||||
<< 16 | *((uint16_t *)(block + i * 32 + 26));
|
||||
file_t *file = malloc(sizeof(file_t));
|
||||
file->size = size;
|
||||
file->start = start;
|
||||
free(block);
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *fat_getname(uint32_t index)
|
||||
{
|
||||
uint8_t *block = malloc(512 * SectorsPerCluster);
|
||||
sd_read(block, fat_cluster2lba(RootDirCluster), 512 * SectorsPerCluster);
|
||||
|
||||
uint32_t idx = 0;
|
||||
for (unsigned int i = 0; block[i * 32] != 0; i++) {
|
||||
if (block[i * 32] == 0xE5 || (block[i * 32 + 11] & 0x0F) == 0x0F)
|
||||
continue;
|
||||
|
||||
if (idx == index) {
|
||||
char *name = strncpy(malloc(11), (char *)(block + i * 32), 11);
|
||||
free(block);
|
||||
return name;
|
||||
}
|
||||
idx++;
|
||||
}
|
||||
|
||||
free(block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
char *fat_readfile(file_t *file)
|
||||
{
|
||||
if (file == 0)
|
||||
return 0;
|
||||
|
||||
uint8_t *block = malloc(512);
|
||||
|
||||
uint32_t start = file->start;
|
||||
uint8_t *buffer = malloc(file->size + 1);
|
||||
uint32_t offset = 0;
|
||||
buffer[file->size] = '\0';
|
||||
while (start != 0) {
|
||||
// find in FAT
|
||||
sd_read(block, FATStartLBA + (start / 128), 512);
|
||||
uint32_t next = ((uint32_t *)block)[start % 128];
|
||||
|
||||
// read start cluster
|
||||
uint32_t size = 512 * SectorsPerCluster;
|
||||
if (file->size - offset < size)
|
||||
size = file->size - offset;
|
||||
sd_read(buffer, fat_cluster2lba(start), size);
|
||||
offset += size;
|
||||
|
||||
if ((next & 0x0FFFFFFF) == 0x0FFFFFFF)
|
||||
start = 0;
|
||||
else
|
||||
start = next;
|
||||
|
||||
}
|
||||
|
||||
free(block);
|
||||
return (char *)buffer;
|
||||
}
|
@ -0,0 +1,222 @@
|
||||
/**
|
||||
* @file sdcard.c
|
||||
* Provides a basic library for accessing an SD card
|
||||
*
|
||||
* Copyright (C) 2018 Clyne Sullivan
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <clock.h>
|
||||
#include <gpio.h>
|
||||
#include <heap.h>
|
||||
#include <sdcard.h>
|
||||
#include <string.h>
|
||||
|
||||
#define SCK GPIO_PORT(A, 5)
|
||||
#define SO GPIO_PORT(A, 6)
|
||||
#define SI GPIO_PORT(A, 7)
|
||||
#define CS GPIO_PORT(B, 6)
|
||||
|
||||
typedef struct {
|
||||
uint8_t cmd;
|
||||
uint32_t arg;
|
||||
uint8_t crc;
|
||||
} __attribute__ ((packed)) sdcmd_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t zero :1;
|
||||
uint8_t param :1;
|
||||
uint8_t address :1;
|
||||
uint8_t erase :1;
|
||||
uint8_t crc :1;
|
||||
uint8_t badcmd :1;
|
||||
uint8_t ereset :1;
|
||||
uint8_t idle :1;
|
||||
} __attribute__ ((packed)) r1_t;
|
||||
|
||||
void flash_out(uint8_t byte)
|
||||
{
|
||||
for (int i = 0; i < 8; i++) {
|
||||
gpio_dout(SI, byte & (1 << (7 - i)));
|
||||
gpio_dout(SCK, 1);
|
||||
gpio_dout(SCK, 0);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t flash_in(void)
|
||||
{
|
||||
uint8_t byte = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (gpio_din(SO))
|
||||
byte |= 1 << (7 - i);
|
||||
gpio_dout(SCK, 1);
|
||||
gpio_dout(SCK, 0);
|
||||
}
|
||||
return byte;
|
||||
}
|
||||
|
||||
void sd_delay(void)
|
||||
{
|
||||
gpio_dout(SI, 1);
|
||||
uint8_t so;
|
||||
int i = 0;
|
||||
do {
|
||||
so = flash_in();
|
||||
if (i < 8)
|
||||
i++;
|
||||
} while (i < 8 || so != 0xFF);
|
||||
}
|
||||
|
||||
uint8_t sd_send_cmd(uint8_t cmd, uint32_t arg)
|
||||
{
|
||||
sdcmd_t cmdp;
|
||||
cmdp.cmd = (cmd & 0x3F) | 0x40;
|
||||
cmdp.arg = arg;
|
||||
|
||||
sd_delay();
|
||||
flash_out(cmdp.cmd);
|
||||
flash_out(cmdp.arg >> 24);
|
||||
flash_out(cmdp.arg >> 16);
|
||||
flash_out(cmdp.arg >> 8);
|
||||
flash_out(cmdp.arg);
|
||||
flash_out(cmd == 8 ? 0x87 : 0x95);
|
||||
|
||||
// wait for a zero
|
||||
gpio_dout(SI, 1);
|
||||
uint8_t r1;
|
||||
do {
|
||||
r1 = flash_in();
|
||||
} while (r1 & 0x80);
|
||||
|
||||
return r1;
|
||||
}
|
||||
|
||||
void sd_init(void)
|
||||
{
|
||||
gpio_mode(SCK, OUTPUT);
|
||||
gpio_mode(SI, OUTPUT);
|
||||
gpio_mode(CS, OUTPUT);
|
||||
gpio_mode(SO, OUTPUT);
|
||||
gpio_speed(SCK, VERYHIGH);
|
||||
gpio_speed(SI, VERYHIGH);
|
||||
gpio_speed(SO, VERYHIGH);
|
||||
gpio_speed(CS, VERYHIGH);
|
||||
gpio_pupd(SCK, PULLUP);
|
||||
gpio_pupd(SI, PULLUP);
|
||||
gpio_pupd(SO, PULLUP);
|
||||
gpio_pupd(CS, PULLUP);
|
||||
gpio_dout(SO, 0);
|
||||
gpio_mode(SO, INPUT);
|
||||
gpio_dout(CS, 1);
|
||||
gpio_dout(SCK, 0);
|
||||
gpio_dout(SI, 1);
|
||||
|
||||
// init? cs and si are high
|
||||
delay(10);
|
||||
sd_delay();
|
||||
|
||||
// pull cs low, send cmd0
|
||||
gpio_dout(CS, 0);
|
||||
uint8_t resp = sd_send_cmd(0, 0);
|
||||
sd_delay();
|
||||
gpio_dout(CS, 1);
|
||||
|
||||
if (resp != 0x01)
|
||||
while (1);
|
||||
|
||||
// do cmd8
|
||||
delay(10);
|
||||
gpio_dout(CS, 0);
|
||||
resp = sd_send_cmd(8, 0x1AA);
|
||||
uint8_t ocr[4];
|
||||
for (int i = 0; i < 4; i++)
|
||||
ocr[i] = flash_in();
|
||||
sd_delay();
|
||||
gpio_dout(CS, 1);
|
||||
(void)ocr;
|
||||
|
||||
// initialize
|
||||
do {
|
||||
// cmd55
|
||||
gpio_dout(CS, 0);
|
||||
resp = sd_send_cmd(55, 0);
|
||||
sd_delay();
|
||||
gpio_dout(CS, 1);
|
||||
delay(10);
|
||||
|
||||
// acmd41
|
||||
gpio_dout(CS, 0);
|
||||
resp = sd_send_cmd(41, 0x40000000);
|
||||
sd_delay();
|
||||
gpio_dout(CS, 1);
|
||||
} while (resp != 0x00);
|
||||
|
||||
// set block length
|
||||
gpio_dout(CS, 0);
|
||||
resp = sd_send_cmd(16, 512);
|
||||
sd_delay();
|
||||
gpio_dout(CS, 1);
|
||||
}
|
||||
|
||||
uint8_t *sd_read_block(uint8_t *buf, uint32_t lba)
|
||||
{
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
|
||||
// send command
|
||||
gpio_dout(CS, 0);
|
||||
if (sd_send_cmd(17, lba) != 0)
|
||||
return 0;
|
||||
|
||||
// wait for block
|
||||
gpio_dout(SI, 1);
|
||||
uint8_t byte;
|
||||
do byte = flash_in();
|
||||
while (byte == 0xFF);
|
||||
if (byte != 0xFE)
|
||||
return 0;
|
||||
|
||||
// get block
|
||||
uint32_t i = 0;
|
||||
for (i = 0; i < 512; i++)
|
||||
buf[i] = flash_in();
|
||||
|
||||
sd_delay();
|
||||
gpio_dout(CS, 1);
|
||||
return buf;
|
||||
}
|
||||
|
||||
uint8_t *sd_read(uint8_t *buf, uint32_t lba, uint32_t count)
|
||||
{
|
||||
if (buf == 0)
|
||||
return 0;
|
||||
|
||||
uint8_t *block_buf = malloc(512);
|
||||
uint32_t i = 0;
|
||||
while (count > 0) {
|
||||
sd_read_block(block_buf, lba);
|
||||
memcpy(buf + i, block_buf, (count < 512) ? count : 512);
|
||||
if (count < 512)
|
||||
count = 0;
|
||||
else
|
||||
count -= 512;
|
||||
i += 512;
|
||||
lba++;
|
||||
}
|
||||
|
||||
free(block_buf);
|
||||
return buf;
|
||||
}
|
||||
|
Loading…
Reference in New Issue