diff --git a/boards/common/esp32x/include/board_common.h b/boards/common/esp32x/include/board_common.h index ca5a074d1ec8..684f13a6638a 100644 --- a/boards/common/esp32x/include/board_common.h +++ b/boards/common/esp32x/include/board_common.h @@ -103,11 +103,15 @@ extern "C" { #define SPI_FLASH_DRIVE_START 0 #endif -/** Default MTD drive definition */ -#define MTD_0 mtd0 +#define MTD_0 mtd0 /**< Flash MTD device */ +extern mtd_dev_t *mtd0; /**< Flash MTD device pointer */ -/** Pointer to the default MTD drive structure */ -extern mtd_dev_t *mtd0; +#if MODULE_MTD_SDCARD_DEFAULT || DOXYGEN + +#define MTD_1 mtd1 /**< SD Card MTD device */ +extern mtd_dev_t *mtd1; /**< SD Card MTD device pointer */ + +#endif /* MODULE_MTD_SDCARD_DEFAULT || DOXYGEN */ /** * @brief MTD offset for SD Card interfaces diff --git a/boards/seeedstudio-gd32/include/board.h b/boards/seeedstudio-gd32/include/board.h index c48afec589da..d41e2d14676d 100644 --- a/boards/seeedstudio-gd32/include/board.h +++ b/boards/seeedstudio-gd32/include/board.h @@ -22,6 +22,7 @@ #define BOARD_H #include "board_common.h" +#include "mtd.h" #ifdef __cplusplus extern "C" { @@ -67,6 +68,25 @@ extern "C" { #define LED_BLUE_PIN LED2_PIN /**< LED2 is blue */ /** @} */ +/** + * @name MTD configuration + * @{ + */ +#define MTD_0 mtd0 /**< MTD device for SD Card */ +extern mtd_dev_t *mtd0; /**< MTD device pointer for SD Card */ +/** @} */ + +/** + * @name SD-Card interface configuration + * @{ + */ +#define SDCARD_SPI_PARAM_SPI SPI_DEV(0) +#define SDCARD_SPI_PARAM_CS GPIO_PIN(PORT_B, 12) +#define SDCARD_SPI_PARAM_CLK GPIO_PIN(PORT_B, 13) +#define SDCARD_SPI_PARAM_MISO GPIO_PIN(PORT_B, 14) +#define SDCARD_SPI_PARAM_MOSI GPIO_PIN(PORT_B, 15) +/** @} */ + #ifdef __cplusplus } #endif diff --git a/boards/sipeed-longan-nano/include/board.h b/boards/sipeed-longan-nano/include/board.h index fbb971eb228e..a22c4554c9cb 100644 --- a/boards/sipeed-longan-nano/include/board.h +++ b/boards/sipeed-longan-nano/include/board.h @@ -21,6 +21,7 @@ #define BOARD_H #include "board_common.h" +#include "mtd.h" #ifdef __cplusplus extern "C" { @@ -62,13 +63,24 @@ extern "C" { #define LED_BLUE_PIN LED2_PIN /**< LED2 is blue */ /** @} */ -#if defined(MODULE_SDCARD_SPI) +/** + * @name MTD configuration + * @{ + */ +#define MTD_0 mtd0 /**< MTD device for SD Card */ +extern mtd_dev_t *mtd0; /**< MTD device pointer for SD Card */ +/** @} */ + +/** + * @name SD-Card interface configuration + * @{ + */ #define SDCARD_SPI_PARAM_SPI SPI_DEV(0) #define SDCARD_SPI_PARAM_CS GPIO_PIN(PORT_B, 12) #define SDCARD_SPI_PARAM_CLK GPIO_PIN(PORT_B, 13) #define SDCARD_SPI_PARAM_MISO GPIO_PIN(PORT_B, 14) #define SDCARD_SPI_PARAM_MOSI GPIO_PIN(PORT_B, 15) -#endif +/** @} */ #if defined(MODULE_ST77XX) && defined(BOARD_SIPEED_LONGAN_NANO_TFT) #define ST77XX_PARAM_SPI SPI_DEV(1) /**< SPI device */ diff --git a/boards/waveshare-nrf52840-eval-kit/include/board.h b/boards/waveshare-nrf52840-eval-kit/include/board.h index 7b7598831587..8f55b3aa95a8 100644 --- a/boards/waveshare-nrf52840-eval-kit/include/board.h +++ b/boards/waveshare-nrf52840-eval-kit/include/board.h @@ -20,6 +20,7 @@ #define BOARD_H #include "board_common.h" +#include "mtd.h" #ifdef __cplusplus extern "C" { @@ -82,6 +83,14 @@ extern "C" { #define SDCARD_SPI_PARAM_MISO GPIO_PIN(0, 20) /** @} */ +/** + * @name MTD configuration + * @{ + */ +#define MTD_0 mtd0 /**< MTD device for SD Card */ +extern mtd_dev_t *mtd0; /**< MTD device pointer for SD Card */ +/** @} */ + #ifdef __cplusplus } #endif diff --git a/drivers/ili9341/include/ili9341_params.h b/drivers/ili9341/include/ili9341_params.h index 0a8ee0dc79cc..e41804eb5675 100644 --- a/drivers/ili9341/include/ili9341_params.h +++ b/drivers/ili9341/include/ili9341_params.h @@ -71,13 +71,45 @@ extern "C" { #define ILI9341_PARAM_OFFSET_Y 0 /**< Vertival offset */ #endif +#if MODULE_LCD_SPI || DOXYGEN +/** Default interface params if SPI serial interface is enabled */ +#define ILI9341_PARAM_IF_SPI .spi = ILI9341_PARAM_SPI, \ + .spi_clk = ILI9341_PARAM_SPI_CLK, \ + .spi_mode = ILI9341_PARAM_SPI_MODE, +#else +#define ILI9341_PARAM_IF_SPI +#endif + +#if MODULE_LCD_PARALLEL || DOXYGEN +/** Default interface params if MCU 8080 8-bit parallel interface is enabled */ +#define ILI9341_PARAM_IF_PAR .d0_pin = ILI9341_PARAM_D0, \ + .d1_pin = ILI9341_PARAM_D1, \ + .d2_pin = ILI9341_PARAM_D2, \ + .d3_pin = ILI9341_PARAM_D3, \ + .d4_pin = ILI9341_PARAM_D4, \ + .d5_pin = ILI9341_PARAM_D5, \ + .d6_pin = ILI9341_PARAM_D6, \ + .d7_pin = ILI9341_PARAM_D7, \ + .wrx_pin = ILI9341_PARAM_WRX, \ + .rdx_pin = ILI9341_PARAM_RDX, +#else +#define ILI9341_PARAM_IF_PAR +#endif + /** * @brief Default params + * + * @note The default parameter set defined here can only be used if a single + * ILI9341 display and only one interface mode is used. If multiple + * ILI9341 displays are used or if multiple interface modes are enabled + * by the modules `lcd_spi`, lcd_parallel and `lcd_parallel_16bit`, a user + * defined parameter set @ref ILI9341_PARAMS has to be defined. In the + * latter case @ref lcd_params_t::spi must then be set to @ref SPI_UNDEF + * for displays with MCU 8080 8-/16-bit parallel interfaces. */ #ifndef ILI9341_PARAMS -#define ILI9341_PARAMS { .spi = ILI9341_PARAM_SPI, \ - .spi_clk = ILI9341_PARAM_SPI_CLK, \ - .spi_mode = ILI9341_PARAM_SPI_MODE, \ +#define ILI9341_PARAMS { ILI9341_PARAM_IF_SPI \ + ILI9341_PARAM_IF_PAR \ .cs_pin = ILI9341_PARAM_CS, \ .dcx_pin = ILI9341_PARAM_DCX, \ .rst_pin = ILI9341_PARAM_RST, \ @@ -124,7 +156,6 @@ static const uint8_t ili9341_screen_ids[] = */ #define ILI9341_SCREEN_NUMOF ARRAY_SIZE(ili9341_screen_ids) - #ifdef __cplusplus } #endif diff --git a/drivers/include/lcd.h b/drivers/include/lcd.h index cf45407a2f0d..11a2959e900a 100644 --- a/drivers/include/lcd.h +++ b/drivers/include/lcd.h @@ -1,6 +1,7 @@ /* * Copyright (C) 2018 Koen Zandberg * 2021 Francisco Molina + * 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 @@ -13,8 +14,22 @@ * * @brief Driver for the LCD display * - * The LCD is a generic display driver for small RGB displays. The driver - * implemented here operates over SPI to communicate with the device. + * The LCD is a generic display driver for small RGB displays. It communicates + * with the device either via an + * + * - SPI serial interface (if module `lcd_spi` enabled) or an + * - MCU 8080 8-/16-bit parallel interface (if module `lcd_parallel` or + * module `lcd_parallel_16` is enabled). + * + * Usually the device driver is used either for a single display with SPI serial + * interface or for a display with parallel MCU 8080 8-/16-bit parallel + * interface. However, the device driver can also be used simultaneously for + * multiple displays with different interfaces if several of the `lcd_spi`, + * `lcd_parallel` and `lcd_parallel_16bit` modules are enabled at the same time. + * In this case, please refer to the notes in @ref lcd_params_t. + * + * @warning MCU 8080 16-bit parallel interface (module `lcd_parallel_16bit`) is + * not supported yet. * * The device requires colors to be send in big endian RGB-565 format. The * @ref CONFIG_LCD_LE_MODE compile time option can switch this, but only use this @@ -28,6 +43,7 @@ * * @author Koen Zandberg * @author Francisco Molina + * @author Gunar Schorcht * */ @@ -35,6 +51,7 @@ #define LCD_H #include "board.h" +#include "mutex.h" #include "periph/spi.h" #include "periph/gpio.h" @@ -70,18 +87,58 @@ extern "C" { /** * @brief Device initialization parameters + * + * @note The device driver can be used simultaneously for displays with + * SPI serial interface and parallel MCU 8080 8-/16-bit interfaces + * if the modules `lcd_spi` and `lcd_parallel` or `lcd_parallel_16bit` + * are enabled at the same time. In this case the interface parameters + * for the SPI serial interface and the MCU 8080 parallel 8-/16-bit + * interfaces are defined. @ref lcd_params_t::spi must then be set to + * @ref SPI_UNDEF for displays that use the MCU-8080-parallel-8-/16-bit + * interface, i.e. @ref lcd_params_t::spi is then used to detect the + * interface mode. */ typedef struct { +#if MODULE_LCD_SPI || DOXYGEN + /* Interface parameters used for serial interface */ spi_t spi; /**< SPI device that the display is connected to */ spi_clk_t spi_clk; /**< SPI clock speed to use */ spi_mode_t spi_mode; /**< SPI mode */ +#endif +#if MODULE_LCD_PARALLEL || DOXYGEN + /* Interface parameters used for MCU 8080 8-bit parallel interface */ + gpio_t wrx_pin; /**< pin connected to the WRITE ENABLE line */ + gpio_t rdx_pin; /**< pin connected to the READ ENABLE line */ + gpio_t d0_pin; /**< pin connected to the D0 line */ + gpio_t d1_pin; /**< pin connected to the D1 line */ + gpio_t d2_pin; /**< pin connected to the D2 line */ + gpio_t d3_pin; /**< pin connected to the D3 line */ + gpio_t d4_pin; /**< pin connected to the D4 line */ + gpio_t d5_pin; /**< pin connected to the D5 line */ + gpio_t d6_pin; /**< pin connected to the D6 line */ + gpio_t d7_pin; /**< pin connected to the D7 line */ +#if MODULE_LCD_PARALLEL_16BIT || DOXYGEN + /* Interface parameters used for MCU 8080 16-bit parallel interface */ + gpio_t d8_pin; /**< pin connected to the D8 line */ + gpio_t d9_pin; /**< pin connected to the D9 line */ + gpio_t d10_pin; /**< pin connected to the D10 line */ + gpio_t d11_pin; /**< pin connected to the D11 line */ + gpio_t d12_pin; /**< pin connected to the D12 line */ + gpio_t d13_pin; /**< pin connected to the D13 line */ + gpio_t d14_pin; /**< pin connected to the D14 line */ + gpio_t d15_pin; /**< pin connected to the D15 line */ +#endif /* MODULE_LCD_PARALLEL_16BIT */ +#endif /* MODULE_LCD_PARALLEL */ + /* Common interface parameters */ gpio_t cs_pin; /**< pin connected to the CHIP SELECT line */ gpio_t dcx_pin; /**< pin connected to the DC line */ - gpio_t rst_pin; /**< pin connected to the reset line */ - bool rgb; /**< True when display is connected in RGB mode - * False when display is connected in BGR mode */ + gpio_t rst_pin; /**< pin connected to the RESET line */ + bool rgb; /**< True when display is connected in RGB mode\n + False when display is connected in BGR mode */ bool inverted; /**< Display works in inverted color mode */ - uint16_t lines; /**< Number of lines, from 16 to 320 in 8 line steps */ + uint16_t lines; /**< Number of lines, from 16 to the number of + lines supported by the driver IC in 8 line + steps */ uint16_t rgb_channels; /**< Display rgb channels */ uint8_t rotation; /**< Display rotation mode */ uint8_t offset_x; /**< LCD offset to apply on x axis. */ @@ -104,11 +161,15 @@ typedef struct lcd_driver lcd_driver_t; * @brief Device descriptor for a lcd */ typedef struct { -#ifdef MODULE_DISP_DEV +#if MODULE_DISP_DEV || DOXYGEN disp_dev_t *dev; /**< Pointer to the generic display device */ #endif const lcd_driver_t *driver; /**< LCD driver */ const lcd_params_t *params; /**< Device initialization parameters */ +#if MODULE_LCD_PARALLEL || DOXYGEN + mutex_t lock; /**< Mutex used to lock the device in + MCU 8080 parallel interface mode */ +#endif } lcd_t; /** @@ -142,7 +203,7 @@ struct lcd_driver { * @param[in] y2 y coordinate of the opposite corner * */ - void (*set_area)(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, + void (*set_area)(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2); }; @@ -162,14 +223,14 @@ struct lcd_driver { * * @param[out] dev device descriptor */ -void lcd_ll_acquire(const lcd_t *dev); +void lcd_ll_acquire(lcd_t *dev); /** * @brief Low-level function to release the device * * @param[out] dev device descriptor */ -void lcd_ll_release(const lcd_t *dev); +void lcd_ll_release(lcd_t *dev); /** * @brief Low-level function to write a command @@ -182,7 +243,7 @@ void lcd_ll_release(const lcd_t *dev); * @param[in] data command data to the device * @param[in] len length of the command data */ -void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, +void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, size_t len); /** @@ -201,7 +262,7 @@ void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, * @param[out] data data from the device * @param[in] len length of the returned data */ -void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len); +void lcd_ll_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len); /** @} */ /** @@ -234,7 +295,7 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params); * @param[in] y2 y coordinate of the opposite corner * @param[in] color single color to fill the area with */ -void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, +void lcd_fill(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, uint16_t color); /** @@ -253,7 +314,7 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, * @param[in] y2 y coordinate of the opposite corner * @param[in] color array of colors to fill the area with */ -void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, +void lcd_pixmap(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, const uint16_t *color); /** @@ -264,12 +325,16 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, * @param[in] data command data to the device * @param[in] len length of the command data */ -void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, +void lcd_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, size_t len); /** * @brief Raw read command * + * @note Very often the SPI MISO signal of the serial interface or the RDX + * signal of the MCU 8080 parallel interface are not connected to the + * display. In this case the read command does not provide valid data. + * * @pre len > 0 * * @param[in] dev device descriptor @@ -277,21 +342,21 @@ void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, * @param[out] data data from the device * @param[in] len length of the returned data */ -void lcd_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len); +void lcd_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len); /** * @brief Invert the display colors * * @param[in] dev device descriptor */ -void lcd_invert_on(const lcd_t *dev); +void lcd_invert_on(lcd_t *dev); /** * @brief Disable color inversion * * @param[in] dev device descriptor */ -void lcd_invert_off(const lcd_t *dev); +void lcd_invert_off(lcd_t *dev); /** @} */ #ifdef __cplusplus diff --git a/drivers/include/st77xx.h b/drivers/include/st77xx.h index 2353aca0f67e..8c9e760fee48 100644 --- a/drivers/include/st77xx.h +++ b/drivers/include/st77xx.h @@ -22,8 +22,18 @@ * @ref lcd_params_t::cntrl or as macro @ref ST77XX_PARAM_CNTRL if the * default parameter set @ref ST77XX_PARAMS is used. * - * The driver uses the SPI serial interface to communicate with the display - * controller. + * The driver communicates with the device either via an + * + * - SPI serial interface (if module `lcd_spi` enabled) or an + * - MCU 8080 8-/16-bit parallel interface (if module `lcd_parallel` or + * module `lcd_parallel_16` is enabled). + * + * Usually the device driver is used either for a single display with SPI serial + * interface or for a display with parallel MCU 8080 8-/16-bit parallel + * interface. However, the device driver can also be used simultaneously for + * multiple displays with different interfaces if several of the `lcd_spi`, + * `lcd_parallel` and `lcd_parallel_16bit` modules are enabled at the same time. + * In this case, please refer to the notes in @ref lcd_params_t. * * The device requires colors to be send in big endian RGB-565 format. The * @ref CONFIG_LCD_LE_MODE compile time option can switch this, but only use this diff --git a/drivers/lcd/Kconfig b/drivers/lcd/Kconfig index ddbdb30db738..05626f433c0a 100644 --- a/drivers/lcd/Kconfig +++ b/drivers/lcd/Kconfig @@ -7,10 +7,8 @@ config MODULE_LCD bool "LCD display driver" - depends on HAS_PERIPH_SPI depends on HAS_PERIPH_GPIO depends on TEST_KCONFIG - select MODULE_PERIPH_SPI select MODULE_PERIPH_GPIO config MODULE_LCD_MULTI_CNTRL @@ -18,6 +16,48 @@ config MODULE_LCD_MULTI_CNTRL help The controller-specific driver supports multiple controller variants. +config MODULE_LCD_SPI + bool + 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 + +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 HAVE_LCD_SPI + bool + help + Indicates that a display with MCU 8080 8-/16-bit parallel interface + is present + +config HAVE_LCD_PARALLEL + bool + help + Indicates that a display with MCU 8080 8-/16-bit parallel interface + is present + +config HAVE_LCD_PARALLEL_16BIT + bool + help + Indicates that a display with MCU 8080 16-bit parallel interface + is present + 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 81b9570471bf..0a69ce521695 100644 --- a/drivers/lcd/Makefile.dep +++ b/drivers/lcd/Makefile.dep @@ -1,2 +1,14 @@ -FEATURES_REQUIRED += periph_spi FEATURES_REQUIRED += periph_gpio + +ifneq (,$(filter lcd_parallel_16bit,$(USEMODULE))) + USEMODULE += lcd_parallel +endif + +ifeq (,$(filter lcd_parallel%,$(USEMODULE))) + # default to SPI serial interface if no MCU 8080 parallel interface is enabled + USEMODULE += lcd_spi +endif + +ifneq (,$(filter lcd_spi,$(USEMODULE))) + FEATURES_REQUIRED += periph_spi +endif diff --git a/drivers/lcd/Makefile.include b/drivers/lcd/Makefile.include index 50d8dcd5fe75..92015f1c5fb9 100644 --- a/drivers/lcd/Makefile.include +++ b/drivers/lcd/Makefile.include @@ -1,4 +1,8 @@ PSEUDOMODULES += lcd_multi_cntrl +PSEUDOMODULES += lcd_spi +PSEUDOMODULES += lcd_parallel +PSEUDOMODULES += lcd_parallel_16bit + USEMODULE_INCLUDES_lcd := $(LAST_MAKEFILEDIR)/include USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_lcd) diff --git a/drivers/lcd/lcd.c b/drivers/lcd/lcd.c index 1b7685fc36e1..0085cf735488 100644 --- a/drivers/lcd/lcd.c +++ b/drivers/lcd/lcd.c @@ -25,43 +25,149 @@ #include #include #include "byteorder.h" -#include "periph/spi.h" #include "kernel_defines.h" #include "ztimer.h" +#if IS_USED(MODULE_LCD_SPI) +#include "periph/spi.h" +#endif + #include "lcd.h" #include "lcd_internal.h" #define ENABLE_DEBUG 0 #include "debug.h" -static inline void _lcd_write_byte(const lcd_t *dev, bool cont, uint8_t data) +#if IS_USED(MODULE_LCD_PARALLEL) + +#if MODULE_LCD_PARALLEL_16BIT +#error "MCU 8080 16-bit parallel interface is not supported yet" +#endif + +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); + }; +} + +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; +} + +static void lcd_ll_par_read_bytes(lcd_t *dev, bool cont, + void *data, size_t len) +{ + assert(len); + + uint8_t *data_in = data; + + for (size_t i = 0; i < len; i++) { + data_in[i] = lcd_ll_par_read_byte(dev, i == (len - 1) ? cont : true); + } +} + +static void lcd_ll_par_write_bytes(lcd_t *dev, bool cont, + const void *data, size_t len) +{ + assert(len); + + const uint8_t *data_out = data; + + for (size_t i = 0; i < len; i++) { + lcd_ll_par_write_byte(dev, i == (len - 1) ? cont : true, data_out[i]); + } +} + +#endif /* IS_USED(MODULE_LCD_PARALLEL) */ + +static inline void lcd_ll_write_byte(lcd_t *dev, bool cont, uint8_t data) +{ +#if IS_USED(MODULE_LCD_SPI) if (dev->params->spi != SPI_UNDEF) { /* SPI serial interface is used */ spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, data); } else { +#endif +#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) } +#endif } -static inline void _lcd_write_bytes(const lcd_t *dev, bool cont, - const void *data, size_t len) +static inline void lcd_ll_write_bytes(lcd_t *dev, bool cont, + const void *data, size_t len) { +#if IS_USED(MODULE_LCD_SPI) if (dev->params->spi != SPI_UNDEF) { /* SPI serial interface is used */ spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, cont, data, NULL, len); } else { +#endif +#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) } +#endif } -static inline void _lcd_read_bytes(const lcd_t *dev, bool cont, - void *data, size_t len) +static inline void lcd_ll_read_bytes(lcd_t *dev, bool cont, + void *data, size_t len) { +#if IS_USED(MODULE_LCD_SPI) if (dev->params->spi != SPI_UNDEF) { /* SPI serial interface is used */ /* Dummy read */ @@ -71,19 +177,50 @@ static inline void _lcd_read_bytes(const lcd_t *dev, bool cont, dev->params->cs_pin, cont, NULL, data, len); } else { +#endif +#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); + + /* 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); +#else assert(false); +#endif +#if IS_USED(MODULE_LCD_SPI) } +#endif } -static void _lcd_cmd_start(const lcd_t *dev, uint8_t cmd, bool cont) +static void lcd_ll_cmd_start(lcd_t *dev, uint8_t cmd, bool cont) { gpio_clear(dev->params->dcx_pin); - _lcd_write_byte(dev, cont, cmd); + lcd_ll_write_byte(dev, cont, cmd); gpio_set(dev->params->dcx_pin); } -static void _lcd_set_area_default(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) +static void lcd_ll_set_area_default(lcd_t *dev, uint16_t x1, uint16_t x2, + uint16_t y1, uint16_t y2) { be_uint16_t params[2]; @@ -106,54 +243,72 @@ static void _lcd_set_area_default(const lcd_t *dev, uint16_t x1, uint16_t x2, sizeof(params)); } -static void _lcd_set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) +static 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); } else { - _lcd_set_area_default(dev, x1, x2, y1, y2); + lcd_ll_set_area_default(dev, x1, x2, y1, y2); } } -void lcd_ll_acquire(const lcd_t *dev) +void lcd_ll_acquire(lcd_t *dev) { +#if IS_USED(MODULE_LCD_SPI) if (dev->params->spi != SPI_UNDEF) { /* SPI serial interface is used */ spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode, dev->params->spi_clk); } else { +#endif +#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) } +#endif } -void lcd_ll_release(const lcd_t *dev) +void lcd_ll_release(lcd_t *dev) { +#if IS_USED(MODULE_LCD_SPI) if (dev->params->spi != SPI_UNDEF) { /* SPI serial interface is used */ spi_release(dev->params->spi); } else { +#endif +#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) } +#endif } -void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, +void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, size_t len) { - _lcd_cmd_start(dev, cmd, len ? true : false); + lcd_ll_cmd_start(dev, cmd, len ? true : false); if (len) { - _lcd_write_bytes(dev, false, data, len); + lcd_ll_write_bytes(dev, false, data, len); } } -void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) +void lcd_ll_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) { assert(len); - _lcd_cmd_start(dev, cmd, len ? true : false); - _lcd_read_bytes(dev, false, data, len); + lcd_ll_cmd_start(dev, cmd, len ? true : false); + lcd_ll_read_bytes(dev, false, data, len); } int lcd_init(lcd_t *dev, const lcd_params_t *params) @@ -163,6 +318,7 @@ int lcd_init(lcd_t *dev, const lcd_params_t *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) { /* SPI serial interface is used */ int res = spi_init_cs(dev->params->spi, dev->params->cs_pin); @@ -173,8 +329,50 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) } } else { - assert(false); +#endif +#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->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); +#else + assert(false); +#endif +#if IS_USED(MODULE_LCD_SPI) } +#endif if (gpio_is_valid(dev->params->rst_pin)) { gpio_init(dev->params->rst_pin, GPIO_OUT); @@ -184,12 +382,16 @@ 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); } -void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, +void lcd_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data, size_t len) { lcd_ll_acquire(dev); @@ -197,14 +399,14 @@ void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, lcd_ll_release(dev); } -void lcd_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) +void lcd_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) { lcd_ll_acquire(dev); lcd_ll_read_cmd(dev, cmd, data, len); lcd_ll_release(dev); } -void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, +void lcd_fill(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, uint16_t color) { /* Send fill area to the display */ @@ -219,22 +421,22 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, /* Send fill area to the display */ lcd_ll_acquire(dev); - _lcd_set_area(dev, x1, x2, y1, y2); + lcd_ll_set_area(dev, x1, x2, y1, y2); /* Memory access command */ - _lcd_cmd_start(dev, LCD_CMD_RAMWR, true); + lcd_ll_cmd_start(dev, LCD_CMD_RAMWR, true); if (IS_ACTIVE(CONFIG_LCD_LE_MODE)) { color = htons(color); } for (int i = 0; i < (num_pix - 1); i++) { - _lcd_write_bytes(dev, true, (uint8_t *)&color, sizeof(color)); + lcd_ll_write_bytes(dev, true, (uint8_t *)&color, sizeof(color)); } - _lcd_write_bytes(dev, false, (uint8_t *)&color, sizeof(color)); + lcd_ll_write_bytes(dev, false, (uint8_t *)&color, sizeof(color)); lcd_ll_release(dev); } -void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, +void lcd_pixmap(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, uint16_t y2, const uint16_t *color) { size_t num_pix = (x2 - x1 + 1) * (y2 - y1 + 1); @@ -246,27 +448,27 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, lcd_ll_acquire(dev); /* Send fill area to the display */ - _lcd_set_area(dev, x1, x2, y1, y2); + lcd_ll_set_area(dev, x1, x2, y1, y2); /* Memory access command */ - _lcd_cmd_start(dev, LCD_CMD_RAMWR, true); + lcd_ll_cmd_start(dev, LCD_CMD_RAMWR, true); if (IS_ACTIVE(CONFIG_LCD_LE_MODE)) { for (size_t i = 0; i < num_pix - 1; i++) { uint16_t ncolor = htons(*(color + i)); - _lcd_write_bytes(dev, true, &ncolor, sizeof(uint16_t)); + lcd_ll_write_bytes(dev, true, &ncolor, sizeof(uint16_t)); } uint16_t ncolor = htons(*(color + num_pix - 1)); - _lcd_write_bytes(dev, false, &ncolor, sizeof(uint16_t)); + lcd_ll_write_bytes(dev, false, &ncolor, sizeof(uint16_t)); } else { - _lcd_write_bytes(dev, false, (const uint8_t *)color, num_pix * 2); + lcd_ll_write_bytes(dev, false, (const uint8_t *)color, num_pix * 2); } lcd_ll_release(dev); } -void lcd_invert_on(const lcd_t *dev) +void lcd_invert_on(lcd_t *dev) { uint8_t command = (dev->params->inverted) ? LCD_CMD_DINVOFF : LCD_CMD_DINVON; @@ -274,7 +476,7 @@ void lcd_invert_on(const lcd_t *dev) lcd_write_cmd(dev, command, NULL, 0); } -void lcd_invert_off(const lcd_t *dev) +void lcd_invert_off(lcd_t *dev) { uint8_t command = (dev->params->inverted) ? LCD_CMD_DINVON : LCD_CMD_DINVOFF; @@ -282,7 +484,7 @@ void lcd_invert_off(const lcd_t *dev) lcd_write_cmd(dev, command, NULL, 0); } -void lcd_set_brightness(const lcd_t *dev, uint8_t brightness) +void lcd_set_brightness(lcd_t *dev, uint8_t brightness) { lcd_write_cmd(dev, LCD_CMD_WRDISBV, &brightness, 1); uint8_t param = 0x26; diff --git a/drivers/lcd/lcd_disp_dev.c b/drivers/lcd/lcd_disp_dev.c index 05309981c4b6..fc2a92d646be 100644 --- a/drivers/lcd/lcd_disp_dev.c +++ b/drivers/lcd/lcd_disp_dev.c @@ -57,7 +57,7 @@ static uint8_t _lcd_color_depth(const disp_dev_t *disp_dev) static void _lcd_set_invert(const disp_dev_t *disp_dev, bool invert) { - const lcd_t *dev = (lcd_t *)disp_dev; + lcd_t *dev = (lcd_t *)disp_dev; assert(dev); diff --git a/drivers/st77xx/include/st77xx_params.h b/drivers/st77xx/include/st77xx_params.h index e3b2ab7b309a..37508059cf4a 100644 --- a/drivers/st77xx/include/st77xx_params.h +++ b/drivers/st77xx/include/st77xx_params.h @@ -137,14 +137,46 @@ extern "C" { #define ST77XX_PARAM_OFFSET_Y 0 /**< Vertival offset */ #endif +#if MODULE_LCD_SPI || DOXYGEN +/** Default interface params if SPI serial interface is enabled */ +#define ST77XX_PARAM_IF_SPI .spi = ST77XX_PARAM_SPI, \ + .spi_clk = ST77XX_PARAM_SPI_CLK, \ + .spi_mode = ST77XX_PARAM_SPI_MODE, +#else +#define ST77XX_PARAM_IF_SPI +#endif + +#if MODULE_LCD_PARALLEL || DOXYGEN +/** Default interface params if MCU 8080 8-bit parallel interface is enabled */ +#define ST77XX_PARAM_IF_PAR .d0_pin = ST77XX_PARAM_D0, \ + .d1_pin = ST77XX_PARAM_D1, \ + .d2_pin = ST77XX_PARAM_D2, \ + .d3_pin = ST77XX_PARAM_D3, \ + .d4_pin = ST77XX_PARAM_D4, \ + .d5_pin = ST77XX_PARAM_D5, \ + .d6_pin = ST77XX_PARAM_D6, \ + .d7_pin = ST77XX_PARAM_D7, \ + .wrx_pin = ST77XX_PARAM_WRX, \ + .rdx_pin = ST77XX_PARAM_RDX, +#else +#define ST77XX_PARAM_IF_PAR +#endif + /** * @brief Default params + * + * @note The default parameter set defined here can only be used if a single + * ST77xx display and only one interface mode is used. If multiple + * ST77xx displays are used or if multiple interface modes are enabled + * by the modules `lcd_spi`, lcd_parallel and `lcd_parallel_16bit`, a user + * defined parameter set @ref ST77XX_PARAMS has to be defined. In the + * latter case @ref lcd_params_t::spi must then be set to @ref SPI_UNDEF + * for displays with MCU 8080 8-/16-bit parallel interfaces. */ #ifndef ST77XX_PARAMS #define ST77XX_PARAMS { .cntrl = ST77XX_PARAM_CNTRL, \ - .spi = ST77XX_PARAM_SPI, \ - .spi_clk = ST77XX_PARAM_SPI_CLK, \ - .spi_mode = ST77XX_PARAM_SPI_MODE, \ + ST77XX_PARAM_IF_SPI \ + ST77XX_PARAM_IF_PAR \ .cs_pin = ST77XX_PARAM_CS, \ .dcx_pin = ST77XX_PARAM_DCX, \ .rst_pin = ST77XX_PARAM_RST, \ @@ -156,7 +188,7 @@ extern "C" { .offset_x = ST77XX_PARAM_OFFSET_X, \ .offset_y = ST77XX_PARAM_OFFSET_Y, \ } -#endif +#endif /* ST77XX_PARAMS */ /** @} */ /**