【正点原子STM32】FSMC_FMC——外部SRAM实验(SRAM外部静态随机存取存储器、SRAM读写操作步骤、FSMC灵活的静态存储控制器、FSMC HAL库相关驱动、SRAM模块驱动步骤)

一、SRAM简介
二、FSMC介绍
三、SRAM模块驱动步骤
四、编程实战
五、总结

一、SRAM简介

在这里插入图片描述
外部静态随机存取存储器(SRAM)在嵌入式系统中有多种用途,包括但不限于以下几个方面:

  1. 存储器扩展: 微控制器或微处理器的内置存储器通常有限,而外部 SRAM 可以用于扩展系统的存储容量。这对于需要处理大量数据或运行复杂程序的应用程序非常有用。

  2. 高速缓存: 外部 SRAM 可用作高速缓存,以提高系统的性能和响应速度。高速缓存存储器通常用于存储频繁访问的数据或指令,以减少访问内存的延迟时间。

  3. 临时存储: 外部 SRAM 可用作临时存储器,用于存储临时数据或中间结果。这对于处理大型数据集或执行复杂算法时非常有用。

  4. DMA(直接内存访问)缓冲区: 外部 SRAM 可用作 DMA 缓冲区,用于在系统内部和外部设备之间进行高速数据传输。DMA 控制器可以直接访问外部 SRAM,而不需要 CPU 的干预,从而提高数据传输效率。

  5. 内存映射 I/O: 外部 SRAM 还可以用于实现内存映射 I/O,将外部设备(如外部存储器、传感器、执行器等)映射到系统的地址空间中,以便通过内存访问这些设备。

总的来说,外部 SRAM 提供了额外的存储容量和更高的性能,使得嵌入式系统能够处理更复杂的任务和更大量的数据。
在这里插入图片描述
SRAM(Static Random-Access Memory,静态随机存取存储器)是一种存储数据的半导体存储器,具有许多优点,包括:

  1. 高速访问: SRAM具有非常快的访问速度,使得它非常适合需要快速访问数据的应用程序。典型的访问时间在纳秒级别,比许多其他类型的存储器更快。

  2. 低功耗: 尽管相对于DRAM而言,SRAM的功耗较高,但它仍然比许多其他存储器类型具有较低的功耗。这使得它适用于对功耗敏感的应用,如移动设备和电池供电的系统。

  3. TTL电平兼容: SRAM的输入和输出信号通常与TTL(Transistor-Transistor Logic)电平兼容,这使得它易于集成到各种类型的电子系统中。

  4. 全静态操作: SRAM是全静态操作的,不需要周期性刷新或时钟信号来保持存储的数据。这种特性使得SRAM在需要快速响应和稳定性的应用中表现出色。

  5. 三态输出: SRAM具有三态输出功能,允许多个设备共享同一总线,从而提高系统的灵活性和效率。

  6. 字节控制功能: SRAM通常具有字节控制功能,可以单独读取或写入存储器中的每个字节,这提供了对数据的更精细的控制和管理。

综上所述,SRAM是一种高性能、低功耗、易于集成和操作的存储器类型,适用于许多不同的应用领域,包括计算机内存、嵌入式系统、通信设备和其他需要快速、可靠的数据存储和访问的设备。
在这里插入图片描述
XM8A51216是一种静态随机访问存储器(SRAM),具有以下功能和特性:

  1. 存储容量: 每个地址存储16位(2字节)数据,总容量为1MB(1 Megabyte)。

  2. 地址线和数据线: 具有19根地址线(A0~A18) 和 16根数据线(DQ0~DQ15)。地址线用于选择存储器中的特定地址,而数据线用于输入和输出数据。

  3. 使能信号:

    • CEn(芯片使能信号):用于启用或禁用整个存储器芯片。当CEn为低电平时,存储器处于使能状态。
    • OEn(输出使能信号):用于控制数据的输出(读取)。当OEn为低电平时,允许从存储器读取数据。
    • WEn(写使能信号):用于控制数据的写入。当WEn为低电平时,允许向存储器写入数据。
  4. 字节控制信号:

    • BLEn(低字节控制信号):用于控制DQ0~DQ7 数据线的有效性。当BLEn为低电平时,表示DQ0~DQ7有效。
    • BHEn(高字节控制信号):用于控制DQ8~DQ15 数据线的有效性。当BHEn为低电平时,表示DQ8~DQ15有效。

总的来说,XM8A51216是一种高容量、高性能的SRAM,适用于需要快速随机访问和可靠数据存储的应用,如计算机内存、缓存存储、嵌入式系统等。其具有多种使能信号和字节控制信号,使得它更灵活,适应不同的数据访问和操作需求。
在这里插入图片描述
在这里插入图片描述

SRAM 读写操作步骤

在这里插入图片描述
SRAM读写操作步骤。下面是详细的解释:

  1. 设置地址信号线: 在进行读取或写入操作之前,需要向SRAM发送要访问的目标地址。这通过在地址线上设置相应的地址来完成。

  2. 控制片选信号: SRAM通常与其他器件共享总线,因此在访问SRAM之前需要选择该器件。这通过控制片选信号(CE)来完成。当片选信号为有效低电平时,SRAM被选中。

  3. 决定数据操作方式: 在读取操作中,需要将读使能信号(OE)设置为有效低电平,以表示准备从SRAM读取数据。在写入操作中,需要将写使能信号(WE)设置为有效低电平,以表示准备向SRAM写入数据。

  4. 设置获取数据方式: SRAM中的数据通常被组织为字节。因此,需要确定要访问的是目标地址的高字节还是低字节部分。这通过设置字节掩码信号(BLE和BHE)来完成。当相应的字节掩码信号为有效低电平时,表示要访问的是目标地址的相应字节。

  5. 获取数据: 在读取操作中,SRAM会将目标地址的数据通过数据线输出到主机。在写入操作中,主机会将要写入的数据通过数据线发送到SRAM的目标地址。

这些步骤确保了对SRAM进行有效的读取和写入操作,从而实现了对存储器的可靠访问和数据操作。

二、FSMC介绍

在这里插入图片描述
FSMC(Flexible Static Memory Controller)是一种用于驱动静态存储器的控制器,可以用于连接和控制各种类型的存储器,包括SRAM、NOR Flash、NAND Flash等。

MCU通过HADDR总线(地址总线)与FSMC建立数据关系,通过设置FSMC配置寄存器来配置和控制FSMC的工作模式、时序参数等,从而实现对外部存储器的读写操作。FSMC提供了灵活的配置选项,可以适应不同类型和规格的外部存储器,同时也提供了丰富的时序设置,以确保对外部存储器的稳定和可靠访问。

总之,FSMC作为一种灵活的存储器控制器,为MCU提供了连接和控制外部存储器的能力,为嵌入式系统中对存储器的高效管理和访问提供了重要支持。

  1. 时序控制:

    • FSMC_NE[4:1]: FSMC片选信号,用于选择要访问的存储器块。每个片选信号对应于不同的存储器块,使得MCU可以同时访问多个存储器设备。
    • FSMC_NOE: 输出使能信号,用于控制从存储器读取数据时输出数据的使能。
    • FSMC_NWE: 写使能信号,用于控制向存储器写入数据时写入操作的使能。
    • FSMC_NBL[1:0]: 低字节掩码信号,用于选择要读取或写入的数据字节。在16位数据总线的情况下,可以选择访问的是数据的高字节、低字节还是同时访问两个字节。
  2. 数据交互:

    • FSMC_A[0:25]: 地址线,用于指定要访问的存储器中的特定位置。根据地址的范围和配置,可以访问存储器中的不同单元或数据。
    • FSMC_D[0:15]: 数据线,用于传输数据。在读取操作中,存储器将数据输出到这些数据线上;在写入操作中,MCU将要写入的数据发送到这些数据线上。

通过使用这些信号线,MCU可以与外部的SRAM或其他存储器设备进行高效的数据交互,实现数据的读取和写入操作。FSMC提供了灵活的配置选项和丰富的时序控制功能,使得MCU能够适应不同类型的存储器设备,并实现可靠的数据交换。
在这里插入图片描述
针对NOR/PSRAM控制器和SRAM(比如XM8A51216)的FSMC时序,需要根据具体的存储器和系统要求来设置时序参数。这些参数包括读取和写入操作的时序,如地址建立时间、数据保持时间、读写周期等。下面是一般情况下的一些基本时序参数:

  1. 读取时序参数:

    • 地址建立时间(tAS): 从地址变化到读取数据开始的延迟时间。
    • 地址保持时间(tAH): 在读取过程中,地址信号需要保持的时间。
    • 数据保持时间(tDH): 在读取过程中,数据信号需要保持稳定的时间。
    • 读取周期时间(tRC): 连续读取操作之间的最小间隔时间。
  2. 写入时序参数:

    • 地址建立时间(tAS): 从地址变化到写入数据开始的延迟时间。
    • 地址保持时间(tAH): 在写入过程中,地址信号需要保持的时间。
    • 数据保持时间(tDH): 在写入过程中,数据信号需要保持稳定的时间。
    • 写入周期时间(tWC): 连续写入操作之间的最小间隔时间。

除了以上时序参数外,还需要考虑到信号的稳定时间、时钟速率等因素。具体的时序参数需要参考存储器的数据手册和FSMC控制器的技术文档,并根据实际情况进行设置和调整。正确配置时序参数可以确保系统稳定运行,并提高数据读写的可靠性和性能。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述内核地址映射指的是将外部存储器的地址空间映射到CPU的内存地址空间,以便CPU可以通过内存地址来访问外部存储器的数据。对于FSMC控制器,它可以控制外部存储器(如SRAM、NOR Flash等)的访问,并将外部存储器的地址映射到CPU的内存地址空间中。

在STM32系列的MCU中,FSMC控制器通过地址线(FSMC_A[0:25])和数据线(FSMC_D[0:15])与外部存储器进行通信。为了让CPU能够通过内存地址来访问外部存储器,需要将外部存储器的地址范围映射到CPU的内存地址空间中的某个区域。

具体的内核地址映射配置需要在系统初始化阶段完成,通常通过设置MMU(内存管理单元)或者直接配置存储器映射寄存器来实现。在STM32中,可以通过配置MMU或者修改内存映射表(Memory Map)来实现内核地址映射。

例如,可以将外部存储器的地址范围映射到CPU的内存地址空间中的某个片区,比如将外部存储器的地址范围映射到内存地址0x60000000开始的区域。这样,CPU就可以通过内存地址0x60000000开始的地址范围来访问外部存储器的数据。

总之,内核地址映射是通过配置MMU或者直接修改内存映射表来实现的,通过将外部存储器的地址空间映射到CPU的内存地址空间中,从而实现CPU对外部存储器的访问。
在这里插入图片描述
在STM32中,使用FSMC(Flexible Static Memory Controller)控制外部SRAM(Static Random Access Memory)时,可以将外部SRAM的存储单元映射到STM32的内部寻址空间。通过设置合适的基地址(SRAM_BASE_ADDR),可以让外部SRAM的地址范围映射到STM32的内存地址空间中。

为了向外部SRAM的某个地址写入数据,可以通过以下代码实现:

*(uint16_t *)(SRAM_BASE_ADDR + addr) = data;

这行代码将数据写入到外部SRAM的指定地址。其中,SRAM_BASE_ADDR 是外部SRAM的基地址,在设置时需要根据实际连接和配置情况确定。addr 是要写入数据的地址偏移量,data 是要写入的数据。

同样地,如果要从外部SRAM的某个地址读取数据,可以使用类似的方法:

data = *(uint16_t *)(SRAM_BASE_ADDR + addr);

这行代码将从外部SRAM的指定地址读取数据并存储到变量 data 中。

需要注意的是,对外部SRAM进行读写操作时,要确保地址和数据的类型正确匹配,以及SRAM_BASE_ADDR 的设置正确。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、SRAM模块驱动步骤

在这里插入图片描述
SRAM模块驱动步骤。下面是对每个步骤的简要说明:

  1. 配置FSMC:

    • 启用FSMC时钟:在使用FSMC之前,需要确保FSMC时钟已经使能。
    • 配置FSMC相关的IO:将FSMC的控制信号和数据线连接到外部SRAM上,并设置为复用输出模式。同时,确保这些IO的时钟也被使能。
  2. 设置FSMC相关参数:

    • 配置存储器工作模式:根据外部SRAM的特性,选择合适的工作模式。通常是选择 NOR/PSRAM 模式。
    • 配置位宽:根据外部SRAM的数据位宽,设置FSMC的位宽参数。
    • 设置读写时序参数:根据外部SRAM的时序要求,设置FSMC的读写时序参数,包括地址建立时间、数据保持时间等。
  3. 进行数据访问:

    • 确定操作外部内存的首地址:根据外部SRAM在FSMC地址空间的映射,确定要访问的外部内存的首地址。

直接指定变量存储到SRAM空间:

  • 使用 __attribute__((at(SRAM_BASE_ADDR))) 来将指定的变量存储到外部SRAM空间。这样做可以确保变量被放置在指定的外部SRAM地址空间中。
  • 然后可以像操作普通变量一样对外部SRAM中的数据进行读写操作。

需要注意的是,确保配置参数和操作都符合外部SRAM的规格和要求,以确保数据的正确性和稳定性。同时,还要注意外部SRAM的地址映射和访问权限等问题。

四、编程实战

sram.c

#include "./BSP/SRAM/sram.h"
#include "./SYSTEM/usart/usart.h"

SRAM_HandleTypeDef g_sram_handler; //SRAM句柄

/**
 * @brief       初始化 外部SRAM
 * @param       无
 * @retval      无
 */
void sram_init(void)
{
    GPIO_InitTypeDef GPIO_Initure;
    FSMC_NORSRAM_TimingTypeDef fsmc_readwritetim;

    SRAM_CS_GPIO_CLK_ENABLE();      /* SRAM_CS脚时钟使能 */
    SRAM_WR_GPIO_CLK_ENABLE();      /* SRAM_WR脚时钟使能 */
    SRAM_RD_GPIO_CLK_ENABLE();      /* SRAM_RD脚时钟使能 */
    __HAL_RCC_FSMC_CLK_ENABLE();    /* 使能FSMC时钟 */
    __HAL_RCC_GPIOD_CLK_ENABLE();   /* 使能GPIOD时钟 */
    __HAL_RCC_GPIOE_CLK_ENABLE();   /* 使能GPIOE时钟 */
    __HAL_RCC_GPIOF_CLK_ENABLE();   /* 使能GPIOF时钟 */
    __HAL_RCC_GPIOG_CLK_ENABLE();   /* 使能GPIOG时钟 */

    GPIO_Initure.Pin = SRAM_CS_GPIO_PIN;
    GPIO_Initure.Mode = GPIO_MODE_AF_PP;       
    GPIO_Initure.Pull = GPIO_PULLUP;           
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; 
    HAL_GPIO_Init(SRAM_CS_GPIO_PORT, &GPIO_Initure); /* SRAM_CS引脚模式设置 */

    GPIO_Initure.Pin = SRAM_WR_GPIO_PIN;
    HAL_GPIO_Init(SRAM_WR_GPIO_PORT, &GPIO_Initure); /* SRAM_WR引脚模式设置 */

    GPIO_Initure.Pin = SRAM_RD_GPIO_PIN;
    HAL_GPIO_Init(SRAM_RD_GPIO_PORT, &GPIO_Initure); /* SRAM_CS引脚模式设置 */

    
    /* PD0,1,4,5,8~15 */
    GPIO_Initure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_8 | GPIO_PIN_9 | 
                       GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 |
                       GPIO_PIN_14 | GPIO_PIN_15;
    GPIO_Initure.Mode = GPIO_MODE_AF_PP;       /* 推挽复用 */
    GPIO_Initure.Pull = GPIO_PULLUP;           /* 上拉 */
    GPIO_Initure.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
    HAL_GPIO_Init(GPIOD, &GPIO_Initure);

    /* PE0,1,7~15 */
    GPIO_Initure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 |
                       GPIO_PIN_10 | GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |
                       GPIO_PIN_15;
    HAL_GPIO_Init(GPIOE, &GPIO_Initure);

    /* PF0~5,12~15 */
    GPIO_Initure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 |
                       GPIO_PIN_5 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
    HAL_GPIO_Init(GPIOF, &GPIO_Initure);

    /* PG0~5,10 */
    GPIO_Initure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5;
    HAL_GPIO_Init(GPIOG, &GPIO_Initure);

    g_sram_handler.Instance = FSMC_NORSRAM_DEVICE;
    g_sram_handler.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;

    g_sram_handler.Init.NSBank = (SRAM_FSMC_NEX == 1) ? FSMC_NORSRAM_BANK1 : \
                                 (SRAM_FSMC_NEX == 2) ? FSMC_NORSRAM_BANK2 : \
                                 (SRAM_FSMC_NEX == 3) ? FSMC_NORSRAM_BANK3 : 
                                                        FSMC_NORSRAM_BANK4; /* 根据配置选择FSMC_NE1~4 */
    g_sram_handler.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;     /* 地址/数据线不复用 */
    g_sram_handler.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;                 /* SRAM */
    g_sram_handler.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;    /* 16位数据宽度 */
    g_sram_handler.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;   /* 是否使能突发访问,仅对同步突发存储器有效,此处未用到 */
    g_sram_handler.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号的极性,仅在突发模式访问下有用 */
    g_sram_handler.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;      /* 存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT */
    g_sram_handler.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;       /* 存储器写使能 */
    g_sram_handler.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;              /* 等待使能位,此处未用到 */
    g_sram_handler.Init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE;          /* 读写使用相同的时序 */
    g_sram_handler.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;  /* 是否使能同步传输模式下的等待信号,此处未用到 */
    g_sram_handler.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;              /* 禁止突发写 */

    /* FSMC读时序控制寄存器 */
    fsmc_readwritetim.AddressSetupTime = 0x00;                              /* 地址建立时间(ADDSET)为1个HCLK 1/72M=13.8ns */
    fsmc_readwritetim.AddressHoldTime = 0x00;                               /* 地址保持时间(ADDHLD)模式A未用到 */
    fsmc_readwritetim.DataSetupTime = 0x01;                                 /* 数据保存时间为2个HCLK = 2*13.8 = 27.6ns */
    fsmc_readwritetim.BusTurnAroundDuration = 0X00;
    fsmc_readwritetim.AccessMode = FSMC_ACCESS_MODE_A;                      /* 模式A */
    HAL_SRAM_Init(&g_sram_handler, &fsmc_readwritetim, &fsmc_readwritetim);
}

/**
 * @brief       往SRAM指定地址写入指定长度数据
 * @param       pbuf    : 数据存储区
 * @param       addr    : 开始写入的地址(最大32bit)
 * @param       datalen : 要写入的字节数(最大32bit)
 * @retval      无
 */
void sram_write(uint8_t *pbuf, uint32_t addr, uint32_t datalen)
{
    for (; datalen != 0; datalen--)
    {
        *(volatile uint8_t *)(SRAM_BASE_ADDR + addr) = *pbuf;
        addr++;
        pbuf++;
    }
}

/**
 * @brief       从SRAM指定地址读取指定长度数据
 * @param       pbuf    : 数据存储区
 * @param       addr    : 开始读取的地址(最大32bit)
 * @param       datalen : 要读取的字节数(最大32bit)
 * @retval      无
 */
void sram_read(uint8_t *pbuf, uint32_t addr, uint32_t datalen)
{
    for (; datalen != 0; datalen--)
    {
        *pbuf++ = *(volatile uint8_t *)(SRAM_BASE_ADDR + addr);
        addr++;
    }
}

/*******************测试函数**********************************/

/**
 * @brief       测试函数 在SRAM指定地址写入1个字节
 * @param       addr    : 开始写入的地址(最大32bit)
 * @param       data    : 要写入的字节
 * @retval      无
 */
void sram_test_write(uint32_t addr, uint8_t data)
{
    sram_write(&data, addr, 1); /* 写入1个字节 */
}

/**
 * @brief       测试函数 在SRAM指定地址读取1个字节
 * @param       addr    : 开始读取的地址(最大32bit)
 * @retval      读取到的数据(1个字节)
 */
uint8_t sram_test_read(uint32_t addr)
{
    uint8_t data;
    sram_read(&data, addr, 1); /* 读取1个字节 */
    return data;
}

sram.h

#ifndef __SRAM_H
#define __SRAM_H

#include "./SYSTEM/sys/sys.h"


/******************************************************************************************/
/* SRAM WR/RD/CS 引脚 定义 
 * SRAM_D0~D15 及 地址线,由于引脚太多,就不在这里定义了,直接在SRAM_init里面修改.所以在移植的时候,
 * 除了改这3个IO口, 还得改SRAM_init里面的 数据线 和 地址线 所在的IO口.
 */

#define SRAM_WR_GPIO_PORT               GPIOD
#define SRAM_WR_GPIO_PIN                GPIO_PIN_5
#define SRAM_WR_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)   /* 所在IO口时钟使能 */

#define SRAM_RD_GPIO_PORT               GPIOD
#define SRAM_RD_GPIO_PIN                GPIO_PIN_4
#define SRAM_RD_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0)   /* 所在IO口时钟使能 */

/* SRAM_CS(需要根据SRAM_FSMC_NEX设置正确的IO口) 引脚 定义 */
#define SRAM_CS_GPIO_PORT                GPIOG
#define SRAM_CS_GPIO_PIN                 GPIO_PIN_10
#define SRAM_CS_GPIO_CLK_ENABLE()        do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0)   /* 所在IO口时钟使能 */

/* FSMC相关参数 定义 
 * 注意: 我们默认是通过FSMC块3来连接SRAM, 块1有4个片选: FSMC_NE1~4
 *
 * 修改SRAM_FSMC_NEX, 对应的SRAM_CS_GPIO相关设置也得改
 */
#define SRAM_FSMC_NEX           3         /* 使用FSMC_NE3接SRAM_CS,取值范围只能是: 1~4 */

/******************************************************************************************/

/* SRAM基地址, 根据 SRAM_FSMC_NEX 的设置来决定基址地址
 * 我们一般使用FSMC的块1(BANK1)来驱动SRAM, 块1地址范围总大小为256MB,均分成4块:
 * 存储块1(FSMC_NE1)地址范围: 0X6000 0000 ~ 0X63FF FFFF
 * 存储块2(FSMC_NE2)地址范围: 0X6400 0000 ~ 0X67FF FFFF
 * 存储块3(FSMC_NE3)地址范围: 0X6800 0000 ~ 0X6BFF FFFF
 * 存储块4(FSMC_NE4)地址范围: 0X6C00 0000 ~ 0X6FFF FFFF
 */
#define SRAM_BASE_ADDR         (0X60000000 + (0X4000000 * (SRAM_FSMC_NEX - 1)))

extern SRAM_HandleTypeDef g_sram_handler;    /* SRAM句柄 */


void sram_init(void);
void sram_write(uint8_t *pbuf, uint32_t addr, uint32_t datalen);
void sram_read(uint8_t *pbuf, uint32_t addr, uint32_t datalen);

uint8_t sram_test_read(uint32_t addr);
void sram_test_write(uint32_t addr, uint8_t data);

#endif

main.c

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./USMART/usmart.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/KEY/key.h"
#include "./BSP/SRAM/sram.h"


/* 测试用数组, 起始地址为: SRAM_BASE_ADDR */
#if (__ARMCC_VERSION >= 6010050)
uint32_t g_test_buffer[250000] __attribute__((section(".bss.ARM.__at_0x68000000")));
#else
uint32_t g_test_buffer[250000] __attribute__((at(SRAM_BASE_ADDR)));
#endif

/**
 * @brief       外部内存测试(最大支持1M字节内存测试)
 * @param       无
 * @retval      无
 */
void fsmc_sram_test(uint16_t x, uint16_t y)
{
    uint32_t i = 0;
    uint8_t temp = 0;
    uint8_t sval = 0; /* 在地址0读到的数据 */

    lcd_show_string(x, y, 239, y + 16, 16, "Ex Memory Test:   0KB", BLUE);

    /* 每隔4K字节,写入一个数据,总共写入256个数据,刚好是1M字节 */
    for (i = 0; i < 1024 * 1024; i += 4096)
    {
        sram_write(&temp, i, 1);
        temp++;
    }

    /* 依次读出之前写入的数据,进行校验 */
    for (i = 0; i < 1024 * 1024; i += 4096)
    {
        sram_read(&temp, i, 1);

        if (i == 0)
        {
            sval = temp;
        }
        else if (temp <= sval)
        {
            break; /* 后面读出的数据一定要比第一次读到的数据大 */
        }
        lcd_show_xnum(x + 15 * 8, y, (uint16_t)(temp - sval + 1) * 4, 4, 16, 0, BLUE); /* 显示内存容量 */
    }
}

int main(void)
{
    uint8_t key;
    uint8_t i = 0;
    uint32_t ts = 0;

    HAL_Init();                         /* 初始化HAL库 */
    sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
    delay_init(72);                     /* 延时初始化 */
    usart_init(115200);                 /* 串口初始化为115200 */
    usmart_dev.init(72);                /* 初始化USMART */
    led_init();                         /* 初始化LED */
    lcd_init();                         /* 初始化LCD */
    key_init();                         /* 初始化按键 */
    sram_init();                        /* SRAM初始化 */

    lcd_show_string(30,  50, 200, 16, 16, "STM32", RED);
    lcd_show_string(30,  70, 200, 16, 16, "SRAM TEST", RED);
    lcd_show_string(30,  90, 200, 16, 16, "ATOM@ALIENTEK", RED);
    lcd_show_string(30, 110, 200, 16, 16, "KEY0:Test Sram", RED);
    lcd_show_string(30, 130, 200, 16, 16, "KEY1:TEST Data", RED);

    for (ts = 0; ts < 250000; ts++)
    {
        g_test_buffer[ts] = ts; /* 预存测试数据 */
    }

    while (1)
    {
        key = key_scan(0); /* 不支持连按 */

        if (key == KEY0_PRES)
        {
            fsmc_sram_test(30, 150);    /* 测试SRAM容量 */
        }
        else if (key == KEY1_PRES)      /* 打印预存测试数据 */
        {
            for (ts = 0; ts < 250000; ts++)
            {
                lcd_show_xnum(30, 170, g_test_buffer[ts], 6, 16, 0, BLUE); /* 显示测试数据 */
            }
        }
        else
        {
            delay_ms(10);
        }

        i++;

        if (i == 20)
        {
            i = 0;
            LED0_TOGGLE(); /* LED0闪烁 */
        }
    }
}

在这里插入图片描述

五、总结

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 24
    点赞
  • 42
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

咖喱年糕

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值