st7789: add support for 3 wire interface

3 wire interface for ST7789 LCD controller does not use  CMD/DATA pin to
specify whether data  or command is send but uses 9th bit of SPI transfer.

This commit adds support for 3 wire interface to ST7789 controller.

Signed-off-by: Michal Lenc <michallenc@seznam.cz>
This commit is contained in:
Michal Lenc 2023-07-13 16:13:52 +02:00 committed by Xiang Xiao
parent 8706d68318
commit 548f4b652c
2 changed files with 125 additions and 31 deletions

View File

@ -705,6 +705,14 @@ config LCD_ST7789
default n
if LCD_ST7789
config LCD_ST7789_3WIRE
bool "Use 3 wire interface"
default n
---help---
Specifies whether 3 wire or 4 wire (default) interface is
used. 3 wire interface drops CMD/DATA pin and uses 9th bit
to determine data/command message.
config LCD_ST7789_XRES
int "ST7789 X Resolution"
default 240

View File

@ -45,9 +45,9 @@
* Pre-processor Definitions
****************************************************************************/
/* CONFIG_SPI_CMDDATA has to be set */
/* CONFIG_SPI_CMDDATA has to be set for 4 wire interface */
#ifndef CONFIG_SPI_CMDDATA
#if !defined(CONFIG_LCD_ST7789_3WIRE) && !defined(CONFIG_SPI_CMDDATA)
# error "CONFIG_SPI_CMDDATA option has to be set for SPI communication"
#endif
@ -103,6 +103,18 @@
# define CONFIG_LCD_RPORTRAIT 1
#endif
/* Define prefixes for 3 wire communication if used */
#ifdef CONFIG_LCD_ST7789_3WIRE
# define LCD_ST7789_SPI_BITS 9
# define LCD_ST7789_DATA_PREFIX (1 << 8)
# define LCD_ST7789_CMD_PREFIX (0 << 8)
#else
# define LCD_ST7789_SPI_BITS 8
# define LCD_ST7789_DATA_PREFIX (0)
# define LCD_ST7789_CMD_PREFIX (0)
#endif
/* Display Resolution */
#if !defined(CONFIG_LCD_ST7789_XRES)
@ -184,6 +196,18 @@ struct st7789_dev_s
uint16_t runbuffer[ST7789_LUT_SIZE];
};
/* 3 wire interface for ST7789 requires the driver to send information
* about command/data transfer as 9th bit of SPI transfer. This would
* require non standard SPI interface that is not supported so a little
* workaround is used here (inspire by SSD1351 driver). We split our
* buffer into rows and send those rows separately with added 9th bit.
* The price for this is a small overhead in SPI communication.
*/
#ifdef CONFIG_LCD_ST7789_3WIRE
uint16_t rowbuff[ST7789_XRES * ST7789_BYTESPP];
#endif
/****************************************************************************
* Private Function Protototypes
****************************************************************************/
@ -325,11 +349,23 @@ static void st7789_deselect(FAR struct spi_dev_s *spi)
static inline void st7789_sendcmd(FAR struct st7789_dev_s *dev, uint8_t cmd)
{
st7789_select(dev->spi, 8);
#ifdef CONFIG_LCD_ST7789_3WIRE
uint16_t txbuf;
/* Add command prefix (9th bit shoudl be 0 ) */
txbuf = LCD_ST7789_CMD_PREFIX | cmd;
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
SPI_SEND(dev->spi, txbuf);
st7789_deselect(dev->spi);
#else
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
SPI_CMDDATA(dev->spi, SPIDEV_DISPLAY(0), true);
SPI_SEND(dev->spi, cmd);
SPI_CMDDATA(dev->spi, SPIDEV_DISPLAY(0), false);
st7789_deselect(dev->spi);
#endif
}
/****************************************************************************
@ -380,26 +416,26 @@ static void st7789_setorientation(FAR struct st7789_dev_s *dev,
if (orientation != LCD_PORTRAIT)
{
st7789_sendcmd(dev, ST7789_MADCTL);
st7789_select(dev->spi, 8);
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
}
if (orientation == LCD_RLANDSCAPE)
{
/* RLANDSCAPE : MY=1 MV=1 */
SPI_SEND(dev->spi, 0xa0);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | 0xa0);
}
else if (orientation == LCD_LANDSCAPE)
{
/* LANDSCAPE : MX=1 MV=1 */
SPI_SEND(dev->spi, 0x70);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | 0x70);
}
else if (orientation == LCD_RPORTRAIT)
{
/* RPORTRAIT : MX=1 MY=1 */
SPI_SEND(dev->spi, 0xc0);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | 0xc0);
}
st7789_deselect(dev->spi);
@ -412,7 +448,7 @@ static void st7789_setorientation(FAR struct st7789_dev_s *dev)
uint8_t madctl = 0x00;
st7789_sendcmd(dev, ST7789_MADCTL);
st7789_select(dev->spi, 8);
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
#if !defined(CONFIG_LCD_PORTRAIT)
@ -444,7 +480,7 @@ static void st7789_setorientation(FAR struct st7789_dev_s *dev)
madctl ^= 0x80;
#endif
SPI_SEND(dev->spi, madctl);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | madctl);
st7789_deselect(dev->spi);
}
@ -465,34 +501,38 @@ static void st7789_setarea(FAR struct st7789_dev_s *dev,
/* Set row address */
st7789_sendcmd(dev, ST7789_RASET);
st7789_select(dev->spi, 8);
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
#ifdef CONFIG_LCD_DYN_ORIENTATION
SPI_SEND(dev->spi, (y0 + g_lcddev.yoff) >> 8);
SPI_SEND(dev->spi, (y0 + g_lcddev.yoff) & 0xff);
SPI_SEND(dev->spi, (y1 + g_lcddev.yoff) >> 8);
SPI_SEND(dev->spi, (y1 + g_lcddev.yoff) & 0xff);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y0 + g_lcddev.yoff) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y0 + g_lcddev.yoff) & 0xff));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y1 + g_lcddev.yoff) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y1 + g_lcddev.yoff) & 0xff));
#else
SPI_SEND(dev->spi, (y0 + ST7789_YOFFSET) >> 8);
SPI_SEND(dev->spi, (y0 + ST7789_YOFFSET) & 0xff);
SPI_SEND(dev->spi, (y1 + ST7789_YOFFSET) >> 8);
SPI_SEND(dev->spi, (y1 + ST7789_YOFFSET) & 0xff);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y0 + ST7789_YOFFSET) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX |
((y0 + ST7789_YOFFSET) & 0xff));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y1 + ST7789_YOFFSET) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX |
((y1 + ST7789_YOFFSET) & 0xff));
#endif
st7789_deselect(dev->spi);
/* Set column address */
st7789_sendcmd(dev, ST7789_CASET);
st7789_select(dev->spi, 8);
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
#ifdef CONFIG_LCD_DYN_ORIENTATION
SPI_SEND(dev->spi, (x0 + g_lcddev.xoff) >> 8);
SPI_SEND(dev->spi, (x0 + g_lcddev.xoff) & 0xff);
SPI_SEND(dev->spi, (x1 + g_lcddev.xoff) >> 8);
SPI_SEND(dev->spi, (x1 + g_lcddev.xoff) & 0xff);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x0 + g_lcddev.xoff) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x0 + g_lcddev.xoff) & 0xff));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x1 + g_lcddev.xoff) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x1 + g_lcddev.xoff) & 0xff));
#else
SPI_SEND(dev->spi, (x0 + ST7789_XOFFSET) >> 8);
SPI_SEND(dev->spi, (x0 + ST7789_XOFFSET) & 0xff);
SPI_SEND(dev->spi, (x1 + ST7789_XOFFSET) >> 8);
SPI_SEND(dev->spi, (x1 + ST7789_XOFFSET) & 0xff);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x0 + ST7789_XOFFSET) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX |
((x0 + ST7789_XOFFSET) & 0xff));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x1 + ST7789_XOFFSET) >> 8));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX |
((x1 + ST7789_XOFFSET) & 0xff));
#endif
st7789_deselect(dev->spi);
}
@ -513,8 +553,8 @@ static void st7789_bpp(FAR struct st7789_dev_s *dev, int bpp)
depth = bpp >> 2 | 1;
st7789_sendcmd(dev, ST7789_COLMOD);
st7789_select(dev->spi, 8);
SPI_SEND(dev->spi, depth);
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | depth);
st7789_deselect(dev->spi);
/* Cache the new BPP */
@ -536,16 +576,52 @@ static void st7789_wrram(FAR struct st7789_dev_s *dev,
size_t count)
{
size_t i;
#ifdef CONFIG_LCD_ST7789_3WIRE
size_t j;
#endif
st7789_sendcmd(dev, ST7789_RAMWR);
st7789_select(dev->spi, ST7789_BYTESPP * 8);
#ifdef CONFIG_LCD_ST7789_3WIRE
if (count == 1)
{
/* We cannot send the entire buffer at once, split it to
* separate rows.
*/
count = ST7789_YRES;
size = ST7789_XRES * ST7789_BYTESPP;
}
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
/* For each row */
for (i = 0; i < count; i++)
{
/* Copy data to rowbuff and add 9th bit */
for (j = 0; j < ST7789_XRES * ST7789_BYTESPP; j += 2)
{
/* Take care of correct byte order. */
rowbuff[j] = LCD_ST7789_DATA_PREFIX |
(uint16_t)buff[j + 1 + (i * (size + skip))];
rowbuff[j + 1] = LCD_ST7789_DATA_PREFIX |
(uint16_t)buff[j + (i * (size + skip))];
}
SPI_SNDBLOCK(dev->spi, rowbuff, size);
}
#else
st7789_select(dev->spi, ST7789_BYTESPP * LCD_ST7789_SPI_BITS);
for (i = 0; i < count; i++)
{
SPI_SNDBLOCK(dev->spi, buff + (i * (size + skip)),
size / ST7789_BYTESPP);
}
#endif
st7789_deselect(dev->spi);
}
@ -585,12 +661,22 @@ static void st7789_fill(FAR struct st7789_dev_s *dev, uint16_t color)
st7789_setarea(dev, 0, 0, ST7789_XRES - 1, ST7789_YRES - 1);
st7789_sendcmd(dev, ST7789_RAMWR);
st7789_select(dev->spi, ST7789_BYTESPP *8);
#ifdef CONFIG_LCD_ST7789_3WIRE
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
for (i = 0; i < ST7789_XRES * ST7789_YRES; i++)
{
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | (color & 0xff));
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | (color & 0xff00) >> 8);
}
#else
st7789_select(dev->spi, ST7789_BYTESPP * LCD_ST7789_SPI_BITS);
for (i = 0; i < ST7789_XRES * ST7789_YRES; i++)
{
SPI_SEND(dev->spi, color);
}
#endif
st7789_deselect(dev->spi);
}