Skip to content

Commit a7e10a9

Browse files
bors[bot]gschorcht
andauthored
Merge #19915
19915: drivers/lcd: support MCU 8080 8-bit parallel mode r=benpicco a=gschorcht ### Contribution description LCD driver ICs usually support - SPI serial mode, - MCU 8080 8-bit parallel mode and - MCU 8080 16-bit parallel mode. This PR extends the LCD display driver API to support the MCU 8080 8-/16-bit parallel modes and implements a GPIO-driven MCU 8080 8-bit parallel mode. The following features are already working locally and will be provided as follow-on PRs for which this PR is a prerequisite. - GPIO-driven bit-banging implementation of the 16-bit mode of the MCU 8080 parallel interface - Enabling the display on `stm32f723e-disco` and `stm32l496g-disco` using the feature above - Definition of a low-level API for the parallel modes using the LCD controller of the MCU - Using FMC for the display on `stm32f723e-disco` and `stm32l496g-disco` - Using LCD controller for the display of `esp32-wt32-sc01-plus` (PR #19917) ### Testing procedure The PR can be tested with PR #19917 on top of this PR. ``` BOARD=esp32s3-wt32-sc01-plus make -j8 -C tests/drivers/st77xx flash ``` The following video shows the test. **Please note** The test is pretty slow because the display has 480 x 320 pixels and the MCU 8080 8-bit parallel interface is realized by a GPIO-driven bit-banging implementation where each GPIO of the data bus is set separately. A follow-up PR will use the ESP32-S3 LCD controller and DMA for this board. This PR just defines the extension of the driver by the parallel interface and provides the bit-banging implementation for MCUs that don't have a LCD controller on chip. https://github.com/RIOT-OS/RIOT/assets/31932013/c1e3e3d7-05d9-4ca5-8fff-9a5eaca50fba ### Issues/PRs references Co-authored-by: Gunar Schorcht <[email protected]>
2 parents ec69cfd + b0ec24b commit a7e10a9

File tree

9 files changed

+466
-70
lines changed

9 files changed

+466
-70
lines changed

drivers/ili9341/include/ili9341_params.h

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,45 @@ extern "C" {
7171
#define ILI9341_PARAM_OFFSET_Y 0 /**< Vertival offset */
7272
#endif
7373

74+
#if MODULE_LCD_SPI || DOXYGEN
75+
/** Default interface params if SPI serial interface is enabled */
76+
#define ILI9341_PARAM_IF_SPI .spi = ILI9341_PARAM_SPI, \
77+
.spi_clk = ILI9341_PARAM_SPI_CLK, \
78+
.spi_mode = ILI9341_PARAM_SPI_MODE,
79+
#else
80+
#define ILI9341_PARAM_IF_SPI
81+
#endif
82+
83+
#if MODULE_LCD_PARALLEL || DOXYGEN
84+
/** Default interface params if MCU 8080 8-bit parallel interface is enabled */
85+
#define ILI9341_PARAM_IF_PAR .d0_pin = ILI9341_PARAM_D0, \
86+
.d1_pin = ILI9341_PARAM_D1, \
87+
.d2_pin = ILI9341_PARAM_D2, \
88+
.d3_pin = ILI9341_PARAM_D3, \
89+
.d4_pin = ILI9341_PARAM_D4, \
90+
.d5_pin = ILI9341_PARAM_D5, \
91+
.d6_pin = ILI9341_PARAM_D6, \
92+
.d7_pin = ILI9341_PARAM_D7, \
93+
.wrx_pin = ILI9341_PARAM_WRX, \
94+
.rdx_pin = ILI9341_PARAM_RDX,
95+
#else
96+
#define ILI9341_PARAM_IF_PAR
97+
#endif
98+
7499
/**
75100
* @brief Default params
101+
*
102+
* @note The default parameter set defined here can only be used if a single
103+
* ILI9341 display and only one interface mode is used. If multiple
104+
* ILI9341 displays are used or if multiple interface modes are enabled
105+
* by the modules `lcd_spi`, lcd_parallel and `lcd_parallel_16bit`, a user
106+
* defined parameter set @ref ILI9341_PARAMS has to be defined. In the
107+
* latter case @ref lcd_params_t::spi must then be set to @ref SPI_UNDEF
108+
* for displays with MCU 8080 8-/16-bit parallel interfaces.
76109
*/
77110
#ifndef ILI9341_PARAMS
78-
#define ILI9341_PARAMS { .spi = ILI9341_PARAM_SPI, \
79-
.spi_clk = ILI9341_PARAM_SPI_CLK, \
80-
.spi_mode = ILI9341_PARAM_SPI_MODE, \
111+
#define ILI9341_PARAMS { ILI9341_PARAM_IF_SPI \
112+
ILI9341_PARAM_IF_PAR \
81113
.cs_pin = ILI9341_PARAM_CS, \
82114
.dcx_pin = ILI9341_PARAM_DCX, \
83115
.rst_pin = ILI9341_PARAM_RST, \
@@ -124,7 +156,6 @@ static const uint8_t ili9341_screen_ids[] =
124156
*/
125157
#define ILI9341_SCREEN_NUMOF ARRAY_SIZE(ili9341_screen_ids)
126158

127-
128159
#ifdef __cplusplus
129160
}
130161
#endif

drivers/include/lcd.h

Lines changed: 83 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/*
22
* Copyright (C) 2018 Koen Zandberg
33
* 2021 Francisco Molina
4+
* 2023 Gunar Schorcht
45
*
56
* This file is subject to the terms and conditions of the GNU Lesser
67
* General Public License v2.1. See the file LICENSE in the top level
@@ -13,8 +14,22 @@
1314
*
1415
* @brief Driver for the LCD display
1516
*
16-
* The LCD is a generic display driver for small RGB displays. The driver
17-
* implemented here operates over SPI to communicate with the device.
17+
* The LCD is a generic display driver for small RGB displays. It communicates
18+
* with the device either via an
19+
*
20+
* - SPI serial interface (if module `lcd_spi` enabled) or an
21+
* - MCU 8080 8-/16-bit parallel interface (if module `lcd_parallel` or
22+
* module `lcd_parallel_16` is enabled).
23+
*
24+
* Usually the device driver is used either for a single display with SPI serial
25+
* interface or for a display with parallel MCU 8080 8-/16-bit parallel
26+
* interface. However, the device driver can also be used simultaneously for
27+
* multiple displays with different interfaces if several of the `lcd_spi`,
28+
* `lcd_parallel` and `lcd_parallel_16bit` modules are enabled at the same time.
29+
* In this case, please refer to the notes in @ref lcd_params_t.
30+
*
31+
* @warning MCU 8080 16-bit parallel interface (module `lcd_parallel_16bit`) is
32+
* not supported yet.
1833
*
1934
* The device requires colors to be send in big endian RGB-565 format. The
2035
* @ref CONFIG_LCD_LE_MODE compile time option can switch this, but only use this
@@ -28,13 +43,15 @@
2843
*
2944
* @author Koen Zandberg <[email protected]>
3045
* @author Francisco Molina <[email protected]>
46+
* @author Gunar Schorcht <[email protected]>
3147
*
3248
*/
3349

3450
#ifndef LCD_H
3551
#define LCD_H
3652

3753
#include "board.h"
54+
#include "mutex.h"
3855
#include "periph/spi.h"
3956
#include "periph/gpio.h"
4057

@@ -70,18 +87,58 @@ extern "C" {
7087

7188
/**
7289
* @brief Device initialization parameters
90+
*
91+
* @note The device driver can be used simultaneously for displays with
92+
* SPI serial interface and parallel MCU 8080 8-/16-bit interfaces
93+
* if the modules `lcd_spi` and `lcd_parallel` or `lcd_parallel_16bit`
94+
* are enabled at the same time. In this case the interface parameters
95+
* for the SPI serial interface and the MCU 8080 parallel 8-/16-bit
96+
* interfaces are defined. @ref lcd_params_t::spi must then be set to
97+
* @ref SPI_UNDEF for displays that use the MCU-8080-parallel-8-/16-bit
98+
* interface, i.e. @ref lcd_params_t::spi is then used to detect the
99+
* interface mode.
73100
*/
74101
typedef struct {
102+
#if MODULE_LCD_SPI || DOXYGEN
103+
/* Interface parameters used for serial interface */
75104
spi_t spi; /**< SPI device that the display is connected to */
76105
spi_clk_t spi_clk; /**< SPI clock speed to use */
77106
spi_mode_t spi_mode; /**< SPI mode */
107+
#endif
108+
#if MODULE_LCD_PARALLEL || DOXYGEN
109+
/* Interface parameters used for MCU 8080 8-bit parallel interface */
110+
gpio_t wrx_pin; /**< pin connected to the WRITE ENABLE line */
111+
gpio_t rdx_pin; /**< pin connected to the READ ENABLE line */
112+
gpio_t d0_pin; /**< pin connected to the D0 line */
113+
gpio_t d1_pin; /**< pin connected to the D1 line */
114+
gpio_t d2_pin; /**< pin connected to the D2 line */
115+
gpio_t d3_pin; /**< pin connected to the D3 line */
116+
gpio_t d4_pin; /**< pin connected to the D4 line */
117+
gpio_t d5_pin; /**< pin connected to the D5 line */
118+
gpio_t d6_pin; /**< pin connected to the D6 line */
119+
gpio_t d7_pin; /**< pin connected to the D7 line */
120+
#if MODULE_LCD_PARALLEL_16BIT || DOXYGEN
121+
/* Interface parameters used for MCU 8080 16-bit parallel interface */
122+
gpio_t d8_pin; /**< pin connected to the D8 line */
123+
gpio_t d9_pin; /**< pin connected to the D9 line */
124+
gpio_t d10_pin; /**< pin connected to the D10 line */
125+
gpio_t d11_pin; /**< pin connected to the D11 line */
126+
gpio_t d12_pin; /**< pin connected to the D12 line */
127+
gpio_t d13_pin; /**< pin connected to the D13 line */
128+
gpio_t d14_pin; /**< pin connected to the D14 line */
129+
gpio_t d15_pin; /**< pin connected to the D15 line */
130+
#endif /* MODULE_LCD_PARALLEL_16BIT */
131+
#endif /* MODULE_LCD_PARALLEL */
132+
/* Common interface parameters */
78133
gpio_t cs_pin; /**< pin connected to the CHIP SELECT line */
79134
gpio_t dcx_pin; /**< pin connected to the DC line */
80-
gpio_t rst_pin; /**< pin connected to the reset line */
81-
bool rgb; /**< True when display is connected in RGB mode
82-
* False when display is connected in BGR mode */
135+
gpio_t rst_pin; /**< pin connected to the RESET line */
136+
bool rgb; /**< True when display is connected in RGB mode\n
137+
False when display is connected in BGR mode */
83138
bool inverted; /**< Display works in inverted color mode */
84-
uint16_t lines; /**< Number of lines, from 16 to 320 in 8 line steps */
139+
uint16_t lines; /**< Number of lines, from 16 to the number of
140+
lines supported by the driver IC in 8 line
141+
steps */
85142
uint16_t rgb_channels; /**< Display rgb channels */
86143
uint8_t rotation; /**< Display rotation mode */
87144
uint8_t offset_x; /**< LCD offset to apply on x axis. */
@@ -104,11 +161,15 @@ typedef struct lcd_driver lcd_driver_t;
104161
* @brief Device descriptor for a lcd
105162
*/
106163
typedef struct {
107-
#ifdef MODULE_DISP_DEV
164+
#if MODULE_DISP_DEV || DOXYGEN
108165
disp_dev_t *dev; /**< Pointer to the generic display device */
109166
#endif
110167
const lcd_driver_t *driver; /**< LCD driver */
111168
const lcd_params_t *params; /**< Device initialization parameters */
169+
#if MODULE_LCD_PARALLEL || DOXYGEN
170+
mutex_t lock; /**< Mutex used to lock the device in
171+
MCU 8080 parallel interface mode */
172+
#endif
112173
} lcd_t;
113174

114175
/**
@@ -142,7 +203,7 @@ struct lcd_driver {
142203
* @param[in] y2 y coordinate of the opposite corner
143204
*
144205
*/
145-
void (*set_area)(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
206+
void (*set_area)(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
146207
uint16_t y2);
147208
};
148209

@@ -162,14 +223,14 @@ struct lcd_driver {
162223
*
163224
* @param[out] dev device descriptor
164225
*/
165-
void lcd_ll_acquire(const lcd_t *dev);
226+
void lcd_ll_acquire(lcd_t *dev);
166227

167228
/**
168229
* @brief Low-level function to release the device
169230
*
170231
* @param[out] dev device descriptor
171232
*/
172-
void lcd_ll_release(const lcd_t *dev);
233+
void lcd_ll_release(lcd_t *dev);
173234

174235
/**
175236
* @brief Low-level function to write a command
@@ -182,7 +243,7 @@ void lcd_ll_release(const lcd_t *dev);
182243
* @param[in] data command data to the device
183244
* @param[in] len length of the command data
184245
*/
185-
void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
246+
void lcd_ll_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data,
186247
size_t len);
187248

188249
/**
@@ -201,7 +262,7 @@ void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
201262
* @param[out] data data from the device
202263
* @param[in] len length of the returned data
203264
*/
204-
void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len);
265+
void lcd_ll_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len);
205266
/** @} */
206267

207268
/**
@@ -234,7 +295,7 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params);
234295
* @param[in] y2 y coordinate of the opposite corner
235296
* @param[in] color single color to fill the area with
236297
*/
237-
void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2,
298+
void lcd_fill(lcd_t *dev, uint16_t x1, uint16_t x2,
238299
uint16_t y1, uint16_t y2, uint16_t color);
239300

240301
/**
@@ -253,7 +314,7 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2,
253314
* @param[in] y2 y coordinate of the opposite corner
254315
* @param[in] color array of colors to fill the area with
255316
*/
256-
void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
317+
void lcd_pixmap(lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
257318
uint16_t y2, const uint16_t *color);
258319

259320
/**
@@ -264,34 +325,38 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
264325
* @param[in] data command data to the device
265326
* @param[in] len length of the command data
266327
*/
267-
void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
328+
void lcd_write_cmd(lcd_t *dev, uint8_t cmd, const uint8_t *data,
268329
size_t len);
269330

270331
/**
271332
* @brief Raw read command
272333
*
334+
* @note Very often the SPI MISO signal of the serial interface or the RDX
335+
* signal of the MCU 8080 parallel interface are not connected to the
336+
* display. In this case the read command does not provide valid data.
337+
*
273338
* @pre len > 0
274339
*
275340
* @param[in] dev device descriptor
276341
* @param[in] cmd command
277342
* @param[out] data data from the device
278343
* @param[in] len length of the returned data
279344
*/
280-
void lcd_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len);
345+
void lcd_read_cmd(lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len);
281346

282347
/**
283348
* @brief Invert the display colors
284349
*
285350
* @param[in] dev device descriptor
286351
*/
287-
void lcd_invert_on(const lcd_t *dev);
352+
void lcd_invert_on(lcd_t *dev);
288353

289354
/**
290355
* @brief Disable color inversion
291356
*
292357
* @param[in] dev device descriptor
293358
*/
294-
void lcd_invert_off(const lcd_t *dev);
359+
void lcd_invert_off(lcd_t *dev);
295360
/** @} */
296361

297362
#ifdef __cplusplus

drivers/include/st77xx.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,18 @@
2222
* @ref lcd_params_t::cntrl or as macro @ref ST77XX_PARAM_CNTRL if the
2323
* default parameter set @ref ST77XX_PARAMS is used.
2424
*
25-
* The driver uses the SPI serial interface to communicate with the display
26-
* controller.
25+
* The driver communicates with the device either via an
26+
*
27+
* - SPI serial interface (if module `lcd_spi` enabled) or an
28+
* - MCU 8080 8-/16-bit parallel interface (if module `lcd_parallel` or
29+
* module `lcd_parallel_16` is enabled).
30+
*
31+
* Usually the device driver is used either for a single display with SPI serial
32+
* interface or for a display with parallel MCU 8080 8-/16-bit parallel
33+
* interface. However, the device driver can also be used simultaneously for
34+
* multiple displays with different interfaces if several of the `lcd_spi`,
35+
* `lcd_parallel` and `lcd_parallel_16bit` modules are enabled at the same time.
36+
* In this case, please refer to the notes in @ref lcd_params_t.
2737
*
2838
* The device requires colors to be send in big endian RGB-565 format. The
2939
* @ref CONFIG_LCD_LE_MODE compile time option can switch this, but only use this

drivers/lcd/Kconfig

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,57 @@
77

88
config MODULE_LCD
99
bool "LCD display driver"
10-
depends on HAS_PERIPH_SPI
1110
depends on HAS_PERIPH_GPIO
1211
depends on TEST_KCONFIG
13-
select MODULE_PERIPH_SPI
1412
select MODULE_PERIPH_GPIO
1513

1614
config MODULE_LCD_MULTI_CNTRL
1715
bool
1816
help
1917
The controller-specific driver supports multiple controller variants.
2018

19+
config MODULE_LCD_SPI
20+
bool
21+
default y if !MODULE_LCD_PARALLEL && !MODULE_LCD_PARALLEL_16BIT
22+
default y if HAVE_LCD_SPI
23+
depends on HAS_PERIPH_SPI
24+
depends on MODULE_LCD
25+
select MODULE_PERIPH_SPI
26+
help
27+
SPI serial interface is used
28+
29+
config MODULE_LCD_PARALLEL
30+
bool
31+
default y if HAVE_LCD_PARALLEL || HAVE_LCD_PARALLEL_16BIT
32+
depends on MODULE_LCD
33+
help
34+
MCU 8080 8-/16-bit parallel interface is used
35+
36+
config MODULE_LCD_PARALLEL_16BIT
37+
bool
38+
default y if HAVE_LCD_PARALLEL_16BIT
39+
depends on MODULE_LCD
40+
help
41+
MCU 8080 16-bit paralell interface is used
42+
43+
config HAVE_LCD_SPI
44+
bool
45+
help
46+
Indicates that a display with MCU 8080 8-/16-bit parallel interface
47+
is present
48+
49+
config HAVE_LCD_PARALLEL
50+
bool
51+
help
52+
Indicates that a display with MCU 8080 8-/16-bit parallel interface
53+
is present
54+
55+
config HAVE_LCD_PARALLEL_16BIT
56+
bool
57+
help
58+
Indicates that a display with MCU 8080 16-bit parallel interface
59+
is present
60+
2161
menuconfig KCONFIG_USEMODULE_LCD
2262
bool "Configure LCD driver"
2363
depends on USEMODULE_LCD

drivers/lcd/Makefile.dep

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,14 @@
1-
FEATURES_REQUIRED += periph_spi
21
FEATURES_REQUIRED += periph_gpio
2+
3+
ifneq (,$(filter lcd_parallel_16bit,$(USEMODULE)))
4+
USEMODULE += lcd_parallel
5+
endif
6+
7+
ifeq (,$(filter lcd_parallel%,$(USEMODULE)))
8+
# default to SPI serial interface if no MCU 8080 parallel interface is enabled
9+
USEMODULE += lcd_spi
10+
endif
11+
12+
ifneq (,$(filter lcd_spi,$(USEMODULE)))
13+
FEATURES_REQUIRED += periph_spi
14+
endif

drivers/lcd/Makefile.include

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
PSEUDOMODULES += lcd_multi_cntrl
22

3+
PSEUDOMODULES += lcd_spi
4+
PSEUDOMODULES += lcd_parallel
5+
PSEUDOMODULES += lcd_parallel_16bit
6+
37
USEMODULE_INCLUDES_lcd := $(LAST_MAKEFILEDIR)/include
48
USEMODULE_INCLUDES += $(USEMODULE_INCLUDES_lcd)

0 commit comments

Comments
 (0)