1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 00:09:46 +01:00

drivers/lcd: add MCU-driven low-level parallel interface

This commit is contained in:
Gunar Schorcht 2023-09-23 07:40:37 +02:00
parent 0353e05bc3
commit e0a76c5768
6 changed files with 172 additions and 38 deletions

View File

@ -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);
@ -350,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);
@ -387,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

View File

@ -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

View File

@ -1,6 +1,6 @@
FEATURES_REQUIRED += periph_gpio
ifneq (,$(filter lcd_parallel_16bit,$(USEMODULE)))
ifneq (,$(filter lcd_parallel_%,$(USEMODULE)))
USEMODULE += lcd_parallel
endif

View File

@ -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)

View File

@ -26,6 +26,7 @@
#include <string.h>
#include "byteorder.h"
#include "kernel_defines.h"
#include "log.h"
#include "ztimer.h"
#if IS_USED(MODULE_LCD_SPI)
@ -43,24 +44,24 @@
static void lcd_ll_par_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
lcd_ll_par_gpio_write_byte(dev, cont, out);
lcd_ll_par_driver.write_byte(dev, cont, out);
}
static uint8_t lcd_ll_par_read_byte(lcd_t *dev, bool cont)
{
return lcd_ll_par_gpio_read_byte(dev, cont);
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)
{
lcd_ll_par_gpio_write_word(dev, cont, out);
lcd_ll_par_driver.write_word(dev, cont, out);
}
static uint16_t lcd_ll_par_read_word(lcd_t *dev, bool cont)
{
return lcd_ll_par_gpio_read_word(dev, cont);
return lcd_ll_par_driver.read_word(dev, cont);
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
@ -83,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]);
@ -108,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);
@ -129,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)
}
@ -151,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)
}
@ -172,21 +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 */
lcd_ll_par_gpio_set_data_dir(dev, false);
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 */
lcd_ll_par_gpio_set_data_dir(dev, true);
#else
assert(false);
lcd_ll_par_driver.set_data_dir(dev, true);
#endif
#if IS_USED(MODULE_LCD_SPI)
}
@ -197,7 +192,7 @@ static void lcd_ll_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
#if IS_USED(MODULE_LCD_PARALLEL)
if (dev->params->mode != LCD_IF_SPI) {
lcd_ll_par_gpio_cmd_start(dev, cmd, cont);
lcd_ll_par_driver.cmd_start(dev, cmd, cont);
}
else {
#endif
@ -265,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)
}
@ -290,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)
}
@ -336,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);
@ -350,12 +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)
lcd_ll_par_gpio_init(dev);
#else
mutex_init(&dev->lock);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
dev->word_access = false;
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
/* 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
@ -368,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);

View File

@ -243,4 +243,20 @@ uint16_t lcd_ll_par_gpio_read_word(lcd_t *dev, bool cont)
}
#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) */