打印
[其他ST产品]

stm32cubeMX配置stm32h743 SDRAM

[复制链接]
2421|81
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本文记录了如何使用stm32cubeMX配置stm32h743iit6的硬件FMC外设与与 SDRAM 通信(W9825G6KH)。具体比较深的内容不作介绍。

1.准备工作
硬件准备

这里使用的正点原子的stm32h743开发板,板载的是一片SDRAM,型号为w9825G6KH,大小为32MB。



软件准备
需要准备一份 W9825G6KH-6 的数据手册。
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/Believeziwo/article/details/131372421

使用特权

评论回复
沙发
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:24 编辑

使用STM32CubeMX生成工程
选择芯片型号
打开STM32CubeMX,打开MCU选择器,选择芯片型号。

使用特权

评论回复
板凳
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:24 编辑

配置时钟源
如果选择使用外部高速时钟(HSE),则需要在System Core中配置RCC;
如果使用默认内部时钟(HSI),这一步可以略过;

使用特权

评论回复
地板
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:25 编辑

这里我都使用外部时钟:

使用特权

评论回复
5
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:26 编辑

配置FMC外设

开发板上SDRAM(W9825G6KH)的原理图如下

使用特权

评论回复
6
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:26 编辑

原子的板子设计和cubemx默认配置并不符合,需要手动检查修改GPIO(引脚基本不用修改,但最好核对一下)。

使用特权

评论回复
7
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:26 编辑

1

使用特权

评论回复
8
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:27 编辑


目前首先是在上图的图形界面中配置引脚,图中的图钉形状的在引脚上了代表已经选上了。

使用特权

评论回复
9
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:28 编辑

根据这些信息,配置SDRAM的基本配置

使用特权

评论回复
10
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:28 编辑

配置时钟树

使用特权

评论回复
11
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:29 编辑

生成工程设置

使用特权

评论回复
12
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:29 编辑

生成工程

点击GENERATE CODE即可生成MDK-V5工程:



使用特权

评论回复
13
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:29 编辑

生成的代码配置参数必须正确,这个地方一定要2分频。

使用特权

评论回复
14
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:30 编辑

测试SDRAM读写
3.1 编写SDRAM初始化代码
新建SDRAM初始化文件sdram.h
/* USER CODE BEGIN Private defines */
#define Bank5_SDRAM_ADDR    ((uint32_t)0xC0000000)
//SDRAM配置参数
#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)


uint8_t SDRAM_Send_Cmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint16_t regval);
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram);

使用特权

评论回复
15
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:30 编辑

然后在sdram.c文件中封装一个向SDRAM发送命令的函数:/* USER CODE BEGIN 0 */
//发送SDRAM初始化序列
void SDRAM_Initialization_Sequence(SDRAM_HandleTypeDef *hsdram)
{
        uint32_t temp=0;

    //SDRAM控制器初始化完成以后还需要按照如下顺序初始化SDRAM
  SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_CLK_ENABLE,1,0); //时钟配置使能
  HAL_Delay(2);                                  //至少延时200us
        SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_PALL,1,0);       //对所有存储区预充电
  SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_AUTOREFRESH_MODE,8,0);//设置自刷新次数
    //配置模式寄存器,SDRAM的bit0~bit2为指定突发访问的长度,
        //bit3为指定突发访问的类型,bit4~bit6为CAS值,bit7和bit8为运行模式
        //bit9为指定的写突发模式,bit10和bit11位保留位
        temp=(uint32_t)SDRAM_MODEREG_BURST_LENGTH_1          |        //设置突发长度:1(可以是1/2/4/8)
              SDRAM_MODEREG_BURST_TYPE_SEQUENTIAL   |        //设置突发类型:连续(可以是连续/交错)
              SDRAM_MODEREG_CAS_LATENCY_3           |        //设置CAS值:3(可以是2/3)
              SDRAM_MODEREG_OPERATING_MODE_STANDARD |   //设置操作模式:0,标准模式
              SDRAM_MODEREG_WRITEBURST_MODE_SINGLE;     //设置突发写模式:1,单点访问
    SDRAM_Send_Cmd(0,FMC_SDRAM_CMD_LOAD_MODE,1,temp);   //设置SDRAM的模式寄存器
   
    //刷新频率计数器(以SDCLK频率计数),计算方法:
        //COUNT=SDRAM刷新周期/行数-20=SDRAM刷新周期(us)*SDCLK频率(Mhz)/行数
    //我们使用的SDRAM刷新周期为64ms,SDCLK=200/2=100Mhz,行数为8192(2^13).
        //所以,COUNT=64*1000*100/8192-20=761
        HAL_SDRAM_ProgramRefreshRate(&hsdram1,761);       
}       

//向SDRAM发送命令
//bankx:0,向BANK5上面的SDRAM发送指令
//      1,向BANK6上面的SDRAM发送指令
//cmd:指令(0,正常模式/1,时钟配置使能/2,预充电所有存储区/3,自动刷新/4,加载模式寄存器/5,自刷新/6,掉电)
//refresh:自刷新次数
//regval:模式寄存器的定义
//返回值:0,正常;1,失败.
uint8_t SDRAM_Send_Cmd(uint8_t bankx,uint8_t cmd,uint8_t refresh,uint16_t regval)
{
    uint32_t target_bank=0;
    FMC_SDRAM_CommandTypeDef Command;
   
    if(bankx==0) target_bank=FMC_SDRAM_CMD_TARGET_BANK1;      
    else if(bankx==1) target_bank=FMC_SDRAM_CMD_TARGET_BANK2;   
    Command.CommandMode=cmd;                //命令
    Command.CommandTarget=target_bank;      //目标SDRAM存储区域
    Command.AutoRefreshNumber=refresh;      //自刷新次数
    Command.ModeRegisterDefinition=regval;  //要写入模式寄存器的值
    if(HAL_SDRAM_SendCommand(&hsdram1,&Command,0XFFFF)==HAL_OK) //向SDRAM发送命令
    {
        return 0;  
    }
    else return 1;   
}

/* USER CODE END 0 */

使用特权

评论回复
16
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:31 编辑

在fmc.c文件中的函数void MX_FMC_Init(void)里面插入如下函数:SDRAM_Initialization_Sequence(&hsdram1);//发送SDRAM初始化序列

使用特权

评论回复
17
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:31 编辑

编写SDRAM读写测试代码

① 引入SDRAM驱动头文件:

/* Private includes ----------------------------------------------------------*/

/* USER CODE BEGIN Includes */

#include <stdio.h>

#include "sdram.h"

/* USER CODE END Includes */

使用特权

评论回复
18
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:31 编辑

宏定义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 */

使用特权

评论回复
19
和下土|  楼主 | 2024-4-30 23:43 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:33 编辑

编写测试函数:/* 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;
        }

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

使用特权

评论回复
20
和下土|  楼主 | 2024-4-30 23:44 | 只看该作者
本帖最后由 和下土 于 2024-5-1 00:34 编辑

在main函数中调用:/* USER CODE BEGIN 2 */
printf("STM32h743 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 */

使用特权

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

本版积分规则

102

主题

1061

帖子

0

粉丝