mirror of
https://github.com/apache/nuttx.git
synced 2026-05-27 11:26:12 +08:00
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:
@@ -705,6 +705,14 @@ config LCD_ST7789
|
|||||||
default n
|
default n
|
||||||
|
|
||||||
if LCD_ST7789
|
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
|
config LCD_ST7789_XRES
|
||||||
int "ST7789 X Resolution"
|
int "ST7789 X Resolution"
|
||||||
default 240
|
default 240
|
||||||
|
|||||||
+117
-31
@@ -45,9 +45,9 @@
|
|||||||
* Pre-processor Definitions
|
* 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"
|
# error "CONFIG_SPI_CMDDATA option has to be set for SPI communication"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -103,6 +103,18 @@
|
|||||||
# define CONFIG_LCD_RPORTRAIT 1
|
# define CONFIG_LCD_RPORTRAIT 1
|
||||||
#endif
|
#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 */
|
/* Display Resolution */
|
||||||
|
|
||||||
#if !defined(CONFIG_LCD_ST7789_XRES)
|
#if !defined(CONFIG_LCD_ST7789_XRES)
|
||||||
@@ -184,6 +196,18 @@ struct st7789_dev_s
|
|||||||
uint16_t runbuffer[ST7789_LUT_SIZE];
|
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
|
* 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)
|
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_CMDDATA(dev->spi, SPIDEV_DISPLAY(0), true);
|
||||||
SPI_SEND(dev->spi, cmd);
|
SPI_SEND(dev->spi, cmd);
|
||||||
SPI_CMDDATA(dev->spi, SPIDEV_DISPLAY(0), false);
|
SPI_CMDDATA(dev->spi, SPIDEV_DISPLAY(0), false);
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/****************************************************************************
|
/****************************************************************************
|
||||||
@@ -380,26 +416,26 @@ static void st7789_setorientation(FAR struct st7789_dev_s *dev,
|
|||||||
if (orientation != LCD_PORTRAIT)
|
if (orientation != LCD_PORTRAIT)
|
||||||
{
|
{
|
||||||
st7789_sendcmd(dev, ST7789_MADCTL);
|
st7789_sendcmd(dev, ST7789_MADCTL);
|
||||||
st7789_select(dev->spi, 8);
|
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (orientation == LCD_RLANDSCAPE)
|
if (orientation == LCD_RLANDSCAPE)
|
||||||
{
|
{
|
||||||
/* RLANDSCAPE : MY=1 MV=1 */
|
/* RLANDSCAPE : MY=1 MV=1 */
|
||||||
|
|
||||||
SPI_SEND(dev->spi, 0xa0);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | 0xa0);
|
||||||
}
|
}
|
||||||
else if (orientation == LCD_LANDSCAPE)
|
else if (orientation == LCD_LANDSCAPE)
|
||||||
{
|
{
|
||||||
/* LANDSCAPE : MX=1 MV=1 */
|
/* LANDSCAPE : MX=1 MV=1 */
|
||||||
|
|
||||||
SPI_SEND(dev->spi, 0x70);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | 0x70);
|
||||||
}
|
}
|
||||||
else if (orientation == LCD_RPORTRAIT)
|
else if (orientation == LCD_RPORTRAIT)
|
||||||
{
|
{
|
||||||
/* RPORTRAIT : MX=1 MY=1 */
|
/* RPORTRAIT : MX=1 MY=1 */
|
||||||
|
|
||||||
SPI_SEND(dev->spi, 0xc0);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | 0xc0);
|
||||||
}
|
}
|
||||||
|
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
@@ -412,7 +448,7 @@ static void st7789_setorientation(FAR struct st7789_dev_s *dev)
|
|||||||
uint8_t madctl = 0x00;
|
uint8_t madctl = 0x00;
|
||||||
|
|
||||||
st7789_sendcmd(dev, ST7789_MADCTL);
|
st7789_sendcmd(dev, ST7789_MADCTL);
|
||||||
st7789_select(dev->spi, 8);
|
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
|
||||||
|
|
||||||
#if !defined(CONFIG_LCD_PORTRAIT)
|
#if !defined(CONFIG_LCD_PORTRAIT)
|
||||||
|
|
||||||
@@ -444,7 +480,7 @@ static void st7789_setorientation(FAR struct st7789_dev_s *dev)
|
|||||||
madctl ^= 0x80;
|
madctl ^= 0x80;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SPI_SEND(dev->spi, madctl);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | madctl);
|
||||||
|
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
}
|
}
|
||||||
@@ -465,34 +501,38 @@ static void st7789_setarea(FAR struct st7789_dev_s *dev,
|
|||||||
/* Set row address */
|
/* Set row address */
|
||||||
|
|
||||||
st7789_sendcmd(dev, ST7789_RASET);
|
st7789_sendcmd(dev, ST7789_RASET);
|
||||||
st7789_select(dev->spi, 8);
|
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
|
||||||
#ifdef CONFIG_LCD_DYN_ORIENTATION
|
#ifdef CONFIG_LCD_DYN_ORIENTATION
|
||||||
SPI_SEND(dev->spi, (y0 + g_lcddev.yoff) >> 8);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y0 + g_lcddev.yoff) >> 8));
|
||||||
SPI_SEND(dev->spi, (y0 + g_lcddev.yoff) & 0xff);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y0 + g_lcddev.yoff) & 0xff));
|
||||||
SPI_SEND(dev->spi, (y1 + g_lcddev.yoff) >> 8);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y1 + g_lcddev.yoff) >> 8));
|
||||||
SPI_SEND(dev->spi, (y1 + g_lcddev.yoff) & 0xff);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y1 + g_lcddev.yoff) & 0xff));
|
||||||
#else
|
#else
|
||||||
SPI_SEND(dev->spi, (y0 + ST7789_YOFFSET) >> 8);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((y0 + ST7789_YOFFSET) >> 8));
|
||||||
SPI_SEND(dev->spi, (y0 + ST7789_YOFFSET) & 0xff);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX |
|
||||||
SPI_SEND(dev->spi, (y1 + ST7789_YOFFSET) >> 8);
|
((y0 + ST7789_YOFFSET) & 0xff));
|
||||||
SPI_SEND(dev->spi, (y1 + 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
|
#endif
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
|
|
||||||
/* Set column address */
|
/* Set column address */
|
||||||
|
|
||||||
st7789_sendcmd(dev, ST7789_CASET);
|
st7789_sendcmd(dev, ST7789_CASET);
|
||||||
st7789_select(dev->spi, 8);
|
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
|
||||||
#ifdef CONFIG_LCD_DYN_ORIENTATION
|
#ifdef CONFIG_LCD_DYN_ORIENTATION
|
||||||
SPI_SEND(dev->spi, (x0 + g_lcddev.xoff) >> 8);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x0 + g_lcddev.xoff) >> 8));
|
||||||
SPI_SEND(dev->spi, (x0 + g_lcddev.xoff) & 0xff);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x0 + g_lcddev.xoff) & 0xff));
|
||||||
SPI_SEND(dev->spi, (x1 + g_lcddev.xoff) >> 8);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x1 + g_lcddev.xoff) >> 8));
|
||||||
SPI_SEND(dev->spi, (x1 + g_lcddev.xoff) & 0xff);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x1 + g_lcddev.xoff) & 0xff));
|
||||||
#else
|
#else
|
||||||
SPI_SEND(dev->spi, (x0 + ST7789_XOFFSET) >> 8);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | ((x0 + ST7789_XOFFSET) >> 8));
|
||||||
SPI_SEND(dev->spi, (x0 + ST7789_XOFFSET) & 0xff);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX |
|
||||||
SPI_SEND(dev->spi, (x1 + ST7789_XOFFSET) >> 8);
|
((x0 + ST7789_XOFFSET) & 0xff));
|
||||||
SPI_SEND(dev->spi, (x1 + 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
|
#endif
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
}
|
}
|
||||||
@@ -513,8 +553,8 @@ static void st7789_bpp(FAR struct st7789_dev_s *dev, int bpp)
|
|||||||
|
|
||||||
depth = bpp >> 2 | 1;
|
depth = bpp >> 2 | 1;
|
||||||
st7789_sendcmd(dev, ST7789_COLMOD);
|
st7789_sendcmd(dev, ST7789_COLMOD);
|
||||||
st7789_select(dev->spi, 8);
|
st7789_select(dev->spi, LCD_ST7789_SPI_BITS);
|
||||||
SPI_SEND(dev->spi, depth);
|
SPI_SEND(dev->spi, LCD_ST7789_DATA_PREFIX | depth);
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
|
|
||||||
/* Cache the new BPP */
|
/* Cache the new BPP */
|
||||||
@@ -536,16 +576,52 @@ static void st7789_wrram(FAR struct st7789_dev_s *dev,
|
|||||||
size_t count)
|
size_t count)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
#ifdef CONFIG_LCD_ST7789_3WIRE
|
||||||
|
size_t j;
|
||||||
|
#endif
|
||||||
|
|
||||||
st7789_sendcmd(dev, ST7789_RAMWR);
|
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++)
|
for (i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
SPI_SNDBLOCK(dev->spi, buff + (i * (size + skip)),
|
SPI_SNDBLOCK(dev->spi, buff + (i * (size + skip)),
|
||||||
size / ST7789_BYTESPP);
|
size / ST7789_BYTESPP);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
st7789_deselect(dev->spi);
|
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_setarea(dev, 0, 0, ST7789_XRES - 1, ST7789_YRES - 1);
|
||||||
|
|
||||||
st7789_sendcmd(dev, ST7789_RAMWR);
|
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++)
|
for (i = 0; i < ST7789_XRES * ST7789_YRES; i++)
|
||||||
{
|
{
|
||||||
SPI_SEND(dev->spi, color);
|
SPI_SEND(dev->spi, color);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
st7789_deselect(dev->spi);
|
st7789_deselect(dev->spi);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user