*
* 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;
&stm_gpioe
};
-static inline int ao_lcd_stm_seg_enabled(int seg) {
+static inline int ao_lcd_stm_seg_enabled(uint32_t 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) {
+static inline int ao_lcd_stm_com_enabled(uint32_t com) {
return (AO_LCD_STM_COM_ENABLED >> com) & 1;
}
(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) | \
#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)
{
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 = (uint8_t) (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)
- stm_lcd.ram[com * 2 + n] |= (1 << (seg & 0x1f));
+
+#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] |= (1UL << (seg & 0x1f));
else
- stm_lcd.ram[com * 2 + n] &= ~(1 << (seg & 0x1f));
- stm_lcd.sr = (1 << STM_LCD_SR_UDR);
+ stm_lcd.ram[com * 2 + n] &= ~(1UL << (seg & 0x1f));
}
+#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) |
- (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.ahbenr |= (((uint32_t) AO_LCD_STM_USES_GPIOA << STM_RCC_AHBENR_GPIOAEN) |
+ ((uint32_t) AO_LCD_STM_USES_GPIOB << STM_RCC_AHBENR_GPIOBEN) |
+ ((uint32_t) AO_LCD_STM_USES_GPIOC << STM_RCC_AHBENR_GPIOCEN) |
+ ((uint32_t) AO_LCD_STM_USES_GPIOD << STM_RCC_AHBENR_GPIODEN) |
+ ((uint32_t) AO_LCD_STM_USES_GPIOE << STM_RCC_AHBENR_GPIOEEN));
stm_rcc.apb1enr |= (1 << STM_RCC_APB1ENR_LCDEN);
}
}
+ /* 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();
/* 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();
/* 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 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
}