micropython/ports/stm32/sdram.c

184 lines
6.3 KiB
C
Raw Normal View History

/*
* This file is part of the OpenMV project.
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* SDRAM Driver.
*
*/
#include <stdio.h>
#include <stdbool.h>
#include <stm32f4xx_hal.h>
#include "mdefs.h"
#include "pincfg.h"
#include "systick.h"
#include "sdram.h"
#define SDRAM_TIMEOUT ((uint32_t)0xFFFF)
#define REFRESH_COUNT ((uint32_t)0x0569) /* SDRAM refresh counter (90Mhz SD clock) */
#define SDRAM_MODEREG_BURST_LENGTH_1 ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_LENGTH_2 ((uint16_t)0x0001)
#define SDRAM_MODEREG_BURST_LENGTH_4 ((uint16_t)0x0002)
#define SDRAM_MODEREG_BURST_LENGTH_8 ((uint16_t)0x0004)
#define SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL ((uint16_t)0x0000)
#define SDRAM_MODEREG_BURST_TYPE_INTERLEAVED ((uint16_t)0x0008)
#define SDRAM_MODEREG_CAS_LATENCY_2 ((uint16_t)0x0020)
#define SDRAM_MODEREG_CAS_LATENCY_3 ((uint16_t)0x0030)
#define SDRAM_MODEREG_OPERATING_MODE_STANDARD ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_PROGRAMMED ((uint16_t)0x0000)
#define SDRAM_MODEREG_WRITEBURST_MODE_SINGLE ((uint16_t)0x0200)
static SDRAM_HandleTypeDef hsdram;
static FMC_SDRAM_TimingTypeDef SDRAM_Timing;
static FMC_SDRAM_CommandTypeDef command;
static void sdram_init_seq(SDRAM_HandleTypeDef
*hsdram, FMC_SDRAM_CommandTypeDef *command);
extern void __fatal_error(const char *msg);
bool sdram_init()
{
/* SDRAM device configuration */
hsdram.Instance = FMC_SDRAM_DEVICE;
/* Timing configuration for 90 Mhz of SD clock frequency (180Mhz/2) */
/* TMRD: 2 Clock cycles */
SDRAM_Timing.LoadToActiveDelay = 2;
/* TXSR: min=70ns (6x11.90ns) */
SDRAM_Timing.ExitSelfRefreshDelay = 7;
/* TRAS: min=45ns (4x11.90ns) max=120k (ns) */
SDRAM_Timing.SelfRefreshTime = 7;
/* TRC: min=67ns (6x11.90ns) */
SDRAM_Timing.RowCycleDelay = 10;
/* TWR: 2 Clock cycles */
SDRAM_Timing.WriteRecoveryTime = 2;
/* TRP: 20ns => 2x11.90ns */
SDRAM_Timing.RPDelay = 3;
/* TRCD: 20ns => 2x11.90ns */
SDRAM_Timing.RCDDelay = 3;
hsdram.Init.SDBank = FMC_SDRAM_BANK1;
hsdram.Init.RowBitsNumber = FMC_SDRAM_ROW_BITS_NUM_12;
hsdram.Init.ColumnBitsNumber = FMC_SDRAM_COLUMN_BITS_NUM_10;
hsdram.Init.MemoryDataWidth = FMC_SDRAM_MEM_BUS_WIDTH_8;
hsdram.Init.InternalBankNumber = FMC_SDRAM_INTERN_BANKS_NUM_4;
hsdram.Init.CASLatency = FMC_SDRAM_CAS_LATENCY_3;
hsdram.Init.WriteProtection = FMC_SDRAM_WRITE_PROTECTION_DISABLE;
hsdram.Init.SDClockPeriod = FMC_SDRAM_CLOCK_PERIOD_3;
hsdram.Init.ReadBurst = FMC_SDRAM_RBURST_DISABLE;
hsdram.Init.ReadPipeDelay = FMC_SDRAM_RPIPE_DELAY_1;
/* Initialize the SDRAM controller */
if(HAL_SDRAM_Init(&hsdram, &SDRAM_Timing) != HAL_OK) {
return false;
}
sdram_init_seq(&hsdram, &command);
return true;
}
static void sdram_init_seq(SDRAM_HandleTypeDef
*hsdram, FMC_SDRAM_CommandTypeDef *command)
{
/* Program the SDRAM external device */
__IO uint32_t tmpmrd =0;
/* Step 3: Configure a clock configuration enable command */
command->CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command->AutoRefreshNumber = 1;
command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, command, 0x1000);
/* Step 4: Insert 100 ms delay */
HAL_Delay(100);
/* Step 5: Configure a PALL (precharge all) command */
command->CommandMode = FMC_SDRAM_CMD_PALL;
command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command->AutoRefreshNumber = 1;
command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, command, 0x1000);
/* Step 6 : Configure a Auto-Refresh command */
command->CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command->AutoRefreshNumber = 4;
command->ModeRegisterDefinition = 0;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, command, 0x1000);
/* Step 7: Program the external memory mode register */
tmpmrd = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_2 |
SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL |
SDRAM_MODEREG_CAS_LATENCY_3 |
SDRAM_MODEREG_OPERATING_MODE_STANDARD |
SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;
command->CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
command->CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
command->AutoRefreshNumber = 1;
command->ModeRegisterDefinition = tmpmrd;
/* Send the command */
HAL_SDRAM_SendCommand(hsdram, command, 0x1000);
/* Step 8: Set the refresh rate counter */
/* (15.62 us x Freq) - 20 */
/* Set the device refresh counter */
HAL_SDRAM_ProgramRefreshRate(hsdram, REFRESH_COUNT);
}
bool DISABLE_OPT sdram_test()
{
uint8_t pattern = 0xAA;
uint8_t antipattern = 0x55;
uint32_t mem_size = (16*1024*1024);
uint8_t * const mem_base = (uint8_t*)0xC0000000;
printf("sdram test...\n");
/* test data bus */
for (uint8_t i=1; i; i<<=1) {
*mem_base = i;
if (*mem_base != i) {
printf("data bus lines test failed! data (%d)\n", i);
BREAK();
}
}
/* test address bus */
/* Check individual address lines */
for (uint32_t i=1; i<mem_size; i<<=1) {
mem_base[i] = pattern;
if (mem_base[i] != pattern) {
printf("address bus lines test failed! address (%p)\n", &mem_base[i]);
BREAK();
}
}
/* Check for aliasing (overlaping addresses) */
mem_base[0] = antipattern;
for (uint32_t i=1; i<mem_size; i<<=1) {
if (mem_base[i] != pattern) {
printf("address bus overlap %p\n", &mem_base[i]);
BREAK();
}
}
/* test all ram cells */
for (uint32_t i=0; i<mem_size; i++) {
mem_base[i] = pattern;
if (mem_base[i] != pattern) {
printf("address bus test failed! address (%p)\n", &mem_base[i]);
BREAK();
}
}
printf("sdram test passed\n");
return true;
}