1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/cpu/stm32/periph/fmc.c
2023-07-26 09:02:10 +02:00

576 lines
20 KiB
C

/*
* Copyright (C) 2023 Gunar Schorcht
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup cpu_stm32
* @ingroup drivers_periph_fmc
* @{
*
* @file
* @brief FMC peripheral driver implementation
*
* @author Gunar Schorcht <gunar@schorcht.net>
* @}
*/
#include <assert.h>
#include "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);
}
}