2019-06-18 13:53:01 +02:00
/** library to communication with Hitacho HD44780 LCD controller
* @ file
* @ author King Kévin < kingkevin @ cuvoodoo . info >
2020-06-06 14:35:55 +02:00
* @ copyright SPDX - License - Identifier : GPL - 3.0 - or - later
2020-02-13 14:23:11 +01:00
* @ date 2019 - 2020
2019-06-18 13:53:01 +02:00
* @ note peripherals used : GPIO @ ref lcd_hd44780_gpio
*/
/* standard libraries */
# include <stdint.h> // standard integer types
# include <stdlib.h> // general utilities
# include <stdbool.h> // boolean utilities
/* STM32 (including CM3) libraries */
# include <libopencmsis/core_cm3.h> // Cortex M3 utilities
# include <libopencm3/stm32/rcc.h> // real-time control clock library
# include <libopencm3/stm32/gpio.h> // general purpose input output library
/* own libraries */
# include "global.h" // common methods
# include "lcd_hd44780.h" // own definitions
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
# include "i2c_master.h" // I²C utilities
# endif
2019-06-18 13:53:01 +02:00
/** include busy time waiting in writes
2019-12-12 18:58:04 +01:00
* @ note this removes the need to call lcd_hd44780_wait_busy but prevents you to do something else meanwhile , particularly when reading is enabled
* @ note because I ² C is already slow enough , there is no need to wait further
2019-06-18 13:53:01 +02:00
*/
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
# define LCD_HD44780_BUSY_WAIT_INCLUDE 1 // lcd_hd44780_wait_busy works, but the I²C bus is often slower
# else // LCD_HD44780_I2C
# define LCD_HD44780_BUSY_WAIT_INCLUDE 1 // you can change this value
# endif // LCD_HD44780_I2C
2019-06-18 13:53:01 +02:00
/** busy wait time for most short writes (37 us with margin) */
# define LCD_HD44780_BUSY_WAIT_SHORT (37 + 5)
/** busy wait time for some long writes (1520 us, but experience shows it's more)
* @ note I have no idea why , but longer times increase the contrast darkness
*/
# define LCD_HD44780_BUSY_WAIT_LONG (1520 + 500)
/* usual HD44780 pinout:
* - 1 GND : ground
* - 2 VCC : 5 V ( 3.3 V versions also exist , but a less common )
* - 3 V0 : LCD bias voltage , connect to 10 - 20 k potentiometer ( VCC to GND )
* - 4 RS : Register Select ( high = data , low = instruction )
* - 5 R / W : Read / Write ( high = read , low = write )
* - 6 E : enable ( falling edge to latch data , high to output register )
* - 7 DB0 : Data Bit 0 ( for 8 - bit transfer )
* - 8 DB1 : Data Bit 1 ( for 8 - bit transfer )
* - 9 DB2 : Data Bit 2 ( for 8 - bit transfer )
* - 10 DB3 : Data Bit 3 ( for 8 - bit transfer )
* - 11 DB4 : Data Bit 4 ( for 4 - bit transfer )
* - 12 DB5 : Data Bit 5 ( for 4 - bit transfer )
* - 13 DB6 : Data Bit 6 ( for 4 - bit transfer )
* - 14 DB7 : Data Bit 7 ( for 4 - bit transfer )
* - 15 BLA : Backlight Anode
* - 16 BLK : Backlight Cathode
*/
2019-12-12 18:58:04 +01:00
/** @defgroup lcd_hd44780_signals HD44780 signals
* @ note can be combined using OR
* @ {
*/
# define LCD_HD44780_RS (1 << 0) /**< RS : Register Select (high = data, low = instruction) */
# define LCD_HD44780_RnW (1 << 1) /**< R/W: Read/Write (high = read, low = write) */
# define LCD_HD44780_E (1 << 2) /**< enable (falling edge to latch data, high to output register) */
# define LCD_HD44780_DB0 (1 << 3) /**< Data Bit 0 */
# define LCD_HD44780_DB1 (1 << 4) /**< Data Bit 1 */
# define LCD_HD44780_DB2 (1 << 5) /**< Data Bit 2 */
# define LCD_HD44780_DB3 (1 << 6) /**< Data Bit 3 */
# define LCD_HD44780_DB4 (1 << 7) /**< Data Bit 4 */
# define LCD_HD44780_DB5 (1 << 8) /**< Data Bit 5 */
# define LCD_HD44780_DB6 (1 << 9) /**< Data Bit 6 */
# define LCD_HD44780_DB7 (1 << 10) /**< Data Bit 7 */
# define LCD_HD44780_LED (1 << 11) /**< Backlight Cathode */
/** @} */
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
/* I²C backpack PCF8574 GPIO expander pinout:
* - P0 : RS
* - P1 : RnW
* - P2 : E
* - P3 : LED
* - P4 : D4
* - P5 : D5
* - P6 : D6
* - P7 : D7
*/
/** register select */
# define LCD_HD44780_I2C_RS (1 << 0)
/** select read or write */
# define LCD_HD44780_I2C_RnW (1 << 1)
/** enable pin */
# define LCD_HD44780_I2C_E (1 << 2)
/** enable LED backlight */
# define LCD_HD44780_I2C_LED (1 << 3)
/** data bit 4 */
# define LCD_HD44780_I2C_DB4 (1 << 4)
/** data bit 5 */
# define LCD_HD44780_I2C_DB5 (1 << 5)
/** data bit 6 */
# define LCD_HD44780_I2C_DB6 (1 << 6)
/** data bit 7 */
# define LCD_HD44780_I2C_DB7 (1 << 7)
/** I²C peripheral base address */
# define LCD_HD44780_I2C_PERIPH I2C1
/** I2C address of I²C backpack adapter (7 bits are LSB) */
uint8_t lcd_hd44780_i2c_addr = 0x3f ; // default PCF8574A I²C backpack slave address
/** I2C GPIO output state */
static uint8_t lcd_hd44780_i2c_output = 0xff ;
# else // LCD_HD44780_I2C
2019-06-18 13:53:01 +02:00
/** @defgroup lcd_hd44780_gpio GPIO used to control the HD44780
* @ {
*/
2019-06-18 16:20:24 +02:00
/** register select
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
2019-06-18 16:20:24 +02:00
*/
2019-12-12 18:58:04 +01:00
# define LCD_HD44780_GPIO_RS PB9
/** pin allowing writing data bits (on low) or reading them (on high)
* @ note remove definition if tied to ground
* @ note this enables read back data , but more importantly read the busy flag to know when the controller finished processing the command . Tying R / nW to ground instead of a GPIO saves a pin , but no data can be read back . Also every command needs to wait a minimum time before being able to send the next one , even if the controlled might actually already have processed it and is not busy anymore .
2019-06-18 16:20:24 +02:00
* @ note is pulled up by HD44780
*/
2019-12-12 18:58:04 +01:00
# define LCD_HD44780_GPIO_RnW PB10
2019-06-18 16:20:24 +02:00
/** enable pin
* @ warning needs an external 10 k pull - up resistor
*/
# define LCD_HD44780_GPIO_E PB11
2019-12-12 18:58:04 +01:00
/** data bit 7
* @ note pulled up by HD44780
2019-06-18 16:20:24 +02:00
*/
# define LCD_HD44780_GPIO_DB7 PB12
/** data bit 6
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
2019-06-18 16:20:24 +02:00
*/
# define LCD_HD44780_GPIO_DB6 PB13
/** data bit 5
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
2019-06-18 16:20:24 +02:00
*/
# define LCD_HD44780_GPIO_DB5 PB14
/** data bit 4
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
2019-06-18 16:20:24 +02:00
*/
# define LCD_HD44780_GPIO_DB4 PB15
/** data bit 3
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
* @ note leave undefined when only 4 - bit mode is used
2019-06-18 16:20:24 +02:00
*/
2019-12-12 18:58:04 +01:00
//#define LCD_HD44780_GPIO_DB3 P
2019-06-18 16:20:24 +02:00
/** data bit 2
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
* @ note leave undefined when only 4 - bit mode is used
2019-06-18 16:20:24 +02:00
*/
2019-12-12 18:58:04 +01:00
//#define LCD_HD44780_GPIO_DB2 P
2019-06-18 16:20:24 +02:00
/** data bit 1
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
* @ note leave undefined when only 4 - bit mode is used
2019-06-18 16:20:24 +02:00
*/
2019-12-12 18:58:04 +01:00
//#define LCD_HD44780_GPIO_DB1 P
2019-06-18 16:20:24 +02:00
/** data bit 0
2019-12-12 18:58:04 +01:00
* @ note pulled up by HD44780
* @ note leave undefined when only 4 - bit mode is used
2019-06-18 16:20:24 +02:00
*/
2019-12-12 18:58:04 +01:00
//#define LCD_HD44780_GPIO_DB0 P
2019-06-18 13:53:01 +02:00
/** @} */
2019-12-12 18:58:04 +01:00
# endif // LCD_HD44780_I2C
2019-06-18 13:53:01 +02:00
2019-12-12 18:58:04 +01:00
/** set for 8-bit interface data
* @ note I ² C implies 4 - bit
*/
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
# define LCD_HD44780_INTERFACE_DL 0
# elif defined(LCD_HD44780_GPIO_DB3) && defined(LCD_HD44780_GPIO_DB2) && defined(LCD_HD44780_GPIO_DB1) && defined(LCD_HD44780_GPIO_DB0)
# define LCD_HD44780_INTERFACE_DL 1
# else
# define LCD_HD44780_INTERFACE_DL 0
2019-12-12 18:58:04 +01:00
# endif
2019-06-18 13:53:01 +02:00
/** if the display is configured having 2 lines */
static bool lcd_hd44780_n_2lines = true ;
2019-12-12 18:58:04 +01:00
/** set signals
* @ param [ in ] signals
2019-06-18 13:53:01 +02:00
*/
2019-12-12 18:58:04 +01:00
static void lcd_hd44780_set_signal ( uint16_t signals )
2019-06-18 13:53:01 +02:00
{
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
if ( signals & LCD_HD44780_RS ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_RS ;
}
if ( signals & LCD_HD44780_RnW ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_RnW ;
}
if ( signals & LCD_HD44780_E ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_E ;
}
if ( signals & LCD_HD44780_DB4 ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_DB4 ;
}
if ( signals & LCD_HD44780_DB5 ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_DB5 ;
}
if ( signals & LCD_HD44780_DB6 ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_DB6 ;
}
if ( signals & LCD_HD44780_DB7 ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_DB7 ;
}
if ( signals & LCD_HD44780_LED ) {
lcd_hd44780_i2c_output | = LCD_HD44780_I2C_LED ;
}
# else // LCD_HD44780_I2C
if ( signals & LCD_HD44780_RS ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_RS ) , GPIO_PIN ( LCD_HD44780_GPIO_RS ) ) ;
}
# ifdef LCD_HD44780_GPIO_RnW
if ( signals & LCD_HD44780_RnW ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_RnW ) , GPIO_PIN ( LCD_HD44780_GPIO_RnW ) ) ;
}
# endif // LCD_HD44780_GPIO_RnW
if ( signals & LCD_HD44780_E ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_E ) , GPIO_PIN ( LCD_HD44780_GPIO_E ) ) ;
2019-06-18 13:53:01 +02:00
}
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-12-12 18:58:04 +01:00
if ( signals & LCD_HD44780_DB0 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB0 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB0 ) ) ;
}
if ( signals & LCD_HD44780_DB1 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB1 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB1 ) ) ;
}
if ( signals & LCD_HD44780_DB2 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB2 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB2 ) ) ;
}
if ( signals & LCD_HD44780_DB3 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB3 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB3 ) ) ;
}
# endif // LCD_HD44780_INTERFACE_DL
if ( signals & LCD_HD44780_DB4 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ;
}
if ( signals & LCD_HD44780_DB5 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ;
}
if ( signals & LCD_HD44780_DB6 ) {
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ;
2019-12-12 18:58:04 +01:00
}
if ( signals & LCD_HD44780_DB7 ) {
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ;
}
if ( signals & LCD_HD44780_LED ) {
// no LED GPIO defined
}
# endif // LCD_HD44780_I2C
}
/** clear signals
* @ param [ in ] signals
*/
static void lcd_hd44780_clear_signal ( uint16_t signals )
{
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
if ( signals & LCD_HD44780_RS ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_RS ;
}
if ( signals & LCD_HD44780_RnW ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_RnW ;
}
if ( signals & LCD_HD44780_E ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_E ;
}
if ( signals & LCD_HD44780_DB4 ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_DB4 ;
}
if ( signals & LCD_HD44780_DB5 ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_DB5 ;
}
if ( signals & LCD_HD44780_DB6 ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_DB6 ;
}
if ( signals & LCD_HD44780_DB7 ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_DB7 ;
}
if ( signals & LCD_HD44780_LED ) {
lcd_hd44780_i2c_output & = ~ LCD_HD44780_I2C_LED ;
}
# else // LCD_HD44780_I2C
if ( signals & LCD_HD44780_RS ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_RS ) , GPIO_PIN ( LCD_HD44780_GPIO_RS ) ) ;
}
# ifdef LCD_HD44780_GPIO_RnW
if ( signals & LCD_HD44780_RnW ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_RnW ) , GPIO_PIN ( LCD_HD44780_GPIO_RnW ) ) ;
}
# endif // LCD_HD44780_GPIO_RnW
if ( signals & LCD_HD44780_E ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_E ) , GPIO_PIN ( LCD_HD44780_GPIO_E ) ) ;
}
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-12-12 18:58:04 +01:00
if ( signals & LCD_HD44780_DB0 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB0 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB0 ) ) ;
}
if ( signals & LCD_HD44780_DB1 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB1 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB1 ) ) ;
}
if ( signals & LCD_HD44780_DB2 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB2 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB2 ) ) ;
}
if ( signals & LCD_HD44780_DB3 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB3 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB3 ) ) ;
}
# endif // LCD_HD44780_INTERFACE_DL
if ( signals & LCD_HD44780_DB4 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ;
}
if ( signals & LCD_HD44780_DB5 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ;
}
if ( signals & LCD_HD44780_DB6 ) {
2020-02-13 14:23:11 +01:00
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ;
2019-12-12 18:58:04 +01:00
}
if ( signals & LCD_HD44780_DB7 ) {
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ;
}
if ( signals & LCD_HD44780_LED ) {
// no LED GPIO defined
}
# endif // LCD_HD44780_I2C
}
/** flush the set and cleared signals
* @ note this only applies to I ² C and helps gain time
*/
static void lcd_hd44780_flush_signal ( void )
{
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
i2c_master_slave_write ( LCD_HD44780_I2C_PERIPH , lcd_hd44780_i2c_addr , false , & lcd_hd44780_i2c_output , 1 ) ; // write the set signals
2019-06-18 13:53:01 +02:00
# endif
2019-12-12 18:58:04 +01:00
}
/** read from controller
* @ param [ in ] data read data ( true ) or busy flag and address counter ( false )
* @ return data / AC read
*/
static uint8_t lcd_hd44780_read ( bool data )
{
# if defined(LCD_HD44780_GPIO_RnW) || defined(LCD_HD44780_I2C)
lcd_hd44780_set_signal ( LCD_HD44780_RnW | LCD_HD44780_DB7 | LCD_HD44780_DB6 | LCD_HD44780_DB5 | LCD_HD44780_DB4 ) ; // switch DB direction to input to read data
if ( data ) {
lcd_hd44780_set_signal ( LCD_HD44780_RS ) ; // set high to read data
} else {
lcd_hd44780_clear_signal ( LCD_HD44780_RS ) ; // set low to read busy flag and AC
}
lcd_hd44780_flush_signal ( ) ;
// no need to wait tAS = 40 ns before next step since the instructions are slower
lcd_hd44780_set_signal ( LCD_HD44780_E ) ; // set high to have data output
lcd_hd44780_flush_signal ( ) ;
sleep_us ( 0 ) ; // wait t_DDR = 160 ns before reading
// read data bits
uint8_t input = 0 ; // to store read data
# if defined(LCD_HD44780_I2C)
uint8_t i2c_data ;
if ( I2C_MASTER_RC_NONE = = i2c_master_slave_read ( LCD_HD44780_I2C_PERIPH , lcd_hd44780_i2c_addr , false , & i2c_data , 1 ) ) {
if ( i2c_data & LCD_HD44780_I2C_DB7 ) {
input | = 0x80 ;
}
if ( i2c_data & LCD_HD44780_I2C_DB6 ) {
input | = 0x40 ;
}
if ( i2c_data & LCD_HD44780_I2C_DB5 ) {
input | = 0x20 ;
}
if ( i2c_data & LCD_HD44780_I2C_DB4 ) {
input | = 0x10 ;
}
}
# else // LCD_HD44780_I2C
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ) {
input | = 0x80 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ) {
input | = 0x40 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ) {
input | = 0x20 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ) {
input | = 0x10 ;
2019-06-18 13:53:01 +02:00
}
2019-12-12 18:58:04 +01:00
# endif // LCD_HD44780_I2C
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-12-12 18:58:04 +01:00
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB3 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB3 ) ) ) {
input | = 0x08 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB2 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB2 ) ) ) {
input | = 0x04 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB1 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB1 ) ) ) {
input | = 0x02 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB0 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB0 ) ) ) {
input | = 0x01 ;
}
# else // LCD_HD44780_INTERFACE_DL
// get second nibble
// don't wait PW_EH = 230 ns since reading took longer
lcd_hd44780_clear_signal ( LCD_HD44780_E ) ; // end current data read
lcd_hd44780_flush_signal ( ) ;
sleep_us ( 1 ) ; // wait t_cycE = 500 ns
lcd_hd44780_set_signal ( LCD_HD44780_E ) ; // have next data output
lcd_hd44780_flush_signal ( ) ;
sleep_us ( 0 ) ; // wait t_DDR = 160 ns before reading
// read second nibble
# if defined(LCD_HD44780_I2C)
if ( I2C_MASTER_RC_NONE = = i2c_master_slave_read ( LCD_HD44780_I2C_PERIPH , lcd_hd44780_i2c_addr , false , & i2c_data , 1 ) ) {
if ( i2c_data & LCD_HD44780_I2C_DB7 ) {
input | = 0x08 ;
}
if ( i2c_data & LCD_HD44780_I2C_DB6 ) {
input | = 0x04 ;
}
if ( i2c_data & LCD_HD44780_I2C_DB5 ) {
input | = 0x02 ;
}
if ( i2c_data & LCD_HD44780_I2C_DB4 ) {
input | = 0x01 ;
}
}
# else // LCD_HD44780_I2C
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ) {
input | = 0x80 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ) {
input | = 0x40 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ) {
input | = 0x20 ;
}
if ( gpio_get ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ) {
input | = 0x10 ;
}
# endif // LCD_HD44780_I2C
# endif // LCD_HD44780_INTERFACE_DL
// don't wait PW_EH = 230 ns since reading took longer
lcd_hd44780_clear_signal ( LCD_HD44780_E ) ; // end data read
lcd_hd44780_flush_signal ( ) ;
return input ;
# else // LCD_HD44780_GPIO_RnW || LCD_HD44780_I2C
return 0 ; // read is not supported
# endif
}
uint8_t lcd_hd44780_read_data ( void )
{
return lcd_hd44780_read ( true ) ;
2019-06-18 13:53:01 +02:00
}
/** write to controller
* @ param [ in ] command true if it is an command , false if it is data
* @ param [ in ] data data bit to write
2019-12-12 18:58:04 +01:00
* @ param [ in ] first_nibble_only if only the first nibble of the data should be written ( only applies to 4 - bit mode )
2019-06-18 13:53:01 +02:00
*/
static void lcd_hd44780_write ( bool command , uint8_t data , bool first_nibble_only )
{
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_RnW ) ; // switch DB direction to output to write data
2019-06-18 13:53:01 +02:00
if ( command ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_RS ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_RS ) ;
2019-06-18 13:53:01 +02:00
}
2019-12-12 18:58:04 +01:00
lcd_hd44780_flush_signal ( ) ;
2019-06-18 13:53:01 +02:00
// no need to wait tAS = 40 ns before next step since the instructions are slower
// write data
if ( data & 0x80 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB7 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB7 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x40 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB6 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB6 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x20 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB5 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB5 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x10 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB4 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB4 ) ;
2019-06-18 13:53:01 +02:00
}
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
if ( data & 0x08 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB3 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB3 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x04 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB2 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB2 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x02 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB1 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB1 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x01 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB0 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB0 ) ;
2019-06-18 13:53:01 +02:00
}
2019-12-12 18:58:04 +01:00
# else // LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
if ( ! first_nibble_only ) { // write second nibble
// pulse E to send data
sleep_us ( 1 ) ; // wait t_cycE = 500 ns
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_E ) ; // set high change output data
lcd_hd44780_flush_signal ( ) ;
2019-06-18 13:53:01 +02:00
sleep_us ( 1 ) ; // wait PW_EH = 230 ns
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_E ) ; // set low to latch data
lcd_hd44780_flush_signal ( ) ;
2019-06-18 13:53:01 +02:00
// no need to wait t_H = 10 ns before next step since next instructions are slower
// send second nibble
if ( data & 0x08 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB7 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB7 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x04 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB6 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB6 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x02 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB5 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB5 ) ;
2019-06-18 13:53:01 +02:00
}
if ( data & 0x01 ) {
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_DB4 ) ;
2019-06-18 13:53:01 +02:00
} else {
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_DB4 ) ;
2019-06-18 13:53:01 +02:00
}
}
2019-12-12 18:58:04 +01:00
# endif // LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
// pulse E to send data
sleep_us ( 1 ) ; // wait t_cycE = 500 ns
2019-12-12 18:58:04 +01:00
lcd_hd44780_set_signal ( LCD_HD44780_E ) ; // set high change output data
lcd_hd44780_flush_signal ( ) ;
2019-06-18 13:53:01 +02:00
sleep_us ( 1 ) ; // wait PW_EH = 230 ns
2019-12-12 18:58:04 +01:00
lcd_hd44780_clear_signal ( LCD_HD44780_E ) ; // set low to latch data
lcd_hd44780_flush_signal ( ) ;
2019-06-18 13:53:01 +02:00
// no need to wait t_H = 10 ns before next step since next instructions are slower
// no need to wait t_AH = 10 ns before next step since next instructions are slower
}
2019-12-12 18:58:04 +01:00
/** wait until controller is not busy anymore
* @ param [ in ] timeout maximum time to wait in us
* @ return address count , or > = 0x80 if timeout expired
*/
static uint8_t lcd_hd44780_wait_busy ( uint16_t timeout )
{
# if defined(LCD_HD44780_GPIO_RnW)
uint8_t ac = 0x80 ; // address counter to return
while ( timeout & & ( ( ac = lcd_hd44780_read ( false ) ) > = 0x80 ) ) { // wait until busy flag is low or timeout
// wait a bit
sleep_us ( 100 ) ;
if ( timeout > 100 ) {
timeout - = 100 ;
} else {
timeout = 0 ;
}
}
return ac ;
# else // I²C is also to slow to read (at least 6400 us per read)
sleep_us ( timeout ) ; // just wait
return 0 ;
# endif
}
2019-06-18 13:53:01 +02:00
/** write function set command
* @ param [ in ] dl_8bit 8 - bit ( true ) or 4 - bit ( false ) data length
* @ param [ in ] n_2lines 2 ( true ) or 1 ( false ) lines
* @ param [ in ] f_5x10 5 x10 ( true ) or 5 x8 ( false ) dots font
*/
static void lcd_hd44780_function_set ( bool dl_8bit , bool n_2lines , bool f_5x10 )
{
uint8_t data = 0x20 ;
if ( dl_8bit ) {
data | = 0x10 ;
}
if ( n_2lines ) {
data | = 0x08 ;
}
if ( f_5x10 ) {
data | = 0x04 ;
}
lcd_hd44780_write ( true , data , false ) ;
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
}
2019-12-12 18:58:04 +01:00
bool lcd_hd44780_setup ( bool n_2lines , bool f_5x10 )
2019-06-18 13:53:01 +02:00
{
2019-12-12 18:58:04 +01:00
sleep_ms ( 40 + 2 ) ; // wait for display to initialise after power on: 15 ms for VCC > 4.5 V, 40 ms for VCC > 2.7 V
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
// configure I²C peripheral
if ( ! i2c_master_check_signals ( LCD_HD44780_I2C_PERIPH ) ) { // check if there are pull-ups to operator I²C
return false ;
}
i2c_master_setup ( LCD_HD44780_I2C_PERIPH , 100 ) ; // setup I²C bus (PCF8574 supports an I²C clock up to 100 kHz)
lcd_hd44780_i2c_output = 0xff ; // put GPIO to input (sort of open drain output)
if ( I2C_MASTER_RC_NONE ! = i2c_master_slave_write ( LCD_HD44780_I2C_PERIPH , lcd_hd44780_i2c_addr , false , & lcd_hd44780_i2c_output , 1 ) ) { // check if the device is present and set inputs
return false ;
}
# else // LCD_HD44780_I2C
// enable all GPIO
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_E ) ) ; // enable clock for GPIO port
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_E ) , GPIO_PIN ( LCD_HD44780_GPIO_E ) ) ; // start idle low
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_E ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_E ) ) ; // set GPIO as output
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB7 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ; // open drain allows to read and write
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB6 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ; // open drain allows to read and write
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB5 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ; // open drain allows to read and write
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB4 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ; // open drain allows to read and write
2020-02-13 14:23:11 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB3 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB3 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB3 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB3 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB3 ) ) ; // open drain allows to read and write
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB2 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB2 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB2 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB2 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB2 ) ) ; // open drain allows to read and write
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB1 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB1 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB1 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB1 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB1 ) ) ; // open drain allows to read and write
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_DB0 ) ) ; // enable clock for GPIO port
2020-02-13 14:23:11 +01:00
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_DB0 ) , GPIO_PIN ( LCD_HD44780_GPIO_DB0 ) ) ; // idle high
2019-12-12 18:58:04 +01:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB0 ) , GPIO_MODE_OUTPUT_10_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_DB0 ) ) ; // open drain allows to read and write
# endif // LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_RS ) ) ; // enable clock for GPIO port
gpio_clear ( GPIO_PORT ( LCD_HD44780_GPIO_RS ) , GPIO_PIN ( LCD_HD44780_GPIO_RS ) ) ; // set low to read busy flag
2019-06-18 16:20:24 +02:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_RS ) , GPIO_MODE_OUTPUT_2_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_RS ) ) ; // set GPIO as output
2019-12-12 18:58:04 +01:00
# ifdef LCD_HD44780_GPIO_RnW
rcc_periph_clock_enable ( GPIO_RCC ( LCD_HD44780_GPIO_RnW ) ) ; // enable clock for GPIO port
gpio_set ( GPIO_PORT ( LCD_HD44780_GPIO_RnW ) , GPIO_PIN ( LCD_HD44780_GPIO_RnW ) ) ; // set high to read
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_RnW ) , GPIO_MODE_OUTPUT_2_MHZ , GPIO_CNF_OUTPUT_OPENDRAIN , GPIO_PIN ( LCD_HD44780_GPIO_RnW ) ) ; // set GPIO as output
# endif // LCD_HD44780_GPIO_RnW
# endif // LCD_HD44780_I2C
2019-06-18 13:53:01 +02:00
// initialize device
lcd_hd44780_write ( true , 0x30 , true ) ; // 1st function write set to go to state 1 (8-bit) or 2 (4-bit first nibble) (BF cannot be checked)
sleep_ms ( 4 + 1 ) ; // wait 4.1 ms
lcd_hd44780_write ( true , 0x30 , true ) ; // 2st function write set to go to state 1 (8-bit) or 3 (4-bit second nibble) (BF cannot be checked)
sleep_us ( 100 + 10 ) ; // wait 100 us
lcd_hd44780_write ( true , 0x30 , true ) ; // 3rd function write set to go to state 1 (8-bit) (BF cannot be checked)
sleep_us ( LCD_HD44780_BUSY_WAIT_SHORT ) ; // wait 37 us
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-12-12 18:58:04 +01:00
lcd_hd44780_function_set ( 1 , n_2lines , f_5x10 ) ; // function set
# else
2020-02-13 14:29:55 +01:00
lcd_hd44780_write ( true , 0x20 , true ) ; // switch to 4-bit mode
sleep_us ( LCD_HD44780_BUSY_WAIT_SHORT ) ; // wait 37 us
2019-12-12 18:58:04 +01:00
lcd_hd44780_function_set ( 0 , n_2lines , f_5x10 ) ; // function set
2019-06-18 13:53:01 +02:00
# endif
lcd_hd44780_n_2lines = n_2lines ; // remember number of lines
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
lcd_hd44780_display_control ( false , false , false ) ; // display off
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
lcd_hd44780_clear_display ( ) ; // display clear
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_LONG ) ;
lcd_hd44780_entry_mode_set ( true , false ) ; // entry mode set
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
2019-12-12 18:58:04 +01:00
return true ; // I²C configuration succeeded
2019-06-18 13:53:01 +02:00
}
void lcd_hd44780_release ( void )
{
2020-02-13 14:28:41 +01:00
# if defined(LCD_HD44780_I2C) && LCD_HD44780_I2C
2019-12-12 18:58:04 +01:00
i2c_master_release ( LCD_HD44780_I2C_PERIPH ) ; // release I²C peripheral
# else // LCD_HD44780_I2C
2019-06-18 13:53:01 +02:00
// switch back GPIO back to input
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB7 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB7 ) ) ;
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB6 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB6 ) ) ;
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB5 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB5 ) ) ;
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB4 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB4 ) ) ;
2020-02-13 14:29:55 +01:00
# if defined(LCD_HD44780_INTERFACE_DL) && LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB3 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB3 ) ) ;
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB2 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB2 ) ) ;
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB1 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB1 ) ) ;
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_DB0 ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_DB0 ) ) ;
2019-12-12 18:58:04 +01:00
# endif // LCD_HD44780_INTERFACE_DL
2019-06-18 13:53:01 +02:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_RS ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_RS ) ) ;
2019-12-12 18:58:04 +01:00
# ifdef LCD_HD44780_GPIO_RnW
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_RnW ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_RnW ) ) ;
# endif // LCD_HD44780_GPIO_RnW
2019-06-18 13:53:01 +02:00
gpio_set_mode ( GPIO_PORT ( LCD_HD44780_GPIO_E ) , GPIO_MODE_INPUT , GPIO_CNF_INPUT_FLOAT , GPIO_PIN ( LCD_HD44780_GPIO_E ) ) ;
2019-12-12 18:58:04 +01:00
# endif // LCD_HD44780_I2C:
2019-06-18 13:53:01 +02:00
}
void lcd_hd44780_write_data ( uint8_t data )
{
lcd_hd44780_write ( false , data , false ) ;
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
}
void lcd_hd44780_write_command ( uint8_t data )
{
lcd_hd44780_write ( true , data , false ) ;
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
}
void lcd_hd44780_clear_display ( void )
{
lcd_hd44780_write_command ( 0x01 ) ;
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_LONG ) ;
}
void lcd_hd44780_return_home ( void )
{
lcd_hd44780_write_command ( 0x02 ) ;
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_LONG ) ;
}
void lcd_hd44780_entry_mode_set ( bool increment , bool shift )
{
uint8_t command = 0x04 ;
if ( increment ) {
command | = 0x02 ;
}
if ( shift ) {
command | = 0x01 ;
}
lcd_hd44780_write_command ( command ) ;
}
void lcd_hd44780_display_control ( bool d , bool c , bool b )
{
uint8_t command = 0x08 ;
if ( d ) {
command | = 0x04 ;
}
if ( c ) {
command | = 0x02 ;
}
if ( b ) {
command | = 0x01 ;
}
lcd_hd44780_write_command ( command ) ;
}
void lcd_hd44780_set_cgram_address ( uint8_t acg )
{
lcd_hd44780_write_command ( 0x40 | ( acg & 0x3f ) ) ;
}
void lcd_hd44780_set_ddram_address ( uint8_t add )
{
lcd_hd44780_write_command ( 0x80 | ( add & 0x7f ) ) ;
}
void lcd_hd44780_write_line ( bool line2 , const char * data , uint8_t length )
{
if ( line2 & & ! lcd_hd44780_n_2lines ) { // writing line 2 when it does not exists is not possible
return ;
}
lcd_hd44780_set_ddram_address ( line2 ? 0x40 : 0x00 ) ; // set start of line
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
for ( uint8_t i = 0 ; i < length & & i < ( lcd_hd44780_n_2lines ? 0x27 : 0x4f ) ; i + + ) { // write line
lcd_hd44780_write_data ( data [ i ] ) ; // write character
lcd_hd44780_wait_busy ( LCD_HD44780_BUSY_WAIT_SHORT ) ;
}
}