mirror of
https://github.com/RIOT-OS/RIOT.git
synced 2024-12-29 04:50:03 +01:00
19843: cpu/stm32/periph: add FMC/FSMC support for STM32 r=aabadie a=gschorcht ### Contribution description The PR provides a driver for STM32 FMC/FSMC peripherals. It supports: - NOR Flashes, - PSRAMs/SRAMs, - SDRAMs, and - Display Controllers with MCU 8-/16-bit parallel interface. NAND Flashes are not yet supported. To use the FMC/FSMC, the `periph_fmc` module has to be enabled. To keep required data structures and resulting code as small as possible, a couple of pseudomodules are defined that have to be used in addition to the `periph_fmc` module to enable supported features. These are: | Module | Feature | |:-----------------------|:----------------------------------------| | `periph_fmc_nor_sram` | enable NOR Flash and PSRAM/SRAM support | | `periph_fmc_sdram` | enable SDRAM support | | `periph_fmc_16bit` | enable 16-bit support | | `periph_fmc_32bit` | enable 32-bit support | The board has then to define - the corresponding features according to the connected external device, - the peripheral configuration of the FMC/FSMC of type `fmc_conf_t,` - the configuration of the FMC banks which describe the connected external devices. The PR includes the support for - `stm32f429i-disc1` with 8 MByte SDRAM - `stm32f746g-disco` with 16 MByte SDRAM - `stm32l496g-disco` with 1 MByte SRAM - `stm32f723e-disco` with 1 MByte SRAM. To use the RAM connected to the FMC as heap, the board defines `FMC_RAM_ADDR` and ` FMC_RAM_LEN`. For that purpose: - the linker symbols `_fmc_ram_addr` and `_fmc_ram_len` are set, - a memory region `fcmram` is added in linker script for the FMC RAM based on these `_fcm_ram_*` linker symbols - a section for the FMC RAM is defined in this memory region that defines the heap by setting `_sheap3` and `_eheap3` and - the number of heaps is set to 4 to use `_sheap3` and `_eheap3` even though `_sheap1` and `_eheap1` (the backup RAM) and `_sheap2` and `_eheap2` (SRAM4) are not present. Once the `drivers/st77xx` and `drivers/lcd` changes are merged, the display for boards like the `stm32l496g-disco` and `stm32f723e-disco` can also use the FMC peripheral. ~**NOTE**: The PR includes the fix in PR #19842 for now (commit 560fea17a0c50483214770855e22cc94df0e55b5).~ ### Testing procedure 1. Use one of the boards above and flash `tests/driver/stm32_fmc`, for example: ``` BOARD=stm32f429i-disc1 make -j8 -C tests/drivers/stm32_fmc flash test ``` The test should succeed. **NOTE**: There is still a problem with `stm32f746g-disco`. It crashes with a hard-fault on accessing the upper 8 MByte of the 16 MByte. 2. Use the board above and flash `tests/sys/malloc`, for example: ``` USEMODULE=periph_fmc CFLAGS='-DCHUNK_SIZE=4096 -DDEBUG_ASSERT_VERBOSE' \ BOARD=stm32f429i-disc1 make -j8 -C tests/sys/malloc ``` The FMC RAM should be used for `malloc`. On `stm32f746g-disco` for example ``` ... Allocated 4096 Bytes at 0x2002d7c8, total 184672 Allocated 4096 Bytes at 0x2002e7e0, total 188776 Allocated 4096 Bytes at 0xd0000008, total 192880 Allocated 4096 Bytes at 0xd0001010, total 196984 Allocated 4096 Bytes at 0xd0002018, total 201088 ... Allocated 4096 Bytes at 0xd07fd6d0, total 8544520 Allocated 4096 Bytes at 0xd07fe6e8, total 8548624 Allocations count: 2083 ``` ### Issues/PRs references ~Depends on PR #19842~ 19847: .github: drop test-on-ryot workflow r=aabadie a=aabadie Co-authored-by: Gunar Schorcht <gunar@schorcht.net> Co-authored-by: Alexandre Abadie <alexandre.abadie@inria.fr>
This commit is contained in:
commit
c4a1802a9f
105
.github/workflows/test-on-ryot.yml
vendored
105
.github/workflows/test-on-ryot.yml
vendored
@ -1,105 +0,0 @@
|
||||
---
|
||||
# Run 'compile_and_test_for_board.py' on connected boards.
|
||||
#
|
||||
# This workflow will run on a RYOT (Run Your Own Test) machine and launch
|
||||
# all tests on all boards currently connected to that machine. This
|
||||
# workflow relies on self-hosted runners, this means building and
|
||||
# flashing happens on the self-hosted runner (all in docker). An alternative
|
||||
# approach was used in https://github.com/RIOT-OS/RIOT/pull/14600, where
|
||||
# the RYOT machine was only used for remote flashing, this is a better
|
||||
# alternative if ssh access is possible.
|
||||
#
|
||||
# Documentation:
|
||||
#
|
||||
# * Setup a RYOT machine:
|
||||
# https://github.com/fjmolinas/riot-ryot/blob/master/setup.md
|
||||
#
|
||||
# * Requirements (already filled by a RYOT machine):
|
||||
# * Add one or more self-hosted runners:
|
||||
# https://docs.github.com/en/actions/hosting-your-own-runners/adding-self-hosted-runners
|
||||
# * All required flashing tools installed
|
||||
# * udev rules that map all BOARD to /dev/riot/tty-$(BOARD), see
|
||||
# http://riot-os.org/api/advanced-build-system-tricks.html#multiple-boards-udev
|
||||
# * RIOT_MAKEFILES_GLOBAL_PRE that sets PORT and DEBUG_ADAPTER_ID for each
|
||||
# BOARD
|
||||
# * A list of connected BOARDs in JSON format so that fromJSON can be used
|
||||
# to dynamically setup the matrix, e.g. make target providing this:
|
||||
# https://github.com/fjmolinas/riot-ryot/blob/72fc9ad710a2219e942c5965a014e934822e9da5/template/conf/makefiles.pre#L19-L24
|
||||
# * RYOT: https://github.com/fjmolinas/riot-ryot
|
||||
|
||||
name: test-on-ryot
|
||||
|
||||
on:
|
||||
# Schedule weekly runs Saturday at 00:00 on master
|
||||
schedule:
|
||||
- cron: '0 0 * * 6'
|
||||
push:
|
||||
# Run on all new release candidates
|
||||
tags:
|
||||
- '[0-9][0-9][0-9][0-9].[0-9][0-9]-RC[0-9]*'
|
||||
- '[0-9][0-9][0-9][0-9].[0-9][0-9]'
|
||||
- '[0-9][0-9][0-9][0-9].[0-9][0-9].*'
|
||||
env:
|
||||
# self-hosted runners are started by a systemd which is not a "login" shell
|
||||
# this means that no local environment variables are loaded (e.g. /etc/environment)
|
||||
# when the runner is started. So explicitly set RIOT_MAKEFILES_GLOBAL_PRE
|
||||
# to set PORT and DEBUG_ADAPTER_ID per BOARD
|
||||
RIOT_MAKEFILES_GLOBAL_PRE: '/builds/conf/makefiles.pre'
|
||||
|
||||
jobs:
|
||||
connected_boards:
|
||||
name: Get Connected Boards
|
||||
runs-on: self-hosted
|
||||
outputs:
|
||||
boards: ${{ steps.ci-connected-boards.outputs.boards }}
|
||||
steps:
|
||||
# Get all currently connected boards if not passed through an input
|
||||
- id: ci-connected-boards
|
||||
run: echo "::set-output name=boards::$(make -C /builds/boards/ list-boards-json --no-print-directory)"
|
||||
|
||||
# Runs all tests on connected boards
|
||||
compile_and_test_for_board:
|
||||
name: ${{ matrix.board }}
|
||||
runs-on: self-hosted
|
||||
needs: connected_boards
|
||||
# ci-riot-tribe has 8 cores, parallelism will depend on actually configured
|
||||
# runners
|
||||
strategy:
|
||||
max-parallel: 7
|
||||
fail-fast: false
|
||||
matrix:
|
||||
board: ${{ fromJson(needs.connected_boards.outputs.boards) }}
|
||||
env:
|
||||
BUILD_IN_DOCKER: 1
|
||||
COMPILE_AND_TEST_FOR_BOARD: /builds/boards/RIOT/dist/tools/compile_and_test_for_board/compile_and_test_for_board.py
|
||||
# args for compile_and_test_for_board script
|
||||
COMPILE_AND_TEST_ARGS: --with-test-only --report-xml --incremental
|
||||
# environment vars for compile_and_test_for_board script to pass
|
||||
# USEMODULE and CFLAGS use:
|
||||
# DOCKER_ENVIRONMENT_CMDLINE=\'-e USEMODULE=<name>\'
|
||||
# DOCKER_ENVIRONMENT_CMDLINE=\'-e CFLAGS=-D<flag>\'
|
||||
COMPILE_AND_TEST_VARS: ''
|
||||
APPLICATIONS: ''
|
||||
# Exclude 'tests/periph/timer_short_relative_set' since its expected
|
||||
# to fail on most BOARDs
|
||||
APPLICATIONS_EXCLUDE: 'tests/periph/timer_short_relative_set'
|
||||
steps:
|
||||
- name: Checkout RIOT
|
||||
uses: actions/checkout@main
|
||||
with:
|
||||
ref: ${{ github.event.inputs.riot_version }}
|
||||
# Make sure it runs git clean -xdff before fetching
|
||||
clean: true
|
||||
- name: Run compile_and_test_for_board.py
|
||||
run: |
|
||||
${COMPILE_AND_TEST_VARS} ${COMPILE_AND_TEST_FOR_BOARD} . \
|
||||
${{ matrix.board }} results-${{ matrix.board }} \
|
||||
${COMPILE_AND_TEST_ARGS} \
|
||||
--applications="${APPLICATIONS}" \
|
||||
--applications-exclude="${APPLICATIONS_EXCLUDE}"
|
||||
- name: Archive results
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: ${{ matrix.board }}
|
||||
path: results-${{ matrix.board }}
|
@ -15,6 +15,9 @@ config BOARD_STM32F429I_DISC1
|
||||
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
select HAS_PERIPH_DMA
|
||||
select HAS_PERIPH_FMC
|
||||
select HAS_PERIPH_FMC_SDRAM
|
||||
select HAS_PERIPH_FMC_16BIT
|
||||
select HAS_PERIPH_I2C
|
||||
select HAS_PERIPH_SPI
|
||||
select HAS_PERIPH_TIMER
|
||||
|
@ -2,6 +2,10 @@ ifneq (,$(filter periph_usbdev,$(USEMODULE)))
|
||||
USEMODULE += periph_usbdev_hs
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_fmc,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_fmc_16bit
|
||||
endif
|
||||
|
||||
ifneq (,$(filter saul_default,$(USEMODULE)))
|
||||
USEMODULE += saul_gpio
|
||||
USEMODULE += l3gxxxx
|
||||
|
@ -3,6 +3,9 @@ CPU_MODEL = stm32f429zi
|
||||
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
FEATURES_PROVIDED += periph_dma
|
||||
FEATURES_PROVIDED += periph_fmc
|
||||
FEATURES_PROVIDED += periph_fmc_16bit
|
||||
FEATURES_PROVIDED += periph_fmc_sdram
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_spi
|
||||
FEATURES_PROVIDED += periph_timer
|
||||
|
@ -8,3 +8,6 @@ OPENOCD_DEBUG_ADAPTER ?= stlink
|
||||
|
||||
# openocd programmer is supported
|
||||
PROGRAMMERS_SUPPORTED += openocd
|
||||
|
||||
FMC_RAM_ADDR=0xd0000000
|
||||
FMC_RAM_LEN=8192K
|
||||
|
@ -132,6 +132,111 @@ static const i2c_conf_t i2c_config[] = {
|
||||
#define I2C_NUMOF ARRAY_SIZE(i2c_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name FMC configuration
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief FMC controller configuration
|
||||
*/
|
||||
static const fmc_conf_t fmc_config = {
|
||||
.bus = AHB3,
|
||||
.rcc_mask = RCC_AHB3ENR_FMCEN,
|
||||
#if MODULE_PERIPH_FMC_SDRAM
|
||||
.ba0_pin = { .pin = GPIO_PIN(PORT_G, 4), .af = GPIO_AF12, }, /* FMC_BA0 signal */
|
||||
.ba1_pin = { .pin = GPIO_PIN(PORT_G, 5), .af = GPIO_AF12, }, /* FMC_BA1 signal */
|
||||
.sdclk_pin = { .pin = GPIO_PIN(PORT_G, 8), .af = GPIO_AF12, }, /* FMC_SDCLK signal */
|
||||
.sdnwe_pin = { .pin = GPIO_PIN(PORT_C, 0), .af = GPIO_AF12, }, /* FMC_SDNWE signal */
|
||||
.sdnras_pin = { .pin = GPIO_PIN(PORT_F, 11), .af = GPIO_AF12, }, /* FMC_SDNRAS signal */
|
||||
.sdncas_pin = { .pin = GPIO_PIN(PORT_G, 15), .af = GPIO_AF12, }, /* FMC_SDNCAS signal */
|
||||
.sdcke1_pin = { .pin = GPIO_PIN(PORT_B, 5), .af = GPIO_AF12, }, /* FMC_SDCKE1 signal */
|
||||
.sdne1_pin = { .pin = GPIO_PIN(PORT_B, 6), .af = GPIO_AF12, }, /* FMC_SDNE1 signal */
|
||||
.addr = {
|
||||
{ .pin = GPIO_PIN(PORT_F, 0), .af = GPIO_AF12, }, /* FMC_A0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 1), .af = GPIO_AF12, }, /* FMC_A1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 2), .af = GPIO_AF12, }, /* FMC_A2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 3), .af = GPIO_AF12, }, /* FMC_A3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 4), .af = GPIO_AF12, }, /* FMC_A4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 5), .af = GPIO_AF12, }, /* FMC_A5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 12), .af = GPIO_AF12, }, /* FMC_A6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 13), .af = GPIO_AF12, }, /* FMC_A7 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 14), .af = GPIO_AF12, }, /* FMC_A8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 15), .af = GPIO_AF12, }, /* FMC_A9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 0), .af = GPIO_AF12, }, /* FMC_A10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 1), .af = GPIO_AF12, }, /* FMC_A11 signal */
|
||||
},
|
||||
#endif
|
||||
.data = {
|
||||
{ .pin = GPIO_PIN(PORT_D, 14), .af = GPIO_AF12, }, /* FMC_D0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 15), .af = GPIO_AF12, }, /* FMC_D1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 0), .af = GPIO_AF12, }, /* FMC_D2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 1), .af = GPIO_AF12, }, /* FMC_D3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 7), .af = GPIO_AF12, }, /* FMC_D4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 8), .af = GPIO_AF12, }, /* FMC_D5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 9), .af = GPIO_AF12, }, /* FMC_D6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 10), .af = GPIO_AF12, }, /* FMC_D7 signal */
|
||||
#if MODULE_PERIPH_FMC_16BIT
|
||||
{ .pin = GPIO_PIN(PORT_E, 11), .af = GPIO_AF12, }, /* FMC_D8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 12), .af = GPIO_AF12, }, /* FMC_D9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 13), .af = GPIO_AF12, }, /* FMC_D10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 14), .af = GPIO_AF12, }, /* FMC_D11 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 15), .af = GPIO_AF12, }, /* FMC_D12 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 8), .af = GPIO_AF12, }, /* FMC_D13 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 9), .af = GPIO_AF12, }, /* FMC_D14 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 10), .af = GPIO_AF12, }, /* FMC_D15 signal */
|
||||
#endif
|
||||
},
|
||||
.nbl0_pin = { .pin = GPIO_PIN(PORT_E, 0), .af = GPIO_AF12, }, /* FMC_NBL0 signal (LB) */
|
||||
.nbl1_pin = { .pin = GPIO_PIN(PORT_E, 1), .af = GPIO_AF12, }, /* FMC_NBL1 signal (UB) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief FMC Bank configuration
|
||||
*
|
||||
* The board has a SDRAM IS42S16400J-7TL with 64 MBit on-board.
|
||||
* It is organized in 4 banks of 1M x 16 bits each and connected to bank 6
|
||||
* at address 0xd0000000.
|
||||
*/
|
||||
static const fmc_bank_conf_t fmc_bank_config[] = {
|
||||
/* bank 6 is used for SDRAM */
|
||||
{
|
||||
.bank = FMC_BANK_6,
|
||||
.mem_type = FMC_SDRAM,
|
||||
.data_width = FMC_BUS_WIDTH_16BIT,
|
||||
.address = 0xd0000000, /* Bank 6 is mapped to 0xd0000000 */
|
||||
.size = MiB(8), /* Size in Mbyte, 4M x 16 bit */
|
||||
.sdram = {
|
||||
.clk_period = 2, /* SDCLK = 2 x HCLK */
|
||||
.row_bits = 12, /* A11..A0 used for row address */
|
||||
.col_bits = 8, /* A8..A0 used for column address */
|
||||
.cas_latency = 3, /* CAS latency is 3 clock cycles */
|
||||
.read_delay = 0, /* No read delay after CAS */
|
||||
.burst_read = false, /* Burst read mode disabled */
|
||||
.burst_write = false, /* Burst write mode disabled */
|
||||
.burst_len = FMC_BURST_LENGTH_1, /* Burst length is 1 if enabled */
|
||||
.burst_interleaved = false, /* Burst mode interleaved */
|
||||
.write_protect = false, /* No write protection */
|
||||
.four_banks = true, /* SDRAM has four internal banks */
|
||||
.timing = { /* SDRAM Timing parameters */
|
||||
.row_to_col_delay = 2, /* Row to column delay (2 clock cycles) */
|
||||
.row_precharge = 2, /* Row precharge delay (2 clock cycles) */
|
||||
.recovery_delay = 2, /* Recovery delay is (2 clock cycles) */
|
||||
.row_cylce = 7, /* Row cycle delay is (7 clock cycles) */
|
||||
.self_refresh = 4, /* Self refresh time is (4 clock cycles) */
|
||||
.exit_self_refresh = 7, /* Exit self-refresh delay (7 clock cycles) */
|
||||
.load_mode_register = 2, /* Load Mode Register to Activate delay */
|
||||
.refresh_period = 64, /* Refresh period in ms */
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Number of configured FMC banks
|
||||
*/
|
||||
#define FMC_BANK_NUMOF ARRAY_SIZE(fmc_bank_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -14,6 +14,9 @@ config BOARD_STM32F723E_DISCO
|
||||
select CPU_MODEL_STM32F723IE
|
||||
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
select HAS_PERIPH_FMC
|
||||
select HAS_PERIPH_FMC_16BIT
|
||||
select HAS_PERIPH_FMC_NOR_SRAM
|
||||
select HAS_PERIPH_I2C
|
||||
select HAS_PERIPH_RTC
|
||||
select HAS_PERIPH_RTT
|
||||
|
@ -10,6 +10,10 @@ ifneq (,$(filter touch_dev,$(USEMODULE)))
|
||||
USEMODULE += ft5x06
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_fmc,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_fmc_16bit
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_spi,$(USEMODULE)))
|
||||
# The LED pin is also used for SPI
|
||||
DISABLE_MODULE += periph_init_led0
|
||||
|
@ -3,6 +3,9 @@ CPU = stm32
|
||||
CPU_MODEL = stm32f723ie
|
||||
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
FEATURES_PROVIDED += periph_fmc
|
||||
FEATURES_PROVIDED += periph_fmc_16bit
|
||||
FEATURES_PROVIDED += periph_fmc_nor_sram
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
FEATURES_PROVIDED += periph_rtt
|
||||
|
@ -13,3 +13,8 @@ PROGRAMMERS_SUPPORTED += openocd
|
||||
# The board can become un-flashable after some execution or after being plugged,
|
||||
# use connect_assert_srst to always be able to flash or reset the board.
|
||||
OPENOCD_RESET_USE_CONNECT_ASSERT_SRST ?= 1
|
||||
|
||||
# Since only 18 of the 19 address lines are connected, only 512 kByte of the
|
||||
# 1 MByte PSRAM can be used.
|
||||
FMC_RAM_ADDR=0x60000000
|
||||
FMC_RAM_LEN=512K
|
||||
|
@ -232,6 +232,107 @@ static const spi_conf_t spi_config[] = {
|
||||
#define SPI_NUMOF ARRAY_SIZE(spi_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name FMC configuration
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief FMC controller configuration
|
||||
*/
|
||||
static const fmc_conf_t fmc_config = {
|
||||
.bus = AHB3,
|
||||
.rcc_mask = RCC_AHB3ENR_FMCEN,
|
||||
#if MODULE_PERIPH_FMC_NOR_SRAM
|
||||
.ne1_pin = { .pin = GPIO_PIN(PORT_D, 7), .af = GPIO_AF12, }, /* PSRAM_NE1 signal, subbank 1 */
|
||||
.ne2_pin = { .pin = GPIO_PIN(PORT_G, 9), .af = GPIO_AF12, }, /* LCD_NE signal, subbank 2 */
|
||||
.noe_pin = { .pin = GPIO_PIN(PORT_D, 4), .af = GPIO_AF12, }, /* LCD_PSRAM_NOE */
|
||||
.nwe_pin = { .pin = GPIO_PIN(PORT_D, 5), .af = GPIO_AF12, }, /* LCD_PSRAM_NWE signal */
|
||||
.addr = {
|
||||
{ .pin = GPIO_PIN(PORT_F, 0), .af = GPIO_AF12, }, /* PSRAM_A0 / LCD_RS signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 1), .af = GPIO_AF12, }, /* PSRAM_A1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 2), .af = GPIO_AF12, }, /* PSRAM_A2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 3), .af = GPIO_AF12, }, /* PSRAM_A3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 4), .af = GPIO_AF12, }, /* PSRAM_A4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 5), .af = GPIO_AF12, }, /* PSRAM_A5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 12), .af = GPIO_AF12, }, /* PSRAM_A6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 13), .af = GPIO_AF12, }, /* PSRAM_A7 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 14), .af = GPIO_AF12, }, /* PSRAM_A8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 15), .af = GPIO_AF12, }, /* PSRAM_A9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 0), .af = GPIO_AF12, }, /* PSRAM_A10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 1), .af = GPIO_AF12, }, /* PSRAM_A11 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 2), .af = GPIO_AF12, }, /* PSRAM_A12 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 3), .af = GPIO_AF12, }, /* PSRAM_A13 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 4), .af = GPIO_AF12, }, /* PSRAM_A14 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 5), .af = GPIO_AF12, }, /* PSRAM_A15 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 11), .af = GPIO_AF12, }, /* PSRAM_A16 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 12), .af = GPIO_AF12, }, /* PSRAM_A17 signal */
|
||||
},
|
||||
#endif
|
||||
.data = {
|
||||
{ .pin = GPIO_PIN(PORT_D, 14), .af = GPIO_AF12, }, /* LCD_PSRAM_D0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 15), .af = GPIO_AF12, }, /* LCD_PSRAM_D1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 0), .af = GPIO_AF12, }, /* LCD_PSRAM_D2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 1), .af = GPIO_AF12, }, /* LCD_PSRAM_D3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 7), .af = GPIO_AF12, }, /* LCD_PSRAM_D4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 8), .af = GPIO_AF12, }, /* LCD_PSRAM_D5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 9), .af = GPIO_AF12, }, /* LCD_PSRAM_D6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 10), .af = GPIO_AF12, }, /* LCD_PSRAM_D7 signal */
|
||||
#if MODULE_PERIPH_FMC_16BIT
|
||||
{ .pin = GPIO_PIN(PORT_E, 11), .af = GPIO_AF12, }, /* LCD_PSRAM_D8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 12), .af = GPIO_AF12, }, /* LCD_PSRAM_D9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 13), .af = GPIO_AF12, }, /* LCD_PSRAM_D10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 14), .af = GPIO_AF12, }, /* LCD_PSRAM_D11 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 15), .af = GPIO_AF12, }, /* LCD_PSRAM_D12 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 8), .af = GPIO_AF12, }, /* LCD_PSRAM_D13 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 9), .af = GPIO_AF12, }, /* LCD_PSRAM_D14 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 10), .af = GPIO_AF12, }, /* LCD_PSRAM_D15 signal */
|
||||
#endif
|
||||
},
|
||||
.nbl0_pin = { .pin = GPIO_PIN(PORT_E, 0), .af = GPIO_AF12, }, /* PSRAM_NBL0 signal (LB) */
|
||||
.nbl1_pin = { .pin = GPIO_PIN(PORT_E, 1), .af = GPIO_AF12, }, /* PSRAM_NBL1 signal (UB) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief FMC Bank configuration
|
||||
*
|
||||
* The board has a PSRAM IS66WV51216EBLL-55BLI with MBit on-board.
|
||||
* It is organized in 512K x 16 bits and connected to bank 1, subbank 1
|
||||
* at address 0x60000000.
|
||||
*
|
||||
* @note A18 of the PSRAM is not used. Therefore, only 256K x 16 bits
|
||||
* (512 kByte) of the 1 MByte PSRAM can be used.
|
||||
*
|
||||
* The LCD display of the board is connected to bank 1, subbank2
|
||||
* at address 0x64000000.
|
||||
*/
|
||||
static const fmc_bank_conf_t fmc_bank_config[] = {
|
||||
/* bank 1, subbank 1 is used for PSRAM with asynchronuous
|
||||
* access in Mode 1, i.e. write timings are not used */
|
||||
{
|
||||
.bank = FMC_BANK_1,
|
||||
.mem_type = FMC_SRAM,
|
||||
.data_width = FMC_BUS_WIDTH_16BIT,
|
||||
.address = 0x60000000, /* Bank 1, subbank 1 is mapped to 0x60000000 */
|
||||
.size = KiB(512), /* Size in byte, 256K x 16 bit */
|
||||
.nor_sram = {
|
||||
.sub_bank = 1,
|
||||
.ext_mode = false, /* Mode 1 used, no separate w_timing */
|
||||
/* timings for IS66WV51216EBLL-55BLI
|
||||
@216 MHz AHB clock */
|
||||
.r_timing = { .addr_setup = 13, /* t_AA = max 60 ns (13 HCLKs a 4.63 ns) */
|
||||
.data_setup = 6, /* t_SD = min 25 ns (6 HCLKs a 4.63 ns) */
|
||||
.bus_turnaround = 3, }, /* 3 HCLKs a 4.63 ns */
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Number of configured FMC banks
|
||||
*/
|
||||
#define FMC_BANK_NUMOF ARRAY_SIZE(fmc_bank_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -15,6 +15,9 @@ config BOARD_STM32F746G_DISCO
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
select HAS_PERIPH_DMA
|
||||
select HAS_PERIPH_ETH
|
||||
select HAS_PERIPH_FMC
|
||||
select HAS_PERIPH_FMC_SDRAM
|
||||
select HAS_PERIPH_FMC_16BIT
|
||||
select HAS_PERIPH_I2C
|
||||
select HAS_PERIPH_LTDC
|
||||
select HAS_PERIPH_RTC
|
||||
|
@ -13,3 +13,7 @@ endif
|
||||
ifneq (,$(filter touch_dev,$(USEMODULE)))
|
||||
USEMODULE += ft5x06
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_fmc,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_fmc_16bit
|
||||
endif
|
||||
|
@ -13,3 +13,6 @@ PROGRAMMERS_SUPPORTED += openocd
|
||||
# The board can become un-flashable after some execution,
|
||||
# use connect_assert_srst to always be able to flash or reset the board.
|
||||
OPENOCD_RESET_USE_CONNECT_ASSERT_SRST ?= 1
|
||||
|
||||
FMC_RAM_ADDR=0xc0000000
|
||||
FMC_RAM_LEN=8192K
|
||||
|
@ -1,6 +1,9 @@
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
FEATURES_PROVIDED += periph_dma
|
||||
FEATURES_PROVIDED += periph_eth
|
||||
FEATURES_PROVIDED += periph_fmc
|
||||
FEATURES_PROVIDED += periph_fmc_16bit
|
||||
FEATURES_PROVIDED += periph_fmc_sdram
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_ltdc
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
|
@ -321,6 +321,115 @@ static const dwc2_usb_otg_fshs_config_t dwc2_usb_otg_fshs_config[] = {
|
||||
/** @} */
|
||||
#endif /* defined(MODULE_PERIPH_USBDEV_HS_ULPI) || DOXYGEN */
|
||||
|
||||
/**
|
||||
* @name FMC configuration
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief FMC controller configuration
|
||||
*/
|
||||
static const fmc_conf_t fmc_config = {
|
||||
.bus = AHB3,
|
||||
.rcc_mask = RCC_AHB3ENR_FMCEN,
|
||||
#if MODULE_PERIPH_FMC_SDRAM
|
||||
.ba0_pin = { .pin = GPIO_PIN(PORT_G, 4), .af = GPIO_AF12, }, /* FMC_BA0 signal */
|
||||
.ba1_pin = { .pin = GPIO_PIN(PORT_G, 5), .af = GPIO_AF12, }, /* FMC_BA1 signal */
|
||||
.sdclk_pin = { .pin = GPIO_PIN(PORT_G, 8), .af = GPIO_AF12, }, /* FMC_SDCLK signal */
|
||||
.sdnwe_pin = { .pin = GPIO_PIN(PORT_H, 5), .af = GPIO_AF12, }, /* FMC_SDNWE signal */
|
||||
.sdnras_pin = { .pin = GPIO_PIN(PORT_F, 11), .af = GPIO_AF12, }, /* FMC_SDNRAS signal */
|
||||
.sdncas_pin = { .pin = GPIO_PIN(PORT_G, 15), .af = GPIO_AF12, }, /* FMC_SDNCAS signal */
|
||||
.sdcke0_pin = { .pin = GPIO_PIN(PORT_C, 3), .af = GPIO_AF12, }, /* FMC_SDCKE0 signal */
|
||||
.sdne0_pin = { .pin = GPIO_PIN(PORT_H, 3), .af = GPIO_AF12, }, /* FMC_SDNE0 signal */
|
||||
.addr = {
|
||||
{ .pin = GPIO_PIN(PORT_F, 0), .af = GPIO_AF12, }, /* FMC_A0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 1), .af = GPIO_AF12, }, /* FMC_A1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 2), .af = GPIO_AF12, }, /* FMC_A2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 3), .af = GPIO_AF12, }, /* FMC_A3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 4), .af = GPIO_AF12, }, /* FMC_A4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 5), .af = GPIO_AF12, }, /* FMC_A5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 12), .af = GPIO_AF12, }, /* FMC_A6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 13), .af = GPIO_AF12, }, /* FMC_A7 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 14), .af = GPIO_AF12, }, /* FMC_A8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 15), .af = GPIO_AF12, }, /* FMC_A9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 0), .af = GPIO_AF12, }, /* FMC_A10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 1), .af = GPIO_AF12, }, /* FMC_A11 signal */
|
||||
},
|
||||
#endif
|
||||
.data = {
|
||||
{ .pin = GPIO_PIN(PORT_D, 14), .af = GPIO_AF12, }, /* FMC_D0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 15), .af = GPIO_AF12, }, /* FMC_D1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 0), .af = GPIO_AF12, }, /* FMC_D2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 1), .af = GPIO_AF12, }, /* FMC_D3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 7), .af = GPIO_AF12, }, /* FMC_D4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 8), .af = GPIO_AF12, }, /* FMC_D5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 9), .af = GPIO_AF12, }, /* FMC_D6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 10), .af = GPIO_AF12, }, /* FMC_D7 signal */
|
||||
#if MODULE_PERIPH_FMC_16BIT
|
||||
{ .pin = GPIO_PIN(PORT_E, 11), .af = GPIO_AF12, }, /* FMC_D8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 12), .af = GPIO_AF12, }, /* FMC_D9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 13), .af = GPIO_AF12, }, /* FMC_D10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 14), .af = GPIO_AF12, }, /* FMC_D11 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 15), .af = GPIO_AF12, }, /* FMC_D12 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 8), .af = GPIO_AF12, }, /* FMC_D13 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 9), .af = GPIO_AF12, }, /* FMC_D14 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 10), .af = GPIO_AF12, }, /* FMC_D15 signal */
|
||||
#endif
|
||||
},
|
||||
.nbl0_pin = { .pin = GPIO_PIN(PORT_E, 0), .af = GPIO_AF12, }, /* FMC_NBL0 signal (LB) */
|
||||
.nbl1_pin = { .pin = GPIO_PIN(PORT_E, 1), .af = GPIO_AF12, }, /* FMC_NBL1 signal (UB) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief FMC Bank configuration
|
||||
*
|
||||
* The board has a SDRAM IS42S32400F-6BL with 128 MBit on-board.
|
||||
* It is organized in 4 banks of 1M x 32 bits each and connected to bank 5
|
||||
* at address 0xc0000000.
|
||||
*
|
||||
* @note Since only D0 to D15 are connected and D16 to D31 are unused, 4 banks
|
||||
* with only 1M x 16 bits and thus half the capacity (8 MByte) can be
|
||||
* used.
|
||||
*/
|
||||
static const fmc_bank_conf_t fmc_bank_config[] = {
|
||||
/* bank 5 is used for SDRAM */
|
||||
{
|
||||
.bank = FMC_BANK_5,
|
||||
.mem_type = FMC_SDRAM,
|
||||
.data_width = FMC_BUS_WIDTH_16BIT,
|
||||
.address = 0xc0000000, /* Bank 6 is mapped to 0xd0000000 */
|
||||
.size = MiB(8), /* Size in MByte, 4M x 16 Bit */
|
||||
.sdram = {
|
||||
.clk_period = 2, /* SDCLK = 2 x HCLK */
|
||||
.row_bits = 12, /* A11..A0 used for row address */
|
||||
.col_bits = 8, /* A7..A0 used for column address */
|
||||
.cas_latency = 2, /* CAS latency is 2 clock cycles */
|
||||
.read_delay = 0, /* No read delay after CAS */
|
||||
.burst_read = true, /* Burst read mode enabled */
|
||||
.burst_write = false, /* Burst write mode disabled */
|
||||
.burst_len = FMC_BURST_LENGTH_1, /* Burst length is 1 */
|
||||
.burst_interleaved = false, /* Burst mode interleaved */
|
||||
.write_protect = false, /* No write protection */
|
||||
.four_banks = true, /* SDRAM has four internal banks */
|
||||
.timing = { /* SDRAM Timing parameters */
|
||||
.row_to_col_delay = 2, /* Row to column delay (2 clock cycles) */
|
||||
.row_precharge = 2, /* Row precharge delay (2 clock cycles) */
|
||||
.recovery_delay = 2, /* Recovery delay is (2 clock cycles) */
|
||||
.row_cylce = 7, /* Row cycle delay is (7 clock cycles) */
|
||||
.self_refresh = 4, /* Self refresh time is (4 clock cycles) */
|
||||
.exit_self_refresh = 7, /* Exit self-refresh delay (7 clock cycles) */
|
||||
.load_mode_register = 2, /* Load Mode Register to Activate delay */
|
||||
.refresh_period = 16, /* Refresh period in ms */
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Number of configured FMC banks
|
||||
*/
|
||||
#define FMC_BANK_NUMOF ARRAY_SIZE(fmc_bank_config)
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -15,6 +15,9 @@ config BOARD_STM32F7508_DK
|
||||
# Put defined MCU peripherals here (in alphabetical order)
|
||||
select HAS_PERIPH_DMA
|
||||
select HAS_PERIPH_ETH
|
||||
select HAS_PERIPH_FMC
|
||||
select HAS_PERIPH_FMC_SDRAM
|
||||
select HAS_PERIPH_FMC_16BIT
|
||||
select HAS_PERIPH_I2C
|
||||
select HAS_PERIPH_LTDC
|
||||
select HAS_PERIPH_RTC
|
||||
|
@ -17,6 +17,9 @@ config BOARD_STM32L496G_DISCO
|
||||
select HAS_PERIPH_ADC
|
||||
select HAS_PERIPH_DAC
|
||||
select HAS_PERIPH_DMA
|
||||
select HAS_PERIPH_FMC
|
||||
select HAS_PERIPH_FMC_NOR_SRAM
|
||||
select HAS_PERIPH_FMC_16BIT
|
||||
select HAS_PERIPH_I2C
|
||||
select HAS_PERIPH_LPUART
|
||||
select HAS_PERIPH_RTC
|
||||
|
@ -10,6 +10,10 @@ ifneq (,$(filter touch_dev,$(USEMODULE)))
|
||||
USEMODULE += ft5x06
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_fmc,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_fmc_16bit
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_uart,$(USEMODULE)))
|
||||
USEMODULE += periph_lpuart
|
||||
ifeq (,$(filter periph_spi_stmod_plus,$(USEMODULE)))
|
||||
|
@ -5,6 +5,9 @@ CPU_MODEL = stm32l496ag
|
||||
FEATURES_PROVIDED += periph_adc
|
||||
FEATURES_PROVIDED += periph_dac
|
||||
FEATURES_PROVIDED += periph_dma
|
||||
FEATURES_PROVIDED += periph_fmc
|
||||
FEATURES_PROVIDED += periph_fmc_16bit
|
||||
FEATURES_PROVIDED += periph_fmc_nor_sram
|
||||
FEATURES_PROVIDED += periph_i2c
|
||||
FEATURES_PROVIDED += periph_lpuart
|
||||
FEATURES_PROVIDED += periph_rtc
|
||||
|
@ -16,3 +16,6 @@ ifneq (,$(filter usbus_dfu tinyusb_dfu,$(USEMODULE)))
|
||||
else
|
||||
RIOTBOOT_LEN ?= 0x2000
|
||||
endif
|
||||
|
||||
FMC_RAM_ADDR=0x64000000
|
||||
FMC_RAM_LEN=1024K
|
||||
|
@ -36,7 +36,7 @@ The main features of this board are:
|
||||
| Capacitive Touch Screen | - | FT3267 used as driver IC (not supported yet) |
|
||||
| Stereo microphones | - | |
|
||||
| SAI audio codec | - | |
|
||||
| External PSRAM | - | Connected to FMC peripheral (not supported yet) |
|
||||
| External PSRAM | x | Connected to FMC peripheral |
|
||||
| External Quad-SPI Flash | - | QSPI peripheral is not yet supported |
|
||||
| SD Card Interface | - | |
|
||||
|
||||
|
@ -156,15 +156,111 @@ static const dac_conf_t dac_config[] = {
|
||||
{ GPIO_PIN(PORT_A, 5), .chan = 1 }, /* Arduino D13, conflicts with SPI_DEV(0) */
|
||||
#endif
|
||||
};
|
||||
/** @}*/
|
||||
|
||||
/**
|
||||
* @brief Number of DACs
|
||||
* @{
|
||||
*/
|
||||
#define DAC_NUMOF ARRAY_SIZE(dac_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name FMC configuration
|
||||
* @{
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief FMC controller configuration
|
||||
*/
|
||||
static const fmc_conf_t fmc_config = {
|
||||
.bus = AHB3,
|
||||
.rcc_mask = RCC_AHB3ENR_FMCEN,
|
||||
#if MODULE_PERIPH_FMC_NOR_SRAM
|
||||
.ne1_pin = { .pin = GPIO_PIN(PORT_D, 7), .af = GPIO_AF12, }, /* LCD_NE signal, subbank 1 */
|
||||
.ne2_pin = { .pin = GPIO_PIN(PORT_G, 9), .af = GPIO_AF12, }, /* PSRAM_NE signal, subbank 2 */
|
||||
.noe_pin = { .pin = GPIO_PIN(PORT_D, 4), .af = GPIO_AF12, }, /* PSRAM/LCD_OE signal (OE) */
|
||||
.nwe_pin = { .pin = GPIO_PIN(PORT_D, 5), .af = GPIO_AF12, }, /* PSRAM/LCD_WE signal (WE) */
|
||||
.addr = {
|
||||
{ .pin = GPIO_PIN(PORT_F, 0), .af = GPIO_AF12, }, /* PSRAM_A0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 1), .af = GPIO_AF12, }, /* PSRAM_A1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 2), .af = GPIO_AF12, }, /* PSRAM_A2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 3), .af = GPIO_AF12, }, /* PSRAM_A3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 4), .af = GPIO_AF12, }, /* PSRAM_A4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 5), .af = GPIO_AF12, }, /* PSRAM_A5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 12), .af = GPIO_AF12, }, /* PSRAM_A6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 13), .af = GPIO_AF12, }, /* PSRAM_A7 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 14), .af = GPIO_AF12, }, /* PSRAM_A8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_F, 15), .af = GPIO_AF12, }, /* PSRAM_A9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 0), .af = GPIO_AF12, }, /* PSRAM_A10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 1), .af = GPIO_AF12, }, /* PSRAM_A11 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 2), .af = GPIO_AF12, }, /* PSRAM_A12 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 3), .af = GPIO_AF12, }, /* PSRAM_A13 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 4), .af = GPIO_AF12, }, /* PSRAM_A14 signal */
|
||||
{ .pin = GPIO_PIN(PORT_G, 5), .af = GPIO_AF12, }, /* PSRAM_A15 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 11), .af = GPIO_AF12, }, /* PSRAM_A16 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 12), .af = GPIO_AF12, }, /* PSRAM_A17 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 13), .af = GPIO_AF12, }, /* PSRAM_A18 / LCD_RS signal */
|
||||
},
|
||||
#endif
|
||||
.data = {
|
||||
{ .pin = GPIO_PIN(PORT_D, 14), .af = GPIO_AF12, }, /* PSRAM_D0 / LCD_D0 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 15), .af = GPIO_AF12, }, /* PSRAM_D1 / LCD_D1 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 0), .af = GPIO_AF12, }, /* PSRAM_D2 / LCD_D2 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 1), .af = GPIO_AF12, }, /* PSRAM_D3 / LCD_D3 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 7), .af = GPIO_AF12, }, /* PSRAM_D4 / LCD_D4 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 8), .af = GPIO_AF12, }, /* PSRAM_D5 / LCD_D5 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 9), .af = GPIO_AF12, }, /* PSRAM_D6 / LCD_D6 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 10), .af = GPIO_AF12, }, /* PSRAM_D7 / LCD_D7 signal */
|
||||
#if MODULE_PERIPH_FMC_16BIT
|
||||
{ .pin = GPIO_PIN(PORT_E, 11), .af = GPIO_AF12, }, /* PSRAM_D8 / LCD_D8 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 12), .af = GPIO_AF12, }, /* PSRAM_D9 / LCD_D9 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 13), .af = GPIO_AF12, }, /* PSRAM_D10 / LCD_D10 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 14), .af = GPIO_AF12, }, /* PSRAM_D11 / LCD_D11 signal */
|
||||
{ .pin = GPIO_PIN(PORT_E, 15), .af = GPIO_AF12, }, /* PSRAM_D12 / LCD_D12 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 8), .af = GPIO_AF12, }, /* PSRAM_D13 / LCD_D13 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 9), .af = GPIO_AF12, }, /* PSRAM_D14 / LCD_D14 signal */
|
||||
{ .pin = GPIO_PIN(PORT_D, 10), .af = GPIO_AF12, }, /* PSRAM_D15 / LCD_D15 signal */
|
||||
#endif
|
||||
},
|
||||
.nbl0_pin = { .pin = GPIO_PIN(PORT_E, 0), .af = GPIO_AF12, }, /* PSRAM_NBL0 signal (LB) */
|
||||
.nbl1_pin = { .pin = GPIO_PIN(PORT_E, 1), .af = GPIO_AF12, }, /* PSRAM_NBL1 signal (UB) */
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief FMC Bank configuration
|
||||
*
|
||||
* The board has a PSRAM IS66WV51216EBLL-70BLI with 8 MBit on-board.
|
||||
* It is organized in 512K x 16 bits and connected to bank 1, subbank 2
|
||||
* at address 0x64000000.
|
||||
*
|
||||
* The LCD display of the board is connected to bank 1, subbank1
|
||||
* at address 0x60000000.
|
||||
*/
|
||||
static const fmc_bank_conf_t fmc_bank_config[] = {
|
||||
/* bank 1, subbank 2 is used for PSRAM with asynchronuous
|
||||
* access in Mode 1, i.e. write timings are not used */
|
||||
{
|
||||
.bank = FMC_BANK_1,
|
||||
.mem_type = FMC_SRAM,
|
||||
.data_width = FMC_BUS_WIDTH_16BIT,
|
||||
.address = 0x64000000, /* Bank 1, subbank 2 is mapped to 0x64000000 */
|
||||
.size = MiB(1), /* Size in Mbyte, 512K x 16 bit */
|
||||
.nor_sram = {
|
||||
.sub_bank = 2,
|
||||
.ext_mode = false, /* Mode 1 used, no separate w_timing */
|
||||
/* timings for IS66WV51216EBLL-70BLI */
|
||||
.r_timing = { .addr_setup = 6, /* t_AA = 70 ns (6 HCLKs a 12.5 ns) */
|
||||
.data_setup = 2, /* t_SD = 30 ns (3 HCLKs a 12.5 ns) */
|
||||
.bus_turnaround = 1, }, /* 1 HCLK a 12.5 ns */
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Number of configured FMC banks
|
||||
*/
|
||||
#define FMC_BANK_NUMOF ARRAY_SIZE(fmc_bank_config)
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name I2C configuration
|
||||
*
|
||||
|
@ -74,6 +74,8 @@ config RDP2
|
||||
bool "RDP2"
|
||||
endchoice
|
||||
|
||||
rsource "periph/Kconfig.fmc"
|
||||
|
||||
if TEST_KCONFIG
|
||||
|
||||
rsource "periph/Kconfig"
|
||||
|
@ -79,4 +79,8 @@ ifneq (,$(filter periph_vbat,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_adc
|
||||
endif
|
||||
|
||||
ifneq (,$(filter periph_fmc_%,$(USEMODULE)))
|
||||
FEATURES_REQUIRED += periph_fmc
|
||||
endif
|
||||
|
||||
include $(RIOTCPU)/cortexm_common/Makefile.dep
|
||||
|
@ -57,7 +57,6 @@ info-stm32:
|
||||
@$(COLOR_ECHO) "\tROM size:\t$(ROM_LEN) ($(FLASHSIZE) Bytes)"
|
||||
@$(COLOR_ECHO) "\tRAM size:\t$(RAM_LEN_K)KiB"
|
||||
|
||||
|
||||
ifneq (,$(CCMRAM_LEN))
|
||||
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_ccmram_length=$(CCMRAM_LEN)
|
||||
endif
|
||||
@ -65,6 +64,17 @@ ifneq (,$(SRAM4_LEN))
|
||||
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_sram4_length=$(SRAM4_LEN)
|
||||
endif
|
||||
|
||||
# if the board uses a FMC RAM, all 4 heaps have to be used even if
|
||||
# some of them are not available
|
||||
ifneq (,$(filter periph_fmc_sdram periph_fmc_nor_sram,$(USEMODULE)))
|
||||
ifneq (,$(FMC_RAM_LEN))
|
||||
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_fmc_ram_addr=$(FMC_RAM_ADDR)
|
||||
LINKFLAGS += $(LINKFLAGPREFIX)--defsym=_fmc_ram_len=$(FMC_RAM_LEN)
|
||||
CFLAGS += -DCPU_HAS_FMC_RAM=1
|
||||
CFLAGS += -DNUM_HEAPS=4
|
||||
endif
|
||||
endif
|
||||
|
||||
VECTORS_O ?= $(BINDIR)/stm32_vectors/$(CPU_LINE).o
|
||||
VECTORS_FILE = $(RIOTCPU)/stm32/vectors/$(CPU_LINE).c
|
||||
BUILDDEPS += $(VECTORS_FILE)
|
||||
|
370
cpu/stm32/include/periph/cpu_fmc.h
Normal file
370
cpu/stm32/include/periph/cpu_fmc.h
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* 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_periph_fmc STM32 FMC/FSMC peripheral driver
|
||||
* @ingroup cpu_stm32
|
||||
*
|
||||
* @{
|
||||
*
|
||||
* The `periph_fmc` module implements a driver for STM32 FMC/FSMC peripherals.
|
||||
* It supports
|
||||
* - NOR Flashes,
|
||||
* - PSRAMs/SRAMs,
|
||||
* - SDRAMs, and
|
||||
* - Display Controllers with MCU 8-/16-bit parallel interface.
|
||||
*
|
||||
* NAND Flashes are not yet supported.
|
||||
*
|
||||
* To use the FMC/FSMC, the `periph_fmc` module has to be enabled.
|
||||
* To keep required data structures and resulting code as small as possible,
|
||||
* a couple of pseudomodules are defined that have to be used in addition to
|
||||
* the `periph_fmc` module to enable supported features. These are:
|
||||
*
|
||||
* | Module | Feature |
|
||||
* |:-----------------------|:----------------------------------------|
|
||||
* | `periph_fmc_nor_sram` | enable NOR Flash and PSRAM/SRAM support |
|
||||
* | `periph_fmc_sdram` | enable SDRAM support |
|
||||
* | `periph_fmc_16bit` | enable 16-bit support |
|
||||
* | `periph_fmc_32bit` | enable 32-bit support |
|
||||
* \n
|
||||
*
|
||||
* The board has then to define
|
||||
* - the corresponding features according to the connected external device,
|
||||
* - the peripheral configuration of the FMC/FSMC of type @ref fmc_conf_t,
|
||||
* - the configuration of the FMC banks which describe the connected external
|
||||
* devices.
|
||||
*
|
||||
* As examples for such configurations, see @ref boards_stm32l496g-disco
|
||||
* (FMC with Display and SRAM) or @ref boards_stm32f429i-disc1 (FMC with SDRAM).
|
||||
*
|
||||
* To use the RAM connected to the FMC as heap, the board has also to define
|
||||
* @ref FMC_RAM_ADDR and @ref FMC_RAM_LEN.
|
||||
*
|
||||
* @file
|
||||
* @brief Specific FMC definitions for the STM32
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
*/
|
||||
|
||||
#ifndef PERIPH_CPU_FMC_H
|
||||
#define PERIPH_CPU_FMC_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cpu.h"
|
||||
#include "periph/cpu_gpio.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of data pins used
|
||||
*
|
||||
* The number of configured data pins depends on the memory with the maximum
|
||||
* data bus width. The maximum data bus width used has to be specified by the
|
||||
* pseudomodules `periph_fmc_16bit` and `periph_fmc_32bit`. 8 bit data bus
|
||||
* width is the default.
|
||||
*/
|
||||
#if MODULE_PERIPH_FMC_32BIT || DOXYGEN
|
||||
#define FMC_DATA_PIN_NUMOF (32)
|
||||
#elif MODULE_PERIPH_FMC_16BIT
|
||||
#define FMC_DATA_PIN_NUMOF (16)
|
||||
#else
|
||||
#define FMC_DATA_PIN_NUMOF (8)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief Number of address pins used
|
||||
*
|
||||
* The number of configured address pins depends on the memory types used.
|
||||
* NORs, PSRAMs and SRAMs (module `periph_fmc_nor_sram`) use up to 26 address
|
||||
* signals A0...A25 if address/data multiplexing is not used. SDRAMs (module
|
||||
* `periph_fmc_sdram`) use only up to 13 address signals A0...A12.
|
||||
* NANDs (module `periph_fmc_sdram`) don't need separate address signals.
|
||||
* The type of used memories is specified by the corresponding pseudomodules.
|
||||
*/
|
||||
#if MODULE_PERIPH_FMC_NOR_SRAM || DOXYGEN
|
||||
#define FMC_ADDR_PIN_NUMOF (26)
|
||||
#elif MODULE_PERIPH_FMC_SDRAM
|
||||
#define FMC_ADDR_PIN_NUMOF (13)
|
||||
#else
|
||||
#define FMC_ADDR_PIN_NUMOF (0)
|
||||
#endif
|
||||
|
||||
#if DOXYGEN
|
||||
/**
|
||||
* @brief Start address of the heap for the FMC RAM
|
||||
*
|
||||
* This variable has to be defined in `Makefile.include` of the board
|
||||
* definition to use the a RAM connected to the FMC as heap. It has to
|
||||
* correspond to the @ref fmc_bank_conf_t::address in FMC bank configuration.
|
||||
*
|
||||
* @note `FMC_RAM_ADDR` is not a macro and cannot be used in C code.
|
||||
* It is just defined for documentation purpose.
|
||||
*/
|
||||
#define FMC_RAM_ADDR 0x60000000
|
||||
|
||||
/**
|
||||
* @brief Length of the heap for the FMC RAM
|
||||
*
|
||||
* This variable has to be defined in `Makefile.include` of the board
|
||||
* definition to use the a RAM connected to the FMC as heap. It has to
|
||||
* correspond to the @ref fmc_bank_conf_t::size in FMC bank configuration.
|
||||
* Since it is used in linker script, it has to be defined in kByte with
|
||||
* suffix `K`, e.g. `1024K`.
|
||||
*
|
||||
* @note `FMC_RAM_SIZE` is not a macro and cannot be used in C code.
|
||||
* It is just defined for documentation purpose.
|
||||
*/
|
||||
#define FMC_RAM_LEN 1024K
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @name Type declarations for NOR Flash, PSRAM and SRAM
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief Memory access modes for NOR/PSRAM/SRAM in extended mode
|
||||
*/
|
||||
typedef enum {
|
||||
FMC_MODE_A = 0, /**< Access mode A */
|
||||
FMC_MODE_B = 1, /**< Access mode B */
|
||||
FMC_MODE_C = 2, /**< Access mode C */
|
||||
FMC_MODE_D = 3, /**< Access mode D */
|
||||
} fmc_access_mode_t;
|
||||
|
||||
/**
|
||||
* @brief Timing configuration for NOR/PSRAM/SRAM
|
||||
*
|
||||
* Used timing configuration parameters depend on used access mode. Please refer
|
||||
* the reference manual of the respective MCU for details.
|
||||
*/
|
||||
typedef struct {
|
||||
fmc_access_mode_t mode; /**< Access Mode used (only used if
|
||||
@ref fmc_nor_sram_bank_conf_t::ext_mode is true) */
|
||||
uint8_t clk_div; /**< Clock divide ratio, FMC_CLK = HCLK / (DIV + 1) */
|
||||
uint8_t addr_setup; /**< Address setup time [0..15], default 15 */
|
||||
uint8_t addr_hold; /**< Address hold time [0..15], default 15 */
|
||||
uint8_t data_setup; /**< Data setup time [0..15], default 15 */
|
||||
uint8_t data_latency; /**< Data latency for synchronous access [0..15],
|
||||
default 15 (only used in read timing) */
|
||||
uint8_t bus_turnaround; /**< Bus turnaround phase duration [0..15], default 15 */
|
||||
} fmc_nor_sram_timing_t;
|
||||
|
||||
/**
|
||||
* @brief Bank configuration structure for NOR/PSRAM/SRAM
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t sub_bank; /**< Bank1 has 4 subbanks 1..4 */
|
||||
bool mux_enable; /**< Multiplexed address/data signals used
|
||||
(only valid for PSRAMs and NORs */
|
||||
bool wait_enable; /**< Wait signal used for synchronous
|
||||
access */
|
||||
bool ext_mode; /**< Extended mode used (separate read and
|
||||
write timings) */
|
||||
fmc_nor_sram_timing_t r_timing; /**< Read timings (also used for write if
|
||||
@ref fmc_nor_sram_bank_conf_t::ext_mode is false) */
|
||||
fmc_nor_sram_timing_t w_timing; /**< Write timings (only used if
|
||||
@ref fmc_nor_sram_bank_conf_t::ext_mode is true) */
|
||||
} fmc_nor_sram_bank_conf_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Type declarations for SDRAMs
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief SDRAM Burst Length as an exponent of a power of two
|
||||
*/
|
||||
typedef enum {
|
||||
FMC_BURST_LENGTH_1 = 0, /* Burst length is 1 */
|
||||
FMC_BURST_LENGTH_2 = 1, /* Burst length is 2 */
|
||||
FMC_BURST_LENGTH_4 = 2, /* Burst length is 4 */
|
||||
FMC_BURST_LENGTH_8 = 3, /* Burst length is 8 */
|
||||
FMC_BURST_LENGTH_16 = 4, /* Burst length is 16 */
|
||||
FMC_BURST_LENGTH_32 = 5, /* Burst length is 32 */
|
||||
FMC_BURST_LENGTH_64 = 6, /* Burst length is 64 */
|
||||
FMC_BURST_LENGTH_FULL = 7, /* Burst length is full page */
|
||||
} fmc_bust_length_t;
|
||||
|
||||
/**
|
||||
* @brief Timing configuration for SDRAM
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t row_to_col_delay; /**< Row to column delay in SDCLK clock
|
||||
cycles [1..16], delay between Activate
|
||||
and Read/Write command */
|
||||
uint8_t row_precharge; /**< Row precharge delay in SDCLK clock
|
||||
cycles [1..15], delay between Precharge
|
||||
and another command */
|
||||
uint8_t recovery_delay; /**< Recovery delay in SDCLK clock
|
||||
cycles [1..15], delay between Write and
|
||||
Precharge command */
|
||||
uint8_t row_cylce; /**< Row cycle delay in SDCLK clock
|
||||
cycles [1..15], delay between Refresh and
|
||||
Activate command */
|
||||
uint8_t self_refresh; /**< Self refresh time in SDCLK clock
|
||||
cycles [1..15] */
|
||||
uint8_t exit_self_refresh; /**< Exit self-refresh delay in SDCLK clock
|
||||
cycles [1..15], delay between Self-Refresh
|
||||
and Activate command */
|
||||
uint8_t load_mode_register; /**< Load Mode Register to Activate delay in
|
||||
SDCLK clock cycles [1..15], delay between
|
||||
Load Mode Register and Activate command */
|
||||
uint8_t refresh_period; /**< Refresh period in milliseconds */
|
||||
} fmc_sdram_timing_t;
|
||||
|
||||
/**
|
||||
* @brief Bank configuration structure for SDRAM
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t clk_period; /**< CLK period [0,2,3] (0 - disabled, n * HCLK cycles) */
|
||||
uint8_t row_bits; /**< Number row address bits [11..13] */
|
||||
uint8_t col_bits; /**< Number column address bits [8..11]*/
|
||||
uint8_t cas_latency; /**< CAS latency in SDCLK clock cycles [1..3] */
|
||||
uint8_t read_delay; /**< Delay for reading data after CAS latency in HCLKs [0..2] */
|
||||
bool four_banks; /**< SDRAM has four internal banks */
|
||||
bool write_protect; /**< Write protection enabled */
|
||||
bool burst_read; /**< Burst read mode enabled */
|
||||
bool burst_write; /**< Burst write mode enabled */
|
||||
bool burst_interleaved; /**< Burst mode interleaved, otherwise sequential */
|
||||
fmc_bust_length_t burst_len; /**< Burst length as an exponent of a power of two */
|
||||
fmc_sdram_timing_t timing; /**< SDRAM Timing configuration */
|
||||
} fmc_sdram_bank_conf_t;
|
||||
/** @} */
|
||||
|
||||
/**
|
||||
* @name Type declarations that are common for all memories
|
||||
* @{
|
||||
*/
|
||||
/**
|
||||
* @brief FMC GPIO configuration type
|
||||
*/
|
||||
typedef struct {
|
||||
gpio_t pin; /**< GPIO pin */
|
||||
gpio_af_t af; /**< Alternate function */
|
||||
} fmc_gpio_t;
|
||||
|
||||
/**
|
||||
* @brief FMC peripheral configuration
|
||||
*
|
||||
* The GPIOs are defined depending on used memory type according to the
|
||||
* FMC pin definition in Table 12 of section 4 in the
|
||||
* [Datasheet for STM32F765xx, STM32F767xx, STM32F768Ax, STM32F769xx]
|
||||
* (https://www.st.com/resource/en/datasheet/stm32f767zi.pdf).
|
||||
* Which memory types are used is defined by the pseudomodules
|
||||
* `periph_fmc_nor_sram`, `periph_fmc_nand` and `periph_fmc_sdram`
|
||||
*
|
||||
* @note For easier handling the configuration structure does not take
|
||||
* multiplexed address/data bits into account.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t bus; /**< AHB/APB bus */
|
||||
uint32_t rcc_mask; /**< Bit in clock enable register */
|
||||
fmc_gpio_t data[FMC_DATA_PIN_NUMOF]; /**< Data pins D0 ... */
|
||||
#if FMC_ADDR_PIN_NUMOF || DOXYGEN
|
||||
fmc_gpio_t addr[FMC_ADDR_PIN_NUMOF]; /**< Address pins A0 ... if any */
|
||||
#endif
|
||||
/* signals used by all kind of memories */
|
||||
fmc_gpio_t nbl0_pin; /**< NBL0 pin */
|
||||
fmc_gpio_t nbl1_pin; /**< NBL1 pin */
|
||||
fmc_gpio_t nbl2_pin; /**< NBL2 pin */
|
||||
fmc_gpio_t nbl3_pin; /**< NBL3 pin */
|
||||
fmc_gpio_t nwait_pin; /**< NWAIT pin */
|
||||
#if MODULE_PERIPH_FMC_NOR_SRAM
|
||||
/* NORs, PSRAMs, and SRAMs use CLK, NOE, NWE, NE, and NADV signals **/
|
||||
fmc_gpio_t clk_pin; /**< CLK pin */
|
||||
fmc_gpio_t noe_pin; /**< NOE pin (output enable / read enable) */
|
||||
fmc_gpio_t nwe_pin; /**< NWE pin (write enable) */
|
||||
fmc_gpio_t ne1_pin; /**< NE1 pin (subbank 1 enable) */
|
||||
fmc_gpio_t ne2_pin; /**< NE2 pin (subbank 2 enable) */
|
||||
fmc_gpio_t ne3_pin; /**< NE3 pin (subbank 3 enable) */
|
||||
fmc_gpio_t ne4_pin; /**< NE4 pin (subbank 4 enable) */
|
||||
fmc_gpio_t nadv_pin; /**< NADV pin (address valid) */
|
||||
#endif /* MODULE_PERIPH_FMC_NORSRAM */
|
||||
#if MODULE_PERIPH_FMC_SDRAM
|
||||
/* SDRAMs use BAx, CLK, RAS, CAS, WE, ... signals **/
|
||||
fmc_gpio_t ba0_pin; /**< BA0 pin */
|
||||
fmc_gpio_t ba1_pin; /**< BA1 pin */
|
||||
fmc_gpio_t sdclk_pin; /**< SDCLK pin */
|
||||
fmc_gpio_t sdnwe_pin; /**< SDWE pin */
|
||||
fmc_gpio_t sdnras_pin; /**< SDNRAS pin */
|
||||
fmc_gpio_t sdncas_pin; /**< SDNCAS pin */
|
||||
fmc_gpio_t sdcke0_pin; /**< SDCKE0 pin (SDRAM bank 5 clock enable) */
|
||||
fmc_gpio_t sdcke1_pin; /**< SDCKE1 pin (SDRAM bank 6 clock enable) */
|
||||
fmc_gpio_t sdne0_pin; /**< SDNE0 pin (SDRAM bank 5 enable) */
|
||||
fmc_gpio_t sdne1_pin; /**< SDNE1 pin (SDRAM bank 6 enable) */
|
||||
#endif /* MODULE_PERIPH_FMC_SDRAM */
|
||||
} fmc_conf_t;
|
||||
|
||||
/**
|
||||
* @brief Memory banks
|
||||
*/
|
||||
typedef enum {
|
||||
FMC_BANK_1 = 1, /**< Bank 1 is always available and used for NOR, PSRAM, SRAM */
|
||||
#if defined(FMC_Bank2_3_R_BASE)
|
||||
FMC_BANK_2 = 2, /**< Bank2 is used for NAND if available */
|
||||
#endif
|
||||
#if defined(FMC_Bank2_3_R_BASE) || defined(FMC_Bank3_R_BASE)
|
||||
FMC_BANK_3 = 3, /**< Bank3 is used for NAND if available */
|
||||
#endif
|
||||
#if defined(FMC_Bank4_R_BASE)
|
||||
FMC_BANK_4 = 4, /**< Bank4 is used for PC Card if available */
|
||||
#endif
|
||||
#if defined(FMC_Bank5_6_R_BASE)
|
||||
FMC_BANK_5 = 5, /**< Bank5 is used for SDRAM if available */
|
||||
FMC_BANK_6 = 6, /**< Bank6 is used for SDRAM if available */
|
||||
#endif
|
||||
} fmc_bank_t;
|
||||
|
||||
/**
|
||||
* @brief Memory types supported by the FMC controller
|
||||
*/
|
||||
typedef enum {
|
||||
FMC_SRAM = 0, /**< SRAM */
|
||||
FMC_PSRAM = 1, /**< PSRAM */
|
||||
FMC_NOR = 2, /**< NOR Flash */
|
||||
FMC_NAND = 3, /**< NAND Flash */
|
||||
FMC_SDRAM = 4, /**< SDRAM Controller used */
|
||||
} fmc_mem_type_t;
|
||||
|
||||
/**
|
||||
* @brief Memory data bus widths
|
||||
*/
|
||||
typedef enum {
|
||||
FMC_BUS_WIDTH_8BIT = 0, /**< 8 bit data bus width */
|
||||
FMC_BUS_WIDTH_16BIT = 1, /**< 16 bit data bus width */
|
||||
FMC_BUS_WIDTH_32BIT = 2, /**< 32 bit data bus width */
|
||||
} fmc_bus_width_t;
|
||||
|
||||
/**
|
||||
* @brief Bank configuration structure
|
||||
*/
|
||||
typedef struct {
|
||||
fmc_bank_t bank; /**< Bank1 .. Bank4/Bank6 (maximum) */
|
||||
fmc_mem_type_t mem_type; /**< Type of memory */
|
||||
fmc_bus_width_t data_width; /**< Data bus width */
|
||||
uint32_t address; /**< Address of the memory bank */
|
||||
uint32_t size; /**< Size in bytes of the memory bank */
|
||||
union {
|
||||
fmc_nor_sram_bank_conf_t nor_sram; /* Configuration in case of NOR/PSRAM/SRAM */
|
||||
fmc_sdram_bank_conf_t sdram; /* Configuration in case of SDRAM */
|
||||
};
|
||||
} fmc_bank_conf_t;
|
||||
|
||||
typedef uint8_t fmc_bank_id_t; /**< FMC bank identifier */
|
||||
/** @} */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PERIPH_CPU_FMC_H */
|
||||
/** @} */
|
@ -62,6 +62,7 @@
|
||||
#include "periph/cpu_common.h"
|
||||
#include "periph/cpu_dma.h"
|
||||
#include "periph/cpu_eth.h"
|
||||
#include "periph/cpu_fmc.h"
|
||||
#include "periph/cpu_gpio.h"
|
||||
#include "periph/cpu_gpio_ll.h"
|
||||
#include "periph/cpu_i2c.h"
|
||||
|
@ -19,12 +19,18 @@
|
||||
*/
|
||||
|
||||
ccmram_length = DEFINED( _ccmram_len ) ? _ccmram_len : 0x0 ;
|
||||
|
||||
sram4_addr = DEFINED( _sram4_length ) ? 0x28000000 : 0x0 ;
|
||||
sram4_length = DEFINED( _sram4_length ) ? _sram4_length : 0x0 ;
|
||||
|
||||
fmc_ram_addr = DEFINED( _fmc_ram_addr ) ? _fmc_ram_addr : 0x0 ;
|
||||
fmc_ram_len = DEFINED( _fmc_ram_len ) ? _fmc_ram_len : 0x0 ;
|
||||
|
||||
MEMORY
|
||||
{
|
||||
ccmram : ORIGIN = 0x10000000, LENGTH = ccmram_length
|
||||
sram4 : ORIGIN = 0x28000000, LENGTH = sram4_length
|
||||
sram4 : ORIGIN = sram4_addr, LENGTH = sram4_length
|
||||
fmcram : ORIGIN = fmc_ram_addr, LENGTH = fmc_ram_len
|
||||
}
|
||||
|
||||
SECTIONS
|
||||
@ -34,6 +40,12 @@ SECTIONS
|
||||
_sheap2 = ORIGIN(sram4);
|
||||
_eheap2 = ORIGIN(sram4) + LENGTH(sram4);
|
||||
} > sram4
|
||||
|
||||
.heap4 ALIGN(4) (NOLOAD) :
|
||||
{
|
||||
_sheap3 = ORIGIN(fmcram);
|
||||
_eheap3 = ORIGIN(fmcram) + LENGTH(fmcram);
|
||||
} > fmcram
|
||||
}
|
||||
|
||||
INCLUDE cortexm.ld
|
||||
|
97
cpu/stm32/periph/Kconfig.fmc
Normal file
97
cpu/stm32/periph/Kconfig.fmc
Normal file
@ -0,0 +1,97 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
menuconfig MODULE_PERIPH_FMC
|
||||
bool "FMC/FSMC peripheral driver"
|
||||
depends on TEST_KCONFIG
|
||||
depends on HAS_PERIPH_FMC
|
||||
help
|
||||
STM32 FMC/FSMC controller
|
||||
|
||||
if MODULE_PERIPH_FMC
|
||||
|
||||
config MODULE_PERIPH_FMC_NOR_SRAM
|
||||
bool "NOR/PSRAM/SRAM support"
|
||||
depends on HAS_PERIPH_FMC_NOR_SRAM
|
||||
help
|
||||
Enables NOR Flash, PSRAM and SRAM support of the STM32 FMC/FSMC
|
||||
driver.
|
||||
|
||||
config MODULE_PERIPH_FMC_SDRAM
|
||||
bool "SDRAM support"
|
||||
depends on HAS_PERIPH_FMC_SDRAM
|
||||
help
|
||||
Enables SDRAM support of the STM32 FMC/FSMC driver.
|
||||
|
||||
config MODULE_PERIPH_FMC_16BIT
|
||||
bool
|
||||
default y if HAS_PERIPH_FMC_16BIT
|
||||
help
|
||||
Enables 16-bit data bus support of the STM32 FMC/FSMC driver.
|
||||
|
||||
config MODULE_PERIPH_FMC_32BIT
|
||||
bool
|
||||
default y if HAS_PERIPH_FMC_32BIT
|
||||
help
|
||||
Enables 32-bit data bus support of the STM32 FMC/FSMC driver.
|
||||
|
||||
config MODULE_PERIPH_INIT_FMC
|
||||
bool "Auto initialize STM32 FMC/FMSC peripheral"
|
||||
default y if MODULE_PERIPH_INIT
|
||||
|
||||
config MODULE_PERIPH_INIT_FMC_NOR_SRAM
|
||||
bool "Auto initialize NOR/PSRAM/SRAM support"
|
||||
default y if MODULE_PERIPH_INIT
|
||||
depends on MODULE_PERIPH_FMC_NOR_SRAM
|
||||
|
||||
config MODULE_PERIPH_INIT_FMC_SDRAM
|
||||
bool "Auto initialize SDRAM support"
|
||||
default y if MODULE_PERIPH_INIT
|
||||
depends on MODULE_PERIPH_FMC_SDRAM
|
||||
|
||||
config MODULE_PERIPH_INIT_FMC_16BIT
|
||||
bool "Auto initialize 16-bit data bus"
|
||||
default y if MODULE_PERIPH_INIT
|
||||
depends on MODULE_PERIPH_FMC_16BIT
|
||||
|
||||
config MODULE_PERIPH_INIT_FMC_32BIT
|
||||
bool "Auto initialize 32-bit data bus"
|
||||
default y if MODULE_PERIPH_INIT
|
||||
depends on MODULE_PERIPH_FMC_32BIT
|
||||
|
||||
endif
|
||||
|
||||
config HAS_PERIPH_FMC
|
||||
bool
|
||||
help
|
||||
Indicates that a STM32 FMC/FSMC peripheral is present.
|
||||
|
||||
config HAS_PERIPH_FMC_NOR_SRAM
|
||||
bool
|
||||
select HAS_PERIPH_FMC
|
||||
help
|
||||
Indicates that a NOR Flash, PSRAM or SRAM connected to the
|
||||
STM32 FMC/FSMC peripheral is present.
|
||||
|
||||
config HAS_PERIPH_FMC_SDRAM
|
||||
bool
|
||||
select HAS_PERIPH_FMC
|
||||
help
|
||||
Indicates that a SDRAM connected to the STM32 FMC/FSMC peripheral
|
||||
is present.
|
||||
|
||||
config HAS_PERIPH_FMC_16BIT
|
||||
bool
|
||||
select HAS_PERIPH_FMC
|
||||
help
|
||||
Indicates that the STM32 FMC/FSMC peripheral uses a 16-bit data bus.
|
||||
|
||||
config HAS_PERIPH_FMC_32BIT
|
||||
bool
|
||||
select HAS_PERIPH_FMC
|
||||
help
|
||||
Indicates that the STM32 FMC/FSMC peripheral uses a 32-bit data bus.
|
575
cpu/stm32/periph/fmc.c
Normal file
575
cpu/stm32/periph/fmc.c
Normal file
@ -0,0 +1,575 @@
|
||||
/*
|
||||
* 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 "log.h"
|
||||
#include "periph/gpio.h"
|
||||
#include "pm_layered.h"
|
||||
|
||||
#define ENABLE_DEBUG 0
|
||||
#include "debug.h"
|
||||
|
||||
#ifndef FMC_BASE
|
||||
#define FMC_BASE (0x60000000UL)
|
||||
#endif
|
||||
|
||||
#if !defined(FMC_Bank1_R_BASE) && defined(FSMC_Bank1_R_BASE)
|
||||
/* FSMC Symbols are defined, mapping is required */
|
||||
|
||||
#define FMC_Bank1_R_BASE FSMC_Bank1_R_BASE /* (FMC_R_BASE + 0x0000UL) */
|
||||
#define FMC_Bank1_TypeDef FSMC_Bank1_TypeDef
|
||||
|
||||
#define FMC_Bank1E_R_BASE FSMC_Bank1E_R_BASE /* (FMC_R_BASE + 0x0104UL) */
|
||||
#define FMC_Bank1E_TypeDef FSMC_Bank1E_TypeDef
|
||||
|
||||
#if defined(FSMC_Bank2_3_R_BASE)
|
||||
#define FMC_Bank2_3_R_BASE FSMC_Bank2_3_R_BASE /* (FMC_R_BASE + 0x0060UL) */
|
||||
#define FMC_Bank2_3_TypeDef FSMC_Bank2_3_TypeDef
|
||||
#endif
|
||||
|
||||
#if defined(FSMC_Bank4_R_BASE)
|
||||
#define FMC_Bank4_R_BASE FSMC_Bank4_R_BASE /* (FMC_R_BASE + 0x00A0UL) */
|
||||
#define FMC_Bank4_TypeDef FSMC_Bank4_TypeDef
|
||||
#endif
|
||||
|
||||
#endif /* !defined(FMC_Bank1_R_BASE) && defined(FSMC_Bank1_R_BASE) */
|
||||
|
||||
#if !defined(FMC_Bank1) && defined(FMC_Bank1_R_BASE)
|
||||
#define FMC_Bank1 ((FMC_Bank1_TypeDef *) FMC_Bank1_R_BASE)
|
||||
#endif
|
||||
#if !defined(FMC_Bank1E) && defined(FMC_Bank1E_R_BASE)
|
||||
#define FMC_Bank1E ((FMC_Bank1E_TypeDef *) FMC_Bank1E_R_BASE)
|
||||
#endif
|
||||
#if !defined(FMC_Bank2_3) && defined(FMC_Bank2_3_R_BASE)
|
||||
#define FMC_Bank2_3 ((FMC_Bank3_TypeDef *) FMC_Bank2_3_R_BASE)
|
||||
#endif
|
||||
#if !defined(FMC_Bank3) && defined(FMC_Bank3_R_BASE)
|
||||
#define FMC_Bank3 ((FMC_Bank3_TypeDef *) FMC_Bank3_R_BASE)
|
||||
#endif
|
||||
#if !defined(FMC_Bank4) && defined(FMC_Bank4_R_BASE)
|
||||
#define FMC_Bank4 ((FMC_Bank4_TypeDef *) FMC_Bank3_R_BASE)
|
||||
#endif
|
||||
#if !defined(FMC_Bank5_6) && defined(FMC_Bank5_6_R_BASE)
|
||||
#define FMC_Bank5_6 ((FMC_Bank5_6_TypeDef *) FMC_Bank5_6_R_BASE)
|
||||
#endif
|
||||
|
||||
#if defined(FMC_BCR1_MBKEN)
|
||||
/* if CMSIS header define FMC_BCR1_* macros instead of FMC_BCRx_*,
|
||||
* mapping is needed */
|
||||
#define FMC_BCRx_MBKEN FMC_BCR1_MBKEN
|
||||
#define FMC_BCRx_MBKEN_Pos FMC_BCR1_MBKEN_Pos
|
||||
#define FMC_BCRx_MUXEN FMC_BCR1_MUXEN
|
||||
#define FMC_BCRx_MUXEN_Pos FMC_BCR1_MUXEN_Pos
|
||||
#define FMC_BCRx_MTYP_Msk FMC_BCR1_MTYP_Msk
|
||||
#define FMC_BCRx_MTYP_Pos FMC_BCR1_MTYP_Pos
|
||||
#define FMC_BCRx_MWID_Msk FMC_BCR1_MWID_Msk
|
||||
#define FMC_BCRx_MWID_Pos FMC_BCR1_MWID_Pos
|
||||
#define FMC_BCRx_FACCEN FMC_BCR1_FACCEN
|
||||
#define FMC_BCRx_FACCEN_Pos FMC_BCR1_FACCEN_Pos
|
||||
#define FMC_BCRx_WAITEN FMC_BCR1_WAITEN
|
||||
#define FMC_BCRx_WAITEN_Pos FMC_BCR1_WAITEN_Pos
|
||||
#define FMC_BCRx_EXTMOD FMC_BCR1_EXTMOD
|
||||
#define FMC_BCRx_EXTMOD_Pos FMC_BCR1_EXTMOD_Pos
|
||||
|
||||
#define FMC_BTRx_ADDSET_Pos FMC_BTR1_ADDSET_Pos
|
||||
#define FMC_BTRx_ADDHLD_Pos FMC_BTR1_ADDHLD_Pos
|
||||
#define FMC_BTRx_DATAST_Pos FMC_BTR1_DATAST_Pos
|
||||
#define FMC_BTRx_DATLAT_Pos FMC_BTR1_DATLAT_Pos
|
||||
#define FMC_BTRx_BUSTURN_Pos FMC_BTR1_BUSTURN_Pos
|
||||
#define FMC_BTRx_CLKDIV_Pos FMC_BTR1_CLKDIV_Pos
|
||||
#endif /* defined(FMC_BCR1_MBKEN) */
|
||||
|
||||
static void _fmc_init_gpio_common(void)
|
||||
{
|
||||
for (unsigned i = 0; i < FMC_DATA_PIN_NUMOF; i++) {
|
||||
assert(gpio_is_valid(fmc_config.data[i].pin));
|
||||
gpio_init(fmc_config.data[i].pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.data[i].pin, fmc_config.data[i].af);
|
||||
}
|
||||
|
||||
#if FMC_ADDR_PIN_NUMOF
|
||||
for (unsigned i = 0; i < FMC_ADDR_PIN_NUMOF; i++) {
|
||||
if (gpio_is_valid(fmc_config.addr[i].pin)) {
|
||||
gpio_init(fmc_config.addr[i].pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.addr[i].pin, fmc_config.addr[i].af);
|
||||
}
|
||||
}
|
||||
#endif /* FMC_ADDR_PIN_NUMOF */
|
||||
|
||||
if (gpio_is_valid(fmc_config.nbl0_pin.pin)) {
|
||||
gpio_init(fmc_config.nbl0_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nbl0_pin.pin, fmc_config.nbl0_pin.af);
|
||||
}
|
||||
if (gpio_is_valid(fmc_config.nbl1_pin.pin)) {
|
||||
gpio_init(fmc_config.nbl1_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nbl1_pin.pin, fmc_config.nbl1_pin.af);
|
||||
}
|
||||
if (gpio_is_valid(fmc_config.nbl2_pin.pin)) {
|
||||
gpio_init(fmc_config.nbl2_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nbl2_pin.pin, fmc_config.nbl2_pin.af);
|
||||
}
|
||||
if (gpio_is_valid(fmc_config.nbl3_pin.pin)) {
|
||||
gpio_init(fmc_config.nbl3_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nbl3_pin.pin, fmc_config.nbl3_pin.af);
|
||||
}
|
||||
if (gpio_is_valid(fmc_config.nwait_pin.pin)) {
|
||||
gpio_init(fmc_config.nwait_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nwait_pin.pin, fmc_config.nwait_pin.af);
|
||||
}
|
||||
}
|
||||
|
||||
#if MODULE_PERIPH_FMC_NOR_SRAM
|
||||
static void _fmc_init_gpio_nor_sram(uint8_t sub_bank, fmc_mem_type_t type)
|
||||
{
|
||||
/* at least either NOE or NWE has to be valid */
|
||||
assert(gpio_is_valid(fmc_config.noe_pin.pin) ||
|
||||
gpio_is_valid(fmc_config.nwe_pin.pin));
|
||||
|
||||
if (gpio_is_valid(fmc_config.clk_pin.pin)) {
|
||||
gpio_init(fmc_config.clk_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.clk_pin.pin, fmc_config.clk_pin.af);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(fmc_config.noe_pin.pin)) {
|
||||
gpio_init(fmc_config.noe_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.noe_pin.pin, fmc_config.noe_pin.af);
|
||||
}
|
||||
|
||||
if (gpio_is_valid(fmc_config.nwe_pin.pin)) {
|
||||
gpio_init(fmc_config.nwe_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nwe_pin.pin, fmc_config.nwe_pin.af);
|
||||
}
|
||||
|
||||
if (type == FMC_NOR) {
|
||||
/* NADV has to be valid for NOR Flash memories */
|
||||
assert(gpio_is_valid(fmc_config.nadv_pin.pin));
|
||||
gpio_init(fmc_config.nadv_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.nadv_pin.pin, fmc_config.nadv_pin.af);
|
||||
}
|
||||
|
||||
/* the corresponding NE pin has to be valid */
|
||||
switch (sub_bank) {
|
||||
case 1:
|
||||
assert(gpio_is_valid(fmc_config.ne1_pin.pin));
|
||||
gpio_init(fmc_config.ne1_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.ne1_pin.pin, fmc_config.ne1_pin.af);
|
||||
break;
|
||||
case 2:
|
||||
assert(gpio_is_valid(fmc_config.ne2_pin.pin));
|
||||
gpio_init(fmc_config.ne2_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.ne2_pin.pin, fmc_config.ne2_pin.af);
|
||||
break;
|
||||
case 3:
|
||||
assert(gpio_is_valid(fmc_config.ne3_pin.pin));
|
||||
gpio_init(fmc_config.ne3_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.ne3_pin.pin, fmc_config.ne3_pin.af);
|
||||
break;
|
||||
case 4:
|
||||
assert(gpio_is_valid(fmc_config.ne4_pin.pin));
|
||||
gpio_init(fmc_config.ne4_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.ne4_pin.pin, fmc_config.ne4_pin.af);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void _fmc_init_nor_sram_bank(const fmc_bank_conf_t *bank_conf)
|
||||
{
|
||||
DEBUG("[%s] subbank %u\n", __func__, bank_conf->nor_sram.sub_bank);
|
||||
|
||||
const fmc_nor_sram_bank_conf_t *conf = &bank_conf->nor_sram;
|
||||
assert((bank_conf->nor_sram.sub_bank) >= 1 &&
|
||||
(bank_conf->nor_sram.sub_bank) <= 4);
|
||||
|
||||
_fmc_init_gpio_nor_sram(conf->sub_bank, bank_conf->mem_type);
|
||||
|
||||
uint32_t *bcr1 = (uint32_t *)(FMC_Bank1_R_BASE);
|
||||
uint32_t *bcr = (uint32_t *)(FMC_Bank1_R_BASE + ((conf->sub_bank - 1) * 8));
|
||||
uint32_t *btr = (uint32_t *)(FMC_Bank1_R_BASE + ((conf->sub_bank - 1) * 8) + 0x04);
|
||||
uint32_t *bwtr = (uint32_t *)(FMC_Bank1E_R_BASE + ((conf->sub_bank - 1) * 8));
|
||||
|
||||
/* disable Memory Bank 1 */
|
||||
*bcr &= ~FMC_BCRx_MBKEN;
|
||||
|
||||
/* set read timing */
|
||||
*btr = conf->r_timing.mode
|
||||
| (conf->r_timing.addr_setup << FMC_BTRx_ADDSET_Pos)
|
||||
| (conf->r_timing.addr_hold << FMC_BTRx_ADDHLD_Pos)
|
||||
| (conf->r_timing.data_setup << FMC_BTRx_DATAST_Pos)
|
||||
| (conf->r_timing.data_latency << FMC_BTRx_DATLAT_Pos)
|
||||
| (conf->r_timing.bus_turnaround << FMC_BTRx_BUSTURN_Pos)
|
||||
| (conf->r_timing.clk_div << FMC_BTRx_CLKDIV_Pos);
|
||||
|
||||
if (conf->mux_enable) {
|
||||
/* enable Extended mode if set and set write timings */
|
||||
*bcr |= FMC_BCRx_EXTMOD;
|
||||
*bwtr = conf->w_timing.mode
|
||||
| (conf->w_timing.addr_setup << FMC_BTRx_ADDSET_Pos)
|
||||
| (conf->w_timing.addr_hold << FMC_BTRx_ADDHLD_Pos)
|
||||
| (conf->w_timing.data_setup << FMC_BTRx_DATAST_Pos)
|
||||
| (conf->w_timing.bus_turnaround << FMC_BTRx_BUSTURN_Pos);
|
||||
}
|
||||
else {
|
||||
*bcr &= ~FMC_BCRx_EXTMOD;
|
||||
}
|
||||
|
||||
#ifdef FMC_BCR1_WFDIS
|
||||
/* disable Write FIFO for all subbanks */
|
||||
*bcr1 |= FMC_BCR1_WFDIS;
|
||||
#else
|
||||
(void)bcr1;
|
||||
#endif
|
||||
|
||||
/* set memory Type */
|
||||
*bcr &= ~FMC_BCRx_MTYP_Msk;
|
||||
*bcr |= bank_conf->mem_type << FMC_BCRx_MTYP_Pos;
|
||||
|
||||
/* set Memory Type to 16 bit (reset default) */
|
||||
*bcr &= ~FMC_BCRx_MWID_Msk;
|
||||
*bcr |= bank_conf->data_width << FMC_BCRx_MWID_Pos;
|
||||
|
||||
/* clear Write Wait, Flash Access and Address/Data Multiplexing */
|
||||
*bcr &= ~(FMC_BCRx_WAITEN | FMC_BCRx_FACCEN | FMC_BCRx_MUXEN);
|
||||
|
||||
/* enable WAIT signal if set */
|
||||
*bcr |= (conf->wait_enable) << FMC_BCRx_WAITEN_Pos;
|
||||
|
||||
/* enable NOR Flash memory access in case of NOR Flash */
|
||||
*bcr |= (bank_conf->mem_type == FMC_NOR) << FMC_BCRx_FACCEN_Pos;
|
||||
|
||||
/* enable MUX in case of PSRAM or NOR if set */
|
||||
*bcr |= (((bank_conf->mem_type == FMC_PSRAM) ||
|
||||
(bank_conf->mem_type == FMC_NOR)) &&
|
||||
conf->mux_enable) << FMC_BCRx_MUXEN_Pos;
|
||||
|
||||
/* leave all other values at reset default 0x000030d2 */
|
||||
/* enable Memory Bank 1 */
|
||||
*bcr |= FMC_BCRx_MBKEN; /* Memory Bank Enable = enabled */
|
||||
|
||||
DEBUG("[%s] FMC BCRx=%08lx BTRx=%08lx BWTR=%08lx\n",
|
||||
__func__, *bcr, *btr, *bwtr);
|
||||
}
|
||||
#endif /* MODULE_PERIPH_FMC_NOR_SRAM */
|
||||
|
||||
#if MODULE_PERIPH_FMC_SDRAM
|
||||
/**
|
||||
* @brief SDRAM Command Mode Register definition
|
||||
*/
|
||||
typedef union {
|
||||
struct __attribute__((__packed__)) {
|
||||
uint32_t command:3; /**< Command mode */
|
||||
uint32_t target:2; /**< Command target */
|
||||
uint32_t auto_refresh:4; /**< Number of auto-refresh cycles */
|
||||
uint32_t mode_reg:13; /**< Mode register */
|
||||
uint32_t reserved:10; /**< reserved bits */
|
||||
};
|
||||
uint32_t value;
|
||||
} fmc_sdram_sdcmr_t;
|
||||
|
||||
/**
|
||||
* @brief SDRAM Mode Register definition
|
||||
*/
|
||||
typedef union __attribute__((__packed__)) {
|
||||
struct {
|
||||
uint16_t burst_len:3; /**< Burst length (0..6: 2^burst_len, 7: full page) */
|
||||
uint16_t burst_type:1; /**< Burst type (0: sequential, 1: interleaved) */
|
||||
uint16_t cas_latency:3; /**< CAS latency (1, 2, 3, other values are reserved) */
|
||||
uint16_t op_mode:2; /**< Operating mode (must be 0) */
|
||||
uint16_t write_burst:1; /**< Write burst mode (0: use read burst length, 1: no bursts) */
|
||||
uint16_t unused:6; /**< unused */
|
||||
};
|
||||
uint16_t value;
|
||||
} fmc_sdram_modereg_t;
|
||||
|
||||
/**
|
||||
* @brief SDRAM Command Mode
|
||||
*/
|
||||
typedef enum {
|
||||
FMC_CMD_NORMAL_MODE = 0, /**< Normal Mode */
|
||||
FMC_CMD_CLK_ENABLE = 1, /**< Clock Configuration Enable */
|
||||
FMC_CMD_PALL = 2, /**< All Bank Precharge command */
|
||||
FMC_CMD_AUTO_REFRESH = 3, /**< Auto-refresh command */
|
||||
FMC_CMD_LOAD_MODE = 4, /**< Load Mode Register */
|
||||
FMC_CMD_SELF_REFRESH = 5, /**< Self-refresh command */
|
||||
FMC_CMD_POWER_DOWN = 6, /**< Power-down command */
|
||||
FMC_CMD_RESERVED = 7, /**< reserved */
|
||||
} fmc_sdram_cmd_t;
|
||||
|
||||
static void _fmc_init_gpio_sdram(fmc_bank_t bank)
|
||||
{
|
||||
/* CLK, RAS, CAS, BA0, BA1 and WE must be valid */
|
||||
assert(gpio_is_valid(fmc_config.sdclk_pin.pin) &&
|
||||
gpio_is_valid(fmc_config.sdnras_pin.pin) &&
|
||||
gpio_is_valid(fmc_config.sdncas_pin.pin) &&
|
||||
gpio_is_valid(fmc_config.sdnwe_pin.pin) &&
|
||||
gpio_is_valid(fmc_config.ba0_pin.pin) &&
|
||||
gpio_is_valid(fmc_config.ba1_pin.pin));
|
||||
|
||||
gpio_init(fmc_config.ba0_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.ba1_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.sdclk_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.sdnras_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.sdncas_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.sdnwe_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.ba0_pin.pin, fmc_config.ba0_pin.af);
|
||||
gpio_init_af(fmc_config.ba1_pin.pin, fmc_config.ba1_pin.af);
|
||||
gpio_init_af(fmc_config.sdclk_pin.pin, fmc_config.sdclk_pin.af);
|
||||
gpio_init_af(fmc_config.sdnras_pin.pin, fmc_config.sdnras_pin.af);
|
||||
gpio_init_af(fmc_config.sdncas_pin.pin, fmc_config.sdncas_pin.af);
|
||||
gpio_init_af(fmc_config.sdnwe_pin.pin, fmc_config.sdnwe_pin.af);
|
||||
|
||||
/* corresponding NE pin and CKE pin must be valid */
|
||||
if (bank == FMC_BANK_5) {
|
||||
assert(gpio_is_valid(fmc_config.sdne0_pin.pin));
|
||||
assert(gpio_is_valid(fmc_config.sdcke0_pin.pin));
|
||||
gpio_init(fmc_config.sdne0_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.sdcke0_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.sdne0_pin.pin, fmc_config.sdne0_pin.af);
|
||||
gpio_init_af(fmc_config.sdcke0_pin.pin, fmc_config.sdcke0_pin.af);
|
||||
}
|
||||
else {
|
||||
assert(gpio_is_valid(fmc_config.sdne1_pin.pin));
|
||||
assert(gpio_is_valid(fmc_config.sdcke1_pin.pin));
|
||||
gpio_init(fmc_config.sdne1_pin.pin, GPIO_OUT);
|
||||
gpio_init(fmc_config.sdcke1_pin.pin, GPIO_OUT);
|
||||
gpio_init_af(fmc_config.sdne1_pin.pin, fmc_config.sdne1_pin.af);
|
||||
gpio_init_af(fmc_config.sdcke1_pin.pin, fmc_config.sdcke1_pin.af);
|
||||
}
|
||||
}
|
||||
|
||||
static void _fmc_init_sdram_bank(const fmc_bank_conf_t *bank_conf)
|
||||
{
|
||||
_fmc_init_gpio_sdram(bank_conf->bank);
|
||||
|
||||
const fmc_sdram_bank_conf_t *conf = &bank_conf->sdram;
|
||||
|
||||
uint8_t bank = (bank_conf->bank == FMC_BANK_5) ? 0 : 1;
|
||||
uint32_t sdcr;
|
||||
|
||||
/* following settings are always configured in SDCR1 independent on the
|
||||
* bank and are don't care in SDCR2 */
|
||||
sdcr = FMC_Bank5_6->SDCR[0];
|
||||
|
||||
/* set read delay */
|
||||
assert(conf->read_delay <= 2);
|
||||
sdcr &= ~FMC_SDCR1_RPIPE_Msk;
|
||||
sdcr |= conf->read_delay << FMC_SDCR1_RPIPE_Pos;
|
||||
|
||||
/* clear and set RBURST if enabled */
|
||||
sdcr &= ~FMC_SDCR1_RBURST;
|
||||
sdcr |= conf->burst_read << FMC_SDCR1_RBURST_Pos;
|
||||
|
||||
/* set clock period */
|
||||
assert(conf->clk_period <= 3);
|
||||
sdcr &= ~FMC_SDCR1_SDCLK_Msk;
|
||||
sdcr |= conf->clk_period << FMC_SDCR1_SDCLK_Pos;
|
||||
|
||||
/* write back register SDCR1 */
|
||||
FMC_Bank5_6->SDCR[0] = sdcr;
|
||||
|
||||
/* other settings are done in SDCRx for bannk x */
|
||||
sdcr = FMC_Bank5_6->SDCR[bank];
|
||||
|
||||
/* set number of row and column bits and the data bus width */
|
||||
assert((conf->row_bits >= 11) && (conf->row_bits <= 13));
|
||||
assert((conf->col_bits >= 8) && (conf->col_bits <= 11));
|
||||
sdcr &= ~(FMC_SDCR1_NR_Msk | FMC_SDCR1_NC_Msk | FMC_SDCR1_MWID_Msk);
|
||||
sdcr |= (conf->row_bits - 11) << FMC_SDCR1_NR_Pos;
|
||||
sdcr |= (conf->col_bits - 8) << FMC_SDCR1_NC_Pos;
|
||||
sdcr |= bank_conf->data_width << FMC_SDCR1_MWID_Pos;
|
||||
|
||||
/* set CAS latency */
|
||||
assert((conf->cas_latency >= 1) && (conf->cas_latency <= 3));
|
||||
sdcr &= ~FMC_SDCR1_CAS_Msk;
|
||||
sdcr |= conf->cas_latency << FMC_SDCR1_CAS_Pos;
|
||||
|
||||
/* clear and set NB and WP */
|
||||
sdcr &= ~(FMC_SDCR1_NB | FMC_SDCR1_WP);
|
||||
sdcr |= conf->four_banks << FMC_SDCR1_NB_Pos;
|
||||
sdcr |= conf->write_protect << FMC_SDCR1_WP_Pos;
|
||||
|
||||
/* write back register SDCRx */
|
||||
FMC_Bank5_6->SDCR[bank] = sdcr;
|
||||
|
||||
uint32_t sdtr = 0;
|
||||
|
||||
assert((conf->timing.row_to_col_delay - 1) <= 15);
|
||||
assert((conf->timing.row_precharge - 1) <= 15);
|
||||
assert((conf->timing.recovery_delay - 1) <= 15);
|
||||
assert((conf->timing.row_cylce - 1) <= 15);
|
||||
assert((conf->timing.self_refresh - 1) <= 15);
|
||||
assert((conf->timing.exit_self_refresh - 1) <= 15);
|
||||
assert((conf->timing.load_mode_register - 1) <= 15);
|
||||
|
||||
/* following settings are always configured in SDTR1 independent on the
|
||||
* bank and are don't care in SDTR2 */
|
||||
sdtr = FMC_Bank5_6->SDTR[0];
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TRP;
|
||||
sdtr |= (conf->timing.row_precharge - 1) << FMC_SDTR1_TRP_Pos;
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TRC;
|
||||
sdtr |= (conf->timing.row_cylce - 1) << FMC_SDTR1_TRC_Pos;
|
||||
|
||||
/* write back register SDCRx */
|
||||
FMC_Bank5_6->SDTR[0] = sdtr;
|
||||
|
||||
/* other settings are done in SDTRx for bannk x */
|
||||
sdtr = FMC_Bank5_6->SDTR[0];
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TRCD;
|
||||
sdtr |= (conf->timing.row_to_col_delay - 1) << FMC_SDTR1_TRCD_Pos;
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TWR;
|
||||
sdtr |= (conf->timing.recovery_delay - 1) << FMC_SDTR1_TWR_Pos;
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TRAS;
|
||||
sdtr |= (conf->timing.self_refresh - 1) << FMC_SDTR1_TRAS_Pos;
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TXSR;
|
||||
sdtr |= (conf->timing.exit_self_refresh - 1) << FMC_SDTR1_TXSR_Pos;
|
||||
|
||||
sdtr &= ~FMC_SDTR1_TMRD;
|
||||
sdtr |= (conf->timing.load_mode_register - 1) << FMC_SDTR1_TMRD_Pos;
|
||||
|
||||
/* write register SDTRx */
|
||||
FMC_Bank5_6->SDTR[bank] = sdtr;
|
||||
|
||||
DEBUG("[%s] DMC SDCR%d=%08lx SDTR%d=%08lx SDCMR=%08lx SDRTR=%08lx SDSR=%08lx\n",
|
||||
__func__,
|
||||
bank, FMC_Bank5_6->SDCR[bank],
|
||||
bank, FMC_Bank5_6->SDTR[bank],
|
||||
FMC_Bank5_6->SDCMR, FMC_Bank5_6->SDRTR, FMC_Bank5_6->SDSR);
|
||||
|
||||
/* Initialization sequence according to the reference manual */
|
||||
|
||||
fmc_sdram_sdcmr_t sdcmr = { .target = (bank) ? 0b01 : 0b10,
|
||||
.auto_refresh = 1,
|
||||
.mode_reg = 0 };
|
||||
|
||||
/* enable clock (SDCKE HIGH) */
|
||||
sdcmr.command = FMC_CMD_CLK_ENABLE;
|
||||
FMC_Bank5_6->SDCMR = sdcmr.value;
|
||||
|
||||
/* wait at least 100 us */
|
||||
uint32_t count = 0xffffff;
|
||||
while (count--) {}
|
||||
|
||||
/* issue Precharge All command */
|
||||
sdcmr.command = FMC_CMD_PALL;
|
||||
FMC_Bank5_6->SDCMR = sdcmr.value;
|
||||
|
||||
/* issue the typical number of Auto-refresh commands */
|
||||
sdcmr.command = FMC_CMD_AUTO_REFRESH;
|
||||
sdcmr.auto_refresh = 8;
|
||||
FMC_Bank5_6->SDCMR = sdcmr.value;
|
||||
|
||||
/* load mode register */
|
||||
fmc_sdram_modereg_t modreg = {
|
||||
.burst_len = 0, // conf->burst_len,
|
||||
.burst_type = conf->burst_interleaved,
|
||||
.cas_latency = conf->cas_latency,
|
||||
.op_mode = 0,
|
||||
.write_burst = (conf->burst_write) ? 0 : 1,
|
||||
};
|
||||
sdcmr.command = FMC_CMD_LOAD_MODE;
|
||||
sdcmr.auto_refresh = 1;
|
||||
sdcmr.mode_reg = modreg.value;
|
||||
FMC_Bank5_6->SDCMR = sdcmr.value;
|
||||
|
||||
/* set refresh timer register */
|
||||
uint32_t cycles;
|
||||
cycles = CLOCK_AHB / KHZ(1) / conf->clk_period; /* SDCLK cycles per ms */
|
||||
cycles = cycles * conf->timing.refresh_period; /* SDCLK cycles per refresh period */
|
||||
cycles = cycles / (1 << conf->row_bits); /* SDCLK cycles per row */
|
||||
cycles = ((cycles - 20) > 41) ? cycles - 20 : 41; /* cycles - margin > min 41 */
|
||||
FMC_Bank5_6->SDRTR &= FMC_SDRTR_COUNT_Msk;
|
||||
FMC_Bank5_6->SDRTR |= cycles << FMC_SDRTR_COUNT_Pos;
|
||||
}
|
||||
#endif
|
||||
|
||||
void fmc_init_bank(fmc_bank_id_t bank)
|
||||
{
|
||||
DEBUG("[%s] bank id %u\n", __func__, bank);
|
||||
|
||||
assert(bank < FMC_BANK_NUMOF);
|
||||
|
||||
const fmc_bank_conf_t *conf = &fmc_bank_config[bank];
|
||||
|
||||
/* ensure that configured bank is valid */
|
||||
switch (conf->bank) {
|
||||
case 1: break;
|
||||
#if defined(FMC_Bank2_3_R_BASE)
|
||||
case 2: break;
|
||||
#endif
|
||||
#if defined(FMC_Bank2_3_R_BASE) || defined(FMC_Bank3_R_BASE)
|
||||
case 3: break;
|
||||
#endif
|
||||
#if defined(FMC_Bank4_R_BASE)
|
||||
case 4: break;
|
||||
#endif
|
||||
#if defined(FMC_Bank5_6_R_BASE)
|
||||
case 5:
|
||||
case 6: break;
|
||||
#endif
|
||||
default: assert(false);
|
||||
}
|
||||
|
||||
if (conf->bank == FMC_BANK_1) {
|
||||
#if MODULE_PERIPH_FMC_NOR_SRAM
|
||||
/* bank 1 has to be NOR, PSRAM or SRAM */
|
||||
assert((conf->mem_type == FMC_SRAM) ||
|
||||
(conf->mem_type == FMC_PSRAM) ||
|
||||
(conf->mem_type == FMC_NOR));
|
||||
_fmc_init_nor_sram_bank(conf);
|
||||
#else
|
||||
LOG_WARNING("NOR/PSRAM/SRAM configured but not enabled by feature periph_fmc_sdram\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(FMC_Bank5_6_R_BASE)
|
||||
else if ((conf->bank == FMC_BANK_5) || (conf->bank == FMC_BANK_6)) {
|
||||
#if MODULE_PERIPH_FMC_SDRAM
|
||||
_fmc_init_sdram_bank(conf);
|
||||
#else
|
||||
LOG_WARNING("SDRAM configured but not enabled by feature periph_fmc_nor_sram\n");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
else {
|
||||
LOG_ERROR("[fmc] Bank %u not supported\n", conf->bank);
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
#include "periph_cpu.h"
|
||||
|
||||
void fmc_init(void)
|
||||
{
|
||||
DEBUG("[%s]\n", __func__);
|
||||
|
||||
periph_clk_en(fmc_config.bus, fmc_config.rcc_mask);
|
||||
|
||||
_fmc_init_gpio_common();
|
||||
for (unsigned i = 0; i < FMC_BANK_NUMOF; i++) {
|
||||
fmc_init_bank(i);
|
||||
}
|
||||
}
|
6
dist/tools/codespell/ignored_words.txt
vendored
6
dist/tools/codespell/ignored_words.txt
vendored
@ -156,3 +156,9 @@ didi
|
||||
|
||||
# loath => loathe (both correct, one is an adjective, the other a verb)
|
||||
loath
|
||||
|
||||
# NOE (Negative Output Enable) ==> NOT, NO, NODE, NOTE, KNOW, NOW
|
||||
noe
|
||||
|
||||
# NWE (Negative Write Enable) ==> NEW
|
||||
nwe
|
||||
|
@ -117,6 +117,11 @@ void periph_init(void)
|
||||
ptp_init();
|
||||
#endif
|
||||
|
||||
#if defined(MODULE_PERIPH_INIT_FMC)
|
||||
extern void fmc_init(void);
|
||||
fmc_init();
|
||||
#endif
|
||||
|
||||
#if defined(MODULE_PERIPH_INIT_VBAT)
|
||||
vbat_init();
|
||||
#endif
|
||||
|
6
tests/periph/fmc/Kconfig
Normal file
6
tests/periph/fmc/Kconfig
Normal file
@ -0,0 +1,6 @@
|
||||
config APPLICATION
|
||||
bool
|
||||
default y
|
||||
imply MODULE_PERIPH_FMC_NOR_SRAM
|
||||
imply MODULE_PERIPH_FMC_SDRAM
|
||||
depends on TEST_KCONFIG
|
11
tests/periph/fmc/Makefile
Normal file
11
tests/periph/fmc/Makefile
Normal file
@ -0,0 +1,11 @@
|
||||
BOARD ?= stm32f429i-disc1
|
||||
include ../Makefile.periph_common
|
||||
|
||||
USEMODULE += benchmark
|
||||
USEMODULE += od
|
||||
|
||||
FEATURES_REQUIRED += periph_fmc
|
||||
FEATURES_OPTIONAL += periph_fmc_nor_sram
|
||||
FEATURES_OPTIONAL += periph_fmc_sdram
|
||||
|
||||
include $(RIOTBASE)/Makefile.include
|
24
tests/periph/fmc/README.md
Normal file
24
tests/periph/fmc/README.md
Normal file
@ -0,0 +1,24 @@
|
||||
Peripheral STM32 FMC Test Application
|
||||
=====================================
|
||||
|
||||
This application tests basic STM32 FMC functionality:
|
||||
|
||||
- 8-bit, 16-bit and 32-bit write and read access
|
||||
- availability of the whole memory
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
The bank to be used is defined by environment variable `FMC_BANK`. For example,
|
||||
if the board configures two banks with RAM, the second bank can be tested by
|
||||
specifying the `FMC_BANK` variable as follows:
|
||||
```
|
||||
FMC_BANK=1 BOARD=... make -j8 -C tests/periph/fmc flash test
|
||||
```
|
||||
|
||||
Expected Output on Success
|
||||
--------------------------
|
||||
|
||||
main(): This is RIOT! (Version: <INSERT VERSION HERE>)
|
||||
...
|
||||
[SUCCESS]
|
3
tests/periph/fmc/app.config.test
Normal file
3
tests/periph/fmc/app.config.test
Normal file
@ -0,0 +1,3 @@
|
||||
CONFIG_MODULE_BENCHMARK=y
|
||||
CONFIG_MODULE_PERIPH_FMC=y
|
||||
CONFIG_MODULE_OD=y
|
166
tests/periph/fmc/main.c
Normal file
166
tests/periph/fmc/main.c
Normal file
@ -0,0 +1,166 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Test for memories connected to the STM32 FMC/FSMC peripheral
|
||||
*
|
||||
* @author Gunar Schorcht <gunar@schorcht.net>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "benchmark.h"
|
||||
#include "od.h"
|
||||
#include "periph_conf.h"
|
||||
|
||||
#ifndef FMC_BANK
|
||||
#define FMC_BANK 0
|
||||
#endif
|
||||
|
||||
#ifndef MEM_BUFSIZ
|
||||
#define MEM_BUFSIZ 1024
|
||||
#endif
|
||||
|
||||
uint8_t mem_buf[MEM_BUFSIZ] = {};
|
||||
|
||||
void bench_mem_write(uint32_t addr, uint32_t len)
|
||||
{
|
||||
uint8_t *mem = (uint8_t *)addr;
|
||||
uint32_t i = 0;
|
||||
|
||||
while (i < len) {
|
||||
memcpy(mem + i, mem_buf, MEM_BUFSIZ);
|
||||
i += MEM_BUFSIZ;
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
printf("FMC HCLK freq %lu MHz\n", CLOCK_AHB/MHZ(1));
|
||||
|
||||
uint8_t *data8 = (uint8_t *)(fmc_bank_config[FMC_BANK].address);
|
||||
uint16_t *data16 = (uint16_t *)((fmc_bank_config[FMC_BANK].address) + 256);
|
||||
uint32_t *data32 = (uint32_t *)((fmc_bank_config[FMC_BANK].address) +
|
||||
(fmc_bank_config[FMC_BANK].size) - 256);
|
||||
|
||||
printf("8-bit data @%p, 16-bit data @%p, 32-bit data @%p\n",
|
||||
data8, data16, data32);
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
for (unsigned i = 0; i < 256; i++) {
|
||||
data8[i] = i;
|
||||
}
|
||||
od_hex_dump_ext(data8, 256, 16, fmc_bank_config[FMC_BANK].address);
|
||||
|
||||
for (unsigned i = 0; i < 256; i++) {
|
||||
if (data8[i] != i) {
|
||||
printf("ERROR: memory content did not match @%p\n", &data8[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
for (unsigned i = 0; i < 128; i++) {
|
||||
data16[i] = ((128 + i) << 8) + i;
|
||||
}
|
||||
od_hex_dump_ext(data16, 256, 16, fmc_bank_config[FMC_BANK].address + 256);
|
||||
|
||||
for (unsigned i = 0; i < 128; i++) {
|
||||
if (data16[i] != ((128 + i) << 8) + i) {
|
||||
printf("ERROR: memory content did not match @%p\n", &data16[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
for (unsigned i = 0; i < 64; i++) {
|
||||
data32[i] = ((192 + i) << 24) + ((128 + i) << 16) + ((64 + i) << 8) + i;
|
||||
}
|
||||
od_hex_dump_ext(data32, 256, 16, (fmc_bank_config[FMC_BANK].address) +
|
||||
(fmc_bank_config[FMC_BANK].size) - 256);
|
||||
|
||||
for (unsigned i = 0; i < 64; i++) {
|
||||
if (data32[i] != ((192 + i) << 24) + ((128 + i) << 16) + ((64 + i) << 8) + i) {
|
||||
printf("ERROR: memory content did not match @%p\n", &data32[i]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
|
||||
printf("fill complete memory of %lu kByte, a . represents a 16 kByte block\n",
|
||||
fmc_bank_config[FMC_BANK].size >> 10);
|
||||
|
||||
data32 = (uint32_t *)(fmc_bank_config[FMC_BANK].address);
|
||||
|
||||
for (uint32_t i = 0; i < (fmc_bank_config[FMC_BANK].size >> 2); i++) {
|
||||
*data32 = (uint32_t)data32;
|
||||
data32++;
|
||||
if (((i << 2) % KiB(16)) == 0) {
|
||||
printf(".");
|
||||
}
|
||||
}
|
||||
puts("\nready");
|
||||
puts("check memory content, a + represents one 16 kByte block of matching data");
|
||||
|
||||
data32 = (uint32_t *)(fmc_bank_config[FMC_BANK].address);
|
||||
|
||||
for (uint32_t i = 0; i < (fmc_bank_config[FMC_BANK].size >> 2); i++) {
|
||||
if (*data32 != (uint32_t)data32) {
|
||||
printf("ERROR: memory content did not match @%p, "
|
||||
"should be %p but was 0x%08"PRIx32"\n",
|
||||
data32, data32, *data32);
|
||||
return 1;
|
||||
}
|
||||
data32++;
|
||||
if (((i << 2) % KiB(16)) == 0) {
|
||||
printf("+");
|
||||
}
|
||||
}
|
||||
puts("\nready");
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
puts("Doing some benchmarks\n");
|
||||
|
||||
volatile uint8_t val8 = 0xf0;
|
||||
volatile uint16_t val16 = 0x5555;
|
||||
volatile uint32_t val32 = 0xaaaaaaaa;
|
||||
|
||||
BENCHMARK_FUNC("write 8 bit", fmc_bank_config[FMC_BANK].size,
|
||||
((uint8_t *)(fmc_bank_config[FMC_BANK].address))[i] = val8);
|
||||
BENCHMARK_FUNC("write 16 bit", fmc_bank_config[FMC_BANK].size / 2,
|
||||
((uint16_t *)(fmc_bank_config[FMC_BANK].address))[i] = val16);
|
||||
BENCHMARK_FUNC("write 32 bit", fmc_bank_config[FMC_BANK].size / 4,
|
||||
((uint32_t *)(fmc_bank_config[FMC_BANK].address))[i] = val32);
|
||||
|
||||
BENCHMARK_FUNC("read 8 bit", fmc_bank_config[FMC_BANK].size,
|
||||
val8 = ((uint8_t *)(fmc_bank_config[FMC_BANK].address))[i]);
|
||||
BENCHMARK_FUNC("read 16 bit", fmc_bank_config[FMC_BANK].size / 2,
|
||||
val16 = ((uint16_t *)(fmc_bank_config[FMC_BANK].address))[i]);
|
||||
BENCHMARK_FUNC("read 32 bit", fmc_bank_config[FMC_BANK].size / 4,
|
||||
val32 = ((uint32_t *)(fmc_bank_config[FMC_BANK].address))[i]);
|
||||
|
||||
puts("\nready");
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
puts("print first and last memory block after benchmark, should be 0xaa\n");
|
||||
od_hex_dump_ext(data8, 256, 16, fmc_bank_config[FMC_BANK].address);
|
||||
puts("");
|
||||
|
||||
data8 = (uint8_t *)((fmc_bank_config[FMC_BANK].address) +
|
||||
(fmc_bank_config[FMC_BANK].size) - 256);
|
||||
od_hex_dump_ext(data8, 256, 16, (fmc_bank_config[FMC_BANK].address) +
|
||||
(fmc_bank_config[FMC_BANK].size) - 256);
|
||||
puts("------------------------------------------------------------------------");
|
||||
|
||||
puts("\n[SUCCESS]\n");
|
||||
|
||||
return 0;
|
||||
}
|
18
tests/periph/fmc/tests/01-run.py
Executable file
18
tests/periph/fmc/tests/01-run.py
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# 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.
|
||||
|
||||
import sys
|
||||
from testrunner import run
|
||||
|
||||
|
||||
def testfunc(child):
|
||||
child.expect_exact("[SUCCESS]")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(run(testfunc))
|
Loading…
Reference in New Issue
Block a user