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

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

文章目录

  • 前言
  • 一、SDRAM介绍
  • 1.在相关博客推荐处看到的这一篇,看了确实会对sdram的配置有一个基础的了解。
  • 2. IS42S16400J-7
  • 二、sdram时钟
  • 三、cubemx配置
  • 四、sdram初始化
  • 五、测试
  • 引用

  • 前言

    随着现代电子设备复杂度的不断增加,对于内存的需求也日益增长。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)详解

    作者:十一月海拒绝河

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32: FMC的简单使用_SDRASM(IS42S16400J)的ram扩展

    发表回复