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)
	{
	}
		
}
相关推荐
森焱森1 小时前
水下航行器外形分类详解
c语言·单片机·算法·架构·无人机
小殷学长3 小时前
【单片机毕业设计17-基于stm32c8t6的智能倒车监测系统】
stm32·单片机·课程设计
TESmart碲视5 小时前
HKS201-M24 大师版 8K60Hz USB 3.0 适用于 2 台 PC 1台显示器 无缝切换 KVM 切换器
单片机·嵌入式硬件·物联网·游戏·计算机外设·电脑·智能硬件
small_wh1te_coder6 小时前
硬件嵌入式学习路线大总结(一):C语言与linux。内功心法——从入门到精通,彻底打通你的任督二脉!
linux·c语言·汇编·嵌入式硬件·算法·c
花落已飘6 小时前
STM32中实现shell控制台(shell窗口输入实现)
stm32·单片机·嵌入式硬件
花落已飘6 小时前
STM32中实现shell控制台(命令解析实现)
stm32·shell
没有钱的钱仔7 小时前
STM32低功耗模式全面指南
css·stm32·css3
牵牛老人8 小时前
Qt处理USB摄像头开发说明与QtMultimedia与V4L2融合应用
stm32·单片机·qt
宇钶宇夕10 小时前
针对工业触摸屏维修的系统指南和资源获取途径
单片机·嵌入式硬件·自动化
和风化雨10 小时前
stm32的三种开发方式
stm32·单片机·嵌入式硬件