Add LCD device driver to STM32L port
authorKeith Packard <keithp@keithp.com>
Fri, 23 Mar 2012 02:43:29 +0000 (19:43 -0700)
committerKeith Packard <keithp@keithp.com>
Thu, 29 Mar 2012 04:37:03 +0000 (21:37 -0700)
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 <keithp@keithp.com>
src/stm-demo/Makefile
src/stm-demo/ao_demo.c
src/stm-demo/ao_pins.h
src/stm/ao-parse-font.5c [new file with mode: 0644]
src/stm/ao_arch.h
src/stm/ao_lcd_font.c [new file with mode: 0644]
src/stm/ao_lcd_font.h [new file with mode: 0644]
src/stm/ao_lcd_stm.c [new file with mode: 0644]

index 9e4f9e38acda8b53e78d2c25a74f1769f74517e1..ecdf6b7f28b27cf36cc0fc860213b69812b3375a 100644 (file)
@@ -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
 
index 94527089b407225a4b3c92993c9c1899e23e777d..24566f9b65412c2031b39a80338e432b36c4dc5d 100644 (file)
@@ -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;
index c72cd04b5003440e04a65c5a3eee68910b76cec0..8d7ed76bb023476f494774b4b7b4dc2185f6a521 100644 (file)
@@ -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
 
 #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 (file)
index 0000000..fe78585
--- /dev/null
@@ -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();
index c4b98c7a4ef9ec0808d7b30d3c1d16b4c2f7bbd9..96cbfe8515f5eeea009d09540672ff093894b17d 100644 (file)
@@ -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 (file)
index 0000000..f607458
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * 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);
+}
diff --git a/src/stm/ao_lcd_font.h b/src/stm/ao_lcd_font.h
new file mode 100644 (file)
index 0000000..08adc9a
--- /dev/null
@@ -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 (file)
index 0000000..2d2fa9b
--- /dev/null
@@ -0,0 +1,393 @@
+/*
+ * 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);
+}