diff options
Diffstat (limited to 'src')
-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 |
8 files changed, 536 insertions, 22 deletions
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 |