☰
STM32外扩SRAM
2026/10/17 8:24:27 网站建设 项目流程

第1章 基础知识

Cortex-M4 处理器使用 32 位地址总线,这意味着它能够直接访问4GB(0x00000000 到 0xFFFFFFFF)的地址空间。ARM 公司为了方便芯片厂商设计和提高软件的可移植性,为这 4GB 空间制定了一个标准的“模板”划分规则,而具体的芯片厂商(如 ST 或 GD32)会在这个模板上填充自己的硬件。总之,单片机是通过地址来访问寄存器、FLASH,ARM寻址范围4GB。

1.1 Cortex-M4 内核的 4GB 寻址空间划分

1.1.1 CODE 区(代码区)

  1. 地址范围:0x00000000-0x1FFFFFFF(512MB)
  2. 作用:主要用于存放程序代码和常量数据。
  3. 实际情况:在 GD32 芯片中,这里通常映射的是片内的 Flash(闪存)。比如您的程序下载进去后,就放在这里运行。
  4. 特点:支持代码直接运行,且通常有预读缓存机制,以加快 CPU 取指令的速度。

1.1.2 SRAM 区(片内数据区)

  1. 地址范围:0x20000000-0x3FFFFFFF(512MB)
  2. 作用:用于存放程序运行时产生的数据,比如全局变量、局部变量、堆栈(Stack)等。
  3. 实际情况:对应 GD32 芯片内部的物理 SRAM。例如,如果一颗 GD32 芯片有 96KB 的 SRAM,这 96KB 就会映射在0x20000000开始的区域。
  4. 特点:读写速度极快,掉电后数据丢失。

1.1.3 片上外设区(Peripheral)

  1. 地址范围:0x40000000-0x5FFFFFFF(512MB)
  2. 作用:所有的片上外设寄存器都映射在这个区域。
  3. 实际情况:当您写代码去控制 GPIO、USART、定时器等时,实际上是在访问这个地址段内的特定地址。
  4. 特点:每个外设占据一段地址,通过读写这些地址来控制硬件的动作。

1.1.4 EXMC 区(外部存储器控制器)

  1. 地址范围:0x60000000-0x9FFFFFFF(1GB)
  2. 作用:这是 GD32 独有的外部存储器扩展接口。
  3. 实际情况:
    1. EXMC是 GD32 对 ARM FSMC 的增强版。
    2. 它允许您通过引脚在芯片外部扩展 SRAM、NAND Flash 或 NOR Flash。
    3. 图中绿色的大区域就是专门留给这些外部存储设备的。访问这里时,MCU 会自动将其转换为外部设备的读写时序。
  4. 注意:虽然这里标了 EXMC,但部分高性能 GD32 芯片的 SDRAM 实际上映射在更靠上的位置(如 0xC0000000)。

1.1.5 未使用区(Reserved)

  1. 地址范围:0xA0000000-0xDFFFFFFF(896MB)
  2. 作用:保留地址空间,目前没有分配具体用途。
  3. 注意:不要尝试访问这部分地址,否则可能会触发“HardFault”硬件错误。部分特定型号的 SDRAM 可能会占用 0xC0000000 开始的地址。

1.1.6 Cortex-M4 内核寄存器区

  1. 地址范围:0xE0000000-0xFFFFFFFF(512MB)
  2. 作用:包含 CPU 核心自身的控制、调试和中断系统。
  3. 实际情况:
    1. NVIC(嵌套向量中断控制器):控制所有中断的优先级和使能。
    2. SysTick:系统滴答定时器,常用于操作系统的任务调度。
    3. MPU / FPU:内存保护单元和浮点运算单元的配置寄存器。

1.2 STM32的片上外设FSMC

STM32 中用于扩展外部存储器的片上外设是 FSMC,而 GD32 中对应的外设称为 EXMC。两者功能类似,都可以作为 MCU 访问外部存储器的总线控制器。

EXMC 主要用于驱动外部扩展的静态存储器,例如 SRAM、NOR Flash 和 NAND Flash;部分 GD32 型号的 EXMC 还支持 SDRAM。但是FSMC 本身只支持静态存储器,而 GD32 的 EXMC 在此基础上扩展了对 SDRAM 的支持。

硬件连接方面,外部 SRAM 只需将其地址线、数据线、片选、读/写使能等信号对应连接到 MCU 的 EXMC 引脚即可完成基本连接。配置好 EXMC 后,外部 SRAM 会被映射到 MCU 的地址空间中,程序可以像访问内部 RAM 一样直接读写外部 SRAM。

1.3 FSMC的地址映射

单片机的外扩 RAM 区域(即 FSMC 地址空间)共划分为四个 Bank:Bank1、Bank2、Bank3 和 Bank4。其中,Bank1专门用于访问静态存储器(如 SRAM、NOR Flash 等),它又被细分为四个子区域(Region),每个子区域拥有独立的片选信号(NE1~NE4),可以分别映射一片独立的 SRAM 芯片。

例如,工程中需要扩展 4 片 SRAM 时,可以将它们的地址线、数据线以及读写控制线并联到 FSMC 的对应引脚上,然后分别使用 Bank1 的四个片选信号 NE1~NE4 来选中不同的 SRAM 芯片。这样,四片 SRAM 就会被映射到四个不同的地址区间,程序通过访问不同的地址段即可读写对应的芯片

1.4 STM32的FSMC外设应用

一个Bank分为4个区域(Region),每个区域表示着不同的外设。每个外设通过不同的GPIO来选中。

每一个Bank的4个区域

STM32端口片选哪个Region区基地址
PD7NE10x60000000
PG9NE20x64000000
PG10NE30x68000000
PG12NE40x6C000000

1.5 STM32操作片上外设(内存映射)

static BYTE g_buffer[1 * 1024] __attribute__((at(0x6C000000), zero_init));

at() : 指定变量存放在绝对地址(外部SRAM起始处)
zero_init: 禁止启动代码在main()之前清零该区域(此时FSMC尚未初始化,
若启动时去写0x6C000000会导致总线错误/硬件错误)
在此,我们只将存储区域开辟了1K的大小。如果你们SRAM芯片的容量大小是1M的,那么这儿就可以写为:1*1024*1024的数组容量。

在程序内部对这块存储区域进行读写操作,就相当于操作外扩的SRAM。或者其他片上外设。

从上图再次验证,我们开辟的存储区域,确实在片上SRAM中。

第2章 工程实践

2.1 头文件

/************************************************************************* * * Copyright (C), 2017-2037, BPG. Co., Ltd. * * 文件名称: EX_SRAM.h * 软件模块: 驱动 * 版 本 号: 1.0 * 生成日期: 2026-10-13 * 作 者: lium * 功 能: 驱动模块头文件 * *************************************************************************/ #ifndef __EX_SRAM__ #define __EX_SRAM__ #ifdef __cplusplus extern "C"{ #endif #include "Drivers.h" void EXSRAMDrvInit(void); void EXSRAMDrvTest(void); #ifdef __cplusplus } #endif #endif /* __EX_SRAM__ */ /************************************************************************* * 改动历史纪录: Revision 1.0, 2026-10-13, lium describe: 初始创建. *************************************************************************/

2.2 源文件

/************************************************************************* * * Copyright (C), 1999-2004, . Co., Ltd. * * 文件名: EX_SRAM.c * 所属模块: 驱动 * 版 本: 1.0 * 创建日期: 2026-10-13 * 作 者: lium * 备 注: 片外SRAM驱动(STM32F103 FSMC) * *************************************************************************/ #include "EX_SRAM.h" /*--------------------------------------------------------------------------- * 注意: GD32 与 STM32 的存储区编号不同 * GD32 EXMC Bank0 Region0~3 (NE0~NE3), 0x6C000000 = GD32 的 Region3/NE3 * STM32 FSMC Bank1 Region1~4 (NE1~NE4), 0x6C000000 = STM32 的 Region4/NE4 * 两者片选引脚同为 PG12, 物理连线一致, 只是编号偏移了 1。 *-------------------------------------------------------------------------*/ #define BANK1_REGION4_ADDR 0x6C000000 /* Bank1 Region4(NE4)起始地址 */ #define EX_SRAM_BUFFER_SIZE (1 * 1024 * 1024) /* 外部SRAM容量, 1M字节 */ #define EX_SRAM_BEGIN_ADDR (BANK1_REGION4_ADDR) #define EX_SRAM_END_ADDR (BANK1_REGION4_ADDR + EX_SRAM_BUFFER_SIZE - 1) /* 0x6C0FFFFF */ /* FSMC SRAM句柄 */ static SRAM_HandleTypeDef s_hsram; /*--------------------------------------------------------------------------- * 函数名: EXSRAM_ConfigFSMCGPIO * 功 能: 配置FSMC相关GPIO引脚(地址线/数据线/控制线) * 参 数: 无 * 返 回: 无 *-------------------------------------------------------------------------*/ static void EXSRAM_ConfigFSMCGPIO(void) { GPIO_InitTypeDef gpioInitStruct; /* 使能相关GPIO时钟 */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOG_CLK_ENABLE(); /* FSMC引脚统一配置为复用推挽输出, 最高速度 */ gpioInitStruct.Mode = GPIO_MODE_AF_PP; gpioInitStruct.Speed = GPIO_SPEED_FREQ_HIGH; /* GPIOF: 地址线 A0~A9 (PF0~PF5, PF12~PF15) */ gpioInitStruct.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, &gpioInitStruct); /* GPIOG: 地址线 A10~A15 (PG0~PG5) + 片选 FSMC_NE4 (PG12) */ gpioInitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_12; HAL_GPIO_Init(GPIOG, &gpioInitStruct); /* GPIOD: 地址线 A16~A18 (PD11~PD13) + 数据线 D0~D3/D13~D15 * + 读/写信号 FSMC_NOE(PD4) / FSMC_NWE(PD5) */ gpioInitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | 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(GPIOD, &gpioInitStruct); /* GPIOE: 数据线 D4~D12 (PE7~PE15) + 字节使能 FSMC_NBL0(PE0)/FSMC_NBL1(PE1) */ gpioInitStruct.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, &gpioInitStruct); } /*--------------------------------------------------------------------------- * 函数名: EXSRAM_ConfigBank1Region4 * 功 能: 配置并启用FSMC Bank1 Region4(NE4, 0x6C000000) * 参 数: 无 * 返 回: 无 *-------------------------------------------------------------------------*/ static void EXSRAM_ConfigBank1Region4(void) { FSMC_NORSRAM_TimingTypeDef timing; FSMC_NORSRAM_InitTypeDef init; /* 使能FSMC时钟 */ __HAL_RCC_FSMC_CLK_ENABLE(); /* 异步SRAM读写时序(模式A) * 注意: 数值n对应(n+1)个HCLK周期, 需按外部SRAM数据手册与HCLK频率调整 */ timing.AddressSetupTime = 2; /* 地址建立时间 */ timing.AddressHoldTime = 2; /* 地址保持时间 */ timing.DataSetupTime = 4; /* 数据建立时间 */ timing.BusTurnAroundDuration = 0; /* 总线周转时间(仅复用模式使用) */ timing.CLKDivision = 0; /* 同步时钟分频(异步模式无效) */ timing.DataLatency = 0; /* 同步数据延迟(异步模式无效) */ timing.AccessMode = FSMC_ACCESS_MODE_A; /* Bank1 Region4(NE4)配置 */ init.NSBank = FSMC_NORSRAM_BANK4; /* 使用Region4 */ init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; /* 地址/数据不复用 */ init.MemoryType = FSMC_MEMORY_TYPE_SRAM; /* 存储器类型: SRAM */ init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; /* 数据宽度: 16位 */ init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; /* 禁用突发访问 */ init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW; /* 等待信号低电平有效 */ init.WrapMode = FSMC_WRAP_MODE_DISABLE; /* 禁用回绕突发 */ init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; /* 等待信号时序 */ init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; /* 使能写操作 */ init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; /* 禁用等待信号 */ init.ExtendedMode = FSMC_EXTENDED_MODE_DISABLE; /* 禁用扩展模式 */ init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE; /* 禁用异步等待 */ init.WriteBurst = FSMC_WRITE_BURST_DISABLE; /* 禁用写突发 */ init.PageSize = FSMC_PAGE_SIZE_NONE; /* 页大小: 无 */ /* FSMC控制寄存器基地址 */ s_hsram.Instance = FSMC_NORSRAM_DEVICE; s_hsram.Extended = FSMC_NORSRAM_EXTENDED_DEVICE; /* 初始化并启用Bank1 Region4 */ s_hsram.Init = init; HAL_SRAM_Init(&s_hsram, &timing, &timing); } /*--------------------------------------------------------------------------- * 函数名: EXSRAMDrvInit * 功 能: 外部SRAM初始化 * 参 数: 无 * 返 回: 无 *-------------------------------------------------------------------------*/ void EXSRAMDrvInit(void) { EXSRAM_ConfigFSMCGPIO(); EXSRAM_ConfigBank1Region4(); } /****************************************************/ /* 测试代码 */ /****************************************************/ #define __DEBUG__ #ifdef __DEBUG__ /* 测试缓冲区大小(字节) */ #define BUFFER_SIZE 1024 /* * 定义一个变量g_buffer;将其放置在外扩的SRAM区域上 * * * 外部SRAM测试缓冲区 * at() : 指定变量存放在绝对地址(外部SRAM起始处) * zero_init: 禁止启动代码在main()之前清零该区域(此时FSMC尚未初始化, * 若启动时去写0x6C000000会导致总线错误/硬件错误) */ static BYTE g_buffer[BUFFER_SIZE] __attribute__((at(EX_SRAM_BEGIN_ADDR), zero_init)); /*--------------------------------------------------------------------------- * 函数名: EXSRAMDrvTest * 功 能: 外部SRAM读写自检, 写入/读回数据均通过串口打印 * 参 数: 无 * 返 回: 无 *-------------------------------------------------------------------------*/ void EXSRAMDrvTest(void) { WORD i; printf("********************************\r\n"); printf("********外部SRAM测试开始********\r\n"); printf("********************************\r\n"); /* 写入测试数据并打印 */ printf("写入数据:\r\n"); for (i = 0; i < BUFFER_SIZE; i++) { g_buffer[i] = (BYTE)i; printf("%02X ", g_buffer[i]); if ((i % 16) == 15) { printf("\r\n"); } } if ((BUFFER_SIZE % 16) != 0) { printf("\r\n"); } /* 读回并打印 */ printf("读回数据:\r\n"); for (i = 0; i < BUFFER_SIZE; i++) { printf("%02X ", g_buffer[i]); if ((i % 16) == 15) { printf("\r\n"); } } if ((BUFFER_SIZE % 16) != 0) { printf("\r\n"); } /* 读回校验 */ for (i = 0; i < BUFFER_SIZE; i++) { if (g_buffer[i] != (BYTE)i) { printf("外部SRAM测试失败: 地址0x%X 写入0x%02X 读回0x%02X\r\n", (unsigned int)(EX_SRAM_BEGIN_ADDR + i), (unsigned int)(i & 0xFF), (unsigned int)g_buffer[i]); return; } } printf("**************************************************\r\n"); printf("********外部SRAM测试通过, 外部SRAM测试结束********\r\n"); printf("**************************************************\r\n"); } #endif /* __DEBUG__ */ /************************************************************************* * 修改历史记录: Revision 1.0, 2026-10-13, lium describe: 初始版本. *************************************************************************/

参考文献

FSMC—扩展外部SRAMhttps://doc.embedfire.com/mcu/stm32/f103badao/std/zh/latest/book/FSMC.html

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询