mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +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
|
||||
|
||||
rsource "lcd_fmc/Kconfig"
|
||||
rsource "periph/Kconfig"
|
||||
rsource "stmclk/Kconfig"
|
||||
rsource "vectors/Kconfig"
|
||||
|
@ -6,4 +6,8 @@ ifneq (,$(filter bootloader_stm32,$(USEMODULE)))
|
||||
DIRS += bootloader
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lcd_fmc,$(USEMODULE)))
|
||||
DIRS += lcd_fmc
|
||||
endif
|
||||
|
||||
include $(RIOTBASE)/Makefile.base
|
||||
|
@ -54,6 +54,10 @@ ifneq (,$(filter stm32_eth,$(USEMODULE)))
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq (,$(filter lcd_parallel_ll_mcu,$(USEMODULE)))
|
||||
USEMODULE += lcd_fmc
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_can,$(FEATURES_USED)))
|
||||
FEATURES_REQUIRED += periph_gpio
|
||||
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" {
|
||||
#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
|
||||
*
|
||||
|
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