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
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;
#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
#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_ */
--- /dev/null
+#!/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();
*/
#define STM_APB1 (16000000 * 6 / 4)
+void ao_lcd_stm_init(void);
+
+void ao_lcd_font_string(char *s);
+
#endif /* _AO_ARCH_H_ */
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * 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 <ao.h>
+
+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);
+}
--- /dev/null
+ [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'
+ -----
+ |\ | /|
+ | \|/ |
+ -- --
+ | /|\ |
+ |/ | \|
+ -----
+*/
+
--- /dev/null
+/*
+ * Copyright © 2012 Keith Packard <keithp@keithp.com>
+ *
+ * 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 <ao.h>
+
+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 <com> <seg> <value>\0Set LCD segment" },
+ { ao_lcd_stm_clear, "C\0Clear LCD" },
+ { ao_lcd_stm_text, "t <string>\0Write <string> 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);
+}