diff --git a/drivers/include/lcd.h b/drivers/include/lcd.h index 16b53eed6d..f1c03e314d 100644 --- a/drivers/include/lcd.h +++ b/drivers/include/lcd.h @@ -256,8 +256,8 @@ void lcd_ll_release(lcd_t *dev); * * @param[in] dev device descriptor * @param[in] cmd command code - * @param[in] data command data to the device - * @param[in] len length of the command data + * @param[in] data command data to the device or NULL for commands without data + * @param[in] len length of the command data or 0 for commands without data */ void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, size_t len); @@ -279,6 +279,18 @@ void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, * @param[in] len length of the returned data */ void lcd_ll_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len); + +/** + * @brief Set the LCD work area + * + * @param[in] dev Pointer to the selected driver + * @param[in] x1 x coordinate of the first corner + * @param[in] x2 x coordinate of the opposite corner + * @param[in] y1 y coordinate of the first corner + * @param[in] y2 y coordinate of the opposite corner + * + */ +void lcd_ll_set_area(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2); /** @} */ /** @@ -338,8 +350,8 @@ void lcd_pixmap(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, * * @param[in] dev device descriptor * @param[in] cmd command code - * @param[in] data command data to the device - * @param[in] len length of the command data + * @param[in] data command data to the device or NULL for commands without data + * @param[in] len length of the command data or 0 for commands without data */ void lcd_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, size_t len); @@ -375,6 +387,109 @@ void lcd_invert_on(lcd_t *dev); void lcd_invert_off(lcd_t *dev); /** @} */ +#if MODULE_LCD_PARALLEL || DOXYGEN +/** + * @name Low-level MCU 8080 8-/16-bit parallel interface + * + * The low-level MCU 8080 8-/16-bit parallel interface (low-level parallel + * interface for short) is used when the LCD device is connected via a parallel + * interface. Either the GPIO-driven low-level parallel interface provided by + * this LCD driver or a low-level parallel interface implemented by the MCU, + * such as the STM32 FMC peripheral, can be used. If the MCU provides its + * own implementation of the low-level parallel interface, it can be used + * by implementing the following low-level parallel interface driver functions, + * enabling the `lcd_parallel_ll_mcu` module and defining the + * @ref lcd_ll_par_driver variable of type @ref lcd_ll_par_driver_t. + * + * @{ + */ + +/** + * @brief Low-level MCU 8080 8-/16-bit parallel interface driver + * + * If the MCU-driven low-level parallel interface is enabled by + * module `lcd_ll_parallel_mcu`, the implementation of the MCU low-level + * parallel interface has to define a variable @ref lcd_ll_par_driver of this + * type. All or a set of members have to point to the low-level parallel + * interface functions implemented by the MCU. For functions that are not + * implemented by the MCU, the members have to be set to the corresponding + * GPIO-driven low-level parallel interface functions provided by the LCD + * driver. + */ +typedef struct { + /** + * @brief Initialize the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + */ + void (*init)(lcd_t *dev); + + /** + * @brief Set the data direction of the low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] output set to output mode if true and to input mode otherwise + */ + void (*set_data_dir)(lcd_t *dev, bool output); + + /** + * @brief Write command using the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cmd command + * @param[in] cont operation is continued + */ + void (*cmd_start)(lcd_t *dev, uint8_t cmd, bool cont); + + /** + * @brief Write a byte using the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * @param[in] out byte to be written + */ + void (*write_byte)(lcd_t *dev, bool cont, uint8_t out); + + /** + * @brief Read a byte using the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * + * @return byte read + */ + uint8_t (*read_byte)(lcd_t *dev, bool cont); + +#if MODULE_LCD_PARALLEL_16BIT || DOXYGEN + /** + * @brief Write a word using the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * @param[in] out word to be written + */ + void (*write_word)(lcd_t *dev, bool cont, uint16_t out); + + /** + * @brief Read a word using the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * + * @return word read + */ + uint16_t (*read_word)(lcd_t *dev, bool cont); +#endif +} lcd_ll_par_driver_t; + +/** + * @brief Low-level parallel interface driver instance + */ +extern const lcd_ll_par_driver_t lcd_ll_par_driver; + +/** @} */ +#endif + #ifdef __cplusplus } #endif diff --git a/drivers/lcd/Kconfig b/drivers/lcd/Kconfig index 05626f433c..64ce2a5571 100644 --- a/drivers/lcd/Kconfig +++ b/drivers/lcd/Kconfig @@ -11,6 +11,8 @@ config MODULE_LCD depends on TEST_KCONFIG select MODULE_PERIPH_GPIO +if MODULE_LCD + config MODULE_LCD_MULTI_CNTRL bool help @@ -21,7 +23,6 @@ config MODULE_LCD_SPI default y if !MODULE_LCD_PARALLEL && !MODULE_LCD_PARALLEL_16BIT default y if HAVE_LCD_SPI depends on HAS_PERIPH_SPI - depends on MODULE_LCD select MODULE_PERIPH_SPI help SPI serial interface is used @@ -29,17 +30,24 @@ config MODULE_LCD_SPI config MODULE_LCD_PARALLEL bool default y if HAVE_LCD_PARALLEL || HAVE_LCD_PARALLEL_16BIT - depends on MODULE_LCD help MCU 8080 8-/16-bit parallel interface is used config MODULE_LCD_PARALLEL_16BIT bool default y if HAVE_LCD_PARALLEL_16BIT - depends on MODULE_LCD help MCU 8080 16-bit paralell interface is used +config MODULE_LCD_PARALLEL_LL_MCU + bool + default y if HAVE_LCD_PARALLEL_LL_MCU + depends on MODULE_LCD_PARALLEL + help + MCU 8080 8-/16-bit low-level parallel interface is provided by the MCU. + +endif + config HAVE_LCD_SPI bool help @@ -58,6 +66,12 @@ config HAVE_LCD_PARALLEL_16BIT Indicates that a display with MCU 8080 16-bit parallel interface is present +config HAVE_LCD_PARALLEL_LL_MCU + bool + help + Indicates that the MCU provides the MCU 8080 8-/16-bit low-level + parallel interface implementation. + menuconfig KCONFIG_USEMODULE_LCD bool "Configure LCD driver" depends on USEMODULE_LCD diff --git a/drivers/lcd/Makefile.dep b/drivers/lcd/Makefile.dep index 0a69ce5216..fbccd59ae7 100644 --- a/drivers/lcd/Makefile.dep +++ b/drivers/lcd/Makefile.dep @@ -1,6 +1,6 @@ FEATURES_REQUIRED += periph_gpio -ifneq (,$(filter lcd_parallel_16bit,$(USEMODULE))) +ifneq (,$(filter lcd_parallel_%,$(USEMODULE))) USEMODULE += lcd_parallel endif diff --git a/drivers/lcd/Makefile.include b/drivers/lcd/Makefile.include index 92015f1c5f..689c7d6969 100644 --- a/drivers/lcd/Makefile.include +++ b/drivers/lcd/Makefile.include @@ -3,6 +3,7 @@ PSEUDOMODULES += lcd_multi_cntrl PSEUDOMODULES += lcd_spi PSEUDOMODULES += lcd_parallel PSEUDOMODULES += lcd_parallel_16bit +PSEUDOMODULES += lcd_parallel_ll_mcu USEMODULE_INCLUDES_lcd := $(LAST_MAKEFILEDIR)/include USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_lcd) diff --git a/drivers/lcd/include/lcd_internal.h b/drivers/lcd/include/lcd_internal.h index 024747af60..50fc6cf0fe 100644 --- a/drivers/lcd/include/lcd_internal.h +++ b/drivers/lcd/include/lcd_internal.h @@ -35,6 +35,7 @@ extern "C" { */ #define LCD_CMD_SWRESET 0x01 /**< Software reset */ #define LCD_CMD_RDDIDIF 0x04 /**< Read display ID */ +#define LCD_CMD_RDDST 0x09 /**< Read display status */ #define LCD_CMD_SLPIN 0x10 /**< Enter sleep mode */ #define LCD_CMD_SLPOUT 0x11 /**< Sleep out */ #define LCD_CMD_NORON 0x13 /**< Normal display mode on */ diff --git a/drivers/lcd/include/lcd_ll_par_gpio.h b/drivers/lcd/include/lcd_ll_par_gpio.h new file mode 100644 index 0000000000..5cc64e52c6 --- /dev/null +++ b/drivers/lcd/include/lcd_ll_par_gpio.h @@ -0,0 +1,100 @@ +/* + * Copyright (C) 2023 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +#if !DOXYGEN /* hide from documentation */ + +/** + * @ingroup drivers_lcd + * + * @brief GPIO-driven low-level parallel interface implementation + * + * @{ + * @file + * @author Gunar Schorcht + */ + +#ifndef LCD_LL_PAR_GPIO_H +#define LCD_LL_PAR_GPIO_H + +#include + +#include "lcd.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Initialize the GPIOs of the GPIO-driven low-level parallel interface + * + * @param[in] dev device descriptor + */ + +void lcd_ll_par_gpio_init(lcd_t *dev); + +/** + * @brief Set the direction of the data GPIOs of the low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] output set to output mode if true and to input mode otherwise + */ +void lcd_ll_par_gpio_set_data_dir(lcd_t *dev, bool output); + +/** + * @brief Write command using the MCU-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cmd command + * @param[in] cont operation is continued + */ +void lcd_ll_par_gpio_cmd_start(lcd_t *dev, uint8_t cmd, bool cont); + +/** + * @brief Write a byte to the GPIO-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * @param[in] out byte to be written + */ +void lcd_ll_par_gpio_write_byte(lcd_t *dev, bool cont, uint8_t out); + +/** + * @brief Write a word to the GPIO-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * @param[in] out word to be written + */ +void lcd_ll_par_gpio_write_word(lcd_t *dev, bool cont, uint16_t out); + +/** + * @brief Read a byte from the GPIO-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * + * @return read byte + */ +uint8_t lcd_ll_par_gpio_read_byte(lcd_t *dev, bool cont); + +/** + * @brief Read a word from the GPIO-driven low-level parallel interface + * + * @param[in] dev device descriptor + * @param[in] cont operation is continued + * + * @return read word + */ +uint16_t lcd_ll_par_gpio_read_word(lcd_t *dev, bool cont); + +#ifdef __cplusplus +} +#endif +#endif /* LCD_LL_PAR_GPIO_H */ +/** @} */ +#endif /* !DOXYGEN */ diff --git a/drivers/lcd/lcd.c b/drivers/lcd/lcd.c index 098c877b5f..b6a89333f2 100644 --- a/drivers/lcd/lcd.c +++ b/drivers/lcd/lcd.c @@ -26,6 +26,7 @@ #include #include "byteorder.h" #include "kernel_defines.h" +#include "log.h" #include "ztimer.h" #if IS_USED(MODULE_LCD_SPI) @@ -34,6 +35,7 @@ #include "lcd.h" #include "lcd_internal.h" +#include "lcd_ll_par_gpio.h" #define ENABLE_DEBUG 0 #include "debug.h" @@ -42,125 +44,26 @@ static void lcd_ll_par_write_byte(lcd_t *dev, bool cont, uint8_t out) { - if (gpio_is_valid(dev->params->cs_pin)) { - gpio_clear(dev->params->cs_pin); - } - - gpio_clear(dev->params->wrx_pin); - - gpio_write(dev->params->d0_pin, out & 0x01); - gpio_write(dev->params->d1_pin, out & 0x02); - gpio_write(dev->params->d2_pin, out & 0x04); - gpio_write(dev->params->d3_pin, out & 0x08); - gpio_write(dev->params->d4_pin, out & 0x10); - gpio_write(dev->params->d5_pin, out & 0x20); - gpio_write(dev->params->d6_pin, out & 0x40); - gpio_write(dev->params->d7_pin, out & 0x80); - - gpio_set(dev->params->wrx_pin); - - if (gpio_is_valid(dev->params->cs_pin) && !cont) { - gpio_set(dev->params->cs_pin); - }; + lcd_ll_par_driver.write_byte(dev, cont, out); } static uint8_t lcd_ll_par_read_byte(lcd_t *dev, bool cont) { - uint8_t in = 0; - - if (gpio_is_valid(dev->params->cs_pin)) { - gpio_clear(dev->params->cs_pin); - } - - gpio_clear(dev->params->rdx_pin); - - in |= gpio_read(dev->params->d0_pin) ? 0x01 : 0; - in |= gpio_read(dev->params->d1_pin) ? 0x02 : 0; - in |= gpio_read(dev->params->d2_pin) ? 0x04 : 0; - in |= gpio_read(dev->params->d3_pin) ? 0x08 : 0; - in |= gpio_read(dev->params->d4_pin) ? 0x10 : 0; - in |= gpio_read(dev->params->d5_pin) ? 0x20 : 0; - in |= gpio_read(dev->params->d6_pin) ? 0x40 : 0; - in |= gpio_read(dev->params->d7_pin) ? 0x80 : 0; - - gpio_set(dev->params->rdx_pin); - - if (gpio_is_valid(dev->params->cs_pin) && !cont) { - gpio_set(dev->params->cs_pin); - }; - - return in; + return lcd_ll_par_driver.read_byte(dev, cont); } #if IS_USED(MODULE_LCD_PARALLEL_16BIT) static void lcd_ll_par_write_word(lcd_t *dev, bool cont, uint16_t out) { - if (gpio_is_valid(dev->params->cs_pin)) { - gpio_clear(dev->params->cs_pin); - } - - gpio_clear(dev->params->wrx_pin); - - gpio_write(dev->params->d0_pin, out & 0x0001); - gpio_write(dev->params->d1_pin, out & 0x0002); - gpio_write(dev->params->d2_pin, out & 0x0004); - gpio_write(dev->params->d3_pin, out & 0x0008); - gpio_write(dev->params->d4_pin, out & 0x0010); - gpio_write(dev->params->d5_pin, out & 0x0020); - gpio_write(dev->params->d6_pin, out & 0x0040); - gpio_write(dev->params->d7_pin, out & 0x0080); - gpio_write(dev->params->d8_pin, out & 0x0100); - gpio_write(dev->params->d9_pin, out & 0x0200); - gpio_write(dev->params->d10_pin, out & 0x0400); - gpio_write(dev->params->d11_pin, out & 0x0800); - gpio_write(dev->params->d12_pin, out & 0x1000); - gpio_write(dev->params->d13_pin, out & 0x2000); - gpio_write(dev->params->d14_pin, out & 0x4000); - gpio_write(dev->params->d15_pin, out & 0x8000); - - gpio_set(dev->params->wrx_pin); - - if (gpio_is_valid(dev->params->cs_pin) && !cont) { - gpio_set(dev->params->cs_pin); - }; + lcd_ll_par_driver.write_word(dev, cont, out); } static uint16_t lcd_ll_par_read_word(lcd_t *dev, bool cont) { - uint16_t in = 0; - - if (gpio_is_valid(dev->params->cs_pin)) { - gpio_clear(dev->params->cs_pin); - } - - gpio_clear(dev->params->rdx_pin); - - in |= gpio_read(dev->params->d0_pin) ? 0x0001 : 0; - in |= gpio_read(dev->params->d1_pin) ? 0x0002 : 0; - in |= gpio_read(dev->params->d2_pin) ? 0x0004 : 0; - in |= gpio_read(dev->params->d3_pin) ? 0x0008 : 0; - in |= gpio_read(dev->params->d4_pin) ? 0x0010 : 0; - in |= gpio_read(dev->params->d5_pin) ? 0x0020 : 0; - in |= gpio_read(dev->params->d6_pin) ? 0x0040 : 0; - in |= gpio_read(dev->params->d7_pin) ? 0x0080 : 0; - in |= gpio_read(dev->params->d8_pin) ? 0x01000 : 0; - in |= gpio_read(dev->params->d9_pin) ? 0x02000 : 0; - in |= gpio_read(dev->params->d10_pin) ? 0x0400 : 0; - in |= gpio_read(dev->params->d11_pin) ? 0x0800 : 0; - in |= gpio_read(dev->params->d12_pin) ? 0x1000 : 0; - in |= gpio_read(dev->params->d13_pin) ? 0x2000 : 0; - in |= gpio_read(dev->params->d14_pin) ? 0x4000 : 0; - in |= gpio_read(dev->params->d15_pin) ? 0x8000 : 0; - - gpio_set(dev->params->rdx_pin); - - if (gpio_is_valid(dev->params->cs_pin) && !cont) { - gpio_set(dev->params->cs_pin); - }; - - return in; + return lcd_ll_par_driver.read_word(dev, cont); } + #endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ static void lcd_ll_par_write_bytes(lcd_t *dev, bool cont, @@ -181,7 +84,7 @@ static void lcd_ll_par_write_bytes(lcd_t *dev, bool cont, } return; } -#endif +#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ for (size_t i = 0; i < len; i++) { lcd_ll_par_write_byte(dev, i == (len - 1) ? cont : true, data_out[i]); @@ -206,7 +109,7 @@ static void lcd_ll_par_read_bytes(lcd_t *dev, bool cont, } return; } -#endif +#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ for (size_t i = 0; i < len; i++) { data_in[i] = lcd_ll_par_read_byte(dev, i == (len - 1) ? cont : true); @@ -227,8 +130,6 @@ static inline void lcd_ll_write_byte(lcd_t *dev, bool cont, uint8_t data) #if IS_USED(MODULE_LCD_PARALLEL) /* MCU 8080 8-/16-bit parallel interface is used */ lcd_ll_par_write_byte(dev, cont, data); -#else - assert(false); #endif #if IS_USED(MODULE_LCD_SPI) } @@ -249,8 +150,6 @@ static inline void lcd_ll_write_bytes(lcd_t *dev, bool cont, #if IS_USED(MODULE_LCD_PARALLEL) /* MCU 8080 8-/16-bit parallel interface is used */ lcd_ll_par_write_bytes(dev, cont, data, len); -#else - assert(false); #endif #if IS_USED(MODULE_LCD_SPI) } @@ -270,59 +169,19 @@ static inline void lcd_ll_read_bytes(lcd_t *dev, bool cont, dev->params->cs_pin, cont, NULL, data, len); } else { -#endif +#endif /* IS_USED(MODULE_LCD_SPI) */ #if IS_USED(MODULE_LCD_PARALLEL) /* MCU 8080 8-/16-bit parallel interface is used */ /* switch GPIO mode to input */ - gpio_init(dev->params->d0_pin, GPIO_IN); - gpio_init(dev->params->d1_pin, GPIO_IN); - gpio_init(dev->params->d2_pin, GPIO_IN); - gpio_init(dev->params->d3_pin, GPIO_IN); - gpio_init(dev->params->d4_pin, GPIO_IN); - gpio_init(dev->params->d5_pin, GPIO_IN); - gpio_init(dev->params->d6_pin, GPIO_IN); - gpio_init(dev->params->d7_pin, GPIO_IN); -#if IS_USED(MODULE_LCD_PARALLEL_16BIT) - if (dev->params->mode == LCD_IF_PARALLEL_16BIT) { - gpio_init(dev->params->d8_pin, GPIO_IN); - gpio_init(dev->params->d9_pin, GPIO_IN); - gpio_init(dev->params->d10_pin, GPIO_IN); - gpio_init(dev->params->d11_pin, GPIO_IN); - gpio_init(dev->params->d12_pin, GPIO_IN); - gpio_init(dev->params->d13_pin, GPIO_IN); - gpio_init(dev->params->d14_pin, GPIO_IN); - gpio_init(dev->params->d15_pin, GPIO_IN); - } -#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ + lcd_ll_par_driver.set_data_dir(dev, false); /* Dummy read */ lcd_ll_par_read_byte(dev, true); lcd_ll_par_read_bytes(dev, cont, data, len); /* switch GPIO mode back to output */ - gpio_init(dev->params->d0_pin, GPIO_OUT); - gpio_init(dev->params->d1_pin, GPIO_OUT); - gpio_init(dev->params->d2_pin, GPIO_OUT); - gpio_init(dev->params->d3_pin, GPIO_OUT); - gpio_init(dev->params->d4_pin, GPIO_OUT); - gpio_init(dev->params->d5_pin, GPIO_OUT); - gpio_init(dev->params->d6_pin, GPIO_OUT); - gpio_init(dev->params->d7_pin, GPIO_OUT); -#if IS_USED(MODULE_LCD_PARALLEL_16BIT) - if (dev->params->mode == LCD_IF_PARALLEL_16BIT) { - gpio_init(dev->params->d8_pin, GPIO_OUT); - gpio_init(dev->params->d9_pin, GPIO_OUT); - gpio_init(dev->params->d10_pin, GPIO_OUT); - gpio_init(dev->params->d11_pin, GPIO_OUT); - gpio_init(dev->params->d12_pin, GPIO_OUT); - gpio_init(dev->params->d13_pin, GPIO_OUT); - gpio_init(dev->params->d14_pin, GPIO_OUT); - gpio_init(dev->params->d15_pin, GPIO_OUT); - } -#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ -#else - assert(false); + lcd_ll_par_driver.set_data_dir(dev, true); #endif #if IS_USED(MODULE_LCD_SPI) } @@ -331,9 +190,18 @@ static inline void lcd_ll_read_bytes(lcd_t *dev, bool cont, static void lcd_ll_cmd_start(lcd_t *dev, uint8_t cmd, bool cont) { - gpio_clear(dev->params->dcx_pin); - lcd_ll_write_byte(dev, cont, cmd); - gpio_set(dev->params->dcx_pin); +#if IS_USED(MODULE_LCD_PARALLEL) + if (dev->params->mode != LCD_IF_SPI) { + lcd_ll_par_driver.cmd_start(dev, cmd, cont); + } + else { +#endif + gpio_clear(dev->params->dcx_pin); + lcd_ll_write_byte(dev, cont, cmd); + gpio_set(dev->params->dcx_pin); +#if IS_USED(MODULE_LCD_PARALLEL) + } +#endif #if IS_USED(MODULE_LCD_PARALLEL_16BIT) /* only the RAMRD and RAMRDC commands use 16-bit data access */ @@ -369,8 +237,7 @@ static void lcd_ll_set_area_default(lcd_t *dev, uint16_t x1, uint16_t x2, sizeof(params)); } -static void lcd_ll_set_area(lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) +void lcd_ll_set_area(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2) { if (dev->driver->set_area) { dev->driver->set_area(dev, x1, x2, y1, y2); @@ -393,8 +260,6 @@ void lcd_ll_acquire(lcd_t *dev) #if IS_USED(MODULE_LCD_PARALLEL) /* MCU 8080 8-/16-bit parallel interface is used */ mutex_lock(&dev->lock); -#else - assert(false); #endif #if IS_USED(MODULE_LCD_SPI) } @@ -418,8 +283,6 @@ void lcd_ll_release(lcd_t *dev) #if IS_USED(MODULE_LCD_PARALLEL) /* MCU 8080 8-/16-bit parallel interface is used */ mutex_unlock(&dev->lock); -#else - assert(false); #endif #if IS_USED(MODULE_LCD_SPI) } @@ -464,11 +327,11 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) { dev->params = params; - assert(gpio_is_valid(dev->params->dcx_pin)); - gpio_init(dev->params->dcx_pin, GPIO_OUT); - #if IS_USED(MODULE_LCD_SPI) if (dev->params->spi != SPI_UNDEF) { + assert(gpio_is_valid(dev->params->dcx_pin)); + gpio_init(dev->params->dcx_pin, GPIO_OUT); + /* SPI serial interface is used */ int res = spi_init_cs(dev->params->spi, dev->params->cs_pin); @@ -478,63 +341,25 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) } } else { -#endif +#endif /* IS_USED(MODULE_LCD_SPI) */ + #if IS_USED(MODULE_LCD_PARALLEL) - /* MCU 8080 8-/16-bit parallel interface is used */ - if (gpio_is_valid(dev->params->cs_pin)) { - gpio_init(dev->params->cs_pin, GPIO_OUT); - gpio_set(dev->params->cs_pin); - } - - assert(gpio_is_valid(dev->params->wrx_pin)); - gpio_init(dev->params->wrx_pin, GPIO_OUT); - gpio_set(dev->params->wrx_pin); - - if (gpio_is_valid(dev->params->rdx_pin)) { - gpio_init(dev->params->rdx_pin, GPIO_OUT); - gpio_set(dev->params->rdx_pin); - } - - assert(gpio_is_valid(dev->params->d0_pin)); - assert(gpio_is_valid(dev->params->d1_pin)); - assert(gpio_is_valid(dev->params->d2_pin)); - assert(gpio_is_valid(dev->params->d3_pin)); - assert(gpio_is_valid(dev->params->d4_pin)); - assert(gpio_is_valid(dev->params->d5_pin)); - assert(gpio_is_valid(dev->params->d6_pin)); - assert(gpio_is_valid(dev->params->d7_pin)); - gpio_init(dev->params->d0_pin, GPIO_OUT); - gpio_init(dev->params->d1_pin, GPIO_OUT); - gpio_init(dev->params->d2_pin, GPIO_OUT); - gpio_init(dev->params->d3_pin, GPIO_OUT); - gpio_init(dev->params->d4_pin, GPIO_OUT); - gpio_init(dev->params->d5_pin, GPIO_OUT); - gpio_init(dev->params->d6_pin, GPIO_OUT); - gpio_init(dev->params->d7_pin, GPIO_OUT); + mutex_init(&dev->lock); #if IS_USED(MODULE_LCD_PARALLEL_16BIT) - if (dev->params->mode == LCD_IF_PARALLEL_16BIT) { - assert(gpio_is_valid(dev->params->d8_pin)); - assert(gpio_is_valid(dev->params->d9_pin)); - assert(gpio_is_valid(dev->params->d10_pin)); - assert(gpio_is_valid(dev->params->d11_pin)); - assert(gpio_is_valid(dev->params->d12_pin)); - assert(gpio_is_valid(dev->params->d13_pin)); - assert(gpio_is_valid(dev->params->d14_pin)); - assert(gpio_is_valid(dev->params->d15_pin)); - gpio_init(dev->params->d8_pin, GPIO_OUT); - gpio_init(dev->params->d9_pin, GPIO_OUT); - gpio_init(dev->params->d10_pin, GPIO_OUT); - gpio_init(dev->params->d11_pin, GPIO_OUT); - gpio_init(dev->params->d12_pin, GPIO_OUT); - gpio_init(dev->params->d13_pin, GPIO_OUT); - gpio_init(dev->params->d14_pin, GPIO_OUT); - gpio_init(dev->params->d15_pin, GPIO_OUT); - } dev->word_access = false; #endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ -#else + + /* Low-level parallel interface initialization */ + lcd_ll_par_driver.init(dev); + /* set output data direction */ + lcd_ll_par_driver.set_data_dir(dev, true); + +#else /* IS_USED(MODULE_LCD_PARALLEL) */ + + LOG_ERROR("[lcd] either lcd_parallel or lcd_spi has to be enabled"); assert(false); #endif + #if IS_USED(MODULE_LCD_SPI) } #endif @@ -547,10 +372,6 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) } ztimer_sleep(ZTIMER_MSEC, 120); -#if IS_USED(MODULE_LCD_PARALLEL) - mutex_init(&dev->lock); -#endif - /* controller-specific init function has to be defined */ assert(dev->driver->init); return dev->driver->init(dev, params); diff --git a/drivers/lcd/lcd_ll_par_gpio.c b/drivers/lcd/lcd_ll_par_gpio.c new file mode 100644 index 0000000000..7db624f355 --- /dev/null +++ b/drivers/lcd/lcd_ll_par_gpio.c @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2023 Gunar Schorcht + * + * This file is subject to the terms and conditions of the GNU Lesser + * General Public License v2.1. See the file LICENSE in the top level + * directory for more details. + */ + +/** + * @ingroup drivers_lcd + * @{ + * + * @file + * @brief GPIO-driven low-level parallel interface implementation + * + * @author Gunar Schorcht + * + * @} + */ + +#include + +#include "lcd.h" +#include "lcd_ll_par_gpio.h" +#include "periph/gpio.h" + +#define ENABLE_DEBUG 0 +#include "debug.h" + +#if IS_USED(MODULE_LCD_PARALLEL) + +void lcd_ll_par_gpio_init(lcd_t *dev) +{ + DEBUG("[lcd] %s\n", __func__); + + /* MCU 8080 8-/16-bit parallel interface is used */ + assert(gpio_is_valid(dev->params->dcx_pin)); + gpio_init(dev->params->dcx_pin, GPIO_OUT); + + if (gpio_is_valid(dev->params->cs_pin)) { + gpio_init(dev->params->cs_pin, GPIO_OUT); + gpio_set(dev->params->cs_pin); + } + + assert(gpio_is_valid(dev->params->wrx_pin)); + gpio_init(dev->params->wrx_pin, GPIO_OUT); + gpio_set(dev->params->wrx_pin); + + if (gpio_is_valid(dev->params->rdx_pin)) { + gpio_init(dev->params->rdx_pin, GPIO_OUT); + gpio_set(dev->params->rdx_pin); + } + + assert(gpio_is_valid(dev->params->d0_pin)); + assert(gpio_is_valid(dev->params->d1_pin)); + assert(gpio_is_valid(dev->params->d2_pin)); + assert(gpio_is_valid(dev->params->d3_pin)); + assert(gpio_is_valid(dev->params->d4_pin)); + assert(gpio_is_valid(dev->params->d5_pin)); + assert(gpio_is_valid(dev->params->d6_pin)); + assert(gpio_is_valid(dev->params->d7_pin)); +#if IS_USED(MODULE_LCD_PARALLEL_16BIT) + if (dev->params->mode == LCD_IF_PARALLEL_16BIT) { + assert(gpio_is_valid(dev->params->d8_pin)); + assert(gpio_is_valid(dev->params->d9_pin)); + assert(gpio_is_valid(dev->params->d10_pin)); + assert(gpio_is_valid(dev->params->d11_pin)); + assert(gpio_is_valid(dev->params->d12_pin)); + assert(gpio_is_valid(dev->params->d13_pin)); + assert(gpio_is_valid(dev->params->d14_pin)); + assert(gpio_is_valid(dev->params->d15_pin)); + } + dev->word_access = false; +#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ + + /* initialize all data GPIOs as outputs */ + lcd_ll_par_gpio_set_data_dir(dev, true); +} + +void lcd_ll_par_gpio_set_data_dir(lcd_t *dev, bool output) +{ + DEBUG("[lcd] %s %u\n", __func__, output); + + gpio_init(dev->params->d0_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d1_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d2_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d3_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d4_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d5_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d6_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d7_pin, output ? GPIO_OUT : GPIO_IN); +#if IS_USED(MODULE_LCD_PARALLEL_16BIT) + if (dev->params->mode == LCD_IF_PARALLEL_16BIT) { + gpio_init(dev->params->d8_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d9_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d10_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d11_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d12_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d13_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d14_pin, output ? GPIO_OUT : GPIO_IN); + gpio_init(dev->params->d15_pin, output ? GPIO_OUT : GPIO_IN); + } +#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ +} + +void lcd_ll_par_gpio_cmd_start(lcd_t *dev, uint8_t cmd, bool cont) +{ + DEBUG("[lcd] %s %02x\n", __func__, cmd); + + gpio_clear(dev->params->dcx_pin); + lcd_ll_par_gpio_write_byte(dev, cont, cmd); + gpio_set(dev->params->dcx_pin); +} + +void lcd_ll_par_gpio_write_byte(lcd_t *dev, bool cont, uint8_t out) +{ + DEBUG("[lcd] %s %02x\n", __func__, out); + + if (gpio_is_valid(dev->params->cs_pin)) { + gpio_clear(dev->params->cs_pin); + } + + gpio_clear(dev->params->wrx_pin); + + gpio_write(dev->params->d0_pin, out & 0x01); + gpio_write(dev->params->d1_pin, out & 0x02); + gpio_write(dev->params->d2_pin, out & 0x04); + gpio_write(dev->params->d3_pin, out & 0x08); + gpio_write(dev->params->d4_pin, out & 0x10); + gpio_write(dev->params->d5_pin, out & 0x20); + gpio_write(dev->params->d6_pin, out & 0x40); + gpio_write(dev->params->d7_pin, out & 0x80); + + gpio_set(dev->params->wrx_pin); + + if (gpio_is_valid(dev->params->cs_pin) && !cont) { + gpio_set(dev->params->cs_pin); + }; +} + +uint8_t lcd_ll_par_gpio_read_byte(lcd_t *dev, bool cont) +{ + uint8_t in = 0; + + if (gpio_is_valid(dev->params->cs_pin)) { + gpio_clear(dev->params->cs_pin); + } + + gpio_clear(dev->params->rdx_pin); + + in |= gpio_read(dev->params->d0_pin) ? 0x01 : 0; + in |= gpio_read(dev->params->d1_pin) ? 0x02 : 0; + in |= gpio_read(dev->params->d2_pin) ? 0x04 : 0; + in |= gpio_read(dev->params->d3_pin) ? 0x08 : 0; + in |= gpio_read(dev->params->d4_pin) ? 0x10 : 0; + in |= gpio_read(dev->params->d5_pin) ? 0x20 : 0; + in |= gpio_read(dev->params->d6_pin) ? 0x40 : 0; + in |= gpio_read(dev->params->d7_pin) ? 0x80 : 0; + + gpio_set(dev->params->rdx_pin); + + if (gpio_is_valid(dev->params->cs_pin) && !cont) { + gpio_set(dev->params->cs_pin); + }; + + DEBUG("[lcd] %s %02x\n", __func__, in); + + return in; +} + +#if IS_USED(MODULE_LCD_PARALLEL_16BIT) + +void lcd_ll_par_gpio_write_word(lcd_t *dev, bool cont, uint16_t out) +{ + DEBUG("[lcd] %s %04x\n", __func__, out); + + if (gpio_is_valid(dev->params->cs_pin)) { + gpio_clear(dev->params->cs_pin); + } + + gpio_clear(dev->params->wrx_pin); + + gpio_write(dev->params->d0_pin, out & 0x0001); + gpio_write(dev->params->d1_pin, out & 0x0002); + gpio_write(dev->params->d2_pin, out & 0x0004); + gpio_write(dev->params->d3_pin, out & 0x0008); + gpio_write(dev->params->d4_pin, out & 0x0010); + gpio_write(dev->params->d5_pin, out & 0x0020); + gpio_write(dev->params->d6_pin, out & 0x0040); + gpio_write(dev->params->d7_pin, out & 0x0080); + gpio_write(dev->params->d8_pin, out & 0x0100); + gpio_write(dev->params->d9_pin, out & 0x0200); + gpio_write(dev->params->d10_pin, out & 0x0400); + gpio_write(dev->params->d11_pin, out & 0x0800); + gpio_write(dev->params->d12_pin, out & 0x1000); + gpio_write(dev->params->d13_pin, out & 0x2000); + gpio_write(dev->params->d14_pin, out & 0x4000); + gpio_write(dev->params->d15_pin, out & 0x8000); + + gpio_set(dev->params->wrx_pin); + + if (gpio_is_valid(dev->params->cs_pin) && !cont) { + gpio_set(dev->params->cs_pin); + }; +} + +uint16_t lcd_ll_par_gpio_read_word(lcd_t *dev, bool cont) +{ + uint16_t in = 0; + + if (gpio_is_valid(dev->params->cs_pin)) { + gpio_clear(dev->params->cs_pin); + } + + gpio_clear(dev->params->rdx_pin); + + in |= gpio_read(dev->params->d0_pin) ? 0x0001 : 0; + in |= gpio_read(dev->params->d1_pin) ? 0x0002 : 0; + in |= gpio_read(dev->params->d2_pin) ? 0x0004 : 0; + in |= gpio_read(dev->params->d3_pin) ? 0x0008 : 0; + in |= gpio_read(dev->params->d4_pin) ? 0x0010 : 0; + in |= gpio_read(dev->params->d5_pin) ? 0x0020 : 0; + in |= gpio_read(dev->params->d6_pin) ? 0x0040 : 0; + in |= gpio_read(dev->params->d7_pin) ? 0x0080 : 0; + in |= gpio_read(dev->params->d8_pin) ? 0x01000 : 0; + in |= gpio_read(dev->params->d9_pin) ? 0x02000 : 0; + in |= gpio_read(dev->params->d10_pin) ? 0x0400 : 0; + in |= gpio_read(dev->params->d11_pin) ? 0x0800 : 0; + in |= gpio_read(dev->params->d12_pin) ? 0x1000 : 0; + in |= gpio_read(dev->params->d13_pin) ? 0x2000 : 0; + in |= gpio_read(dev->params->d14_pin) ? 0x4000 : 0; + in |= gpio_read(dev->params->d15_pin) ? 0x8000 : 0; + + gpio_set(dev->params->rdx_pin); + + if (gpio_is_valid(dev->params->cs_pin) && !cont) { + gpio_set(dev->params->cs_pin); + }; + + DEBUG("[lcd] %s %04x\n", __func__, in); + + return in; +} +#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */ + +#if !IS_USED(MODULE_LCD_PARALLEL_LL_MCU) +/* If MCU-driven low-level implementation is not used, the GPIO-driven + * implementation is used as driver. */ +const lcd_ll_par_driver_t lcd_ll_par_driver = { + .init = lcd_ll_par_gpio_init, + .set_data_dir = lcd_ll_par_gpio_set_data_dir, + .cmd_start = lcd_ll_par_gpio_cmd_start, + .write_byte = lcd_ll_par_gpio_write_byte, + .read_byte = lcd_ll_par_gpio_read_byte, +#if IS_USED(MODULE_LCD_PARALLEL_16BIT) + .write_word = lcd_ll_par_gpio_write_word, + .read_word = lcd_ll_par_gpio_read_word, +#endif +}; +#endif + +#endif /* IS_USED(MODULE_LCD_PARALLEL) */ diff --git a/drivers/st77xx/st7735_init.c b/drivers/st77xx/st7735_init.c index 273e3fe9b0..7cea363ab5 100644 --- a/drivers/st77xx/st7735_init.c +++ b/drivers/st77xx/st7735_init.c @@ -142,6 +142,7 @@ static inline uint8_t _st7735_calc_vghl(uint16_t vgh, int16_t vgl, uint16_t avdd int st7735_init(lcd_t *dev, const lcd_params_t *params) { + (void)params; assert(params->lines <= 162); assert(params->rgb_channels <= 132); diff --git a/drivers/st77xx/st7789_init.c b/drivers/st77xx/st7789_init.c index b1ab9da9c0..ec15de5f61 100644 --- a/drivers/st77xx/st7789_init.c +++ b/drivers/st77xx/st7789_init.c @@ -124,6 +124,7 @@ static inline uint8_t _st7789_calc_vrh(int16_t vrh) int st7789_init(lcd_t *dev, const lcd_params_t *params) { + (void)params; assert(params->lines <= 320); assert(params->rgb_channels <= 240); diff --git a/drivers/st77xx/st7796_init.c b/drivers/st77xx/st7796_init.c index 8385d04b90..29f7207765 100644 --- a/drivers/st77xx/st7796_init.c +++ b/drivers/st77xx/st7796_init.c @@ -124,6 +124,7 @@ static inline uint8_t _st7796_calc_vrh(int16_t vrh) int st7796_init(lcd_t *dev, const lcd_params_t *params) { + (void)params; assert(params->lines <= 480); assert(params->rgb_channels <= 320); diff --git a/tests/drivers/st77xx/main.c b/tests/drivers/st77xx/main.c index 8421325aa2..d6bfffec4d 100644 --- a/tests/drivers/st77xx/main.c +++ b/tests/drivers/st77xx/main.c @@ -25,6 +25,7 @@ #include "ztimer.h" #include "board.h" #include "lcd.h" +#include "lcd_internal.h" #include "riot_logo.h" @@ -54,6 +55,18 @@ int main(void) return 1; } +#if MODULE_LCD_PARALLEL + if (gpio_is_valid(st77xx_params[0].rdx_pin)) { + uint8_t data[4]; + + lcd_read_cmd(&dev, LCD_CMD_RDDIDIF, data, 3); + printf("lcd ID: %02x %02x %02x\n", data[0], data[1], data[2]); + + lcd_read_cmd(&dev, LCD_CMD_RDDST, data, 4); + printf("lcd status: %02x %02x %02x %02x\n", data[0], data[1], data[2], data[3]); + } +#endif + puts("lcd TFT display filling map"); lcd_fill(&dev, 0, dev.params->lines, 0, dev.params->rgb_channels, 0x0000); puts("lcd TFT display map filled");