altos: Work on MAX6691 driver
[fw/altos] / src / stm / ao_lcd_stm.c
index b19094440a9ff8f1027510f026f8266a150e0396..1947012b86000357445af1ce739a7616cbb03fbf 100644 (file)
@@ -3,7 +3,8 @@
  *
  * 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.
+ * the Free Software Foundation; either version 2 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
  */
 
 #include <ao.h>
+#include <ao_lcd_stm.h>
+
+#ifndef LCD_DEBUG
+#define LCD_DEBUG      0
+#endif
 
 struct ao_lcd_segment {
        uint8_t reg;
@@ -88,7 +94,7 @@ static inline int ao_lcd_stm_com_enabled(int com) {
                (1 << 31))
 
 #else
-#define AO_LCD_STM_GPIOC_28_C_SEGS     0
+#define AO_LCD_STM_GPIOC_28_SEGS       0
 
 #define AO_LCD_STM_GPIOD_28_SEGS       (       \
                (1 << 28) |                     \
@@ -227,6 +233,21 @@ static const struct ao_lcd_segment coms[] = {
 #define NSEG   (sizeof segs/sizeof segs[0])
 #define NCOM   (sizeof coms/sizeof coms[0])
 
+static uint8_t ao_lcd_update_active;
+
+void
+stm_lcd_isr(void)
+{
+       if (stm_lcd.sr & (1 << STM_LCD_SR_UDD)) {
+               stm_lcd.clr = (1 << STM_LCD_CLR_UDDC);
+               if (ao_lcd_update_active) {
+                       ao_lcd_update_active = 0;
+                       ao_wakeup(&ao_lcd_update_active);
+               }
+       }
+}
+
+
 static void
 ao_lcd_stm_fcr_sync(void)
 {
@@ -234,52 +255,96 @@ ao_lcd_stm_fcr_sync(void)
                asm("nop");
 }
 
-static void
-ao_lcd_stm_seg_set(void)
+void
+ao_lcd_flush(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;
+       ao_arch_block_interrupts();
+       ao_lcd_update_active = 1;
+       stm_lcd.sr = (1 << STM_LCD_SR_UDR);
+       while (ao_lcd_update_active)
+               ao_sleep(&ao_lcd_update_active);
+       ao_arch_release_interrupts();
+}
+
+void
+ao_lcd_clear(void)
+{
+       uint8_t i;
+
+       for (i = 0; i < sizeof (stm_lcd.ram) / 4; i++)
+               stm_lcd.ram[i] = 0;
+       ao_lcd_flush();
+}
+
+#ifdef AO_SEGMENT_MAP
+#if AO_LCD_PER_DIGIT
+static const struct ao_lcd_map {
+       uint8_t com, seg;
+} ao_lcd_map[AO_LCD_DIGITS * AO_LCD_SEGMENTS] = AO_SEGMENT_MAP;
+#else
+static const uint8_t ao_lcd_map[] = AO_SEGMENT_MAP;
+#endif
+#endif
+
+void
+ao_lcd_set(uint8_t digit, uint8_t segment, uint8_t value)
+{
+       uint8_t n;
+       uint8_t com, seg;
+
+#ifdef AO_SEGMENT_MAP
+#if AO_LCD_PER_DIGIT
+       n = digit * AO_LCD_SEGMENTS + segment;
+       com = ao_lcd_map[n].com;
+       seg = ao_lcd_map[n].seg;
+#else
+       com = digit;
+       seg = ao_lcd_map[segment];
+#endif
+#else
+       com = digit;
+       seg = segment;
+#endif
        if (com >= NCOM)
                com = NCOM-1;
        if (seg >= NSEG)
                seg = NSEG-1;
-       if (val)
+
+#if LCD_DEBUG
+       printf ("digit %d segment %d -> com %d seg %d\n", digit, segment, com, seg);
+#endif
+       n = (seg >> 5) & 1;
+       if (value)
                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);
 }
 
+#if LCD_DEBUG
 static void
-ao_lcd_stm_clear(void)
+ao_lcd_stm_seg_set(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);
+       int     com, seg, val;
+       int     n, bit;
+       com = ao_cmd_decimal();
+       seg = ao_cmd_decimal();
+       val = ao_cmd_decimal();
+       printf ("com: %d seg: %d val: %d\n", com, seg, val);
+       ao_lcd_set(com, seg, val);
+       ao_lcd_flush();
 }
 
-
-const struct ao_cmds ao_lcd_stm_cmds[] = {
+static 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_clear,         "x\0Clear LCD" },
        { 0, NULL },
 };
+#endif
 
 void
 ao_lcd_stm_init(void)
 {
-       int s, c;
-       int r;
+       unsigned int s, c;
        uint32_t        csr;
 
        stm_rcc.ahbenr |= ((AO_LCD_STM_USES_GPIOA << STM_RCC_AHBENR_GPIOAEN) |
@@ -332,14 +397,14 @@ ao_lcd_stm_init(void)
        stm_lcd.cr = 0;
 
        /* duty cycle 1/3, radio 352, frame rate about 33Hz */
-       stm_lcd.fcr = ((STM_LCD_FCR_PS_16 << STM_LCD_FCR_PS) |
+       stm_lcd.fcr = ((STM_LCD_FCR_PS_8 << STM_LCD_FCR_PS) |
                       (STM_LCD_FCR_DIV_20 << STM_LCD_FCR_DIV) |
-                      (4 << STM_LCD_FCR_CC) |
+                      (7 << STM_LCD_FCR_CC) |
                       (0 << STM_LCD_FCR_DEAD) |
-                      (4 << STM_LCD_FCR_PON) |
-                      (0 << STM_LCD_FCR_UDDIE) |
+                      (1 << STM_LCD_FCR_PON) |
+                      (1 << STM_LCD_FCR_UDDIE) |
                       (0 << STM_LCD_FCR_SOFIE) |
-                      (0 << STM_LCD_FCR_HD));
+                      (1 << STM_LCD_FCR_HD));
 
        ao_lcd_stm_fcr_sync();
 
@@ -347,10 +412,10 @@ ao_lcd_stm_init(void)
        /* Program desired BIAS in LCD_CR */
        /* Enable mux seg */
        /* Internal voltage source */
-       stm_lcd.cr = ((STM_LCD_CR_DUTY_STATIC << STM_LCD_CR_DUTY) |
+       stm_lcd.cr = ((AO_LCD_DUTY << STM_LCD_CR_DUTY) |
                      (STM_LCD_CR_BIAS_1_2 << STM_LCD_CR_BIAS) |
                      (0 << STM_LCD_CR_VSEL) |
-                     (1 << STM_LCD_CR_MUX_SEG));
+                     (0 << STM_LCD_CR_MUX_SEG));
 
        ao_lcd_stm_fcr_sync();
 
@@ -362,12 +427,6 @@ ao_lcd_stm_init(void)
 
        /* 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) */
 
@@ -376,7 +435,11 @@ ao_lcd_stm_init(void)
        /* Program optional features (BLINK, BLINKF, PON, DEAD, HD) */
 
        /* Program the required interrupts */
+       stm_nvic_set_enable(STM_ISR_LCD_POS);
+       stm_nvic_set_priority(STM_ISR_LCD_POS, AO_STM_NVIC_LOW_PRIORITY);
 
        /* All done */
+#if LCD_DEBUG
        ao_cmd_register(ao_lcd_stm_cmds);
+#endif
 }