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

177 lines
4.4 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_stm32
* @ingroup drivers_periph_fmc
* @{
*
* @file
* @brief FMC peripheral driver implementation
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include "periph/gpio.h"
#include "lcd.h"
#include "lcd_internal.h"
#include "ztimer.h"
#define ENABLE_DEBUG 0
#include "debug.h"
#ifndef LCD_FMC_NUMOF
#define LCD_FMC_NUMOF 1
#endif
#define FMC_LCD_CMD(d) (*((__IO uint16_t *)(d->bank->address + d->cmd_offset)))
#define FMC_LCD_DATA(d) (*((__IO uint16_t *)(d->bank->address + d->data_offset)))
/* sanity check */
static_assert(LCD_FMC_NUMOF == ARRAY_SIZE(lcd_fmc_desc),
"LCD_FMC_NUMOF is not equal to the number of elements in lcd_fmc_desc");
#if LCD_FMC_NUMOF > 1
/* In the case that multiple LCDs are connected to FMC banks, an array
* for mapping the LCD device pointer to the FMC bank descriptor is used.
* This requires that the FMC bank descriptors for LCDs in `lcd_fmc_desc`
* are defined in same order as the LCD devices. */
static lcd_t *_lcd_fmc_desc_map[LCD_FMC_NUMOF];
static uint8_t _lcd_index = 0;
static inline uint8_t _dev_to_lcd_fmc_desc(lcd_t *dev)
{
for (uint8_t i = 0; i < LCD_FMC_NUMOF; i++) {
if (_lcd_fmc_desc_map[i] == dev) {
return i;
}
}
assert(false);
}
#endif
static void lcd_ll_mcu_init(lcd_t *dev)
{
#if LCD_FMC_NUMOF > 1
/* The FMC bank descriptors for LCDs in `lcd_fmc_desc` must be defined
* in same order as the LCD display devices. We suppose that the
* LCDs are initialized in that order. */
assert(_lcd_index < LCD_FMC_NUMOF);
_lcd_fmc_desc_map[_lcd_index++] = dev;
#else
(void)dev;
#endif
}
static void lcd_ll_mcu_set_data_dir(lcd_t *dev, bool output)
{
/* no action needed */
(void)dev;
(void)output;
}
static void lcd_ll_mcu_cmd_start(lcd_t *dev, uint8_t cmd, bool cont)
{
DEBUG("[lcd_ll_mcu] write cmd: %02x\n", cmd);
(void)cont;
#if LCD_FMC_NUMOF > 1
const lcd_fmc_desc_t *desc = &lcd_fmc_desc[_dev_to_lcd_fmc_desc(dev)];
#else
(void)dev;
const lcd_fmc_desc_t *desc = lcd_fmc_desc;
#endif
FMC_LCD_CMD(desc) = cmd;
/* data synchronization barrier seems to be necessary on some STM32 MCUs. */
__DSB();
}
static void lcd_ll_mcu_write_byte(lcd_t *dev, bool cont, uint8_t out)
{
DEBUG("[lcd_ll_mcu] write byte: %02x\n", out);
(void)cont;
#if LCD_FMC_NUMOF > 1
const lcd_fmc_desc_t *desc = &lcd_fmc_desc[_dev_to_lcd_fmc_desc(dev)];
#else
(void)dev;
const lcd_fmc_desc_t *desc = lcd_fmc_desc;
#endif
FMC_LCD_DATA(desc) = out;
/* data synchronization barrier seems to be necessary on some STM32 MCUs. */
__DSB();
}
static uint8_t lcd_ll_mcu_read_byte(lcd_t *dev, bool cont)
{
(void)cont;
#if LCD_FMC_NUMOF > 1
const lcd_fmc_desc_t *desc = &lcd_fmc_desc[_dev_to_lcd_fmc_desc(dev)];
#else
(void)dev;
const lcd_fmc_desc_t *desc = lcd_fmc_desc;
#endif
uint8_t in = FMC_LCD_DATA(desc);
DEBUG("[lcd_ll_mcu] read byte: %02x\n", in);
return in;
}
#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);
(void)cont;
#if LCD_FMC_NUMOF > 1
const lcd_fmc_desc_t *desc = &lcd_fmc_desc[_dev_to_lcd_fmc_desc(dev)];
#else
(void)dev;
const lcd_fmc_desc_t *desc = lcd_fmc_desc;
#endif
FMC_LCD_DATA(desc) = out;
/* data synchronization barrier seems to be necessary on some STM32 MCUs. */
__DSB();
}
static uint16_t lcd_ll_mcu_read_word(lcd_t *dev, bool cont)
{
(void)cont;
#if LCD_FMC_NUMOF > 1
const lcd_fmc_desc_t *desc = &lcd_fmc_desc[_dev_to_lcd_fmc_desc(dev)];
#else
(void)dev;
const lcd_fmc_desc_t *desc = lcd_fmc_desc;
#endif
uint16_t in = FMC_LCD_DATA(desc);
DEBUG("[lcd_ll_mcu] read word: %04x\n", in);
return in;
}
#endif /* MODULE_LCD_PARALLEL_16BIT */
const lcd_ll_par_driver_t lcd_ll_par_driver = {
.init = lcd_ll_mcu_init,
.set_data_dir = lcd_ll_mcu_set_data_dir,
.cmd_start = lcd_ll_mcu_cmd_start,
.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
};