From 6da2f5846f2d28ea1f09f60ef2cc3f68113ac62a Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Thu, 22 Mar 2012 19:43:29 -0700 Subject: [PATCH] Add LCD device driver to STM32L port This enables the 6-digit 14-character display on the STM32L discovery board and provides an ascii output to it. Signed-off-by: Keith Packard --- src/stm-demo/Makefile | 6 +- src/stm-demo/ao_demo.c | 5 +- src/stm-demo/ao_pins.h | 59 +- src/stm/ao-parse-font.5c | 174 ++++++ src/stm/ao_arch.h | 4 + src/stm/ao_lcd_font.c | 101 ++++ src/stm/ao_lcd_font.h | 1152 ++++++++++++++++++++++++++++++++++++++ src/stm/ao_lcd_stm.c | 393 +++++++++++++ 8 files changed, 1888 insertions(+), 6 deletions(-) create mode 100644 src/stm/ao-parse-font.5c create mode 100644 src/stm/ao_lcd_font.c create mode 100644 src/stm/ao_lcd_font.h create mode 100644 src/stm/ao_lcd_stm.c diff --git a/src/stm-demo/Makefile b/src/stm-demo/Makefile index 9e4f9e38..ecdf6b7f 100644 --- a/src/stm-demo/Makefile +++ b/src/stm-demo/Makefile @@ -42,14 +42,16 @@ ALTOS_SRC = \ ao_stdio.c \ ao_panic.c \ ao_timer.c \ - ao_serial_stm.c + ao_serial_stm.c \ + ao_lcd_stm.c \ + ao_lcd_font.c PRODUCT=StmDemo-v0.0 PRODUCT_DEF=-DSTM_DEMO IDPRODUCT=0x000a CPU=cortex-m3 CFLAGS = $(PRODUCT_DEF) -I. -I../stm -I../core -I.. -CFLAGS += -g -std=gnu99 -Os -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib -I../stm $(CINC) +CFLAGS += -g -std=gnu99 -O0 -mlittle-endian -mcpu=cortex-m3 -mthumb -ffreestanding -nostdlib -I../stm $(CINC) NICKLE=nickle diff --git a/src/stm-demo/ao_demo.c b/src/stm-demo/ao_demo.c index 94527089..24566f9b 100644 --- a/src/stm-demo/ao_demo.c +++ b/src/stm-demo/ao_demo.c @@ -47,8 +47,9 @@ main(void) ao_serial_init(); ao_timer_init(); ao_cmd_init(); - ao_led_init(LEDS_AVAILABLE); - ao_add_task(&demo_task, ao_demo, "demo"); +// ao_led_init(LEDS_AVAILABLE); + ao_lcd_stm_init(); +// ao_add_task(&demo_task, ao_demo, "demo"); ao_start_scheduler(); return 0; diff --git a/src/stm-demo/ao_pins.h b/src/stm-demo/ao_pins.h index c72cd04b..8d7ed76b 100644 --- a/src/stm-demo/ao_pins.h +++ b/src/stm-demo/ao_pins.h @@ -19,8 +19,8 @@ #define _AO_PINS_H_ #define HAS_SERIAL_1 1 -#define HAS_SERIAL_2 1 -#define HAS_SERIAL_3 1 +#define HAS_SERIAL_2 0 +#define HAS_SERIAL_3 0 #define USE_SERIAL_STDIN 1 #define HAS_USB 0 #define HAS_BEEP 0 @@ -39,4 +39,59 @@ #define LEDS_AVAILABLE (AO_LED_BLUE | AO_LED_GREEN) +#define AO_LCD_STM_SEG_ENABLED_0 ( \ + (1 << 0) | /* PA1 */ \ + (1 << 1) | /* PA2 */ \ + (1 << 2) | /* PA3 */ \ + (0 << 3) | /* PA6 */ \ + (0 << 4) | /* PA7 */ \ + (0 << 5) | /* PB0 */ \ + (0 << 6) | /* PB1 */ \ + (1 << 7) | /* PB3 */ \ + (1 << 8) | /* PB4 */ \ + (1 << 9) | /* PB5 */ \ + (1 << 10) | /* PB10 */ \ + (1 << 11) | /* PB11 */ \ + (1 << 12) | /* PB12 */ \ + (1 << 13) | /* PB13 */ \ + (1 << 14) | /* PB14 */ \ + (1 << 15) | /* PB15 */ \ + (1 << 16) | /* PB8 */ \ + (1 << 17) | /* PA15 */ \ + (1 << 18) | /* PC0 */ \ + (1 << 19) | /* PC1 */ \ + (1 << 20) | /* PC2 */ \ + (1 << 21) | /* PC3 */ \ + (0 << 22) | /* PC4 */ \ + (0 << 23) | /* PC5 */ \ + (1 << 24) | /* PC6 */ \ + (1 << 25) | /* PC7 */ \ + (1 << 26) | /* PC8 */ \ + (1 << 27) | /* PC9 */ \ + (1 << 28) | /* PC10 or PD8 */ \ + (1 << 29) | /* PC11 or PD9 */ \ + (0 << 30) | /* PC12 or PD10 */ \ + (0 << 31)) /* PD2 or PD11 */ + +#define AO_LCD_STM_SEG_ENABLED_1 ( \ + (0 << 0) | /* PD12 */ \ + (0 << 1) | /* PD13 */ \ + (0 << 2) | /* PD14 */ \ + (0 << 3) | /* PD15 */ \ + (0 << 4) | /* PE0 */ \ + (0 << 5) | /* PE1 */ \ + (0 << 6) | /* PE2 */ \ + (0 << 7)) /* PE3 */ + +#define AO_LCD_STM_COM_ENABLED ( \ + (1 << 0) | /* PA8 */ \ + (1 << 1) | /* PA9 */ \ + (1 << 2) | /* PA10 */ \ + (1 << 3) | /* PB9 */ \ + (0 << 4) | /* PC10 */ \ + (0 << 5) | /* PC11 */ \ + (0 << 6)) /* PC12 */ + +#define AO_LCD_28_ON_C 1 + #endif /* _AO_PINS_H_ */ diff --git a/src/stm/ao-parse-font.5c b/src/stm/ao-parse-font.5c new file mode 100644 index 00000000..fe785854 --- /dev/null +++ b/src/stm/ao-parse-font.5c @@ -0,0 +1,174 @@ +#!/usr/bin/env nickle +# +# Parse a 14-segment font file +# and construct the bitmasks for each +# character. Output is in the same +# format as the input: +# [5] = 0x1212, +# /* +# CHAR 37 '%' +# +# | / +# | / +# +# / | +# / | +# +# */ +# +# Note that there can only be tabs before the glyph image +# as spaces are significant in the image itself. +# + +typedef struct { + int c; + bool[14] bits; +} glyph; + +exception done(); + +glyph read_glyph(file f) { + int c; + + for (;;) { + if (File::end(f)) + raise done(); + string l = File::fgets(f); + if (File::sscanf(l, "CHAR %d", &c) == 1) + break; + } + + string strip_tab(string x) { + int i = 0; + while (i < String::length(x) && x[i] == '\t') + i++; + string n = String::substr(x, i, String::length(x) - i); + while (String::length(n) < 7) + n = n + " "; + return n; + } + + string[7] lines = { [i] = strip_tab(File::fgets(f)) }; + + glyph g = { .c = c }; + + g.bits[0] = lines[0][1] == '-'; + + g.bits[1] = lines[1][0] == '|'; + g.bits[2] = lines[1][1] == '\\'; + g.bits[3] = lines[1][3] == '|'; + g.bits[4] = lines[1][5] == '/'; + g.bits[5] = lines[1][6] == '|'; + + g.bits[6] = lines[3][1] == '-'; + g.bits[7] = lines[3][4] == '-'; + + g.bits[8] = lines[5][0] == '|'; + g.bits[9] = lines[5][1] == '/'; + g.bits[10] = lines[5][3] == '|'; + g.bits[11] = lines[5][5] == '\\'; + g.bits[12] = lines[5][6] == '|'; + + g.bits[13] = lines[6][1] == '-'; + return g; +} + +string[*] glyph_image(glyph g) { + int[7][7] chars = { { ' ' ... } ... }; + + if (g.bits[0]) + for (int c = 1; c < 6; c++) + chars[0][c] = '-'; + + if (g.bits[1]) + for (int r = 1; r < 3; r++) + chars[r][0] = '|'; + if (g.bits[2]) + for (int p = 1; p < 3; p++) + chars[p][p] = '\\'; + if (g.bits[3]) + for (int p = 1; p < 3; p++) + chars[p][3] = '|'; + if (g.bits[4]) + for (int p = 1; p < 3; p++) + chars[p][6-p] = '/'; + if (g.bits[5]) + for (int p = 1; p < 3; p++) + chars[p][6] = '|'; + + if (g.bits[6]) + for (int p = 1; p < 3; p++) + chars[3][p] = '-'; + if (g.bits[7]) + for (int p = 4; p < 6; p++) + chars[3][p] = '-'; + + if (g.bits[8]) + for (int r = 4; r < 6; r++) + chars[r][0] = '|'; + if (g.bits[9]) + for (int p = 4; p < 6; p++) + chars[p][6-p] = '/'; + if (g.bits[10]) + for (int p = 4; p < 6; p++) + chars[p][3] = '|'; + if (g.bits[11]) + for (int p = 4; p < 6; p++) + chars[p][p] = '\\'; + if (g.bits[12]) + for (int p = 4; p < 6; p++) + chars[p][6] = '|'; + + if (g.bits[13]) + for (int c = 1; c < 6; c++) + chars[6][c] = '-'; + + return (string[7]) { [i] = String::new(chars[i]) }; + +} + +int glyph_value(glyph g) { + int v = 0; + + for (int b = 0; b < 14; b++) + if (g.bits[b]) + v |= (1 << b); + return v; +} + +void write_glyph(file f, glyph g) { + File::fprintf (f, "CHAR %d '%s'\n", g.c, g.c == 127 ? "DEL" : String::new(g.c)); + string[7] lines = glyph_image(g); + for (int i = 0; i < 7; i++) + File::fprintf (f, "\t%s\n", lines[i]); +} + +autoload Sort; + +glyph[*] read_font(file f) { + glyph[128 - 32] font = { [i] = read_glyph(f) }; + + Sort::qsort(&font, bool func (glyph a, glyph b) = (a.c > b.c)); + return font; +} + +glyph[*] font; +void init () { + twixt (file f = File::open("ao_lcd_font.h", "r"); File::close(f)) { + font = read_font(f); + } +} + +void dump() { + twixt(file f = File::open("ao_lcd_font.h.new", "w"); File::close(f)) { + for (int i = 0; i < dim(font); i++) { + File::fprintf (f, "\t[%d] = 0x%04x,\n", i, glyph_value(font[i])); + File::fprintf (f, "/*\n"); + write_glyph(f, font[i]); + File::fprintf (f, "*/\n\n"); + } + } +} + +init(); +dump(); diff --git a/src/stm/ao_arch.h b/src/stm/ao_arch.h index c4b98c7a..96cbfe85 100644 --- a/src/stm/ao_arch.h +++ b/src/stm/ao_arch.h @@ -155,5 +155,9 @@ struct ao_adc { */ #define STM_APB1 (16000000 * 6 / 4) +void ao_lcd_stm_init(void); + +void ao_lcd_font_string(char *s); + #endif /* _AO_ARCH_H_ */ diff --git a/src/stm/ao_lcd_font.c b/src/stm/ao_lcd_font.c new file mode 100644 index 00000000..f6074587 --- /dev/null +++ b/src/stm/ao_lcd_font.c @@ -0,0 +1,101 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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; version 2 of the License. + * + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +static const uint16_t ao_lcd_font[] = { +#include "ao_lcd_font.h" +}; + +/* + ----- 0 + |\ | /| 1 2 3 4 5 + | \|/ | @ 14 + -- -- 6 7 + | /|\ | 8 9 10 11 12 + |/ | \| @ 14 + ----- 13 + @ 15 +*/ + +static const uint8_t ao_bit_src[] = { + 8, 7, 5, 6, + 13, 12, 0, 1, + 10, 14, 4, 9, + 11, 15, 3, 2 +}; + +static const uint8_t ao_bit_dst[6][4] = { + { 0, 1, 28, 29 }, + { 2, 7, 26, 27 }, + { 8, 9, 24, 25 }, + { 10, 11, 20, 21 }, + { 12, 13, 18, 19 }, + { 14, 15, 17, 16 }, +}; + +static void +ao_draw_glyph(uint8_t pos, uint16_t glyph) { + uint8_t col, seg, src, dst; + uint32_t ram; + + for (col = 0; col < 4; col++) { + for (seg = 0; seg < 4; seg++) { + src = ao_bit_src[(col << 2) | seg]; + dst = ao_bit_dst[pos][seg]; + ram = stm_lcd.ram[col * 2]; + ram &= ~(1 << dst); + ram |= (uint32_t) ((glyph >> src) & 1) << dst; + stm_lcd.ram[col*2] = ram; + } + } +} + +#define AO_LCD_FONT_COLON (1 << 14) +#define AO_LCD_FONT_DECIMAL (1 << 15) + +void +ao_lcd_font_char(uint8_t pos, char c, uint16_t flags) { + if (pos > 5) + pos = 5; + if (c < ' ' || c > 127) + c = 127; + ao_draw_glyph(pos, ao_lcd_font[c - ' '] | flags); +} + +void +ao_lcd_font_string(char *s) { + uint8_t pos = 0; + uint16_t flags; + char c; + + while (pos < 6 && (c = *s++)) { + flags = 0; + for (;;) { + if (*s == ':') + flags |= AO_LCD_FONT_COLON; + else if (*s == '.') + flags |= AO_LCD_FONT_DECIMAL; + else + break; + s++; + } + ao_lcd_font_char(pos++, c, flags); + } + while (pos < 6) + ao_lcd_font_char(pos++, ' ', 0); +} diff --git a/src/stm/ao_lcd_font.h b/src/stm/ao_lcd_font.h new file mode 100644 index 00000000..08adc9ab --- /dev/null +++ b/src/stm/ao_lcd_font.h @@ -0,0 +1,1152 @@ + [0] = 0x0000, +/* +CHAR 32 ' ' + + + + + + + +*/ + + [1] = 0x0102, +/* +CHAR 33 '!' + + | + | + + | + | + +*/ + + [2] = 0x000a, +/* +CHAR 34 '"' + + | | + | | + + + + +*/ + + [3] = 0x05e8, +/* +CHAR 35 '#' + + | | + | | + -- -- + | | + | | + +*/ + + [4] = 0x34cb, +/* +CHAR 36 '$' + ----- + | | + | | + -- -- + | | + | | + ----- +*/ + + [5] = 0x1212, +/* +CHAR 37 '%' + + | / + | / + + / | + / | + +*/ + + [6] = 0x2955, +/* +CHAR 38 '&' + ----- + \ / + \ / + -- + | \ + | \ + ----- +*/ + + [7] = 0x0008, +/* +CHAR 39 ''' + + | + | + + + + +*/ + + [8] = 0x2103, +/* +CHAR 40 '(' + ----- + | + | + + | + | + ----- +*/ + + [9] = 0x3021, +/* +CHAR 41 ')' + ----- + | + | + + | + | + ----- +*/ + + [10] = 0x0e1c, +/* +CHAR 42 '*' + + \ | / + \|/ + + /|\ + / | \ + +*/ + + [11] = 0x04c8, +/* +CHAR 43 '+' + + | + | + -- -- + | + | + +*/ + + [12] = 0x0200, +/* +CHAR 44 ',' + + + + + / + / + +*/ + + [13] = 0x00c0, +/* +CHAR 45 '-' + + + + -- -- + + + +*/ + + [14] = 0x0800, +/* +CHAR 46 '.' + + + + + \ + \ + +*/ + + [15] = 0x0210, +/* +CHAR 47 '/' + + / + / + + / + / + +*/ + + [16] = 0x3333, +/* +CHAR 48 '0' + ----- + | /| + | / | + + | / | + |/ | + ----- +*/ + + [17] = 0x1030, +/* +CHAR 49 '1' + + /| + / | + + | + | + +*/ + + [18] = 0x21e1, +/* +CHAR 50 '2' + ----- + | + | + -- -- + | + | + ----- +*/ + + [19] = 0x30a1, +/* +CHAR 51 '3' + ----- + | + | + -- + | + | + ----- +*/ + + [20] = 0x10e2, +/* +CHAR 52 '4' + + | | + | | + -- -- + | + | + +*/ + + [21] = 0x30c3, +/* +CHAR 53 '5' + ----- + | + | + -- -- + | + | + ----- +*/ + + [22] = 0x31c3, +/* +CHAR 54 '6' + ----- + | + | + -- -- + | | + | | + ----- +*/ + + [23] = 0x0411, +/* +CHAR 55 '7' + ----- + / + / + + | + | + +*/ + + [24] = 0x31e3, +/* +CHAR 56 '8' + ----- + | | + | | + -- -- + | | + | | + ----- +*/ + + [25] = 0x10e3, +/* +CHAR 57 '9' + ----- + | | + | | + -- -- + | + | + +*/ + + [26] = 0x0408, +/* +CHAR 58 ':' + + | + | + + | + | + +*/ + + [27] = 0x0208, +/* +CHAR 59 ';' + + | + | + + / + / + +*/ + + [28] = 0x0810, +/* +CHAR 60 '<' + + / + / + + \ + \ + +*/ + + [29] = 0x20c0, +/* +CHAR 61 '=' + + + + -- -- + + + ----- +*/ + + [30] = 0x0204, +/* +CHAR 62 '>' + + \ + \ + + / + / + +*/ + + [31] = 0x0413, +/* +CHAR 63 '?' + ----- + | / + | / + + | + | + +*/ + + [32] = 0x39b3, +/* +CHAR 64 '@' + ----- + | /| + | / | + -- + | \ | + | \| + ----- +*/ + + [33] = 0x11e3, +/* +CHAR 65 'A' + ----- + | | + | | + -- -- + | | + | | + +*/ + + [34] = 0x34a9, +/* +CHAR 66 'B' + ----- + | | + | | + -- + | | + | | + ----- +*/ + + [35] = 0x2103, +/* +CHAR 67 'C' + ----- + | + | + + | + | + ----- +*/ + + [36] = 0x3429, +/* +CHAR 68 'D' + ----- + | | + | | + + | | + | | + ----- +*/ + + [37] = 0x2143, +/* +CHAR 69 'E' + ----- + | + | + -- + | + | + ----- +*/ + + [38] = 0x0143, +/* +CHAR 70 'F' + ----- + | + | + -- + | + | + +*/ + + [39] = 0x3183, +/* +CHAR 71 'G' + ----- + | + | + -- + | | + | | + ----- +*/ + + [40] = 0x11e2, +/* +CHAR 72 'H' + + | | + | | + -- -- + | | + | | + +*/ + + [41] = 0x2409, +/* +CHAR 73 'I' + ----- + | + | + + | + | + ----- +*/ + + [42] = 0x3120, +/* +CHAR 74 'J' + + | + | + + | | + | | + ----- +*/ + + [43] = 0x0952, +/* +CHAR 75 'K' + + | / + | / + -- + | \ + | \ + +*/ + + [44] = 0x2102, +/* +CHAR 76 'L' + + | + | + + | + | + ----- +*/ + + [45] = 0x1136, +/* +CHAR 77 'M' + + |\ /| + | \ / | + + | | + | | + +*/ + + [46] = 0x1926, +/* +CHAR 78 'N' + + |\ | + | \ | + + | \ | + | \| + +*/ + + [47] = 0x3123, +/* +CHAR 79 'O' + ----- + | | + | | + + | | + | | + ----- +*/ + + [48] = 0x01e3, +/* +CHAR 80 'P' + ----- + | | + | | + -- -- + | + | + +*/ + + [49] = 0x3923, +/* +CHAR 81 'Q' + ----- + | | + | | + + | \ | + | \| + ----- +*/ + + [50] = 0x09e3, +/* +CHAR 82 'R' + ----- + | | + | | + -- -- + | \ + | \ + +*/ + + [51] = 0x3085, +/* +CHAR 83 'S' + ----- + \ + \ + -- + | + | + ----- +*/ + + [52] = 0x0409, +/* +CHAR 84 'T' + ----- + | + | + + | + | + +*/ + + [53] = 0x3122, +/* +CHAR 85 'U' + + | | + | | + + | | + | | + ----- +*/ + + [54] = 0x0312, +/* +CHAR 86 'V' + + | / + | / + + | / + |/ + +*/ + + [55] = 0x1b22, +/* +CHAR 87 'W' + + | | + | | + + | / \ | + |/ \| + +*/ + + [56] = 0x0a14, +/* +CHAR 88 'X' + + \ / + \ / + + / \ + / \ + +*/ + + [57] = 0x0414, +/* +CHAR 89 'Y' + + \ / + \ / + + | + | + +*/ + + [58] = 0x2211, +/* +CHAR 90 'Z' + ----- + / + / + + / + / + ----- +*/ + + [59] = 0x2103, +/* +CHAR 91 '[' + ----- + | + | + + | + | + ----- +*/ + + [60] = 0x0804, +/* +CHAR 92 '\' + + \ + \ + + \ + \ + +*/ + + [61] = 0x3021, +/* +CHAR 93 ']' + ----- + | + | + + | + | + ----- +*/ + + [62] = 0x0023, +/* +CHAR 94 '^' + ----- + | | + | | + + + + +*/ + + [63] = 0x2000, +/* +CHAR 95 '_' + + + + + + + ----- +*/ + + [64] = 0x0004, +/* +CHAR 96 '`' + + \ + \ + + + + +*/ + + [65] = 0x2540, +/* +CHAR 97 'a' + + + + -- + | | + | | + ----- +*/ + + [66] = 0x2942, +/* +CHAR 98 'b' + + | + | + -- + | \ + | \ + ----- +*/ + + [67] = 0x21c0, +/* +CHAR 99 'c' + + + + -- -- + | + | + ----- +*/ + + [68] = 0x32a0, +/* +CHAR 100 'd' + + | + | + -- + / | + / | + ----- +*/ + + [69] = 0x2340, +/* +CHAR 101 'e' + + + + -- + | / + |/ + ----- +*/ + + [70] = 0x0143, +/* +CHAR 102 'f' + ----- + | + | + -- + | + | + +*/ + + [71] = 0x10a5, +/* +CHAR 103 'g' + ----- + \ | + \ | + -- + | + | + +*/ + + [72] = 0x11c2, +/* +CHAR 104 'h' + + | + | + -- -- + | | + | | + +*/ + + [73] = 0x0400, +/* +CHAR 105 'i' + + + + + | + | + +*/ + + [74] = 0x3000, +/* +CHAR 106 'j' + + + + + | + | + ----- +*/ + + [75] = 0x0c88, +/* +CHAR 107 'k' + + | + | + -- + |\ + | \ + +*/ + + [76] = 0x0408, +/* +CHAR 108 'l' + + | + | + + | + | + +*/ + + [77] = 0x15c0, +/* +CHAR 109 'm' + + + + -- -- + | | | + | | | + +*/ + + [78] = 0x0940, +/* +CHAR 110 'n' + + + + -- + | \ + | \ + +*/ + + [79] = 0x31c0, +/* +CHAR 111 'o' + + + + -- -- + | | + | | + ----- +*/ + + [80] = 0x0146, +/* +CHAR 112 'p' + + |\ + | \ + -- + | + | + +*/ + + [81] = 0x10b0, +/* +CHAR 113 'q' + + /| + / | + -- + | + | + +*/ + + [82] = 0x0140, +/* +CHAR 114 'r' + + + + -- + | + | + +*/ + + [83] = 0x2880, +/* +CHAR 115 's' + + + + -- + \ + \ + ----- +*/ + + [84] = 0x2142, +/* +CHAR 116 't' + + | + | + -- + | + | + ----- +*/ + + [85] = 0x3100, +/* +CHAR 117 'u' + + + + + | | + | | + ----- +*/ + + [86] = 0x0300, +/* +CHAR 118 'v' + + + + + | / + |/ + +*/ + + [87] = 0x1b00, +/* +CHAR 119 'w' + + + + + | / \ | + |/ \| + +*/ + + [88] = 0x0a14, +/* +CHAR 120 'x' + + \ / + \ / + + / \ + / \ + +*/ + + [89] = 0x3800, +/* +CHAR 121 'y' + + + + + \ | + \| + ----- +*/ + + [90] = 0x2240, +/* +CHAR 122 'z' + + + + -- + / + / + ----- +*/ + + [91] = 0x2245, +/* +CHAR 123 '{' + ----- + \ + \ + -- + / + / + ----- +*/ + + [92] = 0x0408, +/* +CHAR 124 '|' + + | + | + + | + | + +*/ + + [93] = 0x2891, +/* +CHAR 125 '}' + ----- + / + / + -- + \ + \ + ----- +*/ + + [94] = 0x000e, +/* +CHAR 126 '~' + + |\ | + | \| + + + + +*/ + + [95] = 0x3fff, +/* +CHAR 127 'DEL' + ----- + |\ | /| + | \|/ | + -- -- + | /|\ | + |/ | \| + ----- +*/ + diff --git a/src/stm/ao_lcd_stm.c b/src/stm/ao_lcd_stm.c new file mode 100644 index 00000000..2d2fa9b3 --- /dev/null +++ b/src/stm/ao_lcd_stm.c @@ -0,0 +1,393 @@ +/* + * Copyright © 2012 Keith Packard + * + * 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; version 2 of the License. + * + * 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, write to the Free Software Foundation, Inc., + * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ + +#include + +struct ao_lcd_segment { + uint8_t reg; + uint8_t bit; +}; + +#define A 0 +#define B 1 +#define C 2 +#define D 3 +#define E 4 + +static struct stm_gpio *gpios[] = { + &stm_gpioa, + &stm_gpiob, + &stm_gpioc, + &stm_gpiod, + &stm_gpioe +}; + +static inline int ao_lcd_stm_seg_enabled(int seg) { + if (seg < 32) + return (AO_LCD_STM_SEG_ENABLED_0 >> seg) & 1; + else + return (AO_LCD_STM_SEG_ENABLED_1 >> (seg - 32)) & 1; +} + +static inline int ao_lcd_stm_com_enabled(int com) { + return (AO_LCD_STM_COM_ENABLED >> com) & 1; +} + +#define AO_LCD_STM_GPIOA_SEGS_0 ( \ + (1 << 0) | \ + (1 << 1) | \ + (1 << 2) | \ + (1 << 3) | \ + (1 << 4) | \ + (1 << 17)) + +#define AO_LCD_STM_GPIOA_SEGS_1 0 + +#define AO_LCD_STM_USES_GPIOA (!!((AO_LCD_STM_GPIOA_SEGS_0 & AO_LCD_STM_SEG_ENABLED_0) | \ + (AO_LCD_STM_GPIOA_SEGS_1 & AO_LCD_STM_SEG_ENABLED_1))) + + +#define AO_LCD_STM_GPIOB_SEGS_0 ( \ + (1 << 5) | \ + (1 << 6) | \ + (1 << 7) | \ + (1 << 8) | \ + (1 << 9) | \ + (1 << 10) | \ + (1 << 11) | \ + (1 << 12) | \ + (1 << 13) | \ + (1 << 14) | \ + (1 << 15) | \ + (1 << 16)) + +#define AO_LCD_STM_GPIOB_SEGS_1 0 + +#if AO_LCD_28_ON_C + +#define AO_LCD_STM_GPIOC_28_SEGS ( \ + (1 << 28) | \ + (1 << 29) | \ + (1 << 30)) + +#define AO_LCD_STM_GPIOD_28_SEGS ( \ + (1 << 31)) + +#else +#define AO_LCD_STM_GPIOC_28_C_SEGS 0 + +#define AO_LCD_STM_GPIOD_28_SEGS ( \ + (1 << 28) | \ + (1 << 29) | \ + (1 << 30) | \ + (1 << 31)) +#endif + +#define AO_LCD_STM_GPIOC_SEGS_0 ( \ + (1 << 18) | \ + (1 << 19) | \ + (1 << 20) | \ + (1 << 21) | \ + (1 << 22) | \ + (1 << 23) | \ + (1 << 24) | \ + (1 << 25) | \ + (1 << 26) | \ + (1 << 27) | \ + AO_LCD_STM_GPIOC_28_SEGS) + +#define AO_LCD_STM_GPIOC_SEGS_1 ( \ + (1 << (40 - 32)) | \ + (1 << (41 - 32)) | \ + (1 << (42 - 32))) + +#define AO_LCD_STM_GPIOD_SEGS_0 ( \ + AO_LCD_STM_GPIOD_28_SEGS) + +#define AO_LCD_STM_GPIOD_SEGS_1 ( \ + (1 << (32 - 32)) | \ + (1 << (33 - 32)) | \ + (1 << (34 - 32)) | \ + (1 << (35 - 32)) | \ + (1 << (43 - 32))) + +#define AO_LCD_STM_GPIOE_SEGS_0 0 + +#define AO_LCD_STM_GPIOE_SEGS_1 ( \ + (1 << (36 - 32)) | \ + (1 << (37 - 32)) | \ + (1 << (38 - 32)) | \ + (1 << (39 - 32))) + +#define AO_LCD_STM_USES_GPIOA (!!((AO_LCD_STM_GPIOA_SEGS_0 & AO_LCD_STM_SEG_ENABLED_0) | \ + (AO_LCD_STM_GPIOA_SEGS_1 & AO_LCD_STM_SEG_ENABLED_1))) + +#define AO_LCD_STM_USES_GPIOB (!!((AO_LCD_STM_GPIOB_SEGS_0 & AO_LCD_STM_SEG_ENABLED_0) | \ + (AO_LCD_STM_GPIOB_SEGS_1 & AO_LCD_STM_SEG_ENABLED_1))) + + +#define AO_LCD_STM_USES_GPIOC (!!((AO_LCD_STM_GPIOC_SEGS_0 & AO_LCD_STM_SEG_ENABLED_0) | \ + (AO_LCD_STM_GPIOC_SEGS_1 & AO_LCD_STM_SEG_ENABLED_1))) + + +#define AO_LCD_STM_USES_GPIOD (!!((AO_LCD_STM_GPIOD_SEGS_0 & AO_LCD_STM_SEG_ENABLED_0) | \ + (AO_LCD_STM_GPIOD_SEGS_1 & AO_LCD_STM_SEG_ENABLED_1))) + +#define AO_LCD_STM_USES_GPIOE (!!((AO_LCD_STM_GPIOE_SEGS_0 & AO_LCD_STM_SEG_ENABLED_0) | \ + (AO_LCD_STM_GPIOE_SEGS_1 & AO_LCD_STM_SEG_ENABLED_1))) + + +static const struct ao_lcd_segment segs[] = { + { A, 1 }, /* 0 */ + { A, 2 }, + { A, 3 }, + { A, 6 }, + + { A, 7 }, /* 4 */ + { B, 0 }, + { B, 1 }, + { B, 3 }, + + { B, 4 }, /* 8 */ + { B, 5 }, + { B, 10 }, + { B, 11 }, + + { B, 12 }, /* 12 */ + { B, 13 }, + { B, 14 }, + { B, 15 }, + + { B, 8 }, /* 16 */ + { A, 15 }, + { C, 0 }, + { C, 1 }, + + { C, 2 }, /* 20 */ + { C, 3 }, + { C, 4 }, + { C, 5 }, + + { C, 6 }, /* 24 */ + { C, 7 }, + { C, 8 }, + { C, 9 }, + +#if AO_LCD_28_ON_C + { C, 10 }, /* 28 */ + { C, 11 }, + { C, 12 }, + { D, 2 }, +#else + { D, 8 }, /* 28 */ + { D, 9 }, + { D, 10 }, + { D, 11 }, +#endif + { D, 12 }, /* 32 */ + { D, 13 }, + { D, 14 }, + { D, 15 }, + + { E, 0 }, /* 36 */ + { E, 1 }, + { E, 2 }, + { E, 3 }, + + { C, 10 }, /* 40 */ + { C, 11 }, + { C, 12 }, + { D, 2 }, +}; + +static const struct ao_lcd_segment coms[] = { + { A, 8 }, /* 0 */ + { A, 9 }, /* 1 */ + { A, 10 }, /* 2 */ + { B, 9 }, /* 3 */ + { C, 10 }, /* 4 */ + { C, 11 }, /* 5 */ + { C, 12 }, /* 6 */ +}; + +#define NSEG (sizeof segs/sizeof segs[0]) +#define NCOM (sizeof coms/sizeof coms[0]) + +static void +ao_lcd_stm_fcr_sync(void) +{ + while ((stm_lcd.sr & (1 << STM_LCD_SR_FCRSF)) == 0) + asm("nop"); +} + +static void +ao_lcd_stm_seg_set(void) +{ + int com, seg, val; + int n, bit; + ao_cmd_decimal(); + com = ao_cmd_lex_i; + ao_cmd_decimal(); + seg = ao_cmd_lex_u32; + ao_cmd_decimal(); + val = ao_cmd_lex_i; + printf ("com: %d seg: %d val: %d\n", com, seg, val); + n = (seg >> 5) & 1; + if (com >= NCOM) + com = NCOM-1; + if (seg >= NSEG) + seg = NSEG-1; + if (val) + stm_lcd.ram[com * 2 + n] |= (1 << (seg & 0x1f)); + else + stm_lcd.ram[com * 2 + n] &= ~(1 << (seg & 0x1f)); + stm_lcd.sr = (1 << STM_LCD_SR_UDR); +} + +static void +ao_lcd_stm_clear(void) +{ + int i; + + for (i = 0; i < sizeof (stm_lcd.ram) / 4; i++) + stm_lcd.ram[i] = 0; + stm_lcd.sr = (1 << STM_LCD_SR_UDR); +} + +static void +ao_lcd_stm_text(void) +{ + char string[7]; + uint8_t c = 0; + ao_cmd_white(); + while (ao_cmd_lex_c != '\n' && c < sizeof (string)) { + string[c++] = ao_cmd_lex_c; + ao_cmd_lex(); + } + string[c++] = '\0'; + ao_lcd_font_string(string); + stm_lcd.sr = (1 << STM_LCD_SR_UDR); +} + +const struct ao_cmds ao_lcd_stm_cmds[] = { + { ao_lcd_stm_seg_set, "s \0Set LCD segment" }, + { ao_lcd_stm_clear, "C\0Clear LCD" }, + { ao_lcd_stm_text, "t \0Write to LCD" }, + { 0, NULL }, +}; + +void +ao_lcd_stm_init(void) +{ + int s, c; + int r; + uint32_t csr; + + stm_rcc.ahbenr |= ((AO_LCD_STM_USES_GPIOA << STM_RCC_AHBENR_GPIOAEN) | + (AO_LCD_STM_USES_GPIOB << STM_RCC_AHBENR_GPIOBEN) | + (AO_LCD_STM_USES_GPIOC << STM_RCC_AHBENR_GPIOCEN) | + (AO_LCD_STM_USES_GPIOD << STM_RCC_AHBENR_GPIODEN) | + (AO_LCD_STM_USES_GPIOE << STM_RCC_AHBENR_GPIOEEN)); + + stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_LCDEN); + + /* Turn on the LSI clock */ + if ((stm_rcc.csr & (1 << STM_RCC_CSR_LSIRDY)) == 0) { + stm_rcc.csr |= (1 << STM_RCC_CSR_LSION); + while ((stm_rcc.csr & (1 << STM_RCC_CSR_LSIRDY)) == 0) + asm("nop"); + } + + /* Enable RTC clock config (required to change the RTC/LCD clock */ + + stm_pwr.cr |= (1 << STM_PWR_CR_DBP); + + /* Configure the LCDCLK - use the LSI clock */ + + csr = stm_rcc.csr; + csr &= ~(STM_RCC_CSR_RTCSEL_MASK << STM_RCC_CSR_RTCSEL); + csr |= (STM_RCC_CSR_RTCSEL_LSI << STM_RCC_CSR_RTCSEL); + stm_rcc.csr = csr; + + for (s = 0; s < NSEG; s++) { + uint8_t reg = segs[s].reg; + uint8_t bit = segs[s].bit; + + if (ao_lcd_stm_seg_enabled(s)) { + stm_moder_set(gpios[reg], bit, STM_MODER_ALTERNATE); + stm_afr_set(gpios[reg], bit, STM_AFR_AF11); + } + } + + for (c = 0; c < NCOM; c++) { + uint8_t reg = coms[c].reg; + uint8_t bit = coms[c].bit; + + if (ao_lcd_stm_com_enabled(c)) { + stm_moder_set(gpios[reg], bit, STM_MODER_ALTERNATE); + stm_afr_set(gpios[reg], bit, STM_AFR_AF11); + } + } + + /* duty cycle 1/3, radio 352, frame rate about 33Hz */ + stm_lcd.fcr = ((STM_LCD_FCR_PS_1 << STM_LCD_FCR_PS) | + (STM_LCD_FCR_DIV_31 << STM_LCD_FCR_DIV) | + (4 << STM_LCD_FCR_CC) | + (4 << STM_LCD_FCR_PON) | + (0 << STM_LCD_FCR_UDDIE) | + (0 << STM_LCD_FCR_SOFIE) | + (0 << STM_LCD_FCR_HD)); + + ao_lcd_stm_fcr_sync(); + + /* Program desired DUTY in LCD_CR */ + /* Program desired BIAS in LCD_CR */ + /* Enable mux seg */ + /* Internal voltage source */ + stm_lcd.cr = ((STM_LCD_CR_DUTY_1_4 << STM_LCD_CR_DUTY) | + (STM_LCD_CR_BIAS_1_3 << STM_LCD_CR_BIAS) | + (0 << STM_LCD_CR_VSEL) | + (1 << STM_LCD_CR_MUX_SEG)); + + ao_lcd_stm_fcr_sync(); + + /* Enable the display (LCDEN bit in LCD_CR) */ + stm_lcd.cr |= (1 << STM_LCD_CR_LCDEN); + + while ((stm_lcd.sr & (1 << STM_LCD_SR_RDY)) == 0) + asm("nop"); + + /* Load initial data into LCD_RAM and set the + * UDR bit in the LCD_SR register */ + for (r = 0; r < NCOM; r++) { + stm_lcd.ram[r*2] = 0; + stm_lcd.ram[r*2 + 1] = 0; + } + + stm_lcd.sr = (1 << STM_LCD_SR_UDR); + + /* Program desired frame rate (PS and DIV bits in LCD_FCR) */ + + /* Program the contrast (CC bits in LCD_FCR) */ + + /* Program optional features (BLINK, BLINKF, PON, DEAD, HD) */ + + /* Program the required interrupts */ + + /* All done */ + ao_cmd_register(ao_lcd_stm_cmds); +} -- 2.30.2