STM32: FMC的简单使用_SDRASM(IS42S16400J)的ram扩展

本文介绍了用IS42S16400J给stm32的ram增加8M字节扩容


前言

随着现代电子设备复杂度的不断增加,对于内存的需求也日益增长。STM32微控制器提供了多种方式来连接外部存储器,以满足不同的应用场景和性能需求。其中,FMC接口是一个能够支持SRAM、NOR Flash、PSRAM、NAND Flash和SDRAM等不同类型存储器的强大工具。特别是对于需要大量数据缓存或快速读写操作的应用,如图像处理、音频播放或复杂的图形用户界面(GUI),SDRAM以其高速度和大容量成为了理想的选择。

在这里,我们将深入探讨STM32系列微控制器中一个非常强大的外设——FMC(Flexible Memory Controller),以及它在SDRAM(同步动态随机存取存储器)扩展中的应用。

一、SDRAM介绍

1.在相关博客推荐处看到的这一篇,看了确实会对sdram的配置有一个基础的了解。

高手进阶,终极内存技术指南——完整/进阶版 I
那篇博客也贴在这里
STM32F429驱动SDRAM(IS42S16400J)详解

2. IS42S16400J-7

IS42S16400J是一种高速同步动态随机存储器(SDRAM),有4个bank,每个bank有12根行地址线(A0-A11),8根列地址线(A0-A7),总线宽度为16位,所以它的容量为4*212*28*16=64M bit=8M Byte。

后续的文章我会讲解stm32H743上使用fmc->W9825G6KH和lcd/dma2d的使用。

二、sdram时钟

查找图中的时间都能找到
在这里插入图片描述

在这里插入图片描述

三、cubemx配置

在这里插入图片描述

在这里插入图片描述

这里根据手册选择bank1应该也是可以的。

在这里插入图片描述

四、sdram初始化

在配置好了fmc接口之后,需要对sdram进行初始化流程
在这里插入图片描述

总结流程为
1.上电
2.初始化时钟延迟至少100us
3.在一个无效命令或空操作后执行执行预充电延迟至少100us,所有bank都需要被预充电
4.执行两个自动刷新周期
5.配置模式寄存器

在这里插入图片描述

 /************************************************************************
  * * *@brief 对SDRAM芯片进行初始化配置
  * * *
 ************************************************************************/
void SDRAM_InitSequence(void)
{
  uint32_t tmpr = 0;
  
  /* 配置命令:开启提供给SDRAM的时钟 */
  Command.CommandMode = FMC_SDRAM_CMD_CLK_ENABLE;
  Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
  Command.AutoRefreshNumber = 1;
  Command.ModeRegisterDefinition = 0;
/* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);

  /* Step 2: Insert 100 us minimum delay */ 
  /* Inserted delay is equal to 1 ms due to systick time base unit (ms) */
  HAL_Delay(1);
    
/* Step 5 --------------------------------------------------------------------*/
  /* 配置命令:对所有的bank预充电 */ 
  Command.CommandMode = FMC_SDRAM_CMD_PALL;
  Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
  Command.AutoRefreshNumber = 1;
  Command.ModeRegisterDefinition = 0;
/* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);   
  
/* Step 6 --------------------------------------------------------------------*/
  /* 配置命令:自动刷新 */   
  Command.CommandMode = FMC_SDRAM_CMD_AUTOREFRESH_MODE;
  Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
  Command.AutoRefreshNumber = 4;
  Command.ModeRegisterDefinition = 0;
 /* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
  
/* Step 7 --------------------------------------------------------------------*/
  /* 设置sdram寄存器配置 */
  tmpr = (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;
  
  /* 配置命令:设置SDRAM寄存器 */
  Command.CommandMode = FMC_SDRAM_CMD_LOAD_MODE;
  Command.CommandTarget = FMC_COMMAND_TARGET_BANK;
  Command.AutoRefreshNumber = 1;
  Command.ModeRegisterDefinition = tmpr;
  /* Send the command */
  HAL_SDRAM_SendCommand(&sdramHandle, &Command, SDRAM_TIMEOUT);
  
/* Step 8 --------------------------------------------------------------------*/

  /* 设置刷新计数器 */
  /* (15.62 us x Freq) - 20 */
	  /* Step 6: Set the refresh rate counter */
  /* Set the device refresh rate */
  HAL_SDRAM_ProgramRefreshRate(&sdramHandle, 1386); 
}

五、测试

在配置和初始化之后,我们使用sdram就可以像使用内部ram一样,直接使用地址访问,这就是fmc的魅力啊。

sdram.c

#include "sdram.h"
#include "fmc.h"
#include "sdram_bsp.h"
#include "rng.h"
#include "usart.h"

#define MAX_SDRAM_TEST_SIZE 10000
#define SDRAM_SIZE (IS42S16400J_SIZE / 4)

static uint32_t RadomBuffer[MAX_SDRAM_TEST_SIZE];
//static uint32_t ReadBuffer[MAX_SDRAM_TEST_SIZE];
uint32_t *pSDRAM;

/************************************************************************
 * * *@brief rng buff填充
 * * *
 ************************************************************************/
void rng_padding(void)
{
    printf("开始生成10000个SDRAM测试随机数\n");
    for (uint16_t i = 0; i < MAX_SDRAM_TEST_SIZE; i++)
    {
        RadomBuffer[i] = HAL_RNG_GetRandomNumber(&hrng);
    }
}

/************************************************************************
 * * *@brief sdram检测
 * * *
 ************************************************************************/
void SDRAM_Check(void)
{
    pSDRAM = (uint32_t *)SDRAM_BANK_ADDR;
    long long count = 0;
    long long sdram_count = 0;

    printf("开始写入SDRAM\n");
    for (sdram_count = 0; sdram_count < SDRAM_SIZE; sdram_count++)
    {
        *pSDRAM = RadomBuffer[count];
        count++;
        pSDRAM++;
        
        if (count >= MAX_SDRAM_TEST_SIZE)
        {
            count = 0;
        }
    }
    printf("写入总字节数:%d\n", (uint32_t)pSDRAM - SDRAM_BANK_ADDR);

    count = 0;
    pSDRAM = (uint32_t *)SDRAM_BANK_ADDR;
    printf("开始读取SDRAM并与原随机数比较\n");
    sdram_count = 0;
    for (; sdram_count < SDRAM_SIZE; sdram_count++)
    {
        if (*pSDRAM != RadomBuffer[count])
        {
            printf("数据比较错误——退出~\n");
            break;
        }
        count++;
        pSDRAM++;
        if (count >= MAX_SDRAM_TEST_SIZE)
        {
            count = 0;
        }
    }

    printf("比较通过总字节数:%d\n", (uint32_t)pSDRAM - SDRAM_BANK_ADDR);

    if (sdram_count == SDRAM_SIZE)
    {
        // LED_GREEN;
        printf("SDRAM测试成功\n");
    }
    else
    {
        // LED_RED;
        printf("SDRAM测试失败\n");
    }
}

sdram.h

#pragma once

#include "stm32f4xx.h"
#include <stdio.h>

#define IS42S16400J_SIZE 0x800000  //400000*16bits = 0x800000  ,8M字节


/*SDRAM 的bank选择*/  
#define FMC_BANK_SDRAM            FMC_Bank2_SDRAM  
#define FMC_COMMAND_TARGET_BANK   FMC_SDRAM_CMD_TARGET_BANK2

/**
  * @brief  FMC SDRAM 数据基地址
  */   
#define SDRAM_BANK_ADDR     ((uint32_t)0xD0000000)//如果使用bank1,0xC0000000
  
/**
  * @brief  FMC SDRAM 数据宽度
  */  
#define SDRAM_MEMORY_WIDTH    FMC_SDRAM_MEM_BUS_WIDTH_16 


#define SDRAM_TIMEOUT                    ((uint32_t)0xFFFF)


#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) 


void SDRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize);
void SDRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize);
void SDRAM_InitSequence(void);



引用

相关博客
STM32 FMC篇-SDRAM(IS42S16400J)
STM32F429DISC开发板SDRAM(IS42S16400J)实验—基于STM32cubeMX HAL库
STM32F429驱动SDRAM(IS42S16400J)详解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值