altos: Add ao_boot_chain to telemega v0.3
[fw/altos] / src / stm / ao_lcd_stm.c
index f68cf165fc076a8528ae23654d401584b0c952b4..47ea374ed6070303b5b306db6cb1719e825ea891 100644 (file)
  */
 
 #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 +93,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 +232,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,46 +254,94 @@ 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;
+       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);
+       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)
@@ -328,14 +396,18 @@ ao_lcd_stm_init(void)
                }
        }
 
+       /* Disable the LCD */
+       stm_lcd.cr = 0;
+
        /* 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) |
+       stm_lcd.fcr = ((STM_LCD_FCR_PS_8 << STM_LCD_FCR_PS) |
+                      (STM_LCD_FCR_DIV_20 << STM_LCD_FCR_DIV) |
+                      (7 << STM_LCD_FCR_CC) |
+                      (0 << STM_LCD_FCR_DEAD) |
+                      (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();
 
@@ -343,10 +415,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_1_4 << STM_LCD_CR_DUTY) |
-                     (STM_LCD_CR_BIAS_1_3 << STM_LCD_CR_BIAS) |
+       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();
 
@@ -358,12 +430,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) */
 
@@ -372,7 +438,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
 }