diff --git a/drivers/include/lcd.h b/drivers/include/lcd.h index 8ab2dbb2ce..a44d6bb7f6 100644 --- a/drivers/include/lcd.h +++ b/drivers/include/lcd.h @@ -137,6 +137,52 @@ struct lcd_driver { uint16_t y2); }; +/** + * @brief Low Level to acquire the device + * + * @param[out] dev device descriptor + */ +void lcd_ll_acquire(const lcd_t *dev); + +/** + * @brief Low Level function to release the device + * + * @param[out] dev device descriptor + */ +void lcd_ll_release(const lcd_t *dev); + +/** + * @brief Low level function to write a command + * + * @pre The device must have already been acquired with @ref lcd_ll_acquire + * before this function can be called. + * + * @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 + */ +void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, + size_t len); + +/** + * @brief Low level function for read command 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 The device must have already been acquired with @ref lcd_ll_acquire + * before this function can be called. + * @pre len > 0 + * + * @param[in] dev device descriptor + * @param[in] cmd command + * @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); + /** * @brief Setup an lcd display device * diff --git a/drivers/lcd/lcd.c b/drivers/lcd/lcd.c index bb6b0cfd74..c903a1b94a 100644 --- a/drivers/lcd/lcd.c +++ b/drivers/lcd/lcd.c @@ -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 @@ -16,6 +17,7 @@ * * @author Koen Zandberg * @author Francisco Molina + * @author Gunar Schorcht * * @} */ @@ -25,6 +27,7 @@ #include "byteorder.h" #include "periph/spi.h" #include "kernel_defines.h" +#include "ztimer.h" #include "lcd.h" #include "lcd_internal.h" @@ -32,38 +35,127 @@ #define ENABLE_DEBUG 0 #include "debug.h" -static void _lcd_spi_acquire(const lcd_t *dev) +static inline void _lcd_write_byte(const lcd_t *dev, bool cont, uint8_t data) { - spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode, - dev->params->spi_clk); + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, data); + } + else { + assert(false); + } +} + +static inline void _lcd_write_bytes(const lcd_t *dev, bool cont, + const void *data, size_t len) +{ + 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 { + assert(false); + } +} + +static inline void _lcd_read_bytes(const lcd_t *dev, bool cont, + void *data, size_t len) +{ + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + /* Dummy read */ + spi_transfer_byte(dev->params->spi, + dev->params->cs_pin, true, 0x00); + spi_transfer_bytes(dev->params->spi, + dev->params->cs_pin, cont, NULL, data, len); + } + else { + assert(false); + } } static void _lcd_cmd_start(const lcd_t *dev, uint8_t cmd, bool cont) { gpio_clear(dev->params->dcx_pin); - spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, cmd); + _lcd_write_byte(dev, cont, cmd); gpio_set(dev->params->dcx_pin); } -static void _write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, - size_t len) -{ - _lcd_cmd_start(dev, cmd, len ? true : false); - if (len) { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, data, - NULL, len); - } -} - static void _lcd_set_area(const lcd_t *dev, uint16_t x1, uint16_t x2, - uint16_t y1, uint16_t y2) + uint16_t y1, uint16_t y2) { assert(dev->driver->set_area); dev->driver->set_area(dev, x1, x2, y1, y2); } +void lcd_ll_acquire(const lcd_t *dev) +{ + 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 { + assert(false); + } +} + +void lcd_ll_release(const lcd_t *dev) +{ + if (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + spi_release(dev->params->spi); + } + else { + assert(false); + } +} + +void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, + size_t len) +{ + _lcd_cmd_start(dev, cmd, len ? true : false); + if (len) { + _lcd_write_bytes(dev, false, data, len); + } +} + +void lcd_ll_read_cmd(const 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); +} + 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 (dev->params->spi != SPI_UNDEF) { + /* SPI serial interface is used */ + int res = spi_init_cs(dev->params->spi, dev->params->cs_pin); + + if (res != SPI_OK) { + DEBUG("[st7735] init: error initializing the CS pin [%i]\n", res); + return -1; + } + } + else { + assert(false); + } + + if (gpio_is_valid(dev->params->rst_pin)) { + gpio_init(dev->params->rst_pin, GPIO_OUT); + gpio_clear(dev->params->rst_pin); + ztimer_sleep(ZTIMER_MSEC, 120); + gpio_set(dev->params->rst_pin); + } + ztimer_sleep(ZTIMER_MSEC, 120); + if (dev->driver->init) { return dev->driver->init(dev, params); } @@ -73,28 +165,22 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params) } void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data, - size_t len) + size_t len) { - _lcd_spi_acquire(dev); - _write_cmd(dev, cmd, data, len); - spi_release(dev->params->spi); + lcd_ll_acquire(dev); + lcd_ll_write_cmd(dev, cmd, data, len); + lcd_ll_release(dev); } void lcd_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len) { - assert(len); - _lcd_spi_acquire(dev); - _lcd_cmd_start(dev, cmd, true); - /* Dummy transfer */ - spi_transfer_byte(dev->params->spi, dev->params->cs_pin, true, 0x00); - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, NULL, - data, len); - spi_release(dev->params->spi); + 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, - uint16_t y2, uint16_t color) + uint16_t y2, uint16_t color) { /* Send fill area to the display */ @@ -106,7 +192,7 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, x1, x2, y1, y2, (unsigned long)num_pix); /* Send fill area to the display */ - _lcd_spi_acquire(dev); + lcd_ll_acquire(dev); _lcd_set_area(dev, x1, x2, y1, y2); /* Memory access command */ @@ -117,16 +203,14 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1, } for (int i = 0; i < (num_pix - 1); i++) { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true, - (uint8_t *)&color, NULL, sizeof(color)); + _lcd_write_bytes(dev, true, (uint8_t *)&color, sizeof(color)); } - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, - (uint8_t *)&color, NULL, sizeof(color)); - spi_release(dev->params->spi); + _lcd_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, - uint16_t y1, uint16_t y2, const uint16_t *color) + uint16_t y1, uint16_t y2, const uint16_t *color) { size_t num_pix = (x2 - x1 + 1) * (y2 - y1 + 1); @@ -134,7 +218,7 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, "y1: %" PRIu16 ", y2: %" PRIu16 ". Num pixels: %lu\n", x1, x2, y1, y2, (unsigned long)num_pix); - _lcd_spi_acquire(dev); + lcd_ll_acquire(dev); /* Send fill area to the display */ _lcd_set_area(dev, x1, x2, y1, y2); @@ -145,19 +229,16 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, if (IS_ACTIVE(CONFIG_LCD_LE_MODE)) { for (size_t i = 0; i < num_pix - 1; i++) { uint16_t ncolor = htons(*(color + i)); - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true, - &ncolor, NULL, sizeof(uint16_t)); + _lcd_write_bytes(dev, true, &ncolor, sizeof(uint16_t)); } uint16_t ncolor = htons(*(color + num_pix - 1)); - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, - &ncolor, NULL, sizeof(uint16_t)); + _lcd_write_bytes(dev, false, &ncolor, sizeof(uint16_t)); } else { - spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, - (const uint8_t *)color, NULL, num_pix * 2); + _lcd_write_bytes(dev, false, (const uint8_t *)color, num_pix * 2); } - spi_release(dev->params->spi); + lcd_ll_release(dev); } void lcd_invert_on(const lcd_t *dev)