From abf8c8a13a02f6463ba77063412a06dbf1799c07 Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Thu, 23 May 2013 15:23:29 -0600 Subject: [PATCH] STM32L-Discovery LCD driver is code compele but untested --- ChangeLog | 2 + arch/arm/src/stm32/Kconfig | 24 +- arch/arm/src/stm32/chip/stm32_lcd.h | 8 +- configs/stm32ldiscovery/README.txt | 211 ++-- configs/stm32ldiscovery/nsh/Make.defs | 2 +- configs/stm32ldiscovery/nsh/setenv.sh | 2 +- configs/stm32ldiscovery/src/stm32_lcd.c | 969 ++++++++++++++++-- configs/stm32ldiscovery/src/stm32ldiscovery.h | 62 +- include/nuttx/ascii.h | 4 +- include/nuttx/lcd/slcd_codec.h | 4 +- libc/misc/lib_slcddecode.c | 25 +- 11 files changed, 1094 insertions(+), 219 deletions(-) diff --git a/ChangeLog b/ChangeLog index 93212d83e15..e3366023162 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4781,3 +4781,5 @@ should set the POLLNVAL event and return immediately (2013-5-23). * libc/misc/lib_slcdencode.c and lib_slcddecode.c: Add logic to marshal and serialized special SLCD intermixed with normal ASCII data (2013-5-23) + * configs/stm32ldiscovery/src/stm32_lcd.c: STM32L-Discovery's segment LCD + is code complete but completely untested (2013-5-23). diff --git a/arch/arm/src/stm32/Kconfig b/arch/arm/src/stm32/Kconfig index 458e7155ae1..5420f713834 100644 --- a/arch/arm/src/stm32/Kconfig +++ b/arch/arm/src/stm32/Kconfig @@ -500,7 +500,7 @@ config STM32_CAN1 default n select CAN select STM32_CAN - depends on !STM32_VALUELINE + depends on !STM32_VALUELINE && !STM32_STM32L15XX config STM32_CAN2 bool "CAN2" @@ -586,11 +586,6 @@ config STM32_I2C3 depends on STM32_STM32F20XX || STM32_STM32F40XX select STM32_I2C -config STM32_IWDG - bool "IWDG" - default n - select WATCHDOG - config STM32_OTGFS bool "OTG FS" default n @@ -664,6 +659,7 @@ config STM32_SYSCFG config STM32_TIM1 bool "TIM1" default n + depends on !STM32_STM32L15XX config STM32_TIM2 bool "TIM2" @@ -693,7 +689,7 @@ config STM32_TIM7 config STM32_TIM8 bool "TIM8" default n - depends on !STM32_VALUELINE + depends on !STM32_VALUELINE && !STM32_STM32L15XX config STM32_TIM9 bool "TIM9" @@ -767,14 +763,14 @@ config STM32_USART3 config STM32_UART4 bool "UART4" default n - depends on !STM32_STM32F30XX + depends on !STM32_STM32F30XX &&!STM32_STM32L15XX select ARCH_HAVE_UART4 select STM32_USART config STM32_UART5 bool "UART5" default n - depends on !STM32_STM32F30XX + depends on !STM32_STM32F30XX &&!STM32_STM32L15XX select ARCH_HAVE_UART5 select STM32_USART @@ -805,6 +801,16 @@ config STM32_USB depends on (STM32_STM32F10XX && !STM32_VALUELINE) || STM32_STM32L15XX || STM32_STM32F30XX select USBDEV +config STM32_LCD + bool "Segment LCD" + default n + depends on STM32_STM32L15XX + +config STM32_IWDG + bool "IWDG" + default n + select WATCHDOG + config STM32_WWDG bool "WWDG" default n diff --git a/arch/arm/src/stm32/chip/stm32_lcd.h b/arch/arm/src/stm32/chip/stm32_lcd.h index d79348bcfe6..70d6be54894 100644 --- a/arch/arm/src/stm32/chip/stm32_lcd.h +++ b/arch/arm/src/stm32/chip/stm32_lcd.h @@ -125,7 +125,7 @@ # define LCD_CR_BIAS_1TO4 (0 << LCD_CR_BIAS_SHIFT) /* 00: Bias 1/4 */ # define LCD_CR_BIAS_1TO2 (1 << LCD_CR_BIAS_SHIFT) /* 01: Bias 1/2 */ # define LCD_CR_BIAS_1TO3 (2 << LCD_CR_BIAS_SHIFT) /* 10: Bias 1/3 */ -#define LCD_CR_MUX_SEG (1 << 7) /* Bit 7: Mux segment enable +#define LCD_CR_MUX_SEG (1 << 7) /* Bit 7: Mux segment enable */ /* Bits 8-31 Reserved */ /* LCD frame control register */ @@ -181,7 +181,7 @@ # define LCD_FCR_PS_DIV8192 (13 << LCD_FCR_PS_SHIFT) /* 0011: ck_ps = LCDCLK/8192 */ # define LCD_FCR_PS_DIV16384 (14 << LCD_FCR_PS_SHIFT) /* 0011: ck_ps = LCDCLK/16384 */ # define LCD_FCR_PS_DIV32768 (15 << LCD_FCR_PS_SHIFT) /* 0011: ck_ps = LCDCLK/32768 */ - /* Bits 26-31 Reserved + /* Bits 26-31 Reserved */ /* LCD status register */ @@ -191,14 +191,14 @@ #define LCD_SR_UDD (1 << 3) /* Bit 3: Update Display Done */ #define LCD_SR_RDY (1 << 4) /* Bit 4: Ready flag */ #define LCD_SR_FCRSF (1 << 5) /* Bit 5: LCD Frame Control Register Synchronization flag */ - /* Bits 6-31 Reserved + /* Bits 6-31 Reserved */ /* LCD clear register */ /* Bit 0 Reserved */ #define LCD_CLR_SOFC (1 << 1) /* Bit 1: Start of frame flag clear */ /* Bit 2 Reserved */ -#define LCD_CLR_UDDC (1 << 2) /* Bit 3: Update display done clear +#define LCD_CLR_UDDC (1 << 2) /* Bit 3: Update display done clear */ /* Bits 31:2-31 Reserved */ /* LCD display memory, COMn, S00-S31 */ diff --git a/configs/stm32ldiscovery/README.txt b/configs/stm32ldiscovery/README.txt index 734505f5c62..308dec381dc 100644 --- a/configs/stm32ldiscovery/README.txt +++ b/configs/stm32ldiscovery/README.txt @@ -1,22 +1,22 @@ README ====== -This README discusses issues unique to NuttX configurations for the -STMicro STM32L-Discovery development board. The STM32L-Discovery board -is based on the STM32L152RBT6 MCU (128KB FLASH and 16KB of SRAM). + This README discusses issues unique to NuttX configurations for the + STMicro STM32L-Discovery development board. The STM32L-Discovery board + is based on the STM32L152RBT6 MCU (128KB FLASH and 16KB of SRAM). -The STM32L-Discovery and 32L152CDISCOVERY kits are functionally -equivalent. The difference is the internal Flash memory size (STM32L152RBT6 -with 128 Kbytes or STM32L152RCT6 with 256 Kbytes). + The STM32L-Discovery and 32L152CDISCOVERY kits are functionally + equivalent. The difference is the internal Flash memory size (STM32L152RBT6 + with 128 Kbytes or STM32L152RCT6 with 256 Kbytes). -Both boards feature: + Both boards feature: - - An ST-LINK/V2 embedded debug tool interface, - - LCD (24 segments, 4 commons), - - LEDs, - - Pushbuttons, - - A linear touch sensor, and - - Four touchkeys. + - An ST-LINK/V2 embedded debug tool interface, + - LCD (24 segments, 4 commons), + - LEDs, + - Pushbuttons, + - A linear touch sensor, and + - Four touchkeys. Contents ======== @@ -395,107 +395,114 @@ NXFLAT Toolchain LEDs ==== -The STM32L-Discovery board has four LEDs. Two of these are controlled by -logic on the board and are not available for software control: - -LD1 COM: LD2 default status is red. LD2 turns to green to indicate that - communications are in progress between the PC and the ST-LINK/V2. -LD2 PWR: Red LED indicates that the board is powered. - -And two LEDs can be controlled by software: - -User LD3: Green LED is a user LED connected to the I/O PB7 of the STM32L152 - MCU. -User LD4: Blue LED is a user LED connected to the I/O PB6 of the STM32L152 - MCU. - -These LEDs are not used by the board port unless CONFIG_ARCH_LEDS is -defined. In that case, the usage by the board port is defined in -include/board.h and src/up_leds.c. The LEDs are used to encode OS-related -events as follows: - - SYMBOL Meaning LED state - LED3 LED4 - ------------------- ----------------------- -------- -------- - LED_STARTED NuttX has been started OFF OFF - LED_HEAPALLOCATE Heap has been allocated OFF OFF - LED_IRQSENABLED Interrupts enabled OFF OFF - LED_STACKCREATED Idle stack created ON OFF - LED_INIRQ In an interrupt No change - LED_SIGNAL In a signal handler No change - LED_ASSERTION An assertion failed No change - LED_PANIC The system has crashed OFF Blinking - LED_IDLE STM32 is is sleep mode Not used + The STM32L-Discovery board has four LEDs. Two of these are controlled by + logic on the board and are not available for software control: + + LD1 COM: LD2 default status is red. LD2 turns to green to indicate + that communications are in progress between the PC and the + ST-LINK/V2. + LD2 PWR: Red LED indicates that the board is powered. + + And two LEDs can be controlled by software: + + User LD3: Green LED is a user LED connected to the I/O PB7 of the + STM32L152 MCU. + User LD4: Blue LED is a user LED connected to the I/O PB6 of the + STM32L152 MCU. + + These LEDs are not used by the board port unless CONFIG_ARCH_LEDS is + defined. In that case, the usage by the board port is defined in + include/board.h and src/up_leds.c. The LEDs are used to encode OS-related + events as follows: + + SYMBOL Meaning LED state + LED3 LED4 + ------------------- ----------------------- -------- -------- + LED_STARTED NuttX has been started OFF OFF + LED_HEAPALLOCATE Heap has been allocated OFF OFF + LED_IRQSENABLED Interrupts enabled OFF OFF + LED_STACKCREATED Idle stack created ON OFF + LED_INIRQ In an interrupt No change + LED_SIGNAL In a signal handler No change + LED_ASSERTION An assertion failed No change + LED_PANIC The system has crashed OFF Blinking + LED_IDLE STM32 is is sleep mode Not used Serial Console ============== -The STM32L-Discovery has no on-board RS-232 driver. Further, there are no -USART pins that do not conflict with the on board resources, in particular, -the LCD: Most USART pins are available if the LCD is enabled; USART2 may be -used if either the LCD or the on-board LEDs are disabled. + The STM32L-Discovery has no on-board RS-232 driver. Further, there are no + USART pins that do not conflict with the on board resources, in particular, + the LCD: Most USART pins are available if the LCD is enabled; USART2 may + be used if either the LCD or the on-board LEDs are disabled. - PA9 USART1_TX LCD glass COM1 P2, pin 22 - PA10 USART1_RX LCD glass COM2 P2, pin 21 - PB6 USART1_TX LED Blue P2, pin 8 - PB7 USART1_RX LED Green P2, pin 7 + PA9 USART1_TX LCD glass COM1 P2, pin 22 + PA10 USART1_RX LCD glass COM2 P2, pin 21 + PB6 USART1_TX LED Blue P2, pin 8 + PB7 USART1_RX LED Green P2, pin 7 - PA2 USART2_TX LCD SEG1 P1, pin 17 - PA3 USART2_RX LCD SEG2 P1, pin 18 + PA2 USART2_TX LCD SEG1 P1, pin 17 + PA3 USART2_RX LCD SEG2 P1, pin 18 - PB10 USART3_TX LCD SEG6 P1, pin 22 - PB11 USART3_RX LCD SEG7 P1, pin 23 - PC10 USART3_TX LCD SEG22 P2, pin 15 - PC11 USART3_RX LCD SEG23 P2, pin 14 + PB10 USART3_TX LCD SEG6 P1, pin 22 + PB11 USART3_RX LCD SEG7 P1, pin 23 + PC10 USART3_TX LCD SEG22 P2, pin 15 + PC11 USART3_RX LCD SEG23 P2, pin 14 -GND and (external) 5V are available on both P1 and P2. Note: These signals -may be at lower voltage levels and, hence, may not properly drive an external -RS-232 transceiver. + NOTES: -NOTE: The crystal X3 is not installed on the STM32L3-Discovery. As a -result, the HSE clock is not availabled and the less acurate HSI must be -used. This may limit the accuracy of the computed baud, especially at -higher BAUD. The HSI is supposedly calibrated in the factory to within 1% -at room temperatures so perhaps this not a issue. + - GND and (external) 5V are available on both P1 and P2. Note: These + signals may be at lower voltage levels and, hence, may not properly + drive an external RS-232 transceiver. -I have had no problems using the USART1 with PA9 and PA10 with a 3.3-5V -RS-232 transceiver module at 57600 baud. I have not tried higher baud rates. + - The crystal X3 is not installed on the STM32L3-Discovery. As a result, + the HSE clock is not availabled and the less acurate HSI must be used. + This may limit the accuracy of the computed baud, especially at higher + BAUD. The HSI is supposedly calibrated in the factory to within 1% at + room temperatures so perhaps this not a issue. -There is no support for a USB serial connector on the STM32L-Discovery board. -The STM32L152 does support USB, but the USB pins are "free I/O" on the board -and no USB connector is provided. So the use of a USB console is not option. -If you need console output, you will need to disable either LCD (and use any -USART) or the LEDs (and use USART1) + - According to the STM32L-Discovery User Manual, the LCD should be removed + from its socket if you use any of the LCD pins for any other purpose. + + I have had no problems using the USART1 with PA9 and PA10 with a 3.3-5V + RS-232 transceiver module at 57600 baud. I have not tried higher baud + rates. + + - There is no support for a USB serial connector on the STM32L-Discovery + board. The STM32L152 does support USB, but the USB pins are "free I/O" + on the board and no USB connector is provided. So the use of a USB + console is not option. If you need console output, you will need to + disable either LCD (and use any USART) or the LEDs (and use USART1) Debugging ========= -STM32 ST-LINK Utility ---------------------- -For simply writing to FLASH, I use the STM32 ST-LINK Utility. At least -version 2.4.0 is required (older versions do not recognize the STM32 F3 -device). This utility is available from free from the STMicro website. + STM32 ST-LINK Utility + --------------------- + For simply writing to FLASH, I use the STM32 ST-LINK Utility. At least + version 2.4.0 is required (older versions do not recognize the STM32 F3 + device). This utility is available from free from the STMicro website. -Debugging ---------- -If you are going to use a debugger, you should make sure that the following -settings are selection in your configuration file: + Debugging + --------- + If you are going to use a debugger, you should make sure that the following + settings are selection in your configuration file: - CONFIG_DEBUG_SYMBOLS=y : Enable debug symbols in the build - CONFIG_ARMV7M_USEBASEPRI=y : Use the BASEPRI register to disable interrupts + CONFIG_DEBUG_SYMBOLS=y : Enable debug symbols in the build + CONFIG_ARMV7M_USEBASEPRI=y : Use the BASEPRI register to disable interrupts -OpenOCD -------- -I am told that OpenOCD will work with the ST-Link, but I have never tried -it. + OpenOCD + ------- + I am told that OpenOCD will work with the ST-Link, but I have never tried + it. -https://github.com/texane/stlink --------------------------------- -This is an open source server for the ST-Link that I have never used. + https://github.com/texane/stlink + -------------------------------- + This is an open source server for the ST-Link that I have never used. -Atollic GDB Server ------------------- -You can use the Atollic IDE, but I have never done that either. + Atollic GDB Server + ------------------ + You can use the Atollic IDE, but I have never done that either. STM32L-Discovery-specific Configuration Options =============================================== @@ -693,20 +700,20 @@ STM32L-Discovery-specific Configuration Options Configurations ============== -Each STM32L-Discovery configuration is maintained in a sub-directory and -can be selected as follow: + Each STM32L-Discovery configuration is maintained in a sub-directory and + can be selected as follow: cd tools ./configure.sh STM32L-Discovery/ cd - . ./setenv.sh -If this is a Windows native build, then configure.bat should be used -instead of configure.sh: + If this is a Windows native build, then configure.bat should be used + instead of configure.sh: configure.bat STM32L-Discovery\ -Where is one of the following: + Where is one of the following: nsh: --- @@ -739,3 +746,9 @@ Where is one of the following: CONFIG_HOST_WINDOWS=y : Builds under Windows CONFIG_WINDOWS_CYGWIN=y : Using Cygwin CONFIG_ARMV7M_TOOLCHAIN_CODESOURCERYW=y : CodeSourcery for Windows + + 5. To enable SLCD support: + + CONFIG_ARCH_LEDS=y : Disable LED support + CONFIG_LIB_SLCDCODEC=y : Enable the SLCD CODEC + CONFIG_STM32_LCD=y : Enable the SLCD diff --git a/configs/stm32ldiscovery/nsh/Make.defs b/configs/stm32ldiscovery/nsh/Make.defs index 2987bb2007f..a47624868df 100644 --- a/configs/stm32ldiscovery/nsh/Make.defs +++ b/configs/stm32ldiscovery/nsh/Make.defs @@ -1,5 +1,5 @@ ############################################################################ -# configs/stm32f3discovery/nsh/Make.defs +# configs/stm32l1discovery/nsh/Make.defs # # Copyright (C) 2013 Gregory Nutt. All rights reserved. # Author: Gregory Nutt diff --git a/configs/stm32ldiscovery/nsh/setenv.sh b/configs/stm32ldiscovery/nsh/setenv.sh index 0a1e7172039..41d0f760655 100755 --- a/configs/stm32ldiscovery/nsh/setenv.sh +++ b/configs/stm32ldiscovery/nsh/setenv.sh @@ -1,5 +1,5 @@ #!/bin/bash -# configs/stm32f3discovery/nsh/setenv.sh +# configs/stm32l1discovery/nsh/setenv.sh # # Copyright (C) 2013 Gregory Nutt. All rights reserved. # Author: Gregory Nutt diff --git a/configs/stm32ldiscovery/src/stm32_lcd.c b/configs/stm32ldiscovery/src/stm32_lcd.c index 0538429fbab..d5676baad33 100644 --- a/configs/stm32ldiscovery/src/stm32_lcd.c +++ b/configs/stm32ldiscovery/src/stm32_lcd.c @@ -4,6 +4,14 @@ * Copyright (C) 2013 Gregory Nutt. All rights reserved. * Authors: Gregory Nutt * + * References: + * - Based on the NuttX LCD1602 driver. + * - "STM32L100xx, STM32L151xx, STM32L152xx and STM32L162xx advanced ARM-based + * 32-bit MCUs", STMicroelectronics, RM0038 + * - "STM32L1 discovery kits: STM32L-DISCOVERY and 32L152CDISCOVERY," + * STMicroelectronics, UM1079 + * - STM32L-Discovery Firmware Pack V1.0.2 (for character encoding) + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -42,15 +50,21 @@ #include #include #include +#include #include #include #include #include +#include +#include #include +#include #include "up_arch.h" +#include "stm32_gpio.h" #include "chip/stm32_lcd.h" + #include "stm32ldiscovery.h" #ifdef CONFIG_STM32_LCD @@ -60,10 +74,14 @@ ****************************************************************************/ /* Configuration ************************************************************/ -/* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug must - * also be enabled. +/* Define CONFIG_DEBUG_LCD to enable detailed LCD debug output. Verbose debug + * must also be enabled. */ +#ifndef CONFIG_LIB_SLCDCODEC +# error "This SLCD driver requires CONFIG_LIB_SLCDCODEC" +#endif + #ifndef CONFIG_DEBUG # undef CONFIG_DEBUG_VERBOSE # undef CONFIG_DEBUG_GRAPHICS @@ -74,6 +92,14 @@ # undef CONFIG_DEBUG_LCD #endif +#ifndef MIN +# define MIN(a,b) (a < b ? a : b) +#endif + +#ifndef MAX +# define MAX(a,b) (a > b ? a : b) +#endif + /* LCD **********************************************************************/ /* LCD. The STM32L152RBT6 supports either a 4x32 or 8x28. The STM32L- * Discovery has an LCD 24 segments, 4 commons. See stm32ldiscovery.h for @@ -84,19 +110,68 @@ * address: */ -#define LCD_OFFSET (STM32_LCD_BASE - STM32_PERIPH_BASE) -#define LCD_BBADDR(o,b) (STM32_PERIPHBB_BASE + ((LCD_OFFSET + (o)) << 5) + ((b) << 2)) +#define SLCD_OFFSET (STM32_LCD_BASE - STM32_PERIPH_BASE) +#define SLCD_BBADDR(o,b) (STM32_PERIPHBB_BASE + ((SLCD_OFFSET + (o)) << 5) + ((b) << 2)) /* Some useful bit-band addresses */ -#define LCD_CR_LCDEN_BB LCD_BBADDR(STM32_LCD_CR_OFFSET,0) -#define LCD_SR_UDR_BB LCD_BBADDR(STM32_LCD_SR_OFFSET,2) +#define SLCD_CR_LCDEN_BB SLCD_BBADDR(STM32_LCD_CR_OFFSET,0) +#define SLCD_SR_UDR_BB SLCD_BBADDR(STM32_LCD_SR_OFFSET,2) + +/* LCD characteristics */ + +#define SLCD_NCHARS 6 + +/* An ASCII character may need to be decorated with a colon or decimal point */ + +#define SCLD_DP 0x01 +#define SCLD_COLON 0x02 + +/* Macros used for set/reset the LCD bar */ + +#define SCLD_BAR0_ON g_slcdstate.bar[1] |= 8 +#define SCLD_BAR0_OFF g_slcdstate.bar[1] &= ~8 +#define SCLD_BAR1_ON g_slcdstate.bar[0] |= 8 +#define SCLD_BAR1_OFF g_slcdstate.bar[0] &= ~8 +#define SCLD_BAR2_ON g_slcdstate.bar[1] |= 2 +#define SCLD_BAR2_OFF g_slcdstate.bar[1] &= ~2 +#define SCLD_BAR3_ON g_slcdstate.bar[0] |= 2 +#define SCLD_BAR3_OFF g_slcdstate.bar[0] &= ~2 + +/* These definitions support the logic of slcd_writemem() */ + +#define SLCD_CHAR1_MASK 0xcffffffc +#define SLCD_CHAR1_UPDATE(s) (((uint32_t)(s) & 0x0c) << 26) | \ + ((uint32_t)(s) & 0x03) +#define SLCD_CHAR2_MASK 0xf3ffff03 +#define SLCD_CHAR2_UPDATE(s) (((uint32_t)(s) & 0x0c) << 24) | \ + (((uint32_t)(s) & 0x02) << 6) | \ + (((uint32_t)(s) & 0x01) << 2) +#define SLCD_CHAR3_MASK 0xfcfffcff +#define SLCD_CHAR3_UPDATE(s) (((uint32_t)(s) & 0x0c) << 22) | \ + (((uint32_t)(s) & 0x03) << 8) +#define SLCD_CHAR4_MASK 0xffcff3ff +#define SLCD_CHAR4_UPDATE(s) (((uint32_t)(s) & 0x0c) << 18) | \ + (((uint32_t)(s) & 0x03) << 10) +#define SLCD_CHAR5_MASKA 0xfff3cfff +#define SLCD_CHAR5_MASKB 0xfff3efff +#define SLCD_CHAR5_UPDATEA(s) (((uint32_t)(s) & 0x0c) << 16) | \ + (((uint32_t)(s) & 0x03) << 12) +#define SLCD_CHAR5_UPDATEB(s) (((uint32_t)(s) & 0x0c) << 16) | \ + (((uint32_t)(s) & 0x01) << 12) +#define SLCD_CHAR6_MASK 0xfffc3fff +#define SLCD_CHAR6_UPDATEA(s) (((uint32_t)(s) & 0x04) << 15) | \ + (((uint32_t)(s) & 0x08) << 13) | \ + (((uint32_t)(s) & 0x03) << 14) +#define SLCD_CHAR6_UPDATEB(s) (((uint32_t)(s) & 0x04) << 15) | \ + (((uint32_t)(s) & 0x08) << 13) | \ + (((uint32_t)(s) & 0x03) << 14) /* Debug ********************************************************************/ #ifdef CONFIG_DEBUG_LCD -# define lcddbg dbg -# define lcdvdbg vdbg +# define lcddbg dbg +# define lcdvdbg vdbg #else # define lcddbg(x...) # define lcdvdbg(x...) @@ -106,23 +181,26 @@ * Private Type Definition ****************************************************************************/ -/* Indices into the g_lcdgpio[] array */ +/* SLCD incoming stream structure */ -enum stm32_gpio_e +struct slcd_instream_s { - LCD_COM0 = 0, LCD_COM1, LCD_COM2, LCD_COM3, - - LCD_SEG0, LCD_SEG1, LCD_SEG2, LCD_SEG3, LCD_SEG4, LCD_SEG5, LCD_SEG6, - LCD_SEG7, LCD_SEG8, LCD_SEG9, LCD_SEG10, LCD_SEG11, LCD_SEG12, LCD_SEG13, - LCD_SEG14, LCD_SEG15, LCD_SEG16, LCD_SEG17, LCD_SEG18, LCD_SEG19, LCD_SEG20, - LCD_SEG21, LCD_SEG22, LCD_SEG23, - - LCD_NGPIOS + struct lib_instream_s stream; + FAR const char *buffer; + ssize_t nbytes; }; -struct stm32_lcd_s +/* Global SLCD state */ + +struct stm32_slcdstate_s { - bool initialized; /* True: Completed initialization sequence */ + bool initialized; /* True: Completed initialization sequence */ + uint8_t curpos; /* The current cursor position */ + uint8_t buffer[SLCD_NCHARS]; /* SLCD ASCII content */ + uint8_t options[SLCD_NCHARS]; /* With colon or decimal point decoration */ +#if 0 /* Not used */ + uint8_t bar[2]; /* Controls the bars on the far right of the SLCD */ +#endif }; /**************************************************************************** @@ -130,15 +208,25 @@ struct stm32_lcd_s ****************************************************************************/ /* Internal utilities */ -static void lcd_clear(void) +static void slcd_clear(void); +static int slcd_getstream(FAR struct lib_instream_s *instream); +#if 0 /* Not used */ +static uint8_t slcd_getcontrast(void); +static int slcd_setcontrast(uint8_t contrast); +static void slcd_writebar(void); +#endif +static inline uint16_t slcd_mapch(uint8_t ch); +static inline void slcd_writemem(uint16_t bitset, int curpos); +static void slcd_writech(uint8_t ch, uint8_t curpos, uint8_t options); +static inline void slcd_appendch(uint8_t ch, uint8_t options); +static inline void slcd_action(enum slcdcode_e code, uint8_t count); /* Character driver methods */ -static ssize_t lcd_read(FAR struct file *, FAR char *, size_t); -static ssize_t lcd_write(FAR struct file *, FAR const char *, size_t); +static ssize_t slcd_read(FAR struct file *, FAR char *, size_t); +static ssize_t slcd_write(FAR struct file *, FAR const char *, size_t); #ifndef CONFIG_DISABLE_POLL -static int lcd_poll(FAR struct file *filp, FAR struct pollfd *fds, - bool setup); +static int slcd_poll(FAR struct file *filp, FAR struct pollfd *fds, bool setup); #endif /**************************************************************************** @@ -147,31 +235,102 @@ static int lcd_poll(FAR struct file *filp, FAR struct pollfd *fds, /* This is the driver state structure (there is no retained state information) */ -static const struct file_operations g_lcdops = +static const struct file_operations g_slcdops = { 0, /* open */ 0, /* close */ - lcd_read, /* read */ - lcd_write, /* write */ + slcd_read, /* read */ + slcd_write, /* write */ 0, /* seek */ 0 /* ioctl */ #ifndef CONFIG_DISABLE_POLL - , lcd_poll /* poll */ + , slcd_poll /* poll */ #endif }; +/* LCD state data */ + +static struct stm32_slcdstate_s g_slcdstate; + +/* LCD Mapping + * + * A + * --------- _ + * |\ |J /| |_| COL + * F| H | K |B + * | \ | / | _ + * --G-- --M-+ |_| COL + * | /| \ | + * E| Q | N |C + * | / |P \| _ + * --------- |_| DP + * D + * + * LCD character 16-bit-encoding: + * { E , D , P , N, M , C , COL , DP, B , A , K , J, G , F , Q , H } + */ + +#warning "Encodings for all punctuation are incomplete" + +/* Space and ASCII punctuation: 0x20-0x2f */ + +static const uint16_t g_slcdpunct1[ASCII_0 - ASCII_SPACE] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, /* ! " # $ % & ' */ + 0x0000, 0x0000, 0xa0dd, 0x0000, 0x0000, 0xa000, 0x0000, 0x00c0 /* () * + , - . / */ +}; + +/* ASCII numerals 0-9: 0x30-0x39 */ + +static const uint16_t g_slcdnummap[ASCII_COLON - ASCII_0] = +{ + 0x5f00, 0x4200, 0xf500, 0x6700, 0xea00, 0xaf00, 0xbf00, 0x4600, /* 0-7 */ + 0xff00, 0xef00 /* 8-9 */ +}; + +/* ASCII punctuation: 0x3a-0x40 */ + +static const uint16_t g_slcdpunct2[ASCII_A - ASCII_COLON] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /* : ; < = > ? @ */ +}; + +/* Upper case letters A-Z: 0x41-0x5a. Also lower case letters a-z: 0x61-0x7a */ + +static const uint16_t g_slcdalphamap[ASCII_LBRACKET - ASCII_A] = +{ + 0xfe00, 0x6714, 0x1d00, 0x4714, 0x9d00, 0x9c00, 0x3f00, 0xfa00, /* A-H */ + 0x0014, 0x5300, 0x9841, 0x1900, 0x5a48, 0x5a09, 0x5f00, 0xfc00, /* I-P */ + 0x5f01, 0xfc01, 0xaf00, 0x0414, 0x5b00, 0x18c0, 0x5a81, 0x00c9, /* Q-X */ + 0x0058, 0x05c0 /* y-Z */ +}; + +/* ASCII punctuation: 0x5b-0x60 */ + +static const uint16_t g_slcdpunct3[ASCII_a - ASCII_LBRACKET] = +{ + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 /* [ \ ] ^ _ */ +}; + +/* ASCII punctuation: 0x7b-0x7e */ + +static const uint16_t g_slcdpunct4[ASCII_DEL - ASCII_LBRACE]= +{ + 0x0000, 0x0000, 0x0000, 0x0000 /* { | } ~ */ +}; + /* All GPIOs that need to be configured for the STM32L-Discovery LCD */ -static uint32_t g_lcdgpio[BOARD_LCD_NGPIOS] = +static uint32_t g_slcdgpio[BOARD_SLCD_NGPIOS] = { - BOARD_LCD_COM0, BOARD_LCD_COM1, BOARD_LCD_COM2, BOARD_LCD_COM3, - - BOARD_LCD_SEG0, BOARD_LCD_SEG1, BOARD_LCD_SEG2, BOARD_LCD_SEG3, - BOARD_LCD_SEG4, BOARD_LCD_SEG5, BOARD_LCD_SEG6, BOARD_LCD_SEG7, - BOARD_LCD_SEG8, BOARD_LCD_SEG9, BOARD_LCD_SEG10, BOARD_LCD_SEG11, - BOARD_LCD_SEG12, BOARD_LCD_SEG13, BOARD_LCD_SEG14, BOARD_LCD_SEG15, - BOARD_LCD_SEG16, BOARD_LCD_SEG17, BOARD_LCD_SEG18, BOARD_LCD_SEG19, - BOARD_LCD_SEG20, BOARD_LCD_SEG21, BOARD_LCD_SEG22, BOARD_LCD_SEG23 + BOARD_SLCD_COM0, BOARD_SLCD_COM1, BOARD_SLCD_COM2, BOARD_SLCD_COM3, + + BOARD_SLCD_SEG0, BOARD_SLCD_SEG1, BOARD_SLCD_SEG2, BOARD_SLCD_SEG3, + BOARD_SLCD_SEG4, BOARD_SLCD_SEG5, BOARD_SLCD_SEG6, BOARD_SLCD_SEG7, + BOARD_SLCD_SEG8, BOARD_SLCD_SEG9, BOARD_SLCD_SEG10, BOARD_SLCD_SEG11, + BOARD_SLCD_SEG12, BOARD_SLCD_SEG13, BOARD_SLCD_SEG14, BOARD_SLCD_SEG15, + BOARD_SLCD_SEG16, BOARD_SLCD_SEG17, BOARD_SLCD_SEG18, BOARD_SLCD_SEG19, + BOARD_SLCD_SEG20, BOARD_SLCD_SEG21, BOARD_SLCD_SEG22, BOARD_SLCD_SEG23 }; /**************************************************************************** @@ -179,17 +338,12 @@ static uint32_t g_lcdgpio[BOARD_LCD_NGPIOS] = ****************************************************************************/ /**************************************************************************** - * Name: lcd_clear - ****************************************************************************/ - -/**************************************************************************** - * Name: lcd_clear + * Name: slcd_clear ****************************************************************************/ -static void lcd_clear(void) +static void slcd_clear(void) { uint32_t regaddr; - int i; /* Make sure that any previous transfer is complete. The firmware sets * the UDR each it modifies the LCD_RAM. The UDR bit stays set until the @@ -200,40 +354,728 @@ static void lcd_clear(void) /* Write all zerios in to the LCD RAM */ - for (regaddr = STM32_LCD_RAML(0); i <= STM32_LCD_RAMH(7); regaddr++) + for (regaddr = STM32_LCD_RAML(0); regaddr <= STM32_LCD_RAMH(7); regaddr++) { putreg32(0, regaddr); } + /* Set all buffered data to undecorated spaces and home the cursor */ + + memset(g_slcdstate.buffer, ' ', SLCD_NCHARS); + memset(g_slcdstate.options, 0, SLCD_NCHARS); + g_slcdstate.curpos = 0; + + /* Set the UDR bit to transfer the updated data to the second level + * buffer. + */ + + putreg32(1, SLCD_SR_UDR_BB); +} + +/**************************************************************************** + * Name: slcd_getstream + * + * Description: + * Get one character from the keyboard. + * + ****************************************************************************/ + +static int slcd_getstream(FAR struct lib_instream_s *instream) +{ + FAR struct slcd_instream_s *slcdstream = (FAR struct slcd_instream_s *)instream; + + DEBUGASSERT(slcdstream && slcdstream->buffer); + if (slcdstream->nbytes > 0) + { + slcdstream->nbytes--; + slcdstream->stream.nget++; + return (int)*slcdstream->buffer++; + } + + return EOF; +} + +/**************************************************************************** + * Name: slcd_getcontrast + ****************************************************************************/ + +#if 0 /* Not used */ +static uint8_t slcd_getcontrast(void) +{ + return (getreg32(STM32_LCD_FCR) & LCD_FCR_CC_MASK) >> LCD_FCR_CC_SHIFT; +} +#endif + +/**************************************************************************** + * Name: slcd_setcontrast + ****************************************************************************/ + +#if 0 /* Not used */ +static int slcd_setcontrast(uint8_t contrast) +{ + uint2_t regval; + int ret = OK; + + /* Make sure that the contrast setting is within range */ + + if (contrast > 7) + { + contrast = 7; + ret = -ERANGE; + } + + regval = getreg32(STM32_LCD_FCR); + regval &= !LCD_FCR_CC_MASK; + regval |= contrast << LCD_FCR_CC_SHIFT; + putreg32(regval, STM32_LCD_FCR); +} +#endif + +/**************************************************************************** + * Name: slcd_writebar + ****************************************************************************/ + +#if 0 /* Not used */ +static void slcd_writebar(void) +{ + uint32_t regval; + + /* Make sure that any previous transfer is complete. The firmware sets + * the UDR each it modifies the LCD_RAM. The UDR bit stays set until the + * end of the update. During this time the LCD_RAM is write protected. + */ + + while ((getreg32(STM32_LCD_SR) & LCD_SR_UDR) != 0); + + /* Update the BAR */ + + regval = getreg32(STM32_LCD_RAM2L); + regval &= 0xffff5fff; + regval |= (uint32_t)(g_slcdstate.bar[0] << 12); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= 0xffff5fff; + regval |= (uint32_t)(g_slcdstate.bar[1] << 12); + putreg32(regval, STM32_LCD_RAM3L); + + + /* Set the UDR bit to transfer the updated data to the second level + * buffer. + */ + + putreg32(1, SLCD_SR_UDR_BB); +} +#endif + +/**************************************************************************** + * Name: slcd_mapch + ****************************************************************************/ + +static inline uint16_t slcd_mapch(uint8_t ch) +{ + /* ASCII control characters, the forward delete character, period, colon, + * and all 8-bit ASCII character have already been handled prior to this + * function. + */ + + /* Return spaces all control characters (this should not happen) */ + + if (ch < ASCII_SPACE) + { + return 0x0000; + } + + /* Handle space and the first block of puncutation */ + + if (ch < ASCII_0) + { + return g_slcdpunct1[(int)ch - ASCII_SPACE]; + } + + /* Handle numbers */ + + else if (ch < ASCII_COLON) + { + return g_slcdnummap[(int)ch - ASCII_0]; + } + + /* Handle the next block of puncutation */ + + else if (ch < ASCII_A) + { + return g_slcdpunct2[(int)ch - ASCII_COLON]; + } + + /* Handle upper case letters */ + + else if (ch < ASCII_LBRACKET) + { + return g_slcdnummap[(int)ch - ASCII_A]; + } + + /* Handle the next block of puncutation */ + + else if (ch < ASCII_a) + { + return g_slcdpunct3[(int)ch - ASCII_LBRACKET]; + } + + /* Handle lower case letters (by mapping them to upper case */ + + else if (ch < ASCII_LBRACE) + { + return g_slcdnummap[(int)ch - ASCII_a]; + } + + /* Handle the final block of puncutation */ + + else if (ch < ASCII_DEL) + { + return g_slcdpunct4[(int)ch - ASCII_LBRACE]; + } + + /* Ignore 8-bit ASCII and DEL (this should not happen) */ + + return 0x0000; +} + +/**************************************************************************** + * Name: slcd_writemem + ****************************************************************************/ + +static inline void slcd_writemem(uint16_t bitset, int curpos) +{ + uint32_t regval; + uint8_t segments[4]; + int i; + int j; + + /* Isolate the least significant bits */ + + for (i = 12, j = 0; j < 4; i -= 4, j++) + { + segments[j] = (bitset >> i) & 0x0f; + } + + /* Make sure that any previous transfer is complete. The firmware sets + * the UDR each it modifies the LCD_RAM. The UDR bit stays set until the + * end of the update. During this time the LCD_RAM is write protected. + */ + + while ((getreg32(STM32_LCD_SR) & LCD_SR_UDR) != 0); + + /* Now update the SLCD memory for the character at this cursor position by + * decoding the bit-mapped value + */ + + switch (curpos) + { + case 0: + regval = getreg32(STM32_LCD_RAM0L); + regval &= SLCD_CHAR1_MASK; + regval |= SLCD_CHAR1_UPDATE(segments[0]); + putreg32(regval, STM32_LCD_RAM0L); + + regval = getreg32(STM32_LCD_RAM1L); + regval &= SLCD_CHAR1_MASK; + regval |= SLCD_CHAR1_UPDATE(segments[1]); + putreg32(regval, STM32_LCD_RAM1L); + + regval = getreg32(STM32_LCD_RAM2L); + regval &= SLCD_CHAR1_MASK; + regval |= SLCD_CHAR1_UPDATE(segments[2]); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= SLCD_CHAR1_MASK; + regval |= SLCD_CHAR1_UPDATE(segments[3]); + putreg32(regval, STM32_LCD_RAM3L); + break; + + case 1: + regval = getreg32(STM32_LCD_RAM0L); + regval &= SLCD_CHAR2_MASK; + regval |= SLCD_CHAR2_UPDATE(segments[0]); + putreg32(regval, STM32_LCD_RAM0L); + + regval = getreg32(STM32_LCD_RAM1L); + regval &= SLCD_CHAR2_MASK; + regval |= SLCD_CHAR2_UPDATE(segments[1]); + putreg32(regval, STM32_LCD_RAM1L); + + regval = getreg32(STM32_LCD_RAM2L); + regval &= SLCD_CHAR2_MASK; + regval |= SLCD_CHAR2_UPDATE(segments[2]); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= SLCD_CHAR2_MASK; + regval |= SLCD_CHAR2_UPDATE(segments[3]); + putreg32(regval, STM32_LCD_RAM3L); + break; + + case 2: + regval = getreg32(STM32_LCD_RAM0L); + regval &= SLCD_CHAR3_MASK; + regval |= SLCD_CHAR3_UPDATE(segments[0]); + putreg32(regval, STM32_LCD_RAM0L); + + regval = getreg32(STM32_LCD_RAM1L); + regval &= SLCD_CHAR3_MASK; + regval |= SLCD_CHAR3_UPDATE(segments[1]); + putreg32(regval, STM32_LCD_RAM1L); + + regval = getreg32(STM32_LCD_RAM2L); + regval &= SLCD_CHAR3_MASK; + regval |= SLCD_CHAR3_UPDATE(segments[2]); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= SLCD_CHAR3_MASK; + regval |= SLCD_CHAR3_UPDATE(segments[3]); + putreg32(regval, STM32_LCD_RAM3L); + break; + + case 3: + regval = getreg32(STM32_LCD_RAM0L); + regval &= SLCD_CHAR4_MASK; + regval |= SLCD_CHAR4_UPDATE(segments[0]); + putreg32(regval, STM32_LCD_RAM0L); + + regval = getreg32(STM32_LCD_RAM1L); + regval &= SLCD_CHAR4_MASK; + regval |= SLCD_CHAR4_UPDATE(segments[1]); + putreg32(regval, STM32_LCD_RAM1L); + + regval = getreg32(STM32_LCD_RAM2L); + regval &= SLCD_CHAR4_MASK; + regval |= SLCD_CHAR4_UPDATE(segments[2]); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= SLCD_CHAR4_MASK; + regval |= SLCD_CHAR4_UPDATE(segments[3]); + putreg32(regval, STM32_LCD_RAM3L); + break; + + case 4: + regval = getreg32(STM32_LCD_RAM0L); + regval &= SLCD_CHAR5_MASKA; + regval |= SLCD_CHAR5_UPDATEA(segments[0]); + putreg32(regval, STM32_LCD_RAM0L); + + regval = getreg32(STM32_LCD_RAM1L); + regval &= SLCD_CHAR5_MASKA; + regval |= SLCD_CHAR5_UPDATEA(segments[1]); + putreg32(regval, STM32_LCD_RAM1L); + + regval = getreg32(STM32_LCD_RAM2L); + regval &= SLCD_CHAR5_MASKB; + regval |= SLCD_CHAR5_UPDATEB(segments[2]); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= SLCD_CHAR5_MASKB; + regval |= SLCD_CHAR5_UPDATEB(segments[3]); + putreg32(regval, STM32_LCD_RAM3L); + break; + + case 5: + regval = getreg32(STM32_LCD_RAM0L); + regval &= SLCD_CHAR6_MASK; + regval |= SLCD_CHAR6_UPDATEA(segments[0]); + putreg32(regval, STM32_LCD_RAM0L); + + regval = getreg32(STM32_LCD_RAM1L); + regval &= SLCD_CHAR6_MASK; + regval |= SLCD_CHAR6_UPDATEA(segments[1]); + putreg32(regval, STM32_LCD_RAM1L); + + regval = getreg32(STM32_LCD_RAM2L); + regval &= SLCD_CHAR6_MASK; + regval |= SLCD_CHAR6_UPDATEB(segments[2]); + putreg32(regval, STM32_LCD_RAM2L); + + regval = getreg32(STM32_LCD_RAM3L); + regval &= SLCD_CHAR6_MASK; + regval |= SLCD_CHAR6_UPDATEB(segments[3]); + putreg32(regval, STM32_LCD_RAM3L); + break; + + default: + return; + } + /* Set the UDR bit to transfer the updated data to the second level * buffer. */ - putreg32(1, LCD_SR_UDR_BB); + putreg32(1, SLCD_SR_UDR_BB); } /**************************************************************************** - * Name: lcd_read + * Name: slcd_writech ****************************************************************************/ -static ssize_t lcd_read(FAR struct file *filp, FAR char *buffer, size_t len) +static void slcd_writech(uint8_t ch, uint8_t curpos, uint8_t options) { + uint16_t bitset; + + /* Map the character code to a 16-bit encoded value */ + + bitset = slcd_mapch(ch); + + /* Check if the character should be decorated with a decimal point or colon */ + + if ((options & SCLD_DP) != 0) + { + bitset |= 0x0002; + } + else if ((options & SCLD_DP) != 0) + { + bitset |= 0x0020; + } + + /* Decode the value and write it to the SLCD segment memory */ + + slcd_writemem(bitset, curpos); + + /* Save these values in the state structure */ + + g_slcdstate.buffer[curpos] = ch; + g_slcdstate.options[curpos] = options; +} + +/**************************************************************************** + * Name: slcd_appendch + ****************************************************************************/ + +static void slcd_appendch(uint8_t ch, uint8_t options) +{ + /* Write the character at the current cursor position */ + + slcd_writech(ch, g_slcdstate.curpos, options); + if (g_slcdstate.curpos < (SLCD_NCHARS - 1)) + { + g_slcdstate.curpos++; + } } /**************************************************************************** - * Name: lcd_write + * Name: slcd_action ****************************************************************************/ -static ssize_t lcd_write(FAR struct file *filp, FAR const char *buffer, size_t len) +static void slcd_action(enum slcdcode_e code, uint8_t count) { + switch (code) + { + /* Erasure */ + + case SLCDCODE_BACKDEL: /* Backspace (backward delete) N characters */ + { + /* If we are at the home position, then ignore the action */ + + if (g_slcdstate.curpos < 1) + { + break; + } + + /* Otherwise, BACKDEL is like moving the cursor back one then doing a + * forward deletion. Decrement the cursor position and fall through. + */ + + g_slcdstate.curpos--; + } + + case SLCDCODE_FWDDEL: /* DELete (forward delete) N characters moving text */ + { + int i; + + /* Move all characters after the current cursor position left by one */ + + for (i = g_slcdstate.curpos + 1; i < SLCD_NCHARS - 1; i++) + { + slcd_writech(g_slcdstate.buffer[i-1], i, g_slcdstate.options[i-1]); + } + + /* Erase the last character on the display */ + + slcd_writech(' ', SLCD_NCHARS - 1, 0); + } + break; + + case SLCDCODE_ERASE: /* Erase N characters from the cursor position */ + { + int last; + int i; + + /* Get the last position to clear and make sure that the last + * position is on the SLCD. + */ + + last = g_slcdstate.curpos + count - 1; + if (last >= SLCD_NCHARS) + { + last = SLCD_NCHARS - 1; + } + + /* Erase N characters after the current cursor position left by one */ + + for (i = g_slcdstate.curpos; i < last; i++) + { + slcd_writech(' ', i, 0); + } + } + break; + + case SLCDCODE_CLEAR: /* Home the cursor and erase the entire display */ + { + /* This is like HOME followed by ERASEEOL. Home the cursor and + * fall through. + */ + + g_slcdstate.curpos = 0; + } + + case SLCDCODE_ERASEEOL: /* Erase from the cursor position to the end of line */ + { + int i; + + /* Erasecharacters after the current cursor position to the end of the line */ + + for (i = g_slcdstate.curpos; i < SLCD_NCHARS; i++) + { + slcd_writech(' ', i, 0); + } + } + break; + + /* Cursor movement */ + + case SLCDCODE_HOME: /* Cursor home */ + { + g_slcdstate.curpos = 0; + } + break; + + case SLCDCODE_END: /* Cursor end */ + { + g_slcdstate.curpos = SLCD_NCHARS - 1; + } + break; + + case SLCDCODE_LEFT: /* Cursor left by N characters */ + { + /* Don't permit movement past the beginning of the SLCD */ + + if (g_slcdstate.curpos > 0) + { + g_slcdstate.curpos--; + } + } + break; + + case SLCDCODE_RIGHT: /* Cursor right by N characters */ + { + /* Don't permit movement past the lcd of the SLCD */ + + if (g_slcdstate.curpos < (SLCD_NCHARS - 1)) + { + g_slcdstate.curpos++; + } + } + break; + + case SLCDCODE_UP: /* Cursor up by N lines */ + case SLCDCODE_DOWN: /* Cursor down by N lines */ + case SLCDCODE_PAGEUP: /* Cursor up by N pages */ + case SLCDCODE_PAGEDOWN: /* Cursor down by N pages */ + break; /* Not supportable on this SLCD */ + + /* Blinking */ + + case SLCDCODE_BLINKSTART: /* Start blinking with current cursor position */ + case SLCDCODE_BLINKEND: /* End blinking after the current cursor position */ + case SLCDCODE_BLINKOFF: /* Turn blinking off */ + break; /* Not implemented */ + + /* These are actually unreportable errors */ + + default: + case SLCDCODE_NORMAL: /* Not a special keycode */ + break; + } +} + +/**************************************************************************** + * Name: slcd_read + ****************************************************************************/ + +static ssize_t slcd_read(FAR struct file *filp, FAR char *buffer, size_t len) +{ + int ret = 0; + int i; + + for (i = 0; i < SLCD_NCHARS && ret < len; i++) + { + /* Return the character */ + + *buffer++ = g_slcdstate.buffer[i]; + ret++; + + /* Check if the character is decorated with a folling period or colon */ + + if (ret < len && g_slcdstate.buffer[i] != 0) + { + if ((g_slcdstate.buffer[i] & SCLD_DP) != 0) + { + *buffer++ = '.'; + ret++; + } + else if ((g_slcdstate.buffer[i] & SCLD_COLON) != 0) + { + *buffer++ = ':'; + ret++; + } + } + } + + return ret; +} + +/**************************************************************************** + * Name: slcd_write + ****************************************************************************/ + +static ssize_t slcd_write(FAR struct file *filp, + FAR const char *buffer, size_t len) +{ + struct slcd_instream_s instream; + struct slcdstate_s state; + enum slcdret_e result; + uint8_t ch; + uint8_t count; + uint8_t prev = ' '; + bool valid = false; + + /* Initialize the stream for use with the SLCD CODEC */ + + instream.stream.get = slcd_getstream; + instream.stream.nget = 0; + instream.buffer = buffer; + instream.nbytes = len; + + /* Prime the pump */ + + memset(&state, 0, sizeof(struct slcdstate_s)); + result = slcd_decode(&instream.stream, &state, &prev, &count); + switch (result) + { + case SLCDRET_CHAR: + valid = true; + break; + + case SLCDRET_SPEC: + { + slcd_action((enum slcdcode_e)prev, count); + prev = ' '; + } + break; + + case SLCDRET_EOF: + return 0; + } + + /* Now decode and process every byte in the input buffer */ + + while ((result = slcd_decode(&instream.stream, &state, &ch, &count)) != SLCDRET_EOF) + { + if (result == SLCDRET_CHAR) /* A normal character was returned */ + { + /* Check for ASCII control characters */ + + if (ch < ASCII_SPACE) + { + /* All are ignored except for backspace and carriage return */ + + if (ch == ASCII_BS) + { + slcd_action(SLCDCODE_BACKDEL, 1); + } + else if (ch == ASCII_CR) + { + slcd_action(SLCDCODE_HOME, 0); + } + } + + /* Handle characters decoreated with a period or a colon */ + + else if (ch == '.') + { + /* Write the previous character with the decimal point appended */ + + slcd_appendch(prev, SCLD_DP); + prev = ' '; + valid = false; + } + else if (ch == ':') + { + /* Write the previous character with the colon appended */ + + slcd_appendch(prev, SCLD_COLON); + prev = ' '; + valid = false; + } + + /* Handle ASCII_DEL */ + + else if (ch == ASCII_DEL) + { + slcd_action(SLCDCODE_FWDDEL, 1); + } + + /* The rest of the 7-bit ASCII characters are fair game */ + + else if (ch < 128) + { + /* Write the previous character if it valid */ + + if (valid) + { + slcd_appendch(prev, 0); + } + + /* There is now a valid output character */ + + prev = ch; + valid = true; + } + } + else /* (result == SLCDRET_SPEC) */ /* A special SLCD action was returned */ + { + slcd_action((enum slcdcode_e)ch, count); + } + } + + /* Handle any unfinished output */ + + if (valid) + { + slcd_appendch(prev, 0); + } + + /* Assume that the entire input buffer was processed */ + + return (ssize_t)len; } /**************************************************************************** - * Name: lcd_poll + * Name: slcd_poll ****************************************************************************/ #ifndef CONFIG_DISABLE_POLL -static int lcd_poll(FAR struct file *filp, FAR struct pollfd *fds, +static int slcd_poll(FAR struct file *filp, FAR struct pollfd *fds, bool setup) { if (setup) @@ -256,14 +1098,15 @@ static int lcd_poll(FAR struct file *filp, FAR struct pollfd *fds, ****************************************************************************/ /**************************************************************************** - * Name: stm32_lcd_initialize + * Name: stm32_slcd_initialize * * Description: - * Initialize the LCD1602 hardware and register the character driver. + * Initialize the STM32L-Discovery hardware and register the character + * driver. * ****************************************************************************/ -int stm32_lcd_initialize(void) +int stm32_slcd_initialize(void) { uint32_t regval; int ret = OK; @@ -271,15 +1114,15 @@ int stm32_lcd_initialize(void) /* Only initialize the driver once. */ - if (!g_lcdops.initialized) + if (!g_slcdstate.initialized) { lcdvdbg("Initializing\n"); /* Configure LCD GPIO pins */ - for (i = 0; i < BOARD_LCD_NGPIOS; i++); + for (i = 0; i < BOARD_SLCD_NGPIOS; i++) { - stm32_configgpio(g_lcdgpio[i]); + stm32_configgpio(g_slcdgpio[i]); } /* Set the LCD prescaler and divider values */ @@ -329,7 +1172,7 @@ int stm32_lcd_initialize(void) /* Enable LCD peripheral */ - putreg32(1, LCD_CR_LCDEN_BB); + putreg32(1, SLCD_CR_LCDEN_BB); /* Wait Until the LCD is enabled and the LCD booster is ready */ @@ -344,12 +1187,12 @@ int stm32_lcd_initialize(void) /* Register the LCD device driver */ - ret = register_driver("/dev/slcd", &g_lcdops, 0644, &g_lcdops); - g_lcdops.initialized = true; + ret = register_driver("/dev/slcd", &g_slcdops, 0644, (FAR struct file_operations *)&g_slcdops); + g_slcdstate.initialized = true; /* Then clear the display */ - lcd_clear(); + slcd_clear(); } return ret; diff --git a/configs/stm32ldiscovery/src/stm32ldiscovery.h b/configs/stm32ldiscovery/src/stm32ldiscovery.h index 36a48b9982f..7d5c10988ed 100644 --- a/configs/stm32ldiscovery/src/stm32ldiscovery.h +++ b/configs/stm32ldiscovery/src/stm32ldiscovery.h @@ -186,38 +186,38 @@ * PC11 LCD_SEG41 LCD SEG23 */ -#define BOARD_LCD_COM0 GPIO_LCD_COM0 /* PA8 */ -#define BOARD_LCD_COM1 GPIO_LCD_COM1 /* PA9 */ -#define BOARD_LCD_COM2 GPIO_LCD_COM2 /* PA10 */ -#define BOARD_LCD_COM3 GPIO_LCD_COM3 /* PB9 */ -#define BOARD_LCD_SEG0 GPIO_LCD_SEG0 /* PA1 */ -#define BOARD_LCD_SEG1 GPIO_LCD_SEG1 /* PA2 */ -#define BOARD_LCD_SEG2 GPIO_LCD_SEG2 /* PA3 */ -#define BOARD_LCD_SEG3 GPIO_LCD_SEG7 /* PB3 */ -#define BOARD_LCD_SEG4 GPIO_LCD_SEG8 /* PB4 */ -#define BOARD_LCD_SEG5 GPIO_LCD_SEG9 /* PB5 */ -#define BOARD_LCD_SEG6 GPIO_LCD_SEG10 /* PB10 */ -#define BOARD_LCD_SEG7 GPIO_LCD_SEG11 /* PB11 */ -#define BOARD_LCD_SEG8 GPIO_LCD_SEG12 /* PB12 */ -#define BOARD_LCD_SEG9 GPIO_LCD_SEG13 /* PB13 */ -#define BOARD_LCD_SEG10 GPIO_LCD_SEG14 /* PB14 */ -#define BOARD_LCD_SEG11 GPIO_LCD_SEG15 /* PB15 */ -#define BOARD_LCD_SEG12 GPIO_LCD_SEG17 /* PA15 */ -#define BOARD_LCD_SEG13 GPIO_LCD_SEG16 /* PB8 */ -#define BOARD_LCD_SEG14 GPIO_LCD_SEG18 /* PC0 */ -#define BOARD_LCD_SEG15 GPIO_LCD_SEG19 /* PC1 */ -#define BOARD_LCD_SEG16 GPIO_LCD_SEG20 /* PC2 */ -#define BOARD_LCD_SEG17 GPIO_LCD_SEG21 /* PC3 */ -#define BOARD_LCD_SEG18 GPIO_LCD_SEG24 /* PC6 */ -#define BOARD_LCD_SEG19 GPIO_LCD_SEG25 /* PC7 */ -#define BOARD_LCD_SEG20 GPIO_LCD_SEG26 /* PC8 */ -#define BOARD_LCD_SEG21 GPIO_LCD_SEG27 /* PC9 */ -#define BOARD_LCD_SEG22 GPIO_LCD_SEG40 /* PC10 */ -#define BOARD_LCD_SEG23 GPIO_LCD_SEG41 /* PC11 */ +#define BOARD_SLCD_COM0 GPIO_LCD_COM0 /* PA8 */ +#define BOARD_SLCD_COM1 GPIO_LCD_COM1 /* PA9 */ +#define BOARD_SLCD_COM2 GPIO_LCD_COM2 /* PA10 */ +#define BOARD_SLCD_COM3 GPIO_LCD_COM3 /* PB9 */ +#define BOARD_SLCD_SEG0 GPIO_LCD_SEG0 /* PA1 */ +#define BOARD_SLCD_SEG1 GPIO_LCD_SEG1 /* PA2 */ +#define BOARD_SLCD_SEG2 GPIO_LCD_SEG2 /* PA3 */ +#define BOARD_SLCD_SEG3 GPIO_LCD_SEG7 /* PB3 */ +#define BOARD_SLCD_SEG4 GPIO_LCD_SEG8 /* PB4 */ +#define BOARD_SLCD_SEG5 GPIO_LCD_SEG9 /* PB5 */ +#define BOARD_SLCD_SEG6 GPIO_LCD_SEG10 /* PB10 */ +#define BOARD_SLCD_SEG7 GPIO_LCD_SEG11 /* PB11 */ +#define BOARD_SLCD_SEG8 GPIO_LCD_SEG12 /* PB12 */ +#define BOARD_SLCD_SEG9 GPIO_LCD_SEG13 /* PB13 */ +#define BOARD_SLCD_SEG10 GPIO_LCD_SEG14 /* PB14 */ +#define BOARD_SLCD_SEG11 GPIO_LCD_SEG15 /* PB15 */ +#define BOARD_SLCD_SEG12 GPIO_LCD_SEG17 /* PA15 */ +#define BOARD_SLCD_SEG13 GPIO_LCD_SEG16 /* PB8 */ +#define BOARD_SLCD_SEG14 GPIO_LCD_SEG18 /* PC0 */ +#define BOARD_SLCD_SEG15 GPIO_LCD_SEG19 /* PC1 */ +#define BOARD_SLCD_SEG16 GPIO_LCD_SEG20 /* PC2 */ +#define BOARD_SLCD_SEG17 GPIO_LCD_SEG21 /* PC3 */ +#define BOARD_SLCD_SEG18 GPIO_LCD_SEG24 /* PC6 */ +#define BOARD_SLCD_SEG19 GPIO_LCD_SEG25 /* PC7 */ +#define BOARD_SLCD_SEG20 GPIO_LCD_SEG26 /* PC8 */ +#define BOARD_SLCD_SEG21 GPIO_LCD_SEG27 /* PC9 */ +#define BOARD_SLCD_SEG22 GPIO_LCD_SEG40 /* PC10 */ +#define BOARD_SLCD_SEG23 GPIO_LCD_SEG41 /* PC11 */ -#define BOARD LCD_NCOM 4 -#define BOARD LCD_NSEG 24 -#define BOARD_LCD_NGPIOS 28 +#define BOARD_SLCD_NCOM 4 +#define BOARD_SLCD_NSEG 24 +#define BOARD_SLCD_NGPIOS 28 /**************************************************************************************************** * Public Types diff --git a/include/nuttx/ascii.h b/include/nuttx/ascii.h index bfecff520f3..090d7a49a71 100644 --- a/include/nuttx/ascii.h +++ b/include/nuttx/ascii.h @@ -150,8 +150,8 @@ #define ASCII_LBRACKET 0x5b /* Left bracket ([) */ #define ASCII_BACKSLASH 0x5c /* Back slash (\) */ #define ASCII_RBRACKET 0x5d /* Right bracket (]) */ -#define ASCII_CARET 0x5c /* Caret (^) */ -#define ASCII_CIRCUMFLEX 0x5c /* Circumflex (^) */ +#define ASCII_CARET 0x5e /* Caret (^) */ +#define ASCII_CIRCUMFLEX 0x5e /* Circumflex (^) */ #define ASCII_UNDERSCORE 0x5f /* Underscore (_) */ #define ASCII_RSQUOT 0x60 /* Closing single quote */ diff --git a/include/nuttx/lcd/slcd_codec.h b/include/nuttx/lcd/slcd_codec.h index a4379671848..4a9ff312d35 100644 --- a/include/nuttx/lcd/slcd_codec.h +++ b/include/nuttx/lcd/slcd_codec.h @@ -66,8 +66,8 @@ enum slcdcode_e * ASCII BKSP and DEL values. */ - SLCDCODE_FWDDEL, /* DELete (forward delete) N characters moving cursor */ - SLCDCODE_BACKDEL, /* Backspace (backward delete) N characters */ + SLCDCODE_FWDDEL, /* DELete (forward delete) N characters moving text */ + SLCDCODE_BACKDEL, /* Backspace (backward delete) N characters moving cursor */ SLCDCODE_ERASE, /* Erase N characters from the cursor position */ SLCDCODE_ERASEEOL, /* Erase from the cursor position to the end of line */ SLCDCODE_CLEAR, /* Home the cursor and erase the entire display */ diff --git a/libc/misc/lib_slcddecode.c b/libc/misc/lib_slcddecode.c index 05e883f8822..04e9e569e3a 100644 --- a/libc/misc/lib_slcddecode.c +++ b/libc/misc/lib_slcddecode.c @@ -330,19 +330,21 @@ enum slcdret_e slcd_decode(FAR struct lib_instream_s *stream, return slcd_reget(state, pch, parg); } + /* Put the character in the reget buffer because there is on more way + * that we can fail. + */ + + state->buf[NDX_CODE5] = (uint8_t)ch; + state->nch = NCH_CODE5; + /* Verify the special CLCD action code */ if (ch < (int)FIRST_SLCDCODE || ch > (int)LAST_SLCDCODE) { - /* Not a special command code.. put the character in the reget - * buffer. + /* Not a special command code. Return the ESC now and the rest + * of the characters later. */ - state->buf[NDX_CODE5] = (uint8_t)ch; - state->nch = NCH_CODE5; - - /* Return the ESC now and the next two characters later. */ - return slcd_reget(state, pch, parg); } @@ -351,6 +353,15 @@ enum slcdret_e slcd_decode(FAR struct lib_instream_s *stream, code = CODE_RETURN(ch); count = slcd_nibble(state->buf[NDX_COUNTH]) << 4; slcd_nibble(state->buf[NDX_COUNTL]); + + /* All count values must be greater than 0 or something is wrong */ + + if (count < 1) + { + /* Return the ESC now and the rest of the characters later. */ + + return slcd_reget(state, pch, parg); + } } /* We have successfully parsed the the entire escape sequence. Return the