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

drivers/lcd: move basic communication functions to drivers/lcd

In preparation for the parallel interface support the following changes were made:

1. The code for basic communication (acquire/release SPI device, SPI transfers), which were always implemented identically in the individual display drivers again and again, have been moved to the LCD driver as low-level functions and are now used by the display drivers. These low level function allow 
- code deduplication on one hand and 
- to define a more abstract communication interface on the other hand that can then be extended by parallel communication
2. Identical GPIO initialization has  also been moved from display drivers to the LCD driver.
This commit is contained in:
Gunar Schorcht 2023-07-09 11:55:42 +02:00
parent b30401a1c2
commit 3f8ba798cb
2 changed files with 171 additions and 44 deletions

View File

@ -137,6 +137,52 @@ struct lcd_driver {
uint16_t y2);
};
/**
* @brief Low Level to acquire the device
*
* @param[out] dev device descriptor
*/
void lcd_ll_acquire(const lcd_t *dev);
/**
* @brief Low Level function to release the device
*
* @param[out] dev device descriptor
*/
void lcd_ll_release(const lcd_t *dev);
/**
* @brief Low level function to write a command
*
* @pre The device must have already been acquired with @ref lcd_ll_acquire
* before this function can be called.
*
* @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
*/
void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
size_t len);
/**
* @brief Low level function for read command command
*
* @note Very often the SPI MISO signal of the serial interface or the RDX
* signal of the MCU 8080 parallel interface are not connected to the
* display. In this case the read command does not provide valid data.
*
* @pre The device must have already been acquired with @ref lcd_ll_acquire
* before this function can be called.
* @pre len > 0
*
* @param[in] dev device descriptor
* @param[in] cmd command
* @param[out] data data from the device
* @param[in] len length of the returned data
*/
void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len);
/**
* @brief Setup an lcd display device
*

View File

@ -1,6 +1,7 @@
/*
* Copyright (C) 2018 Koen Zandberg
* 2021 Francisco Molina
* 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
@ -16,6 +17,7 @@
*
* @author Koen Zandberg <koen@bergzand.net>
* @author Francisco Molina <francois-xavier.molina@inria.fr>
* @author Gunar Schorcht <gunar@schorcht.net>
*
* @}
*/
@ -25,6 +27,7 @@
#include "byteorder.h"
#include "periph/spi.h"
#include "kernel_defines.h"
#include "ztimer.h"
#include "lcd.h"
#include "lcd_internal.h"
@ -32,38 +35,127 @@
#define ENABLE_DEBUG 0
#include "debug.h"
static void _lcd_spi_acquire(const lcd_t *dev)
static inline void _lcd_write_byte(const lcd_t *dev, bool cont, uint8_t data)
{
spi_acquire(dev->params->spi, dev->params->cs_pin, dev->params->spi_mode,
dev->params->spi_clk);
if (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, data);
}
else {
assert(false);
}
}
static inline void _lcd_write_bytes(const lcd_t *dev, bool cont,
const void *data, size_t len)
{
if (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
spi_transfer_bytes(dev->params->spi,
dev->params->cs_pin, cont, data, NULL, len);
}
else {
assert(false);
}
}
static inline void _lcd_read_bytes(const lcd_t *dev, bool cont,
void *data, size_t len)
{
if (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
/* Dummy read */
spi_transfer_byte(dev->params->spi,
dev->params->cs_pin, true, 0x00);
spi_transfer_bytes(dev->params->spi,
dev->params->cs_pin, cont, NULL, data, len);
}
else {
assert(false);
}
}
static void _lcd_cmd_start(const lcd_t *dev, uint8_t cmd, bool cont)
{
gpio_clear(dev->params->dcx_pin);
spi_transfer_byte(dev->params->spi, dev->params->cs_pin, cont, cmd);
_lcd_write_byte(dev, cont, cmd);
gpio_set(dev->params->dcx_pin);
}
static void _write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
size_t len)
{
_lcd_cmd_start(dev, cmd, len ? true : false);
if (len) {
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, data,
NULL, len);
}
}
static void _lcd_set_area(const lcd_t *dev, uint16_t x1, uint16_t x2,
uint16_t y1, uint16_t y2)
uint16_t y1, uint16_t y2)
{
assert(dev->driver->set_area);
dev->driver->set_area(dev, x1, x2, y1, y2);
}
void lcd_ll_acquire(const lcd_t *dev)
{
if (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
spi_acquire(dev->params->spi, dev->params->cs_pin,
dev->params->spi_mode, dev->params->spi_clk);
}
else {
assert(false);
}
}
void lcd_ll_release(const lcd_t *dev)
{
if (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
spi_release(dev->params->spi);
}
else {
assert(false);
}
}
void lcd_ll_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
size_t len)
{
_lcd_cmd_start(dev, cmd, len ? true : false);
if (len) {
_lcd_write_bytes(dev, false, data, len);
}
}
void lcd_ll_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len)
{
assert(len);
_lcd_cmd_start(dev, cmd, len ? true : false);
_lcd_read_bytes(dev, false, data, len);
}
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 (dev->params->spi != SPI_UNDEF) {
/* SPI serial interface is used */
int res = spi_init_cs(dev->params->spi, dev->params->cs_pin);
if (res != SPI_OK) {
DEBUG("[st7735] init: error initializing the CS pin [%i]\n", res);
return -1;
}
}
else {
assert(false);
}
if (gpio_is_valid(dev->params->rst_pin)) {
gpio_init(dev->params->rst_pin, GPIO_OUT);
gpio_clear(dev->params->rst_pin);
ztimer_sleep(ZTIMER_MSEC, 120);
gpio_set(dev->params->rst_pin);
}
ztimer_sleep(ZTIMER_MSEC, 120);
if (dev->driver->init) {
return dev->driver->init(dev, params);
}
@ -73,28 +165,22 @@ int lcd_init(lcd_t *dev, const lcd_params_t *params)
}
void lcd_write_cmd(const lcd_t *dev, uint8_t cmd, const uint8_t *data,
size_t len)
size_t len)
{
_lcd_spi_acquire(dev);
_write_cmd(dev, cmd, data, len);
spi_release(dev->params->spi);
lcd_ll_acquire(dev);
lcd_ll_write_cmd(dev, cmd, data, len);
lcd_ll_release(dev);
}
void lcd_read_cmd(const lcd_t *dev, uint8_t cmd, uint8_t *data, size_t len)
{
assert(len);
_lcd_spi_acquire(dev);
_lcd_cmd_start(dev, cmd, true);
/* Dummy transfer */
spi_transfer_byte(dev->params->spi, dev->params->cs_pin, true, 0x00);
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false, NULL,
data, len);
spi_release(dev->params->spi);
lcd_ll_acquire(dev);
lcd_ll_read_cmd(dev, cmd, data, len);
lcd_ll_release(dev);
}
void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
uint16_t y2, uint16_t color)
uint16_t y2, uint16_t color)
{
/* Send fill area to the display */
@ -106,7 +192,7 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
x1, x2, y1, y2, (unsigned long)num_pix);
/* Send fill area to the display */
_lcd_spi_acquire(dev);
lcd_ll_acquire(dev);
_lcd_set_area(dev, x1, x2, y1, y2);
/* Memory access command */
@ -117,16 +203,14 @@ void lcd_fill(const lcd_t *dev, uint16_t x1, uint16_t x2, uint16_t y1,
}
for (int i = 0; i < (num_pix - 1); i++) {
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true,
(uint8_t *)&color, NULL, sizeof(color));
_lcd_write_bytes(dev, true, (uint8_t *)&color, sizeof(color));
}
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false,
(uint8_t *)&color, NULL, sizeof(color));
spi_release(dev->params->spi);
_lcd_write_bytes(dev, false, (uint8_t *)&color, sizeof(color));
lcd_ll_release(dev);
}
void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2,
uint16_t y1, uint16_t y2, const uint16_t *color)
uint16_t y1, uint16_t y2, const uint16_t *color)
{
size_t num_pix = (x2 - x1 + 1) * (y2 - y1 + 1);
@ -134,7 +218,7 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2,
"y1: %" PRIu16 ", y2: %" PRIu16 ". Num pixels: %lu\n",
x1, x2, y1, y2, (unsigned long)num_pix);
_lcd_spi_acquire(dev);
lcd_ll_acquire(dev);
/* Send fill area to the display */
_lcd_set_area(dev, x1, x2, y1, y2);
@ -145,19 +229,16 @@ void lcd_pixmap(const lcd_t *dev, uint16_t x1, uint16_t x2,
if (IS_ACTIVE(CONFIG_LCD_LE_MODE)) {
for (size_t i = 0; i < num_pix - 1; i++) {
uint16_t ncolor = htons(*(color + i));
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, true,
&ncolor, NULL, sizeof(uint16_t));
_lcd_write_bytes(dev, true, &ncolor, sizeof(uint16_t));
}
uint16_t ncolor = htons(*(color + num_pix - 1));
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false,
&ncolor, NULL, sizeof(uint16_t));
_lcd_write_bytes(dev, false, &ncolor, sizeof(uint16_t));
}
else {
spi_transfer_bytes(dev->params->spi, dev->params->cs_pin, false,
(const uint8_t *)color, NULL, num_pix * 2);
_lcd_write_bytes(dev, false, (const uint8_t *)color, num_pix * 2);
}
spi_release(dev->params->spi);
lcd_ll_release(dev);
}
void lcd_invert_on(const lcd_t *dev)