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

270 lines
8.0 KiB
C

/*
* Copyright (C) 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
* directory for more details.
*/
/**
* @ingroup cpu_esp32
* @{
*
* @file
* @brief GPIO-driven low-Level parallel interface implementation for LCDs
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include "periph/gpio.h"
#include "lcd.h"
#include "ztimer.h"
#if MODULE_ESP_LCD_GPIO
#include "soc/gpio_reg.h"
#define ENABLE_DEBUG 0
#include "debug.h"
typedef struct {
uint32_t set_mask_0; /* port 0 set mask */
uint32_t set_mask_1; /* port 0 set mask */
uint32_t clr_mask_0; /* port 1 clear mask */
uint32_t clr_mask_1; /* port 1 clear mask */
} _pin_mask_t;
static _pin_mask_t _low_byte_masks[256] = {};
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static _pin_mask_t _high_byte_masks[256] = {};
#endif
/*
* Following functions are not implemented by intention to let the
* GPIO-driven low-level implementation handle the configuration
* of the GPIOs. The function `_lcd_ll_mcu_set_data_dir` is used to
* initialize the GPIO masks when the clear masks are completely 0.
*/
#if 0
static void _lcd_ll_mcu_init(lcd_t *dev)
{
(void)dev;
}
static void _lcd_ll_mcu_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
(void)dev;
(void)cmd;
(void)cont;
}
#endif
static void _lcd_ll_mcu_set_data_dir(lcd_t *dev, bool output)
{
DEBUG("[lcd_ll_mcu] %s %u\n", __func__, output);
/* sanity check to ensure that data pins can be handled as array */
assert((&dev->params->d7_pin - &dev->params->d0_pin) == 7);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
assert((&dev->params->d15_pin - &dev->params->d8_pin) == 7);
#endif
if ((_low_byte_masks[0].clr_mask_0 == 0) &&
(_low_byte_masks[0].clr_mask_1 == 0)) {
/* initialize the mask array if it is not yet initialized */
const gpio_t *pins = &dev->params->d0_pin;
for (unsigned data = 0; data < 256; data++) {
for (unsigned i = 0; i < 8; i++) {
if (data & (1 << i)) {
/* set mask */
if (pins[i] < 32) {
_low_byte_masks[data].set_mask_0 |= 1 << pins[i];
}
else {
_low_byte_masks[data].set_mask_1 |= 1 << (pins[i] - 32);
}
}
else {
/* clear mask */
if (pins[i] < 32) {
_low_byte_masks[data].clr_mask_0 |= 1 << pins[i];
}
else {
_low_byte_masks[data].clr_mask_1 |= 1 << (pins[i] - 32);
}
}
}
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
pins = &dev->params->d8_pin;
for (unsigned data = 0; data < 256; data++) {
for (unsigned i = 0; i < 8; i++) {
if (data & (1 << i)) {
/* set mask */
if (pins[i] < 32) {
_high_byte_masks[data].set_mask_0 |= 1 << pins[i];
}
else {
_high_byte_masks[data].set_mask_1 |= 1 << (pins[i] - 32);
}
}
else {
/* clear mask */
if (pins[i] < 32) {
_high_byte_masks[data].clr_mask_0 |= 1 << pins[i];
}
else {
_high_byte_masks[data].clr_mask_1 |= 1 << (pins[i] - 32);
}
}
}
}
#endif
}
gpio_init(dev->params->d0_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d1_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d2_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d3_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d4_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d5_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d6_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d7_pin, output ? GPIO_OUT : GPIO_IN);
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
gpio_init(dev->params->d8_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d9_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d10_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d11_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d12_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d13_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d14_pin, output ? GPIO_OUT : GPIO_IN);
gpio_init(dev->params->d15_pin, output ? GPIO_OUT : GPIO_IN);
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
}
static void _lcd_ll_mcu_write_data(lcd_t *dev, bool cont,
uint16_t data, unsigned pin_num)
{
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}
gpio_clear(dev->params->wrx_pin);
uint8_t _byte = data & 0xff;
uint32_t set_mask_0 = _low_byte_masks[_byte].set_mask_0;
uint32_t clr_mask_0 = _low_byte_masks[_byte].clr_mask_0;
uint32_t set_mask_1 = _low_byte_masks[_byte].set_mask_1;
uint32_t clr_mask_1 = _low_byte_masks[_byte].clr_mask_1;
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
_byte = data >> 8;
set_mask_0 |= _high_byte_masks[_byte].set_mask_0;
clr_mask_0 |= _high_byte_masks[_byte].clr_mask_0;
set_mask_1 |= _high_byte_masks[_byte].set_mask_1;
clr_mask_1 |= _high_byte_masks[_byte].clr_mask_1;
#endif
*((uint32_t *)GPIO_OUT_W1TS_REG) = set_mask_0;
*((uint32_t *)GPIO_OUT_W1TC_REG) = clr_mask_0;
*((uint32_t *)GPIO_OUT1_W1TS_REG) = set_mask_1;
*((uint32_t *)GPIO_OUT1_W1TC_REG) = clr_mask_1;
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_mcu_read_data(lcd_t *dev, bool cont, unsigned pin_num)
{
const gpio_t *pins = &dev->params->d0_pin;
if (gpio_is_valid(dev->params->cs_pin)) {
gpio_clear(dev->params->cs_pin);
}
gpio_clear(dev->params->rdx_pin);
uint32_t in_0 = *((uint32_t *)GPIO_IN_REG);
uint32_t in_1 = *((uint32_t *)GPIO_IN1_REG);
gpio_set(dev->params->rdx_pin);
if (gpio_is_valid(dev->params->cs_pin) && !cont) {
gpio_set(dev->params->cs_pin);
};
uint16_t in = 0;
for (unsigned i = 0; i < pin_num; i++) {
if (pins[i] < 32) {
in |= in_0 & (1 << pins[i]) ? 1 : 0;
}
else {
in |= in_1 & (1 << (pins[i] - 32)) ? 1 : 0;
}
}
return in;
}
static void _lcd_ll_mcu_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
DEBUG("[lcd_ll_mcu] write byte: %02x\n", out);
_lcd_ll_mcu_write_data(dev, cont, out, 8);
}
static uint8_t _lcd_ll_mcu_read_byte(lcd_t *dev, bool cont)
{
return _lcd_ll_mcu_read_data(dev, cont, 8);
}
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
static void _lcd_ll_mcu_write_word(lcd_t *dev, bool cont, uint16_t out)
{
DEBUG("[lcd_ll_mcu] write word: %04x\n", out);
_lcd_ll_mcu_write_data(dev, cont, out, 16);
}
static uint16_t _lcd_ll_mcu_read_word(lcd_t *dev, bool cont)
{
return _lcd_ll_mcu_read_data(dev, cont, 16);
}
#endif /* IS_USED(MODULE_LCD_PARALLEL_16BIT) */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
.init = lcd_ll_par_gpio_init, /* GPIO-driven `init` is used */
.set_data_dir = _lcd_ll_mcu_set_data_dir,
.cmd_start = lcd_ll_par_gpio_cmd_start, /* GPIO-driven `cmd_start` is used */
.write_byte = _lcd_ll_mcu_write_byte,
.read_byte = _lcd_ll_mcu_read_byte,
#if IS_USED(MODULE_LCD_PARALLEL_16BIT)
.write_word = _lcd_ll_mcu_write_word,
.read_word = _lcd_ll_mcu_read_word,
#endif
};
#else /* MODULE_ESP_LCD_GPIO */
/* the GPIO-driven low-level interface is not used */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
};
#endif /* MODULE_ESP_LCD_GPIO */