打印
[其他ST产品]

stm32cubeMX配置stm32h743 SDRAM

[复制链接]
楼主: 和下土
手机看帖
扫描二维码
随时随地手机跟帖
61
和下土|  楼主 | 2024-5-1 00:43 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
SelfRefreshTime:自刷新周期,最小是42ns,所以设置为6。

使用特权

评论回复
62
和下土|  楼主 | 2024-5-1 00:43 | 只看该作者
RowCycleDelay(tRC):刷新命令和激活命令之间的延迟,最小值为60,所以设置为7。

使用特权

评论回复
63
和下土|  楼主 | 2024-5-1 00:43 | 只看该作者
WriteRecoveryTime:写命令和预充电命令之间的延迟,在CL=3的情况下,最小是2个clk。

使用特权

评论回复
64
和下土|  楼主 | 2024-5-1 00:44 | 只看该作者
RPDelay(tRP):预充电命令与其它命令之间的延迟,最小15ns,所以此项设置为2。

使用特权

评论回复
65
和下土|  楼主 | 2024-5-1 00:44 | 只看该作者
RCDDelay(tRCD):激活命令与读/写命令之间的延迟,最小15ns,所以设置为2。

使用特权

评论回复
66
和下土|  楼主 | 2024-5-1 00:44 | 只看该作者
配置情况如下:

使用特权

评论回复
67
和下土|  楼主 | 2024-5-1 00:44 | 只看该作者
配置时钟树
STM32G070RB的最高主频到216M,使HCLK = 216Mhz即可:

使用特权

评论回复
68
和下土|  楼主 | 2024-5-1 00:45 | 只看该作者
生成工程设置

使用特权

评论回复
69
和下土|  楼主 | 2024-5-1 00:45 | 只看该作者
代码生成设置
最后设置生成独立的初始化文件:

使用特权

评论回复
70
和下土|  楼主 | 2024-5-1 00:45 | 只看该作者
生成代码
点击GENERATE CODE即可生成MDK-V5工程:

使用特权

评论回复
71
和下土|  楼主 | 2024-5-1 00:45 | 只看该作者
测试SDRAM读写
4.1. 编写SDRAM初始化代码
新建SDRAM驱动文件sdram_fmc_drv.h:

/**
*@file    sdram_fmc_drv.h
*@brief   使用 FMC 操作 SDRAM
*@author  mculover666
*@date    2020-08-27
*@NOTE    此驱动测试 W9825G6KH SDRAM芯片通过
*/

#ifndef _SDRAM_FMC_DRV_H_
#define _SDRAM_FMC_DRV_H_

#include "fmc.h"

#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_Init(void);

#endif /* _SDRAM_FMC_DRV_H_ */

使用特权

评论回复
72
和下土|  楼主 | 2024-5-1 00:45 | 只看该作者
然后在c文件中封装一个向SDRAM发送命令的函数:
static int SDRAM_SendCommand(uint32_t CommandMode, uint32_t Bank, uint32_t RefreshNum, uint32_t RegVal)
{
    uint32_t CommandTarget;
    FMC_SDRAM_CommandTypeDef Command;
   
    if (Bank == 1) {
        CommandTarget = FMC_SDRAM_CMD_TARGET_BANK1;
    } else if (Bank == 2) {
        CommandTarget = FMC_SDRAM_CMD_TARGET_BANK2;
    }
   
    Command.CommandMode = CommandMode;
    Command.CommandTarget = CommandTarget;
    Command.AutoRefreshNumber = RefreshNum;
    Command.ModeRegisterDefinition = RegVal;
   
    if (HAL_SDRAM_SendCommand(&hsdram1, &Command, 0x1000) != HAL_OK) {
        return -1;
    }
   
    return 0;
}

使用特权

评论回复
73
和下土|  楼主 | 2024-5-1 00:45 | 只看该作者
最后实现SDRAM初始化的函数:
void SDRAM_Init(void)
{
    uint32_t temp;
   
    /* 1. 时钟使能命令 */
    SDRAM_SendCommand(FMC_SDRAM_CMD_CLK_ENABLE, 1, 1, 0);
   
    /* 2. 延时,至少100us */
    HAL_Delay(1);
   
    /* 3. SDRAM全部预充电命令 */
    SDRAM_SendCommand(FMC_SDRAM_CMD_PALL, 1, 1, 0);
   
    /* 4. 自动刷新命令 */
    SDRAM_SendCommand(FMC_SDRAM_CMD_AUTOREFRESH_MODE, 1, 8, 0);
   
    /* 5. 配置SDRAM模式寄存器 */   
    temp = (uint32_t)SDRAM_MODEREG_BURST_LENGTH_1            |          //设置突发长度:1
                     SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL     |          //设置突发类型:连续
                     SDRAM_MODEREG_CAS_LATENCY_3             |          //设置CL值:3
                     SDRAM_MODEREG_OPERATING_MODE_STANDARD   |          //设置操作模式:标准
                     SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;              //设置突发写模式:单点访问  
    SDRAM_SendCommand(FMC_SDRAM_CMD_LOAD_MODE, 1, 1, temp);
   
    /* 6. 设置自刷新频率 */
    /*
        SDRAM refresh period / Number of rows)*SDRAM时钟速度 – 20
      = 64000(64 ms) / 4096 *108MHz - 20
      = 1667.5 取值1668
    */
    HAL_SDRAM_ProgramRefreshRate(&hsdram1, 1668);
}

使用特权

评论回复
74
和下土|  楼主 | 2024-5-1 00:46 | 只看该作者
编写SDRAM读写测试代码
接下来在main.c中添加SDRAM测试代码。

此测试代码来自安富莱电子。

① 引入SDRAM驱动头文件:

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "sdram_fmc_drv.h"
/* USER CODE END Includes */

使用特权

评论回复
75
和下土|  楼主 | 2024-5-1 00:46 | 只看该作者
宏定义SDRAM的映射地址以及SDRAM的大小:
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
#define EXT_SDRAM_ADDR          ((uint32_t)0xC0000000)
#define EXT_SDRAM_SIZE                (32 * 1024 * 1024)

uint32_t bsp_TestExtSDRAM(void);
/* USER CODE END 0 */

使用特权

评论回复
76
和下土|  楼主 | 2024-5-1 00:46 | 只看该作者
编写测试函数:
/* USER CODE BEGIN 4 */
/*
*********************************************************************************************************
*        函 数 名: bsp_TestExtSDRAM
*        功能说明: 扫描测试外部SDRAM的全部单元。
*        形    参: 无
*        返 回 值: 0 表示测试通过; 大于0表示错误单元的个数。
*********************************************************************************************************
*/
uint32_t bsp_TestExtSDRAM(void)
{
        uint32_t i;
        uint32_t *pSRAM;
        uint8_t *pBytes;
        uint32_t err;
        const uint8_t ByteBuf[4] = {0x55, 0xA5, 0x5A, 0xAA};

        /* 写SDRAM */
        pSRAM = (uint32_t *)EXT_SDRAM_ADDR;
        for (i = 0; i < EXT_SDRAM_SIZE / 4; i++)
        {
                *pSRAM++ = i;
        }

        /* 读SDRAM */
        err = 0;
        pSRAM = (uint32_t *)EXT_SDRAM_ADDR;
        for (i = 0; i < EXT_SDRAM_SIZE / 4; i++)
        {
                if (*pSRAM++ != i)
                {
                        err++;
                }
        }

        if (err >  0)
        {
                return  (4 * err);
        }

        /* 对SDRAM 的数据求反并写入 */
        pSRAM = (uint32_t *)EXT_SDRAM_ADDR;
        for (i = 0; i < EXT_SDRAM_SIZE / 4; i++)
        {
                *pSRAM = ~*pSRAM;
                pSRAM++;
        }

        /* 再次比较SDRAM的数据 */
        err = 0;
        pSRAM = (uint32_t *)EXT_SDRAM_ADDR;
        for (i = 0; i < EXT_SDRAM_SIZE / 4; i++)
        {
                if (*pSRAM++ != (~i))
                {
                        err++;
                }
        }

        if (err >  0)
        {
                return (4 * err);
        }

        /* 测试按字节方式访问, 目的是验证 FSMC_NBL0 、 FSMC_NBL1 口线 */
        pBytes = (uint8_t *)EXT_SDRAM_ADDR;
        for (i = 0; i < sizeof(ByteBuf); i++)
        {
                *pBytes++ = ByteBuf[i];
        }

        /* 比较SDRAM的数据 */
        err = 0;
        pBytes = (uint8_t *)EXT_SDRAM_ADDR;
        for (i = 0; i < sizeof(ByteBuf); i++)
        {
                if (*pBytes++ != ByteBuf[i])
                {
                        err++;
                }
        }
        if (err >  0)
        {
                return err;
        }
        return 0;
}
/* USER CODE END 4 */

使用特权

评论回复
77
和下土|  楼主 | 2024-5-1 00:46 | 只看该作者
在main函数中调用:
/* USER CODE BEGIN 2 */
printf("STM32F767 SDRAM Test By Mculover666\r\n");

SDRAM_Init();

printf("SDRAM W9825G6KH Init success\r\n");

if (bsp_TestExtSDRAM() == 0) {
    printf("SDRAM Test success\r\n");
} else {
    printf("SDRAM Test fail\r\n");
}
/* USER CODE END 2 */

使用特权

评论回复
78
和下土|  楼主 | 2024-5-1 00:46 | 只看该作者
实验结果
编译,下载到开发板中,在串口助手中查看实验结果:

使用特权

评论回复
79
和下土|  楼主 | 2024-5-1 00:47 | 只看该作者
. 直接指定变量存储到 SDRAM 空间
第4节中的测试方法是使用指针访问SDRAM空间,未免过于麻烦。在实际使用中,可以直接定义一个非常大的数组,将整个数组都存储到SDRAM上,然后动态的使用SDRAM内存空间。

要注意使用这种方法定义变量时,必须在函数外把它定义成全局变量,才可以存储到指定地址上。

使用特权

评论回复
80
和下土|  楼主 | 2024-5-1 00:47 | 只看该作者
测试过程如下:

① 定义全局变量并指定绝对地址:

/* 绝对定位方式访问 SDRAM,这种方式必须定义成全局变量 */
uint8_t testValue __attribute__((at(EXT_SDRAM_ADDR)));

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则