STM32进阶 FSMC应用案例:扩展外部 SRAM

需求描述

使用FSMC扩展外部SRAM。然后把内存数据存储到外部SRAM中。

STM32F1 系列的芯片不支持扩展SDRAM(STM32F429 系列支持),它仅支持使用 FSMC 外设扩展 SRAM。由于引脚数量的限制,只有 STM32F103ZE 或以上型号的芯片才可以扩展外部 SRAM。

IS62WV51216

19根地址线

16根数据线

fsmc_sram.h

cs 复制代码
#ifndef __FSMC_SRAM_H__
#define __FSMC_SRAM_H__

#include "stm32f10x.h"

void FSMC_SramInit(void);

void FSMC_SramGPIOInit(void);

#endif /* __FSMC_SRAM_H__ */

fsmc_sram.c

cs 复制代码
#include "fsmc_sram.h"


void FSMC_SramInit(void){
    // 0. 先进行GPIO的初始化
    FSMC_SramGPIOInit();
    // 1. 先放开FSMC的时钟
    RCC->AHBENR |= RCC_AHBENR_FSMCEN;

    // 对于BCR 看着表来配
    // 位19 突发访问 异步模式 没用 不需要配
    // 位18:16 CRAM页大小 SRAM MODE1模式下 不需要配置
    // 位15 异步等待 需要等待引脚 此处我们的SRAM不支持 因此应该配0 默认就是0
    // 位14 拓展模式 一旦开了 可以使用模式B C 等去操作FLASH 因为当前是SRAM模式1 此处必须为0 默认就是0
    // 位13 等待使能 异步模式下没用
    // 位12 写使能 要求是按需配置 我们想要复制 必须配1 不过默认就是1
    FSMC_Bank1->BTCR[4] |= FSMC_BCR3_WREN;
    // 位11 WAITCFG 无所谓
    // 位10 WRAPMOD 跟突发访问相关 文档要求必须配0 默认就是0s
    // 位9  WAITPOL 也是跟等待相关的 需要位15为1时 才有意义 但是现在位15是0 不需要管
    // 位8  BURSTEN 突发访问模式的使能位 文档要求必须为0 默认就是0
    // 位7 是一个默认值为1的保留位 不需要修改
    // 位6 FACCEN falsh访问使能 文档说不用管 但是我们可以试试
    FSMC_Bank1->BTCR[4] |= FSMC_BCR3_FACCEN;
    // 位5:4  外部存储器 数据总线的宽度 16位 默认就是 文档要求按需配置
    FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MWID_1;
    FSMC_Bank1->BTCR[4] |= FSMC_BCR3_MWID_0;
    // 位3: 2  存储器类型 默认是flash 文档要求按需配置 我们配成00 表示SRAM
    FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MTYP;
    // 位1 地址数据复用使能 默认是1 文档要求必须配成0
    FSMC_Bank1->BTCR[4] &= ~FSMC_BCR3_MUXEN;
    // 位0 对应bank的使能
    FSMC_Bank1->BTCR[4] |= FSMC_BCR3_MBKEN;



    /* 3. fsmc的 时序 */
    /* 3.1 地址建立时间 对同步读写来说,永远一个周期 */
    FSMC_Bank1->BTCR[5] &= ~FSMC_BTR3_ADDSET;
    /* 3.2 地址保持时间 对同步读写来说,永远一个周期 */

    /* 3.3 数据保持时间 手册不能低于55ns 我们设置1us*/
    FSMC_Bank1->BTCR[5] &= ~FSMC_BTR3_DATAST;
    FSMC_Bank1->BTCR[5] |= (2 << 8);
}


void FSMC_SramGPIOInit(void){
  /* 1. 时钟开启 */
  RCC->APB2ENR |= (RCC_APB2ENR_IOPDEN |
          RCC_APB2ENR_IOPEEN |
          RCC_APB2ENR_IOPFEN |
          RCC_APB2ENR_IOPGEN );


/* 1 配置 A0-A18 地址端口的输出模式 复用推挽输出CNF:10 50MHz速度 MODE:11*/
  /* =============MODE=============== */
  GPIOF->CRL |= (GPIO_CRL_MODE0 |
         GPIO_CRL_MODE1 |
         GPIO_CRL_MODE2 |
         GPIO_CRL_MODE3 |
         GPIO_CRL_MODE4 |
         GPIO_CRL_MODE5);

  GPIOF->CRH |= (GPIO_CRH_MODE12 |
         GPIO_CRH_MODE13 |
         GPIO_CRH_MODE14 |
         GPIO_CRH_MODE15);

  GPIOG->CRL |= (GPIO_CRL_MODE0 |
         GPIO_CRL_MODE1 |
         GPIO_CRL_MODE2 |
         GPIO_CRL_MODE3 |
         GPIO_CRL_MODE4 |
         GPIO_CRL_MODE5);

  GPIOD->CRH |= (GPIO_CRH_MODE11 |
         GPIO_CRH_MODE12 |
         GPIO_CRH_MODE13);

  /* =============CNF=============== */
  GPIOF->CRL |= (GPIO_CRL_CNF0_1 |
         GPIO_CRL_CNF1_1 |
         GPIO_CRL_CNF2_1 |
         GPIO_CRL_CNF3_1 |
         GPIO_CRL_CNF4_1 |
         GPIO_CRL_CNF5_1);
  GPIOF->CRL &= ~(GPIO_CRL_CNF0_0 |
          GPIO_CRL_CNF1_0 |
          GPIO_CRL_CNF2_0 |
          GPIO_CRL_CNF3_0 |
          GPIO_CRL_CNF4_0 |
          GPIO_CRL_CNF5_0);

  GPIOF->CRH |= (GPIO_CRH_CNF12_1 |
         GPIO_CRH_CNF13_1 |
         GPIO_CRH_CNF14_1 |
         GPIO_CRH_CNF15_1);
  GPIOF->CRH &= ~(GPIO_CRH_CNF12_0 |
          GPIO_CRH_CNF13_0 |
          GPIO_CRH_CNF14_0 |
          GPIO_CRH_CNF15_0);

  GPIOG->CRL |= (GPIO_CRL_CNF0_1 |
         GPIO_CRL_CNF1_1 |
         GPIO_CRL_CNF2_1 |
         GPIO_CRL_CNF3_1 |
         GPIO_CRL_CNF4_1 |
         GPIO_CRL_CNF5_1);
  GPIOG->CRL &= ~(GPIO_CRL_CNF0_0 |
          GPIO_CRL_CNF1_0 |
          GPIO_CRL_CNF2_0 |
          GPIO_CRL_CNF3_0 |
          GPIO_CRL_CNF4_0 |
          GPIO_CRL_CNF5_0);

  GPIOD->CRH |= (GPIO_CRH_CNF11_1 |
         GPIO_CRH_CNF12_1 |
         GPIO_CRH_CNF13_1);
  GPIOD->CRH &= ~(GPIO_CRH_CNF11_0 |
          GPIO_CRH_CNF12_0 |
          GPIO_CRH_CNF13_0);

  /*
    2 数据端口 复用推挽输出
      在实际应用中,即使数据线被配置为输出模式,FSMC控制器仍然能够管理数据线的方向,使其在需要时成为输入线。
      这种自动切换是由FSMC控制器硬件管理的,不需要软件干预。
      因此,即使GPIO配置为复用推挽输出,FSMC依然可以实现读取操作。
  */
  /* =============MODE=============== */
  GPIOD->CRL |= (GPIO_CRL_MODE0 |
         GPIO_CRL_MODE1);
  GPIOD->CRH |= (GPIO_CRH_MODE8 |
         GPIO_CRH_MODE9 |
         GPIO_CRH_MODE10 |
         GPIO_CRH_MODE14 |
         GPIO_CRH_MODE15);

  GPIOE->CRL |= (GPIO_CRL_MODE7);
  GPIOE->CRH |= (GPIO_CRH_MODE8 |
         GPIO_CRH_MODE9 |
         GPIO_CRH_MODE10 |
         GPIO_CRH_MODE11 |
         GPIO_CRH_MODE12 |
         GPIO_CRH_MODE13 |
         GPIO_CRH_MODE14 |
         GPIO_CRH_MODE15);

  /* =============CNF=============== */
  GPIOD->CRL |= (GPIO_CRL_CNF0_1 |
         GPIO_CRL_CNF1_1);
  GPIOD->CRL &= ~(GPIO_CRL_CNF0_0 |
          GPIO_CRL_CNF1_0);

  GPIOD->CRH |= (GPIO_CRH_CNF8_1 |
         GPIO_CRH_CNF9_1 |
         GPIO_CRH_CNF10_1 |
         GPIO_CRH_CNF14_1 |
         GPIO_CRH_CNF15_1);
  GPIOD->CRH &= ~(GPIO_CRH_CNF8_0 |
          GPIO_CRH_CNF9_0 |
          GPIO_CRH_CNF10_0 |
          GPIO_CRH_CNF14_0 |
          GPIO_CRH_CNF15_0);

  GPIOE->CRL |= (GPIO_CRL_CNF7_1);
  GPIOE->CRL &= ~(GPIO_CRL_CNF7_0);

  GPIOE->CRH |= (GPIO_CRH_CNF8_1 |
         GPIO_CRH_CNF9_1 |
         GPIO_CRH_CNF10_1 |
         GPIO_CRH_CNF11_1 |
         GPIO_CRH_CNF12_1 |
         GPIO_CRH_CNF13_1 |
         GPIO_CRH_CNF14_1 |
         GPIO_CRH_CNF15_1);
  GPIOE->CRH &= ~(GPIO_CRH_CNF8_0 |
          GPIO_CRH_CNF9_0 |
          GPIO_CRH_CNF10_0 |
          GPIO_CRH_CNF11_0 |
          GPIO_CRH_CNF12_0 |
          GPIO_CRH_CNF13_0 |
          GPIO_CRH_CNF14_0 |
          GPIO_CRH_CNF15_0);

  /* 3 其他控制端口 复用推挽输出 */
  GPIOD->CRL |= (GPIO_CRL_MODE4 |
         GPIO_CRL_MODE5);
  GPIOD->CRL |= (GPIO_CRL_CNF4_1 |
         GPIO_CRL_CNF5_1);
  GPIOD->CRL &= ~(GPIO_CRL_CNF4_0 |
          GPIO_CRL_CNF5_0);

  GPIOE->CRL |= (GPIO_CRL_MODE0 |
         GPIO_CRL_MODE1);
  GPIOE->CRL |= (GPIO_CRL_CNF0_1 |
         GPIO_CRL_CNF1_1);
  GPIOE->CRL &= ~(GPIO_CRL_CNF0_0 |
          GPIO_CRL_CNF1_0);

  GPIOG->CRH |= (GPIO_CRH_MODE10);
  GPIOG->CRH |= (GPIO_CRH_CNF10_1);
  GPIOG->CRH &= ~(GPIO_CRH_CNF10_0);
}

main.c

cs 复制代码
#include "usart1.h"
#include "string.h"
#include <stdio.h>
#include "systick.h"
#include "fsmc_sram.h"

//0.声明一个变量 但是声明不是初始化
uint8_t v1 __attribute__((at(0x68000000)));
//1. 演示4个字节对齐
uint8_t v2 __attribute__((at(0x68000004)));
//3 一旦地址重复,编译器会自动为你安排一个没有分配过的地址
uint8_t v4 __attribute__((at(0x68000004)));

int main(void){
	Usart1_Init();
	FSMC_SramInit();
	
	// v1 = 4;
	// printf("v1_addr = %x\n",&v1);
	// printf("v1=%d\n",v1);

	// v2 = 100;
	// printf("v2_addr = %x\n",&v2);
	// printf("v2=%d\n",v2);

	
	// //2 attribute这个关键字它是编译器指令 
	// //只能在全局变量中使用 
	// //在局部变量使用会直接失效
	// uint8_t v3 __attribute__((at(0x68000004)));
	// v3 = 232;
	// printf("v3_addr = %x\n",&v3);
	// printf("v3=%d\n",v3);

	// v4 = 123;
	// printf("v4_addr = %x\n",&v4);
	// printf("v4=%d\n",v4);

	//4.直接通过地址访问sram 的值
	*(uint8_t *)(0x68000000) = 0x10;
	printf("00 = %x\n",*(uint8_t *)(0x68000000));

	*(uint8_t *)(0x68000001) = 0x33;
	printf("01 = %x\n",*(uint8_t *)(0x68000001));

	printf("16 00 = %x\n",*(uint16_t *)(0x68000000));

	while (1)
	{
	}
		
}
相关推荐
LS_learner21 分钟前
K210视觉识别模块
嵌入式硬件
Uitwaaien541 小时前
单片机数码管动态显示
单片机·嵌入式硬件
末时清4 小时前
电机驱动-标准库和HAL库
单片机·嵌入式硬件
电鱼智能的电小鱼4 小时前
基于SAIL-RK3576核心板的AI边缘计算网关设计方案——智慧家庭新突破
linux·人工智能·嵌入式硬件·边缘计算
张一西4 小时前
ARM学习(42)CortexM3/M4 MPU配置
stm32·arm·mpu·nxp·arm架构·cortexm3·cortexm4
嵌入式-老费5 小时前
基于海思soc的智能产品开发(高、中、低soc、以及和fpga的搭配)
嵌入式硬件
BuiderCodes7 小时前
STM32 中 GPIO 的八种工作模式介绍
stm32·单片机·嵌入式硬件
Ronin-Lotus9 小时前
嵌入式硬件篇---PWM&电机&舵机
c语言·stm32·单片机·嵌入式硬件·学习·51单片机·硬件工程
Tony小周19 小时前
HC32L136K8TA单片机输出互为反相双路PWM
单片机·嵌入式硬件
DarrenPig20 小时前
NEC纪实 :2024全国机器人大赛 Robocon 常州工学院团队首战国三
人工智能·嵌入式硬件·机器人·开源·开放原子·智能硬件·robocon