]> code.bitgloo.com Git - clyne/calculator.git/commitdiff
SD cardgit status FAT32git status Beautiful!
authorClyne Sullivan <tullivan99@gmail.com>
Thu, 19 Apr 2018 03:17:25 +0000 (23:17 -0400)
committerClyne Sullivan <tullivan99@gmail.com>
Thu, 19 Apr 2018 03:17:25 +0000 (23:17 -0400)
15 files changed:
Makefile
include/display.h
include/fat32.h [new file with mode: 0644]
include/sdcard.h [new file with mode: 0644]
initrd/graph
initrd/table [new file with mode: 0644]
libinterp.a
src/display.c
src/fat32.c [new file with mode: 0644]
src/gpio.c
src/keypad.c
src/main.c
src/script.c
src/sdcard.c [new file with mode: 0644]
src/stdlib.c

index d672a52b5695a0979c376fe66e7f5b2780152bdb..595694a7111c407ec0371fb2a1194be8f933d1ac 100644 (file)
--- 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/*
index b8afe38f94bbe6428a82abb2e1eea57d363c70fd..2d74fcea0510968a2659d35aaf0e46f9e3897562 100644 (file)
@@ -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 (file)
index 0000000..39d22f6
--- /dev/null
@@ -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 (file)
index 0000000..8cdef58
--- /dev/null
@@ -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_
index 8f9916a40ee5d71aedef64d23c23f7f03d52ad0e..949fd5243f1438b72be1fd2374f5c270b14509fc 100644 (file)
@@ -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 (file)
index 0000000..62961e3
--- /dev/null
@@ -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
+       }
+}
index 5b5da09a3d0ffc73319a57032f4b5a978a8522db..c5a233714d2a57a0216e8bb491d33643438db010 100644 (file)
Binary files a/libinterp.a and b/libinterp.a differ
index e9612999010ac5e906dd1fb6db5ebe1b92e8d0ea..376ba433e8ea8ca33bac3ebcec15de9891cb8228 100644 (file)
@@ -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 (file)
index 0000000..1154998
--- /dev/null
@@ -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;
+}
index db674656b41ac082ee3d24c7d0caafc144a1c574..151779d982808b6f301bb5c7cb152b520ceebf0d 100644 (file)
@@ -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)
index b00cf4105bed508e33d4ddf00cb990591e5827a8..cb569e1e3e9f56a66fe80a52c255ddcef240ac50 100644 (file)
@@ -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;
+}
+
index a86db6aa79aa608020ae2107366f5116056654bc..4380eaeca20c8afb95b9b93189e86735e85ec585 100644 (file)
@@ -21,6 +21,7 @@
 #include <clock.h>\r
 #include <display.h>\r
 #include <display_draw.h>\r
+#include <fat32.h>\r
 #include <flash.h>\r
 #include <gpio.h>\r
 #include <heap.h>\r
@@ -30,6 +31,7 @@
 #include <it/parser.h>\r
 #include <random.h>\r
 #include <script.h>\r
+#include <sdcard.h>\r
 #include <serial.h>\r
 #include <stm32l476xx.h>\r
 #include <string.h>\r
@@ -60,7 +62,7 @@ int main(void)
        keypad_init();\r
        flash_init();\r
 \r
-       gpio_mode(GPIOA, 5, OUTPUT);\r
+       //gpio_mode(GPIOA, 5, OUTPUT); // taken by sd\r
 \r
        // enable FPU\r
        SCB->CPACR |= (0xF << 20);\r
@@ -71,9 +73,25 @@ int main(void)
        while (1);\r
 }\r
 \r
+void sleep(void)\r
+{\r
+       dsp_sleep();\r
+       *((uint32_t *)0xE000ED10) |= 4; // SLEEPDEEP\r
+       PWR->CR1 |= 2;\r
+       asm("wfi");\r
+}\r
+\r
+void wakeup(void)\r
+{\r
+       clock_init();\r
+       dsp_wakeup();\r
+}\r
+\r
 void kmain(void)\r
 {\r
        dsp_init();\r
+       sd_init();\r
+       fat_find();\r
        dsp_cursoron();\r
        keypad_start();\r
 \r
@@ -81,30 +99,37 @@ void kmain(void)
        task_start(task_status, 512);\r
 \r
        while (1) {\r
-               gpio_dout(GPIOA, 5, 1);\r
-               delay(250);\r
-               gpio_dout(GPIOA, 5, 0);\r
-               delay(250);\r
+               extern uint32_t sleep_pending;\r
+               if (sleep_pending != 0) {\r
+                       sleep();\r
+                       while (sleep_pending)\r
+                               delay(1);\r
+               }\r
+               //gpio_dout(GPIOA, 5, 1);\r
+               //delay(250);\r
+               //gpio_dout(GPIOA, 5, 0);\r
+               delay(100);\r
        }\r
 }\r
 \r
 instance *load_program(const char *name)\r
 {\r
        // load file\r
-       char *s = initrd_readfile(name);\r
-       if (s == 0) {\r
+       file_t *file = fat_findfile(name);\r
+       if (file == 0) {\r
                dsp_puts("can't find ");\r
                dsp_puts(name);\r
                goto fail;\r
        }\r
 \r
+       char *s = fat_readfile(file);\r
        instance *it = inewinstance();\r
        script_loadlib(it);\r
 \r
        // read in, parse into script code\r
        char *linebuf = (char *)malloc(120);\r
        uint32_t i = 0, prev = 0, lc;\r
-       uint32_t size = initrd_filesize(name);\r
+       uint32_t size = file->size;\r
        int ret = 0;\r
        while (i < size) {\r
                for (; s[i] != '\n' && s[i] != '\0'; i++);\r
@@ -121,6 +146,8 @@ instance *load_program(const char *name)
                prev = ++i;\r
        }\r
        free(linebuf);\r
+       free(s);\r
+       free(file);\r
        return it;\r
 fail:\r
        while (1);\r
index 51a3bb7eb06eb1a33a60aad1a5665d40bfec869f..5ba0c0803327b391297cd9051c178c02a7e196f9 100644 (file)
 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 (file)
index 0000000..6cf602b
--- /dev/null
@@ -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;
+}
+
index 4714e9398cfb8423511f139085299960e71a678a..a47fb032d2697450fd09f1a44f1d85e7a91f98c5 100644 (file)
@@ -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