aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorClyne Sullivan <tullivan99@gmail.com>2018-04-18 23:17:25 -0400
committerClyne Sullivan <tullivan99@gmail.com>2018-04-18 23:17:25 -0400
commit1a11ab00d898c4484bc0f518a1d53b1f4cbf5fb4 (patch)
tree870a9e909d20235e09b4b1b613536ecaf05b17a2
parent8e11f269ce352df26af7c44d283131494dcd70fa (diff)
SD cardgit status FAT32git status Beautiful!
-rw-r--r--Makefile2
-rw-r--r--include/display.h3
-rw-r--r--include/fat32.h31
-rw-r--r--include/sdcard.h42
-rw-r--r--initrd/graph16
-rw-r--r--initrd/table85
-rw-r--r--libinterp.abin66064 -> 68136 bytes
-rw-r--r--src/display.c37
-rw-r--r--src/fat32.c145
-rw-r--r--src/gpio.c2
-rw-r--r--src/keypad.c50
-rw-r--r--src/main.c43
-rw-r--r--src/script.c52
-rw-r--r--src/sdcard.c222
-rw-r--r--src/stdlib.c7
15 files changed, 706 insertions, 31 deletions
diff --git a/Makefile b/Makefile
index d672a52..595694a 100644
--- a/Makefile
+++ b/Makefile
@@ -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
index 5b5da09..c5a2337 100644
--- a/libinterp.a
+++ b/libinterp.a
Binary files differ
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;
+}
diff --git a/src/gpio.c b/src/gpio.c
index db67465..151779d 100644
--- a/src/gpio.c
+++ b/src/gpio.c
@@ -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;
+}
+
diff --git a/src/main.c b/src/main.c
index a86db6a..4380eae 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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