mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2025-01-17 05:32:45 +01:00
cpu/stm32: add FMC support for LCD with parallel interface
This commit is contained in:
parent
dd62f419d7
commit
94fdead641
@ -78,6 +78,7 @@ rsource "periph/Kconfig.fmc"
|
|||||||
|
|
||||||
if TEST_KCONFIG
|
if TEST_KCONFIG
|
||||||
|
|
||||||
|
rsource "lcd_fmc/Kconfig"
|
||||||
rsource "periph/Kconfig"
|
rsource "periph/Kconfig"
|
||||||
rsource "stmclk/Kconfig"
|
rsource "stmclk/Kconfig"
|
||||||
rsource "vectors/Kconfig"
|
rsource "vectors/Kconfig"
|
||||||
|
@ -6,4 +6,8 @@ ifneq (,$(filter bootloader_stm32,$(USEMODULE)))
|
|||||||
DIRS += bootloader
|
DIRS += bootloader
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter lcd_fmc,$(USEMODULE)))
|
||||||
|
DIRS += lcd_fmc
|
||||||
|
endif
|
||||||
|
|
||||||
include $(RIOTBASE)/Makefile.base
|
include $(RIOTBASE)/Makefile.base
|
||||||
|
@ -54,6 +54,10 @@ ifneq (,$(filter stm32_eth,$(USEMODULE)))
|
|||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter lcd_parallel_ll_mcu,$(USEMODULE)))
|
||||||
|
USEMODULE += lcd_fmc
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq (,$(filter periph_can,$(FEATURES_USED)))
|
ifneq (,$(filter periph_can,$(FEATURES_USED)))
|
||||||
FEATURES_REQUIRED += periph_gpio
|
FEATURES_REQUIRED += periph_gpio
|
||||||
FEATURES_REQUIRED += periph_gpio_irq
|
FEATURES_REQUIRED += periph_gpio_irq
|
||||||
|
60
cpu/stm32/include/lcd_fmc.h
Normal file
60
cpu/stm32/include/lcd_fmc.h
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @defgroup cpu_stm32_lcd_fmc STM32 FMC/FSMC LCD low-level parallel interface driver
|
||||||
|
* @ingroup cpu_stm32
|
||||||
|
*
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LCD_FMC_H
|
||||||
|
#define LCD_FMC_H
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Number of LCDs using FMC banks
|
||||||
|
*
|
||||||
|
* It represents the number of elements in LCD FMC bank descriptor array of
|
||||||
|
* type @ref lcd_fmc_desc_t. Because it is used by the preprocessor, it has
|
||||||
|
* to be defined as a number. It is not possible to use the @ref ARRAY_SIZE
|
||||||
|
* macro here.
|
||||||
|
*
|
||||||
|
* @note `LCD_FMC_NUMOF` has to be equal to the number of elements in the
|
||||||
|
* LCD FMC bank descriptor array of type @ref lcd_fmc_desc_t.
|
||||||
|
*/
|
||||||
|
#if DOXYGEN
|
||||||
|
#define LCD_FMC_NUMOF 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Descriptor of the FMC bank used for a LCD
|
||||||
|
*
|
||||||
|
* The board definition has to specify the array @ref lcd_fmc_desc of type
|
||||||
|
* @ref lcd_fmc_desc_t which defines the FMC banks and the address offsets used
|
||||||
|
* for the LCD displays that are connected to FMC banks.
|
||||||
|
*
|
||||||
|
* @note In the case that multiple LCDs are connected to FMC banks, the FMC
|
||||||
|
* bank descriptors for LCDs of type @ref lcd_fmc_desc_t
|
||||||
|
* must be defined in same order as the LCD devices.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const fmc_bank_conf_t *bank; /**< FMC bank config used for the LCD */
|
||||||
|
uint32_t cmd_offset; /**< offset to the bank address used for commands */
|
||||||
|
uint32_t data_offset; /**< offset to the bank address used for data */
|
||||||
|
} lcd_fmc_desc_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* LCD_FMC_H */
|
||||||
|
/** @} */
|
@ -64,6 +64,17 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gives the configuration of n-th bank
|
||||||
|
*
|
||||||
|
* This macro gives a pointer to the n-th entry of type @ref fmc_bank_conf_t of
|
||||||
|
* the banks configured by the board in the @ref fmc_bank_config array. n is in
|
||||||
|
* the range 0 ... @ref FMC_BANK_NUMOF - 1.
|
||||||
|
*/
|
||||||
|
#ifndef FMC_BANK_CONFIG
|
||||||
|
#define FMC_BANK_CONFIG(n) (&fmc_bank_config[n])
|
||||||
|
#endif
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Number of data pins used
|
* @brief Number of data pins used
|
||||||
*
|
*
|
||||||
|
13
cpu/stm32/lcd_fmc/Kconfig
Normal file
13
cpu/stm32/lcd_fmc/Kconfig
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# 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.
|
||||||
|
#
|
||||||
|
|
||||||
|
config MODULE_LCD_FMC
|
||||||
|
bool
|
||||||
|
depends on MODULE_LCD
|
||||||
|
select MODULE_PERIPH_FMC
|
||||||
|
select MODULE_PERIPH_FMC_NOR_SRAM
|
||||||
|
default y if HAVE_LCD_PARALLEL_LL_MCU
|
3
cpu/stm32/lcd_fmc/Makefile
Normal file
3
cpu/stm32/lcd_fmc/Makefile
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
MODULE = lcd_fmc
|
||||||
|
|
||||||
|
include $(RIOTBASE)/Makefile.base
|
176
cpu/stm32/lcd_fmc/lcd_fmc.c
Normal file
176
cpu/stm32/lcd_fmc/lcd_fmc.c
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/*
|
||||||
|
* 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
|
||||||
|
};
|
Loading…
Reference in New Issue
Block a user