diff options
author | Clyne Sullivan <tullivan99@gmail.com> | 2018-04-18 23:17:25 -0400 |
---|---|---|
committer | Clyne Sullivan <tullivan99@gmail.com> | 2018-04-18 23:17:25 -0400 |
commit | 1a11ab00d898c4484bc0f518a1d53b1f4cbf5fb4 (patch) | |
tree | 870a9e909d20235e09b4b1b613536ecaf05b17a2 | |
parent | 8e11f269ce352df26af7c44d283131494dcd70fa (diff) |
SD cardgit status FAT32git status Beautiful!
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | include/display.h | 3 | ||||
-rw-r--r-- | include/fat32.h | 31 | ||||
-rw-r--r-- | include/sdcard.h | 42 | ||||
-rw-r--r-- | initrd/graph | 16 | ||||
-rw-r--r-- | initrd/table | 85 | ||||
-rw-r--r-- | libinterp.a | bin | 66064 -> 68136 bytes | |||
-rw-r--r-- | src/display.c | 37 | ||||
-rw-r--r-- | src/fat32.c | 145 | ||||
-rw-r--r-- | src/gpio.c | 2 | ||||
-rw-r--r-- | src/keypad.c | 50 | ||||
-rw-r--r-- | src/main.c | 43 | ||||
-rw-r--r-- | src/script.c | 52 | ||||
-rw-r--r-- | src/sdcard.c | 222 | ||||
-rw-r--r-- | src/stdlib.c | 7 |
15 files changed, 706 insertions, 31 deletions
@@ -46,7 +46,7 @@ INITRD = initrd.img all: $(OUT) -$(OUT): $(OFILES) initrd/init libinterp.a +$(OUT): $(OFILES) initrd/* libinterp.a @echo " INITRD " $(INITRD) @rm -f $(INITRD) @$(AR) $(INITRD) initrd/* diff --git a/include/display.h b/include/display.h index b8afe38..2d74fce 100644 --- a/include/display.h +++ b/include/display.h @@ -92,4 +92,7 @@ void dsp_set_addr(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); */ void dsp_set_addr_read(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2); +void dsp_sleep(void); +void dsp_wakeup(void); + #endif // DISPLAY_H_ diff --git a/include/fat32.h b/include/fat32.h new file mode 100644 index 0000000..39d22f6 --- /dev/null +++ b/include/fat32.h @@ -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_ diff --git a/include/sdcard.h b/include/sdcard.h new file mode 100644 index 0000000..8cdef58 --- /dev/null +++ b/include/sdcard.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_ diff --git a/initrd/graph b/initrd/graph index 8f9916a..949fd52 100644 --- a/initrd/graph +++ b/initrd/graph @@ -41,24 +41,24 @@ func(makegrid) { # makegrid() -clearcmd = "clear" +clearcmd = "" while (1) { rect(0, 0, 480, 40, 0) print("f(x) = ") - Fx = gets() + fx = gets() - if (Fx == clearcmd) { + if (fx == clearcmd) { makegrid() } else { # do function - x = xmin - while (x < xmax) { - y = solve(Fx) + X = xmin + while (X < xmax) { + y = solve(fx) y = 0 - y if ((y >= ymin) & (y <= ymax)) { - pixel(cx + x * xinc, cy + y * yinc, 511) + pixel(cx + X * xinc, cy + y * yinc, 511) } - x = x + 1 / xinc + X = X + 1 / xinc } } diff --git a/initrd/table b/initrd/table new file mode 100644 index 0000000..62961e3 --- /dev/null +++ b/initrd/table @@ -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 + } +} diff --git a/libinterp.a b/libinterp.a Binary files differindex 5b5da09..c5a2337 100644 --- a/libinterp.a +++ b/libinterp.a diff --git a/src/display.c b/src/display.c index e961299..376ba43 100644 --- a/src/display.c +++ b/src/display.c @@ -206,7 +206,13 @@ void dsp_init(void) dsp_write_cmd(0x11); delay(150); dsp_write_cmd(0x29); // set display on - delay(500); + delay(150); + + dsp_write_cmd(0x53); + dsp_write_data(0x2C); + //dsp_write_cmd(0x51); + //dsp_write_data(128); + /*dsp_write_cmd(0x33); // set scroll area dsp_write_data(0x00); dsp_write_data(0x00); @@ -219,3 +225,32 @@ void dsp_init(void) dsp_write_data(0x00);*/ } +void dsp_backlight(uint8_t value) +{ + dsp_write_cmd(0x51); + dsp_write_data(value); +} + +void dsp_sleep(void) +{ + // backlight + dsp_backlight(0x00); + // display off + dsp_write_cmd(0x28); + // sleep mode + dsp_write_cmd(0x10); + delay(5); +} + +void dsp_wakeup(void) +{ + // unsleep + dsp_write_cmd(0x11); + //delay(5); + for (uint32_t i = 0; i < 20000; i++) + asm(""); + // display on + dsp_write_cmd(0x29); + dsp_backlight(0xFF); +} + diff --git a/src/fat32.c b/src/fat32.c new file mode 100644 index 0000000..1154998 --- /dev/null +++ b/src/fat32.c @@ -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; +} @@ -23,7 +23,7 @@ void gpio_init(void) { // enable clocks - RCC->AHB2ENR |= 0xFF; + RCC->AHB2ENR |= 0x0F; } void gpio_pupd(GPIO_TypeDef *port, uint32_t pin, uint32_t pupd) diff --git a/src/keypad.c b/src/keypad.c index b00cf41..cb569e1 100644 --- a/src/keypad.c +++ b/src/keypad.c @@ -35,6 +35,8 @@ #define COL_3 GPIO_PORT(A, 12) #define COL_4 GPIO_PORT(C, 5) +#define BTN_SLEEP GPIO_PORT(C, 11) + #define ROWS 6 #define COLS 5 @@ -59,7 +61,7 @@ static const port_t keypad_cols[COLS] = { static const char keypad_map[ROWS * COLS * 4] = { "\x7F\0\0\0" "\xFF\0\0\0" "\xFF\x02\0\0" "\x19\0\0\0" "\x18\0\0\0" - "x\0\0\0" "\0\0\0\0" "\0\0\0\0" "\x1B\0\0\0" "\x1A\0\0\0" + "sin\0" "cos\0" "tan\0" "\x1B\0\0\0" "\x1A\0\0\0" "7\0\0\0" "8\0\0\0" "9\0\0\0" "(\0\0\0" ")\0\0\0" "4\0\0\0" "5\0\0\0" "6\0\0\0" "/\0\0\0" "*\0\0\0" "1\0\0\0" "2\0\0\0" "3\0\0\0" "-\0\0\0" "+\0\0\0" @@ -67,12 +69,12 @@ static const char keypad_map[ROWS * COLS * 4] = { }; static const char keypad_map_2nd[ROWS * COLS * 4] = { - "a\0\0\0" "b\0\0\0" "c\0\0\0" "d\0\0\0" "e\0\0\0" - "f\0\0\0" "g\0\0\0" "h\0\0\0" "i\0\0\0" "j\0\0\0" - "k\0\0\0" "l\0\0\0" "m\0\0\0" "n\0\0\0" "o\0\0\0" - "p\0\0\0" "q\0\0\0" "r\0\0\0" "s\0\0\0" "t\0\0\0" - "u\0\0\0" "v\0\0\0" "w\0\0\0" "x\0\0\0" "y\0\0\0" - "z\0\0\0" "\0\0\0\0" "\0\0\0\0" "\0\0\0\0" "\xFF\x01\0\0" + "\x7F\0\0\0" "pi\0\0" "X\0\0\0" "Y\0\0\0" "Z\0\0\0" + "A\0\0\0" "B\0\0\0" "C\0\0\0" "D\0\0\0" "E\0\0\0" + "F\0\0\0" "G\0\0\0" "H\0\0\0" "I\0\0\0" "J\0\0\0" + "K\0\0\0" "L\0\0\0" "M\0\0\0" "N\0\0\0" "O\0\0\0" + "P\0\0\0" "Q\0\0\0" "R\0\0\0" "S\0\0\0" "T\0\0\0" + "U\0\0\0" "V\0\0\0" "W\0\0\0" "\b\0\0\0" "\xFF\x01\0\0" }; #define KEY(r, c, i) map[r * COLS * 4 + c * 4 + i] @@ -142,6 +144,19 @@ void keypad_init(void) gpio_speed(p, pin, VERYHIGH); gpio_dout(p, pin, 0); } + + gpio_mode(BTN_SLEEP, OUTPUT); + gpio_dout(BTN_SLEEP, 0); + gpio_mode(BTN_SLEEP, INPUT); + gpio_pupd(BTN_SLEEP, PULLDOWN); + + //SYSCFG->EXTICR[2] |= 0x200; // C10 + EXTI->RTSR1 |= (1 << 11); + EXTI->EMR1 |= (1 << 11); // Allow *10 + EXTI->IMR1 |= (1 << 11); + + // enable IRQ in NVIC + ((uint32_t *)0xE000E100)[1] |= (1 << 8); } void keypad_start(void) @@ -160,3 +175,24 @@ int keypad_get(void) keypad_buffer_pos--; return key; } + +uint32_t sleep_pending = 0; +void EXTI15_10_IRQHandler(void) +{ + uint32_t PR1 = EXTI->PR1; + + if (gpio_din(BTN_SLEEP)) { + while (gpio_din(BTN_SLEEP)); + if (sleep_pending != 0) { + sleep_pending = 0; + extern void wakeup(void); + wakeup(); + } else { + sleep_pending |= 1; + } + return; + } + + EXTI->PR1 |= PR1; +} + @@ -21,6 +21,7 @@ #include <clock.h>
#include <display.h>
#include <display_draw.h>
+#include <fat32.h>
#include <flash.h>
#include <gpio.h>
#include <heap.h>
@@ -30,6 +31,7 @@ #include <it/parser.h>
#include <random.h>
#include <script.h>
+#include <sdcard.h>
#include <serial.h>
#include <stm32l476xx.h>
#include <string.h>
@@ -60,7 +62,7 @@ int main(void) keypad_init();
flash_init();
- gpio_mode(GPIOA, 5, OUTPUT);
+ //gpio_mode(GPIOA, 5, OUTPUT); // taken by sd
// enable FPU
SCB->CPACR |= (0xF << 20);
@@ -71,9 +73,25 @@ int main(void) while (1);
}
+void sleep(void)
+{
+ dsp_sleep();
+ *((uint32_t *)0xE000ED10) |= 4; // SLEEPDEEP
+ PWR->CR1 |= 2;
+ asm("wfi");
+}
+
+void wakeup(void)
+{
+ clock_init();
+ dsp_wakeup();
+}
+
void kmain(void)
{
dsp_init();
+ sd_init();
+ fat_find();
dsp_cursoron();
keypad_start();
@@ -81,30 +99,37 @@ void kmain(void) task_start(task_status, 512);
while (1) {
- gpio_dout(GPIOA, 5, 1);
- delay(250);
- gpio_dout(GPIOA, 5, 0);
- delay(250);
+ extern uint32_t sleep_pending;
+ if (sleep_pending != 0) {
+ sleep();
+ while (sleep_pending)
+ delay(1);
+ }
+ //gpio_dout(GPIOA, 5, 1);
+ //delay(250);
+ //gpio_dout(GPIOA, 5, 0);
+ delay(100);
}
}
instance *load_program(const char *name)
{
// load file
- char *s = initrd_readfile(name);
- if (s == 0) {
+ file_t *file = fat_findfile(name);
+ if (file == 0) {
dsp_puts("can't find ");
dsp_puts(name);
goto fail;
}
+ char *s = fat_readfile(file);
instance *it = inewinstance();
script_loadlib(it);
// read in, parse into script code
char *linebuf = (char *)malloc(120);
uint32_t i = 0, prev = 0, lc;
- uint32_t size = initrd_filesize(name);
+ uint32_t size = file->size;
int ret = 0;
while (i < size) {
for (; s[i] != '\n' && s[i] != '\0'; i++);
@@ -121,6 +146,8 @@ instance *load_program(const char *name) prev = ++i;
}
free(linebuf);
+ free(s);
+ free(file);
return it;
fail:
while (1);
diff --git a/src/script.c b/src/script.c index 51a3bb7..5ba0c08 100644 --- a/src/script.c +++ b/src/script.c @@ -39,9 +39,11 @@ int script_puts(instance *it); int script_putchar(instance *it); int script_gets(instance *it); +int script_getf(instance *it); int script_delay(instance *it); int script_rect(instance *it); int script_ppos(instance *it); +int script_rpos(instance *it); int script_line(instance *it); int script_color(instance *it); int script_rand(instance *it); @@ -53,6 +55,8 @@ int script_program(instance *it); int script_free(instance *it); int math_sin(instance *it); +int math_cos(instance *it); +int math_tan(instance *it); void script_loadlib(instance *it) { @@ -61,8 +65,10 @@ void script_loadlib(instance *it) inew_cfunc(it, "print", script_puts); inew_cfunc(it, "putchar", script_putchar); inew_cfunc(it, "gets", script_gets); + inew_cfunc(it, "getf", script_getf); inew_cfunc(it, "getkey", script_getkey); inew_cfunc(it, "ppos", script_ppos); + inew_cfunc(it, "rpos", script_rpos); inew_cfunc(it, "pixel", script_pixel); inew_cfunc(it, "line", script_line); @@ -78,6 +84,8 @@ void script_loadlib(instance *it) inew_cfunc(it, "freemem", script_free); inew_cfunc(it, "sin", math_sin); + inew_cfunc(it, "cos", math_cos); + inew_cfunc(it, "tan", math_tan); } int math_sin(instance *it) @@ -88,6 +96,22 @@ int math_sin(instance *it) return 0; } +int math_cos(instance *it) +{ + variable *n = igetarg(it, 0); + variable *v = make_varf(0, cosf(n->value.f)); + ipush(it, (uint32_t)v); + return 0; +} + +int math_tan(instance *it) +{ + variable *n = igetarg(it, 0); + variable *v = make_varf(0, tanf(n->value.f)); + ipush(it, (uint32_t)v); + return 0; +} + int script_menu(instance *it) { char listbuf[4]; @@ -113,13 +137,15 @@ int script_menu(instance *it) return 0; } +#include <fat32.h> + int script_filemenu(instance *it) { char listbuf[4]; char *fname; strncpy(listbuf, " : \0", 4); dsp_puts("Choose a file: \n"); - for (unsigned int i = 0; (fname = initrd_getname(i)) != 0; i++) { + for (unsigned int i = 0; (fname = /*initrd*/fat_getname(i)) != 0; i++) { listbuf[0] = i + '0'; dsp_puts(listbuf); dsp_puts(fname); @@ -163,6 +189,18 @@ int script_putchar(instance *it) return 0; } +int script_getf(instance *it) +{ + if (script_gets(it) != 0) + return -1; + + variable *s = (variable *)ipop(it); + s->value.f = strtof((char *)s->value.p, 0); + s->type = NUMBER; + ipush(it, (uint32_t)s); + return 0; +} + int script_gets(instance *it) { char *s = malloc(64); @@ -261,8 +299,14 @@ int script_line(instance *it) int script_ppos(instance *it) { - dsp_cpos(0, 0); - dsp_coff(igetarg_integer(it, 0), igetarg_integer(it, 1)); + dsp_coff(0, 0); + dsp_cpos(igetarg_integer(it, 0), igetarg_integer(it, 1)); + return 0; +} + +int script_rpos(instance *it) +{ + dsp_spos(igetarg_integer(it, 0), igetarg_integer(it, 1)); return 0; } @@ -305,7 +349,7 @@ extern instance *load_program(const char *name); int script_program(instance *it) { int initrdOffset = (int)igetarg(it, 0)->value.f; - char *name = initrd_getname(initrdOffset); + char *name = fat_getname(initrdOffset); dsp_rect(0, 0, 480, 300, 0); dsp_cpos(0, 0); diff --git a/src/sdcard.c b/src/sdcard.c new file mode 100644 index 0000000..6cf602b --- /dev/null +++ b/src/sdcard.c @@ -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; +} + diff --git a/src/stdlib.c b/src/stdlib.c index 4714e93..a47fb03 100644 --- a/src/stdlib.c +++ b/src/stdlib.c @@ -85,7 +85,6 @@ char *snprintf(char *buf, unsigned int max, const char *format, ...) float strtof(const char *s, char **endptr) { - (void)s; (void)endptr; float res = 0.0f; @@ -139,6 +138,12 @@ char *ftostr(char *buf, float f) if (buf == 0) return 0; + if (f == 0) { + buf[0] = '0'; + buf[1] = '\0'; + return buf; + } + unsigned int i = 0; // offset // strip decimals, convert in reverse |