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)
	{
	}
		
}
相关推荐
Miuney_MAX4 小时前
【单片机】之HC32F460中断向量选择
单片机·嵌入式硬件
XINVRY-FPGA7 小时前
XC3S1000-4FGG320I Xilinx AMD Spartan-3 SRAM-based FPGA
嵌入式硬件·机器学习·计算机视觉·fpga开发·硬件工程·dsp开发·fpga
猫猫的小茶馆9 小时前
【ARM】ARM的介绍
c语言·开发语言·arm开发·stm32·单片机·嵌入式硬件·物联网
猫猫的小茶馆9 小时前
【PCB工艺】数模电及射频电路基础
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·pcb工艺
点灯小铭9 小时前
基于单片机的智能药物盒设计与实现
数据库·单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
梓德原10 小时前
【基础】详细分析带隙型稳压电路的工作原理
单片机·嵌入式硬件·物联网
国科安芯11 小时前
航天医疗领域AS32S601芯片的性能分析与适配性探讨
大数据·网络·人工智能·单片机·嵌入式硬件·fpga开发·性能优化
小李做物联网11 小时前
【物联网毕业设计】60.1基于单片机物联网嵌入式项目程序开发之图像厨房监测系统
stm32·单片机·嵌入式硬件·物联网
贝塔实验室12 小时前
新手如何使用Altium Designer创建第一张原理图(三)
arm开发·单片机·嵌入式硬件·fpga开发·射频工程·基带工程·嵌入式实时数据库
@good_good_study13 小时前
STM32 ADC多通道采样实验
stm32·单片机·嵌入式硬件