• (41)STM32——外部SRAM实验笔记


    目录

    学习目标

    成果展示  

    硬件知识

    特点

    功能框图

    读时序

    ​编辑写时序

    FSMC驱动 

    寄存器

    闪存片选控制寄存器

    硬件

     配置

    代码 

    总结 


    学习目标

            今天我们要学习的是有关外部SRAM实验,其实F4内部也是有一个192K字节的SRAM的,相比于51的512个字节来说,实在是好太多了,但是因为32可能需要跑一些需要大内存的场景的话可能就不够用了。所以我们就需要使用外部SRAM芯片来实现相应功能,这里我们使用的是IS62WV51216,容量为1M,这样就能满足大多数情况了。个人觉得手机电脑什么的内存应该也是使用这样的方式来组成的,但是没有过多了解,只是一个猜测。

    成果展示  

    硬件知识

            IS62WV51216 是 ISSI(Integrated Silicon Solution, Inc)公司生产的一颗 16 位宽 512K(512*16 ,即 1M 字节)容量的 CMOS 静态内存芯片。

    特点

    1. 高速。具有 45ns/55ns 访问速度。
    2. 低功耗。
    3. TTL 电平兼容。
    4. 全静态操作。不需要刷新和时钟电路。
    5. 三态输出。
    6. 字节控制功能。支持高/低字节控制。

    功能框图

            图中 A0~18 为地址线,总共 19 根地址线(即 2^19=512K,1K=1024);IO0~15 为数据线,总共 16 根数据线。CS2 和 CS1 都是片选信号,不过 CS2 是高电平有效 CS1 是低电平有效(不过我们没有用到CS2,只使用了CS1);OE是输出使能信号(读信号);WE 为写使能信号;UB 和 LB 分别是高字节控制和低字节控制信号,这个到后面会有所介绍。

    读时序

            我们重点来介绍一下其中几个时序,首先是读周期时序(tRC),我们是55ns,然后地址建立时间(tAA)为55ns(Max),tDOE为25ns(Max)。我们使用的是55ns的芯片,其他时间的具体值如下表所示: 

    写时序

            这个和前面一样,就不做过多介绍了。写周期时间(tWC),地址建立时间(tSA),WE脉宽(tPWE)。

    FSMC驱动 

            这个其实在LCD屏的时候介绍过,在此就简单的介绍一下,FSMC驱动外部SRAM时,外部SRAM的控制一般有: 地址线(如A0~A25数据线(如D0~D15)、写信号(WE,即WR)、读信号(OE,即RD)、片选信号(CS),如果SRAM支持字节控制,那么还有UB/LB信号。
            而IS62WV51246的信号我们在前面介绍过,包括: I/O0~I/O15、A0~A18、OE、WE、CS、UB、LB等,我们将这些信号依次连接STM32 FSMC接口的D0~D15、A0~A18、OE、WE、CS、UB、LB等信号即可。

            STM32F4 的 FSMC 支持 8/16/32 位数据宽度,我们这里用到的 LCD 是 16 位宽度的,所以在设置的时候,选择 16 位宽就 OK 了。我们再来看看 FSMC 的外部设备地址映像,STM32F4 的 FSMC 将外部存储器划分为固定大小为 256M 字节的四个存储块,如图所示:

            这里 HADDR 是内部 AHB 地址 总线,其 中 HADDR[25:0] 来自外部存储器地址 FSMC_A[25:0],而 HADDR[26:27]对 4 个区进行寻址。如表所示: 

            当 Bank1 接的是 16 位宽度存储器的时候:HADDR[25:1]-> FSMC_A [24:0]。 当 Bank1 接的是 8 位宽度存储器的时候:HADDR[25:0]-> FSMC_A [25:0]。

     

     

            这个是读写时序,就不做详细介绍,LCD里面都有。  

    寄存器

            也不做详细介绍,就讲解几个重要寄存器。

    闪存片选控制寄存器

    硬件

    • A[0:18]接 FMSC_A[0:18](不过顺序错乱了)
    • D[0:15]接 FSMC_D[0:15]
    • UB 接 FSMC_NBL1
    • LB 接 FSMC_NBL0
    • OE 接 FSMC_OE
    • WE 接 FSMC_WE
    • CS 接 FSMC_NE3

     配置

    1. 使能 FSMC 时钟,并配置 FSMC 相关的 IO 及其时钟使能。
    2. 设置 FSMC BANK1 区域 3 的相关寄存器。
    3. 使能 BANK1 区域 3。

    代码 

    1. // sram.c
    2. #include "sram.h"
    3. #include "usart.h"
    4. //使用NOR/SRAM的 Bank1.sector3,地址位HADDR[27,26]=10
    5. //对IS61LV25616/IS62WV25616,地址线范围为A0~A17
    6. //对IS61LV51216/IS62WV51216,地址线范围为A0~A18
    7. #define Bank1_SRAM3_ADDR ((u32)(0x68000000))
    8. //初始化外部SRAM
    9. void FSMC_SRAM_Init(void)
    10. {
    11. GPIO_InitTypeDef GPIO_InitStructure;
    12. FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
    13. FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
    14. RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOD|RCC_AHB1Periph_GPIOE|RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOG, ENABLE);//使能PD,PE,PF,PG时钟
    15. RCC_AHB3PeriphClockCmd(RCC_AHB3Periph_FSMC,ENABLE);//使能FSMC时钟
    16. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PB15 推挽输出,控制背光
    17. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
    18. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    19. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//100MHz
    20. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    21. GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化 //PB15 推挽输出,控制背光
    22. GPIO_InitStructure.GPIO_Pin = (3<<0)|(3<<4)|(0XFF<<8);//PD0,1,4,5,8~15 AF OUT
    23. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
    24. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    25. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    26. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    27. GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化
    28. GPIO_InitStructure.GPIO_Pin = (3<<0)|(0X1FF<<7);//PE0,1,7~15,AF OUT
    29. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
    30. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    31. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    32. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    33. GPIO_Init(GPIOE, &GPIO_InitStructure);//初始化
    34. GPIO_InitStructure.GPIO_Pin = (0X3F<<0)|(0XF<<12); //PF0~5,12~15
    35. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
    36. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    37. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    38. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    39. GPIO_Init(GPIOF, &GPIO_InitStructure);//初始化
    40. GPIO_InitStructure.GPIO_Pin =(0X3F<<0)| GPIO_Pin_10;//PG0~5,10
    41. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用输出
    42. GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
    43. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
    44. GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    45. GPIO_Init(GPIOG, &GPIO_InitStructure);//初始化
    46. GPIO_PinAFConfig(GPIOD,GPIO_PinSource0,GPIO_AF_FSMC);//PD0,AF12
    47. GPIO_PinAFConfig(GPIOD,GPIO_PinSource1,GPIO_AF_FSMC);//PD1,AF12
    48. GPIO_PinAFConfig(GPIOD,GPIO_PinSource4,GPIO_AF_FSMC);
    49. GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_FSMC);
    50. GPIO_PinAFConfig(GPIOD,GPIO_PinSource8,GPIO_AF_FSMC);
    51. GPIO_PinAFConfig(GPIOD,GPIO_PinSource9,GPIO_AF_FSMC);
    52. GPIO_PinAFConfig(GPIOD,GPIO_PinSource10,GPIO_AF_FSMC);
    53. GPIO_PinAFConfig(GPIOD,GPIO_PinSource11,GPIO_AF_FSMC);
    54. GPIO_PinAFConfig(GPIOD,GPIO_PinSource12,GPIO_AF_FSMC);
    55. GPIO_PinAFConfig(GPIOD,GPIO_PinSource13,GPIO_AF_FSMC);
    56. GPIO_PinAFConfig(GPIOD,GPIO_PinSource14,GPIO_AF_FSMC);
    57. GPIO_PinAFConfig(GPIOD,GPIO_PinSource15,GPIO_AF_FSMC);//PD15,AF12
    58. GPIO_PinAFConfig(GPIOE,GPIO_PinSource0,GPIO_AF_FSMC);
    59. GPIO_PinAFConfig(GPIOE,GPIO_PinSource1,GPIO_AF_FSMC);
    60. GPIO_PinAFConfig(GPIOE,GPIO_PinSource7,GPIO_AF_FSMC);//PE7,AF12
    61. GPIO_PinAFConfig(GPIOE,GPIO_PinSource8,GPIO_AF_FSMC);
    62. GPIO_PinAFConfig(GPIOE,GPIO_PinSource9,GPIO_AF_FSMC);
    63. GPIO_PinAFConfig(GPIOE,GPIO_PinSource10,GPIO_AF_FSMC);
    64. GPIO_PinAFConfig(GPIOE,GPIO_PinSource11,GPIO_AF_FSMC);
    65. GPIO_PinAFConfig(GPIOE,GPIO_PinSource12,GPIO_AF_FSMC);
    66. GPIO_PinAFConfig(GPIOE,GPIO_PinSource13,GPIO_AF_FSMC);
    67. GPIO_PinAFConfig(GPIOE,GPIO_PinSource14,GPIO_AF_FSMC);
    68. GPIO_PinAFConfig(GPIOE,GPIO_PinSource15,GPIO_AF_FSMC);//PE15,AF12
    69. GPIO_PinAFConfig(GPIOF,GPIO_PinSource0,GPIO_AF_FSMC);//PF0,AF12
    70. GPIO_PinAFConfig(GPIOF,GPIO_PinSource1,GPIO_AF_FSMC);//PF1,AF12
    71. GPIO_PinAFConfig(GPIOF,GPIO_PinSource2,GPIO_AF_FSMC);//PF2,AF12
    72. GPIO_PinAFConfig(GPIOF,GPIO_PinSource3,GPIO_AF_FSMC);//PF3,AF12
    73. GPIO_PinAFConfig(GPIOF,GPIO_PinSource4,GPIO_AF_FSMC);//PF4,AF12
    74. GPIO_PinAFConfig(GPIOF,GPIO_PinSource5,GPIO_AF_FSMC);//PF5,AF12
    75. GPIO_PinAFConfig(GPIOF,GPIO_PinSource12,GPIO_AF_FSMC);//PF12,AF12
    76. GPIO_PinAFConfig(GPIOF,GPIO_PinSource13,GPIO_AF_FSMC);//PF13,AF12
    77. GPIO_PinAFConfig(GPIOF,GPIO_PinSource14,GPIO_AF_FSMC);//PF14,AF12
    78. GPIO_PinAFConfig(GPIOF,GPIO_PinSource15,GPIO_AF_FSMC);//PF15,AF12
    79. GPIO_PinAFConfig(GPIOG,GPIO_PinSource0,GPIO_AF_FSMC);
    80. GPIO_PinAFConfig(GPIOG,GPIO_PinSource1,GPIO_AF_FSMC);
    81. GPIO_PinAFConfig(GPIOG,GPIO_PinSource2,GPIO_AF_FSMC);
    82. GPIO_PinAFConfig(GPIOG,GPIO_PinSource3,GPIO_AF_FSMC);
    83. GPIO_PinAFConfig(GPIOG,GPIO_PinSource4,GPIO_AF_FSMC);
    84. GPIO_PinAFConfig(GPIOG,GPIO_PinSource5,GPIO_AF_FSMC);
    85. GPIO_PinAFConfig(GPIOG,GPIO_PinSource10,GPIO_AF_FSMC);
    86. // 读写时序
    87. readWriteTiming.FSMC_AddressSetupTime = 0x00; //地址建立时间(ADDSET)为1个HCLK 1/36M=27ns
    88. readWriteTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间(ADDHLD)模式A未用到
    89. readWriteTiming.FSMC_DataSetupTime = 0x08; 数据保持时间(DATAST)为9个HCLK 6*9=54ns
    90. readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
    91. readWriteTiming.FSMC_CLKDivision = 0x00;
    92. readWriteTiming.FSMC_DataLatency = 0x00;
    93. readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A; //模式A
    94. FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;// 这里我们使用NE3 ,也就对应BTCR[4],[5]。
    95. FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; // 地址复用没用到
    96. FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;// FSMC_MemoryType_SRAM; //SRAM
    97. FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//存储器数据宽度为16bit
    98. FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;// FSMC_BurstAccessMode_Disable;
    99. FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;// 低电平有效
    100. FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
    101. FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
    102. FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
    103. FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; //存储器写使能
    104. FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
    105. FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; // 读写使用相同的时序
    106. FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    107. FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
    108. FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming; //读写同样时序
    109. FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化FSMC配置
    110. FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能BANK1区域3
    111. }
    112. //在指定地址(WriteAddr+Bank1_SRAM3_ADDR)开始,连续写入n个字节.
    113. //pBuffer:字节指针
    114. //WriteAddr:要写入的地址
    115. //n:要写入的字节数
    116. void FSMC_SRAM_WriteBuffer(u8* pBuffer,u32 WriteAddr,u32 n)
    117. {
    118. for(;n!=0;n--)
    119. {
    120. *(vu8*)(Bank1_SRAM3_ADDR+WriteAddr)=*pBuffer;
    121. WriteAddr++;
    122. pBuffer++;
    123. }
    124. }
    125. //在指定地址((WriteAddr+Bank1_SRAM3_ADDR))开始,连续读出n个字节.
    126. //pBuffer:字节指针
    127. //ReadAddr:要读出的起始地址
    128. //n:要写入的字节数
    129. void FSMC_SRAM_ReadBuffer(u8* pBuffer,u32 ReadAddr,u32 n)
    130. {
    131. for(;n!=0;n--)
    132. {
    133. *pBuffer++=*(vu8*)(Bank1_SRAM3_ADDR+ReadAddr);
    134. ReadAddr++;
    135. }
    136. }

    1. #include "sys.h"
    2. #include "delay.h"
    3. #include "usart.h"
    4. #include "led.h"
    5. #include "key.h"
    6. #include "sram.h"
    7. //测试用数组,定义一个数组,每个数占4个字节,数组包含250000个值,采用绝对地址定义,数组的起始地址在0x68000000。
    8. u32 testsram[250000] __attribute__((at(0X68000000)));
    9. //外部内存测试(最大支持1M字节内存测试)
    10. void fsmc_sram_test(u16 x,u16 y)
    11. {
    12. u32 i=0;
    13. u8 temp=0;
    14. u8 sval=0; //在地址0读到的数据
    15. printf ("Ex Memory Test: 0KB");
    16. printf ("\r\n\r\n");
    17. //每隔4K字节,写入一个数据,总共写入256个数据,刚好是1M字节
    18. for(i=0;i<1024*1024;i+=4096)
    19. {
    20. FSMC_SRAM_WriteBuffer(&temp,i,1);
    21. temp++;
    22. }
    23. //依次读出之前写入的数据,进行校验
    24. for(i=0;i<1024*1024;i+=4096)
    25. {
    26. FSMC_SRAM_ReadBuffer(&temp,i,1);
    27. if(i==0)sval=temp;
    28. else if(temp<=sval)break;//后面读出的数据一定要比第一次读到的数据大.
    29. printf ("Ex Memory Test: %d KB",(u16)(temp-sval+1)*4);//显示内存容量
    30. printf ("\r\n\r\n");
    31. }
    32. }
    33. int main(void)
    34. {
    35. u8 key;
    36. u8 i=0;
    37. u32 ts=0;
    38. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
    39. delay_init(168); //初始化延时函数
    40. uart_init(115200); //初始化串口波特率为115200
    41. LED_Init(); //初始化LED
    42. KEY_Init(); //按键初始化
    43. FSMC_SRAM_Init(); //初始化外部SRAM
    44. printf ("KEY0:Test Sram");
    45. printf ("KEY1:TEST Data");
    46. for(ts=0;ts<250000;ts++)testsram[ts]=ts;//预存测试数据
    47. while(1)
    48. {
    49. key=KEY_Scan(0);//不支持连按
    50. if(key==KEY0_PRES)fsmc_sram_test(60,170);//测试SRAM容量
    51. else if(key==KEY1_PRES)//打印预存测试数据
    52. {
    53. for(ts=0;ts<250000;ts++)
    54. {
    55. printf ("%d",testsram[ts]);//显示测试数据
    56. printf ("\r\n\r\n");
    57. }
    58. }else delay_ms(10);
    59. i++;
    60. if(i==20)//DS0闪烁.
    61. {
    62. i=0;
    63. LED0=!LED0;
    64. }
    65. }
    66. }

    总结 

            个人感觉这块知识应该还可以再深入学习一点,目前感觉就是皮毛。 

  • 相关阅读:
    ts的.d.ts和declare究竟是干嘛用的
    Arthas(阿尔萨斯)--(四)
    SoC设计更重要的是IP管理
    Qt 布局(QSplitter 类&QDockWidget 类) 总结
    Git学习笔记(五)IDEA使用Git
    技术leader踩坑笔记:引入变化
    【Spring】三周玩转Spring全家桶
    CC57 链表内指定区间反转
    VuePress 不用Algolia 全文搜索那就缺了灵魂
    Linux 中查看本机的子网掩码和网关
  • 原文地址:https://blog.csdn.net/weixin_66578482/article/details/126914767