Skip to content

Commit

Permalink
Merge #19937
Browse files Browse the repository at this point in the history
19937: drivers/lcd: add MCU 8080 16-bit parallel mode support r=benpicco a=gschorcht

### Contribution description

This PR adds the 16-bit support for MCU 8080 parallel mode for LCD driver ICs.

### Testing procedure

Use either PR #19938
```
BOARD=stm32l496g-disco make -j8 -C tests/drivers/st77xx
```
or #19939  on top of this PR to test.
```
BOARD=sstm32f723e-disco make -j8 -C tests/drivers/st77xx
```

### Issues/PRs references

Prerequisite for PR #19938 or PR #19938

Co-authored-by: Gunar Schorcht <gunar@schorcht.net>
  • Loading branch information
bors[bot] and gschorcht authored Sep 21, 2023
2 parents 19efd67 + c3006c5 commit 6bac151
Show file tree
Hide file tree
Showing 5 changed files with 259 additions and 22 deletions.
29 changes: 28 additions & 1 deletion drivers/ili9341/include/ili9341_params.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,31 @@ extern "C" {
#define ILI9341_PARAM_IF_PAR
#endif

#if MODULE_LCD_PARALLEL_16BIT || DOXYGEN
/** Additional default interface params if MCU 8080 16-bit parallel interface is enabled */
#define ILI9341_PARAM_IF_PAR_16BIT .d8_pin = ILI9341_PARAM_D8, \
.d9_pin = ILI9341_PARAM_D9, \
.d10_pin = ILI9341_PARAM_D10, \
.d11_pin = ILI9341_PARAM_D11, \
.d12_pin = ILI9341_PARAM_D12, \
.d13_pin = ILI9341_PARAM_D13, \
.d14_pin = ILI9341_PARAM_D14, \
.d15_pin = ILI9341_PARAM_D15,
#else
#define ILI9341_PARAM_IF_PAR_16BIT
#endif

#if MODULE_LCD_PARALLEL_16BIT || DOXYGEN
/** Interface mode is MCU 8080 16-bit parallel */
#define ILI9341_PARAM_IF_MODE .mode = LCD_IF_PARALLEL_16BIT,
#elif MODULE_LCD_PARALLEL
/** Interface mode is MCU 8080 8-bit parallel */
#define ILI9341_PARAM_IF_MODE .mode = LCD_IF_PARALLEL_8BIT,
#else
/** Interface mode parameter is not defined */
#define ILI9341_PARAM_IF_MODE
#endif

/**
* @brief Default params
*
Expand All @@ -108,8 +133,10 @@ extern "C" {
* for displays with MCU 8080 8-/16-bit parallel interfaces.
*/
#ifndef ILI9341_PARAMS
#define ILI9341_PARAMS { ILI9341_PARAM_IF_SPI \
#define ILI9341_PARAMS { ILI9341_PARAM_IF_MODE \
ILI9341_PARAM_IF_SPI \
ILI9341_PARAM_IF_PAR \
ILI9341_PARAM_IF_PAR_16BIT \
.cs_pin = ILI9341_PARAM_CS, \
.dcx_pin = ILI9341_PARAM_DCX, \
.rst_pin = ILI9341_PARAM_RST, \
Expand Down
22 changes: 19 additions & 3 deletions drivers/include/lcd.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,6 @@
* `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
* when strictly necessary. This option will slow down the driver as it
Expand Down Expand Up @@ -85,6 +82,21 @@ extern "C" {
#define LCD_MADCTL_MH 0x04 /**< Horizontal refresh direction */
/** @} */

#if MODULE_LCD_PARALLEL || DOXYGEN
/**
* @brief Display interface modi
*
* This enumeration is only needed if the MCU 8080 8-/16-bit interfaces are
* enabled by `lcd_parallel` or `lcd_parallel_16bit`. Otherwise the serial
* SPI interface is implicitly assumed.
*/
typedef enum {
LCD_IF_SPI, /**< SPI serial interface mode */
LCD_IF_PARALLEL_8BIT, /**< MCU 8080 8-bit parallel interface mode */
LCD_IF_PARALLEL_16BIT, /**< MCU 8080 16-bit parallel interface mode */
} lcd_if_mode_t;
#endif

/**
* @brief Device initialization parameters
*
Expand All @@ -106,6 +118,7 @@ typedef struct {
spi_mode_t spi_mode; /**< SPI mode */
#endif
#if MODULE_LCD_PARALLEL || DOXYGEN
lcd_if_mode_t mode; /**< LCD driver interface mode */
/* 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 */
Expand Down Expand Up @@ -170,6 +183,9 @@ typedef struct {
mutex_t lock; /**< Mutex used to lock the device in
MCU 8080 parallel interface mode */
#endif
#if MODULE_LCD_PARALLEL_16BIT || DOXYGEN
bool word_access; /**< indicates that a word access is active */
#endif
} lcd_t;

/**
Expand Down
4 changes: 3 additions & 1 deletion drivers/lcd/include/lcd_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extern "C" {
*/
#define LCD_CMD_SWRESET 0x01 /**< Software reset */
#define LCD_CMD_RDDIDIF 0x04 /**< Read display ID */
#define LCD_CMD_SPLIN 0x10 /**< Enter sleep mode */
#define LCD_CMD_SLPIN 0x10 /**< Enter sleep mode */
#define LCD_CMD_SLPOUT 0x11 /**< Sleep out */
#define LCD_CMD_NORON 0x13 /**< Normal display mode on */
#define LCD_CMD_DINVOFF 0x20 /**< Display inversion off */
Expand All @@ -55,6 +55,8 @@ extern "C" {
#define LCD_CMD_TEON 0x35 /**< Tearing Effect Line On */
#define LCD_CMD_COLMOD 0x3A /**< Interface Pixel Format Set */
#define LCD_CMD_PIXSET 0x3A /**< COLMOD: Pixel Format Set */
#define LCD_CMD_RAMWRC 0x3c /**< Memory Write Continue */
#define LCD_CMD_RAMRDC 0x3e /**< Memory Read Continue */
#define LCD_CMD_WRDISBV 0x51 /**< Write Display Brightness */
#define LCD_CMD_WRCTRLD 0x53 /**< Write Control Display */
#define LCD_CMD_RDCTRLD 0x54 /**< Read Control Display */
Expand Down
197 changes: 181 additions & 16 deletions drivers/lcd/lcd.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,6 @@

#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)) {
Expand Down Expand Up @@ -96,17 +92,76 @@ static uint8_t lcd_ll_par_read_byte(lcd_t *dev, bool cont)
return in;
}

static void lcd_ll_par_read_bytes(lcd_t *dev, bool cont,
void *data, size_t len)
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)

static void lcd_ll_par_write_word(lcd_t *dev, bool cont, uint16_t out)
{
assert(len);
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}

uint8_t *data_in = data;
gpio_clear(dev->params->wrx_pin);

for (size_t i = 0; i < len; i++) {
data_in[i] = lcd_ll_par_read_byte(dev, i == (len - 1) ? cont : true);
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);
};
}

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;
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */

static void lcd_ll_par_write_bytes(lcd_t *dev, bool cont,
const void *data, size_t len)
Expand All @@ -115,11 +170,49 @@ static void lcd_ll_par_write_bytes(lcd_t *dev, bool cont,

const uint8_t *data_out = data;

#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
if (dev->word_access) {
/* len has to be a multiple of two for word access */
assert((len % 2) == 0);
for (size_t i = 0; i < len; i += 2) {
/* data[i] is the high byte and data[i+1] is the low byte in BE */
uint16_t out_word = (data_out[i] << 8) + data_out[i + 1];
lcd_ll_par_write_word(dev, i == (len - 2) ? cont : true, out_word);
}
return;
}
#endif

for (size_t i = 0; i < len; i++) {
lcd_ll_par_write_byte(dev, i == (len - 1) ? cont : true, data_out[i]);
}
}

static void lcd_ll_par_read_bytes(lcd_t *dev, bool cont,
void *data, size_t len)
{
assert(len);

uint8_t *data_in = data;

#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
if (dev->word_access) {
/* len has to be a multiple of two for word access */
assert((len % 2) == 0);
for (size_t i = 0; i < len; i += 2) {
uint16_t in_word = lcd_ll_par_read_word(dev, i == (len - 2) ? cont : true);
data_in[i] = in_word >> 8; /* data[i] is the high byte in BE */
data_in[i + 1] = in_word & 0xff; /* data[i+1] is the low byte in BE */
}
return;
}
#endif

for (size_t i = 0; i < len; i++) {
data_in[i] = lcd_ll_par_read_byte(dev, i == (len - 1) ? cont : true);
}
}

#endif /* IS_USED(MODULE_LCD_PARALLEL) */

static inline void lcd_ll_write_byte(lcd_t *dev, bool cont, uint8_t data)
Expand Down Expand Up @@ -190,6 +283,18 @@ static inline void lcd_ll_read_bytes(lcd_t *dev, bool cont,
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) */

/* Dummy read */
lcd_ll_par_read_byte(dev, true);
Expand All @@ -204,6 +309,18 @@ static inline void lcd_ll_read_bytes(lcd_t *dev, bool cont,
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);
#endif
Expand All @@ -217,6 +334,15 @@ 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_16BIT)
/* only the RAMRD and RAMRDC commands use 16-bit data access */
if (((cmd == LCD_CMD_RAMWR) || (cmd == LCD_CMD_RAMWRC) ||
(cmd == LCD_CMD_RAMRD) || (cmd == LCD_CMD_RAMRDC)) &&
(dev->params->mode == LCD_IF_PARALLEL_16BIT)) {
dev->word_access = true;
}
#endif
}

static void lcd_ll_set_area_default(lcd_t *dev, uint16_t x1, uint16_t x2,
Expand Down Expand Up @@ -277,6 +403,11 @@ void lcd_ll_acquire(lcd_t *dev)

void lcd_ll_release(lcd_t *dev)
{
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
/* reset word to byte access */
dev->word_access = false;
#endif

#if IS_USED(MODULE_LCD_SPI)
if (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
Expand All @@ -298,6 +429,14 @@ void lcd_ll_release(lcd_t *dev)
void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data,
size_t len)
{
DEBUG("[%s] command 0x%02x (%u) ", __func__, cmd, len);
if (IS_USED(ENABLE_DEBUG) && len) {
for (uint8_t i = 0; i < len; i++) {
DEBUG("0x%02x ", data[i]);
}
}
DEBUG("\n");

lcd_ll_cmd_start(dev, cmd, len ? true : false);
if (len) {
lcd_ll_write_bytes(dev, false, data, len);
Expand All @@ -307,8 +446,18 @@ void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data,
void lcd_ll_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len)
{
assert(len);
lcd_ll_cmd_start(dev, cmd, len ? true : false);

DEBUG("[%s] command 0x%02x (%u) ", __func__, cmd, len);

lcd_ll_cmd_start(dev, cmd, true);
lcd_ll_read_bytes(dev, false, data, len);

if (IS_USED(ENABLE_DEBUG) && len) {
for (uint8_t i = 0; i < len; i++) {
DEBUG("0x%02x ", data[i]);
}
}
DEBUG("\n");
}

int lcd_init(lcd_t *dev, const lcd_params_t *params)
Expand Down Expand Up @@ -341,11 +490,6 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params)
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);
Expand All @@ -367,6 +511,27 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params)
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) {
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
assert(false);
#endif
Expand Down
Loading

0 comments on commit 6bac151

Please sign in to comment.