野火视频教程:https://www.bilibili.com/video/BV1yW411Y7Gw?p=69

FSMC初始化结构体

时序结构体

  1. typedef struct
  2. {
  3. uint32_t FSMC_AddressSetupTime; // 地址建立时间,0-0xF个HCLK周期
  4. uint32_t FSMC_AddressHoldTime; // 地址保持时间,0-0xF个HCLK周期
  5. uint32_t FSMC_DataSetupTime; // 地址建立时间,0-0xF个HCLK周期
  6. uint32_t FSMC_BusTurnAroundDuration; // 总线转换周期,0-0xF个HCLK周期,在NOR FLASH
  7. uint32_t FSMC_CLKDivision; // 时钟分频因子,1-0xF,若控制异步存储器,本参数无效
  8. uint32_t FSMC_DataLatency; // 数据延迟时间,若控制异步存储器,本参数无效
  9. uint32_t FSMC_AccessMode; // 设置访问模式
  10. }FSMC_NORSRAMTimingInitTypeDef;
  • FSMC_AddressSetupTime:本成员设置地址建立时间,它可以被设置为0-0xF个HCLK周期数,按STM32标准库的默认配置,HCLK的时钟频率为72MHz,即一个HCLK周期为1/72us。
  • FSMC_AddressHoldTime:本成员设置地址保持时间,它可以被设置为0-0xF个HCLK周期数。
  • FSMC_DataSetupTime:本成员设置数据建立时间,它可以被设置为0-0xF个HCLK周期数。
  • FSMC_BusTurnAroundDuration:本成员设置总线转换周期,在NOR FLASH存储器中,地址线与数据线可以分时复用,总线转换周期就是指总线在这两种状态间切换需要的延时,防止冲突。控制其他存储器时这个参数无效,配置为0即可。
  • FSMC_CLKDivision:本成员用于设置时钟分频,它可以HCLK时钟作为输入,经过FSMC_CLKDivision分频后输出到FSMC_CLK引脚作为通讯使用的同步时钟。控制其他异步通讯的存储器时这个参数无效,配置为0即可。
  • FSMC_DataLatency:本成员设置数据保持时间,它表示在读取第一个数据之前要等待的周期数,该周期指同步时钟的周期,本参数仅用于同步NOR FLASH类的存储器,控制其他类型的存储器时,本参数无效。
  • FSMC_AccessMode:本成员设置存储器访问模式,不同的模式下FSMC访问存储器地址时引脚输出的时序不一样,可选FSMC_AccessMode_A/B/C/D模式,一般来说控制SRAM时使用A模式。

这个FSMC_NORSRAMTimingInitTypeDef时序结构体配置的延时参数,将作为下一节的FSMC SRAM初始化结构体的一个成员。

FSMC的SRAM初始化结构体

  1. typedef struct
  2. {
  3. uint32_t FSMC_Bank; /*设置要控制的 Bank 区域 */
  4. uint32_t FSMC_DataAddressMux; /*设置地址总线与数据总线是否复用 */
  5. uint32_t FSMC_MemoryType; /*设置存储器的类型 */
  6. uint32_t FSMC_MemoryDataWidth; /*设置存储器的数据宽度*/
  7. uint32_t FSMC_BurstAccessMode; /*设置是否支持突发访问模式,只支持同步类型的存储器 */
  8. uint32_t FSMC_AsynchronousWait; /*设置是否使能在同步传输时的等待信号, */
  9. uint32_t FSMC_WaitSignalPolarity; /*设置等待信号的极性*/
  10. uint32_t FSMC_WrapMode; /*设置是否支持对齐的突发模式 */
  11. uint32_t FSMC_WaitSignalActive; /*配置等待信号在等待前有效还是等待期间有效 */
  12. uint32_t FSMC_WriteOperation; // 设置是否写使能
  13. uint32_t FSMC_WaitSignal; // 设置是否使能等待状态插入
  14. uint32_t FSMC_ExtendedMode; // 设置是否使能扩展模式
  15. uint32_t FSMC_WriteBurst; // 设置是否使能写突发操作
  16. // 当不使用扩展模式时,本参数用于配置读写时序,否则用于配置读时序
  17. FSMC_NORSRAMTimingInitTypeDef* FSMC_ReadWriteTimingStruct;
  18. // 当使用扩展模式时,本参数用于配置写时序
  19. FSMC_NORSRAMTimingInitTypeDef* FSMC_WriteTimingStruct;
  20. }FSMC_NORSRAMInitTypeDef;

这个结构体,除最后两个成员是上一小节讲解的时序配置外,其它结构体成员的配置都对应到 FSMC_BCR 中的寄存器位。各个成员意义介绍如下,括号中的是 STM32 标准库
定义的宏

  • FSMC_Bank:本成员用于选择 FSMC 映射的存储区域, 它的可选参数以及相应的内核地址映射范围 | 可以输入的宏 | 对应的地址区域 | | —- | —- | | FSMC_Bank1_NORSRAM1 | 0x60000000-0x63FFFFFF | | FSMC_Bank1_NORSRAM2 | 0x64000000-0x67FFFFFF | | FSMC_Bank1_NORSRAM3 | 0x68000000-0x6BFFFFFF | | FSMC_Bank1_NORSRAM4 | 0x6C000000-0x6FFFFFFF |

  • FSMC_DataAddressMux:本成员用于设置地址总线与数据总线是否复用(FSMC_DataAddressMux_Enable/Disable),在控制 NOR FLASH 时,可以地址总线与数据总线可以分时复用,以减少使用 STM32 信号线的数量。

  • FSMC_MemoryType:本成员用于设置要控制的存储器类型,它支持控制的存储器类型为 SRAM、PSRAM以及 NOR FLASH(FSMC_MemoryType_SRAM/PSRAM/NOR)。
  • FSMC_MemoryDataWidth:本成员用于设置要控制的存储器的数据宽度,可选择设置成 8 或 16 位(FSMC_MemoryDataWidth_8b /16b)。
  • FSMC_BurstAccessMode:本成员用于设置是否使用突发访问模式(FSMC_BurstAccessMode_Enable/Disable),突发访问模式是指发送一个地址后连续访问多个数据,非突发模式下每访问一个数据都需要输入一个地址,仅在控制同步类型的存储器时才能使用突发模式。
  • FSMC_AsynchronousWait:本成员用于设置是否使能在同步传输时使用的等待信号(FSMC_AsynchronousWait_Enable/Disable),在控制同步类型的 NOR 或 PSRAM 时,存储器可以使用 FSMC_NWAIT 引脚通知 STM32 需要等待。
  • FSMC_WaitSignalPolarity:本成员用于设置等待信号的有效极性,即要求等待时,使用高电平还是低电平(FSMC_WaitSignalPolarity_High/Low)。
  • FSMC_WrapMode:本成员用于设置是否支持把非对齐的AHB 突发操作分割成 2 次线性操作(FSMC_WrapMode_Enable/Disable),该配置仅在突发模式下有效。
  • FSMC_WaitSignalActive:本成员用于配置在突发传输模式时,决定存储器是在等待状态之前的一个数据周期有效还是在等待状态期间有效(FSMC_WaitSignalActive_BeforeWaitState/DuringWaitState)。
  • FSMC_WriteOperation:这个成员用于设置是否写使能(FSMCWriteOperation Enable /Disable),禁止写使能的话 FSMC 只能从存储器中读取数据,不能写入。
  • FSMC_WaitSignal:本成员用于设置当存储器处于突发传输模式时,是否允许通过 NWAIT 信号插入等待
    状态(FSMC_WaitSignal_Enable/Disable)。
  • FSMC_ExtendedMode:本成员用于设置是否使用扩展模式(FSMC_ExtendedMode_Enable/Disable),在非扩展模式下,对存储器读写的时序都只使用 FSMC_BCR 寄存器中的配置,即下面的FSMC_ReadWriteTimingStruct 结构体成员;在扩展模式下,对存储器的读写时序可以分开配置,读时序使用 FSMC_BCR 寄存器,写时序使用FSMC_BWTR 寄存器的配置,即下面的 FSMC_WriteTimingStruct 结构体。
  • FSMC_ReadWriteTimingStruct:本成员是一个指针,赋值时使用上一小节中讲解的时序结构体FSMC_NORSRAMInitTypeDef 设置,当不使用扩展模式时,读写时序都使用本成员的参数配置。
  • FSMC_WriteTimingStruct:同样地,本成员也是一个时序结构体的指针,只有当使用扩展模式时,本配置才有效,它是写操作使用的时序。

对本结构体赋值完成后,调用 FSMC_NORSRAMInit 库函数即可把配置参数写入到FSMC_BCR 及 FSMC_BTR/BWTR 寄存器中。

读写时序要求

ADDSET+1+DATAST+1 > 55ns
DATAS+1 > 40ns
ADDSET+1 > 0ns

ADDSET+1+DATAST+1 +2HCLK > 55ns
DATAS+1 > 22ns
ADDSET+1 > 0ns

FSMC—外部SRAM实例

bsp_sram.h

  1. #ifndef __BSP_SRAM_H
  2. #define __BSP_SRAM_H
  3. #include "stm32f10x.h"
  4. #include "./usart/bsp_usart.h"
  5. //使用NOR/SRAM的 Bank1.sector3,地址位HADDR[27,26]=10
  6. //对IS61LV25616/IS62WV25616,地址线范围为A0~A17
  7. //对IS61LV51216/IS62WV51216,地址线范围为A0~A18
  8. #define Bank1_SRAM3_ADDR ((uint32_t)(0x68000000))
  9. #define IS62WV51216_SIZE 0x100000 //512*16/2bits = 0x100000 ,1M字节
  10. /*A地址信号线*/
  11. #define FSMC_A0_GPIO_PORT GPIOF
  12. #define FSMC_A0_GPIO_CLK RCC_APB2Periph_GPIOF
  13. #define FSMC_A0_GPIO_PIN GPIO_Pin_0
  14. #define FSMC_A1_GPIO_PORT GPIOF
  15. #define FSMC_A1_GPIO_CLK RCC_APB2Periph_GPIOF
  16. #define FSMC_A1_GPIO_PIN GPIO_Pin_1
  17. #define FSMC_A2_GPIO_PORT GPIOF
  18. #define FSMC_A2_GPIO_CLK RCC_APB2Periph_GPIOF
  19. #define FSMC_A2_GPIO_PIN GPIO_Pin_2
  20. #define FSMC_A3_GPIO_PORT GPIOF
  21. #define FSMC_A3_GPIO_CLK RCC_APB2Periph_GPIOF
  22. #define FSMC_A3_GPIO_PIN GPIO_Pin_3
  23. #define FSMC_A4_GPIO_PORT GPIOF
  24. #define FSMC_A4_GPIO_CLK RCC_APB2Periph_GPIOF
  25. #define FSMC_A4_GPIO_PIN GPIO_Pin_4
  26. #define FSMC_A5_GPIO_PORT GPIOF
  27. #define FSMC_A5_GPIO_CLK RCC_APB2Periph_GPIOF
  28. #define FSMC_A5_GPIO_PIN GPIO_Pin_5
  29. #define FSMC_A6_GPIO_PORT GPIOF
  30. #define FSMC_A6_GPIO_CLK RCC_APB2Periph_GPIOF
  31. #define FSMC_A6_GPIO_PIN GPIO_Pin_12
  32. #define FSMC_A7_GPIO_PORT GPIOF
  33. #define FSMC_A7_GPIO_CLK RCC_APB2Periph_GPIOF
  34. #define FSMC_A7_GPIO_PIN GPIO_Pin_13
  35. #define FSMC_A8_GPIO_PORT GPIOF
  36. #define FSMC_A8_GPIO_CLK RCC_APB2Periph_GPIOF
  37. #define FSMC_A8_GPIO_PIN GPIO_Pin_14
  38. #define FSMC_A9_GPIO_PORT GPIOF
  39. #define FSMC_A9_GPIO_CLK RCC_APB2Periph_GPIOF
  40. #define FSMC_A9_GPIO_PIN GPIO_Pin_15
  41. #define FSMC_A10_GPIO_PORT GPIOG
  42. #define FSMC_A10_GPIO_CLK RCC_APB2Periph_GPIOG
  43. #define FSMC_A10_GPIO_PIN GPIO_Pin_0
  44. #define FSMC_A11_GPIO_PORT GPIOG
  45. #define FSMC_A11_GPIO_CLK RCC_APB2Periph_GPIOG
  46. #define FSMC_A11_GPIO_PIN GPIO_Pin_1
  47. #define FSMC_A12_GPIO_PORT GPIOG
  48. #define FSMC_A12_GPIO_CLK RCC_APB2Periph_GPIOG
  49. #define FSMC_A12_GPIO_PIN GPIO_Pin_2
  50. #define FSMC_A13_GPIO_PORT GPIOG
  51. #define FSMC_A13_GPIO_CLK RCC_APB2Periph_GPIOG
  52. #define FSMC_A13_GPIO_PIN GPIO_Pin_3
  53. #define FSMC_A14_GPIO_PORT GPIOG
  54. #define FSMC_A14_GPIO_CLK RCC_APB2Periph_GPIOG
  55. #define FSMC_A14_GPIO_PIN GPIO_Pin_4
  56. #define FSMC_A15_GPIO_PORT GPIOG
  57. #define FSMC_A15_GPIO_CLK RCC_APB2Periph_GPIOG
  58. #define FSMC_A15_GPIO_PIN GPIO_Pin_5
  59. #define FSMC_A16_GPIO_PORT GPIOD
  60. #define FSMC_A16_GPIO_CLK RCC_APB2Periph_GPIOD
  61. #define FSMC_A16_GPIO_PIN GPIO_Pin_11
  62. #define FSMC_A17_GPIO_PORT GPIOD
  63. #define FSMC_A17_GPIO_CLK RCC_APB2Periph_GPIOD
  64. #define FSMC_A17_GPIO_PIN GPIO_Pin_12
  65. #define FSMC_A18_GPIO_PORT GPIOD
  66. #define FSMC_A18_GPIO_CLK RCC_APB2Periph_GPIOD
  67. #define FSMC_A18_GPIO_PIN GPIO_Pin_13
  68. /*D 数据信号线*/
  69. #define FSMC_D0_GPIO_PORT GPIOD
  70. #define FSMC_D0_GPIO_CLK RCC_APB2Periph_GPIOD
  71. #define FSMC_D0_GPIO_PIN GPIO_Pin_14
  72. #define FSMC_D1_GPIO_PORT GPIOD
  73. #define FSMC_D1_GPIO_CLK RCC_APB2Periph_GPIOD
  74. #define FSMC_D1_GPIO_PIN GPIO_Pin_15
  75. #define FSMC_D2_GPIO_PORT GPIOD
  76. #define FSMC_D2_GPIO_CLK RCC_APB2Periph_GPIOD
  77. #define FSMC_D2_GPIO_PIN GPIO_Pin_0
  78. #define FSMC_D3_GPIO_PORT GPIOD
  79. #define FSMC_D3_GPIO_CLK RCC_APB2Periph_GPIOD
  80. #define FSMC_D3_GPIO_PIN GPIO_Pin_1
  81. #define FSMC_D4_GPIO_PORT GPIOE
  82. #define FSMC_D4_GPIO_CLK RCC_APB2Periph_GPIOE
  83. #define FSMC_D4_GPIO_PIN GPIO_Pin_7
  84. #define FSMC_D5_GPIO_PORT GPIOE
  85. #define FSMC_D5_GPIO_CLK RCC_APB2Periph_GPIOE
  86. #define FSMC_D5_GPIO_PIN GPIO_Pin_8
  87. #define FSMC_D6_GPIO_PORT GPIOE
  88. #define FSMC_D6_GPIO_CLK RCC_APB2Periph_GPIOE
  89. #define FSMC_D6_GPIO_PIN GPIO_Pin_9
  90. #define FSMC_D7_GPIO_PORT GPIOE
  91. #define FSMC_D7_GPIO_CLK RCC_APB2Periph_GPIOE
  92. #define FSMC_D7_GPIO_PIN GPIO_Pin_10
  93. #define FSMC_D8_GPIO_PORT GPIOE
  94. #define FSMC_D8_GPIO_CLK RCC_APB2Periph_GPIOE
  95. #define FSMC_D8_GPIO_PIN GPIO_Pin_11
  96. #define FSMC_D9_GPIO_PORT GPIOE
  97. #define FSMC_D9_GPIO_CLK RCC_APB2Periph_GPIOE
  98. #define FSMC_D9_GPIO_PIN GPIO_Pin_12
  99. #define FSMC_D10_GPIO_PORT GPIOE
  100. #define FSMC_D10_GPIO_CLK RCC_APB2Periph_GPIOE
  101. #define FSMC_D10_GPIO_PIN GPIO_Pin_13
  102. #define FSMC_D11_GPIO_PORT GPIOE
  103. #define FSMC_D11_GPIO_CLK RCC_APB2Periph_GPIOE
  104. #define FSMC_D11_GPIO_PIN GPIO_Pin_14
  105. #define FSMC_D12_GPIO_PORT GPIOE
  106. #define FSMC_D12_GPIO_CLK RCC_APB2Periph_GPIOE
  107. #define FSMC_D12_GPIO_PIN GPIO_Pin_15
  108. #define FSMC_D13_GPIO_PORT GPIOD
  109. #define FSMC_D13_GPIO_CLK RCC_APB2Periph_GPIOD
  110. #define FSMC_D13_GPIO_PIN GPIO_Pin_8
  111. #define FSMC_D14_GPIO_PORT GPIOD
  112. #define FSMC_D14_GPIO_CLK RCC_APB2Periph_GPIOD
  113. #define FSMC_D14_GPIO_PIN GPIO_Pin_9
  114. #define FSMC_D15_GPIO_PORT GPIOD
  115. #define FSMC_D15_GPIO_CLK RCC_APB2Periph_GPIOD
  116. #define FSMC_D15_GPIO_PIN GPIO_Pin_10
  117. /*控制信号线*/
  118. /*CS片选*/
  119. /*NE3 ,对应的基地址0x68000000*/
  120. #define FSMC_CS_GPIO_PORT GPIOG
  121. #define FSMC_CS_GPIO_CLK RCC_APB2Periph_GPIOG
  122. #define FSMC_CS_GPIO_PIN GPIO_Pin_10
  123. /*WE写使能*/
  124. #define FSMC_WE_GPIO_PORT GPIOD
  125. #define FSMC_WE_GPIO_CLK RCC_APB2Periph_GPIOD
  126. #define FSMC_WE_GPIO_PIN GPIO_Pin_5
  127. /*OE读使能*/
  128. #define FSMC_OE_GPIO_PORT GPIOD
  129. #define FSMC_OE_GPIO_CLK RCC_APB2Periph_GPIOD
  130. #define FSMC_OE_GPIO_PIN GPIO_Pin_4
  131. /*UB数据掩码*/
  132. #define FSMC_UDQM_GPIO_PORT GPIOE
  133. #define FSMC_UDQM_GPIO_CLK RCC_APB2Periph_GPIOE
  134. #define FSMC_UDQM_GPIO_PIN GPIO_Pin_1
  135. /*LB数据掩码*/
  136. #define FSMC_LDQM_GPIO_PORT GPIOE
  137. #define FSMC_LDQM_GPIO_CLK RCC_APB2Periph_GPIOE
  138. #define FSMC_LDQM_GPIO_PIN GPIO_Pin_0
  139. /*信息输出*/
  140. #define SRAM_DEBUG_ON 1
  141. #define SRAM_INFO(fmt,arg...) printf("<<-SRAM-INFO->> "fmt"\n",##arg)
  142. #define SRAM_ERROR(fmt,arg...) printf("<<-SRAM-ERROR->> "fmt"\n",##arg)
  143. #define SRAM_DEBUG(fmt,arg...) do{\
  144. if(SRAM_DEBUG_ON)\
  145. printf("<<-SRAM-DEBUG->> [%d]"fmt"\n",__LINE__, ##arg);\
  146. }while(0)
  147. void FSMC_SRAM_Init(void);
  148. void FSMC_SRAM_WriteBuffer(uint8_t* pBuffer,uint32_t WriteAddr,uint32_t NumHalfwordToWrite);
  149. void FSMC_SRAM_ReadBuffer(uint8_t* pBuffer,uint32_t ReadAddr,uint32_t NumHalfwordToRead);
  150. uint8_t SRAM_Test(void);
  151. #endif // BSP_SRAM

bsp_sram.c

  1. /**
  2. ******************************************************************************
  3. * @file bsp_sram.c
  4. * @author fire
  5. * @version V1.0
  6. * @date 2015-xx-xx
  7. * @brief sram应用函数接口
  8. ******************************************************************************
  9. * @attention
  10. *
  11. * 实验平台:野火 F103-霸道 STM32 开发板
  12. * 论坛 :http://www.firebbs.cn
  13. * 淘宝 :https://fire-stm32.taobao.com
  14. *
  15. ******************************************************************************
  16. */
  17. #include "./sram/bsp_sram.h"
  18. /**
  19. * @brief 初始化控制SRAM的IO
  20. * @param 无
  21. * @retval 无
  22. */
  23. static void SRAM_GPIO_Config(void)
  24. {
  25. GPIO_InitTypeDef GPIO_InitStructure;
  26. /* 使能SRAM相关的GPIO时钟 */
  27. /*地址信号线*/
  28. RCC_APB2PeriphClockCmd(FSMC_A0_GPIO_CLK | FSMC_A1_GPIO_CLK | FSMC_A2_GPIO_CLK |
  29. FSMC_A3_GPIO_CLK | FSMC_A4_GPIO_CLK | FSMC_A5_GPIO_CLK |
  30. FSMC_A6_GPIO_CLK | FSMC_A7_GPIO_CLK | FSMC_A8_GPIO_CLK |
  31. FSMC_A9_GPIO_CLK | FSMC_A10_GPIO_CLK| FSMC_A11_GPIO_CLK|
  32. FSMC_A12_GPIO_CLK| FSMC_A13_GPIO_CLK|FSMC_A14_GPIO_CLK|
  33. FSMC_A15_GPIO_CLK|FSMC_A16_GPIO_CLK|FSMC_A17_GPIO_CLK|
  34. FSMC_A18_GPIO_CLK|
  35. /*数据信号线*/
  36. FSMC_D0_GPIO_CLK | FSMC_D1_GPIO_CLK | FSMC_D2_GPIO_CLK |
  37. FSMC_D3_GPIO_CLK | FSMC_D4_GPIO_CLK | FSMC_D5_GPIO_CLK |
  38. FSMC_D6_GPIO_CLK | FSMC_D7_GPIO_CLK | FSMC_D8_GPIO_CLK |
  39. FSMC_D9_GPIO_CLK | FSMC_D10_GPIO_CLK| FSMC_D11_GPIO_CLK|
  40. FSMC_D12_GPIO_CLK| FSMC_D13_GPIO_CLK| FSMC_D14_GPIO_CLK|
  41. FSMC_D15_GPIO_CLK|
  42. /*控制信号线*/
  43. FSMC_CS_GPIO_CLK | FSMC_WE_GPIO_CLK | FSMC_OE_GPIO_CLK |
  44. FSMC_UDQM_GPIO_CLK|FSMC_LDQM_GPIO_CLK, ENABLE);
  45. /*-- GPIO 配置 -----------------------------------------------------*/
  46. /* 通用 GPIO 配置 */
  47. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //配置为复用功能
  48. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  49. /*A地址信号线 针对引脚配置*/
  50. GPIO_InitStructure.GPIO_Pin = FSMC_A0_GPIO_PIN;
  51. GPIO_Init(FSMC_A0_GPIO_PORT, &GPIO_InitStructure);
  52. GPIO_InitStructure.GPIO_Pin = FSMC_A1_GPIO_PIN;
  53. GPIO_Init(FSMC_A1_GPIO_PORT, &GPIO_InitStructure);
  54. GPIO_InitStructure.GPIO_Pin = FSMC_A2_GPIO_PIN;
  55. GPIO_Init(FSMC_A2_GPIO_PORT, &GPIO_InitStructure);
  56. GPIO_InitStructure.GPIO_Pin = FSMC_A3_GPIO_PIN;
  57. GPIO_Init(FSMC_A3_GPIO_PORT, &GPIO_InitStructure);
  58. GPIO_InitStructure.GPIO_Pin = FSMC_A4_GPIO_PIN;
  59. GPIO_Init(FSMC_A4_GPIO_PORT, &GPIO_InitStructure);
  60. GPIO_InitStructure.GPIO_Pin = FSMC_A5_GPIO_PIN;
  61. GPIO_Init(FSMC_A5_GPIO_PORT, &GPIO_InitStructure);
  62. GPIO_InitStructure.GPIO_Pin = FSMC_A6_GPIO_PIN;
  63. GPIO_Init(FSMC_A6_GPIO_PORT, &GPIO_InitStructure);
  64. GPIO_InitStructure.GPIO_Pin = FSMC_A7_GPIO_PIN;
  65. GPIO_Init(FSMC_A7_GPIO_PORT, &GPIO_InitStructure);
  66. GPIO_InitStructure.GPIO_Pin = FSMC_A8_GPIO_PIN;
  67. GPIO_Init(FSMC_A8_GPIO_PORT, &GPIO_InitStructure);
  68. GPIO_InitStructure.GPIO_Pin = FSMC_A9_GPIO_PIN;
  69. GPIO_Init(FSMC_A9_GPIO_PORT, &GPIO_InitStructure);
  70. GPIO_InitStructure.GPIO_Pin = FSMC_A10_GPIO_PIN;
  71. GPIO_Init(FSMC_A10_GPIO_PORT, &GPIO_InitStructure);
  72. GPIO_InitStructure.GPIO_Pin = FSMC_A11_GPIO_PIN;
  73. GPIO_Init(FSMC_A11_GPIO_PORT, &GPIO_InitStructure);
  74. GPIO_InitStructure.GPIO_Pin = FSMC_A12_GPIO_PIN;
  75. GPIO_Init(FSMC_A12_GPIO_PORT, &GPIO_InitStructure);
  76. GPIO_InitStructure.GPIO_Pin = FSMC_A13_GPIO_PIN;
  77. GPIO_Init(FSMC_A13_GPIO_PORT, &GPIO_InitStructure);
  78. GPIO_InitStructure.GPIO_Pin = FSMC_A14_GPIO_PIN;
  79. GPIO_Init(FSMC_A14_GPIO_PORT, &GPIO_InitStructure);
  80. GPIO_InitStructure.GPIO_Pin = FSMC_A15_GPIO_PIN;
  81. GPIO_Init(FSMC_A15_GPIO_PORT, &GPIO_InitStructure);
  82. GPIO_InitStructure.GPIO_Pin = FSMC_A16_GPIO_PIN;
  83. GPIO_Init(FSMC_A16_GPIO_PORT, &GPIO_InitStructure);
  84. GPIO_InitStructure.GPIO_Pin = FSMC_A17_GPIO_PIN;
  85. GPIO_Init(FSMC_A17_GPIO_PORT, &GPIO_InitStructure);
  86. GPIO_InitStructure.GPIO_Pin = FSMC_A18_GPIO_PIN;
  87. GPIO_Init(FSMC_A18_GPIO_PORT, &GPIO_InitStructure);
  88. /*DQ数据信号线 针对引脚配置*/
  89. GPIO_InitStructure.GPIO_Pin = FSMC_D0_GPIO_PIN;
  90. GPIO_Init(FSMC_D0_GPIO_PORT, &GPIO_InitStructure);
  91. GPIO_InitStructure.GPIO_Pin = FSMC_D1_GPIO_PIN;
  92. GPIO_Init(FSMC_D1_GPIO_PORT, &GPIO_InitStructure);
  93. GPIO_InitStructure.GPIO_Pin = FSMC_D2_GPIO_PIN;
  94. GPIO_Init(FSMC_D2_GPIO_PORT, &GPIO_InitStructure);
  95. GPIO_InitStructure.GPIO_Pin = FSMC_D3_GPIO_PIN;
  96. GPIO_Init(FSMC_D3_GPIO_PORT, &GPIO_InitStructure);
  97. GPIO_InitStructure.GPIO_Pin = FSMC_D4_GPIO_PIN;
  98. GPIO_Init(FSMC_D4_GPIO_PORT, &GPIO_InitStructure);
  99. GPIO_InitStructure.GPIO_Pin = FSMC_D5_GPIO_PIN;
  100. GPIO_Init(FSMC_D5_GPIO_PORT, &GPIO_InitStructure);
  101. GPIO_InitStructure.GPIO_Pin = FSMC_D6_GPIO_PIN;
  102. GPIO_Init(FSMC_D6_GPIO_PORT, &GPIO_InitStructure);
  103. GPIO_InitStructure.GPIO_Pin = FSMC_D7_GPIO_PIN;
  104. GPIO_Init(FSMC_D7_GPIO_PORT, &GPIO_InitStructure);
  105. GPIO_InitStructure.GPIO_Pin = FSMC_D8_GPIO_PIN;
  106. GPIO_Init(FSMC_D8_GPIO_PORT, &GPIO_InitStructure);
  107. GPIO_InitStructure.GPIO_Pin = FSMC_D9_GPIO_PIN;
  108. GPIO_Init(FSMC_D9_GPIO_PORT, &GPIO_InitStructure);
  109. GPIO_InitStructure.GPIO_Pin = FSMC_D10_GPIO_PIN;
  110. GPIO_Init(FSMC_D10_GPIO_PORT, &GPIO_InitStructure);
  111. GPIO_InitStructure.GPIO_Pin = FSMC_D11_GPIO_PIN;
  112. GPIO_Init(FSMC_D11_GPIO_PORT, &GPIO_InitStructure);
  113. GPIO_InitStructure.GPIO_Pin = FSMC_D12_GPIO_PIN;
  114. GPIO_Init(FSMC_D12_GPIO_PORT, &GPIO_InitStructure);
  115. GPIO_InitStructure.GPIO_Pin = FSMC_D13_GPIO_PIN;
  116. GPIO_Init(FSMC_D13_GPIO_PORT, &GPIO_InitStructure);
  117. GPIO_InitStructure.GPIO_Pin = FSMC_D14_GPIO_PIN;
  118. GPIO_Init(FSMC_D14_GPIO_PORT, &GPIO_InitStructure);
  119. GPIO_InitStructure.GPIO_Pin = FSMC_D15_GPIO_PIN;
  120. GPIO_Init(FSMC_D15_GPIO_PORT, &GPIO_InitStructure);
  121. /*控制信号线*/
  122. GPIO_InitStructure.GPIO_Pin = FSMC_CS_GPIO_PIN;
  123. GPIO_Init(FSMC_CS_GPIO_PORT, &GPIO_InitStructure);
  124. GPIO_InitStructure.GPIO_Pin = FSMC_WE_GPIO_PIN;
  125. GPIO_Init(FSMC_WE_GPIO_PORT, &GPIO_InitStructure);
  126. GPIO_InitStructure.GPIO_Pin = FSMC_OE_GPIO_PIN;
  127. GPIO_Init(FSMC_OE_GPIO_PORT, &GPIO_InitStructure);
  128. GPIO_InitStructure.GPIO_Pin = FSMC_UDQM_GPIO_PIN;
  129. GPIO_Init(FSMC_UDQM_GPIO_PORT, &GPIO_InitStructure);
  130. GPIO_InitStructure.GPIO_Pin = FSMC_LDQM_GPIO_PIN;
  131. GPIO_Init(FSMC_LDQM_GPIO_PORT, &GPIO_InitStructure);
  132. }
  133. //写时序的要求
  134. //1. ADDSET+1+DATAST+1 >55ns
  135. //2. DATAST+1 > 40ns
  136. //3. ADDSET+1 > 0ns
  137. //读时序的要求
  138. //1. ADDSET+1+DATAST+1 +2 >55ns
  139. //2. DATAST+1 > 25ns
  140. //3. ADDSET+1 > 0ns
  141. //1 个HCLK时钟周期:
  142. //T = 1/72MHz = 1.38*10^-8 s = 13.8 ns
  143. //读时序的要求
  144. //ADDSET = 0
  145. //DATAST =1 (经测试,DATAST配置成1是不能正常工作的)
  146. //1. ADDSET+1+DATAST+1 +2 >55ns ------- 0+1+1+1+2 = 69 ns > 55ns
  147. //2. DATAST+1 > 25ns ------ 1+1 = 27.6 >25 ns
  148. //3. ADDSET+1 > 0ns ------ 0+1 = 13.8ns >0 ns
  149. //写时序的要求
  150. //ADDSET = 0
  151. //DATAST = 2
  152. //1. ADDSET+1+DATAST+1 >55ns ------ 0+1+2+1 =55.2 >55ns
  153. //2. DATAST+1 > 40ns ------ 2+1 = 41.4 >40 ns
  154. //3. ADDSET+1 > 0ns ------ 0+1 = 13.8ns >0 ns
  155. /**
  156. * @brief 初始化FSMC外设
  157. * @param None.
  158. * @retval None.
  159. */
  160. void FSMC_SRAM_Init(void)
  161. {
  162. FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
  163. FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
  164. /*初始化SRAM相关的GPIO*/
  165. SRAM_GPIO_Config();
  166. /*使能FSMC外设时钟*/
  167. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC,ENABLE);
  168. //地址建立时间(ADDSET)为1个HCLK 1/72M=14ns
  169. readWriteTiming.FSMC_AddressSetupTime = 0x00;
  170. //地址保持时间(ADDHLD)模式A未用到
  171. readWriteTiming.FSMC_AddressHoldTime = 0x00;
  172. //数据保持时间(DATAST)+ 1个HCLK = 3/72M=42ns(对EM的SRAM芯片)
  173. readWriteTiming.FSMC_DataSetupTime = 0x02; // 2是经验值,理论值为1
  174. //设置总线转换周期,仅用于复用模式的NOR操作
  175. readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
  176. //设置时钟分频,仅用于同步类型的存储器
  177. readWriteTiming.FSMC_CLKDivision = 0x00;
  178. //数据保持时间,仅用于同步型的NOR
  179. readWriteTiming.FSMC_DataLatency = 0x00;
  180. //选择匹配SRAM的模式
  181. readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;
  182. // 选择FSMC映射的存储区域: Bank1 sram3
  183. FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM3;
  184. //设置地址总线与数据总线是否复用,仅用于NOR
  185. FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
  186. //设置要控制的存储器类型:SRAM类型
  187. FSMC_NORSRAMInitStructure.FSMC_MemoryType =FSMC_MemoryType_SRAM;
  188. //存储器数据宽度:16位
  189. FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
  190. //设置是否使用突发访问模式,仅用于同步类型的存储器
  191. FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode =FSMC_BurstAccessMode_Disable;
  192. //设置是否使能等待信号,仅用于同步类型的存储器
  193. FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait=FSMC_AsynchronousWait_Disable;
  194. //设置等待信号的有效极性,仅用于同步类型的存储器
  195. FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
  196. //设置是否支持把非对齐的突发操作,仅用于同步类型的存储器
  197. FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
  198. //设置等待信号插入的时间,仅用于同步类型的存储器
  199. FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
  200. //存储器写使能
  201. FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
  202. //不使用等待信号
  203. FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
  204. // 不使用扩展模式,读写使用相同的时序
  205. FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
  206. //突发写操作
  207. FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
  208. //读写时序配置
  209. FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
  210. //读写同样时序,使用扩展模式时这个配置才有效
  211. FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming;
  212. FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); //初始化FSMC配置
  213. FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM3, ENABLE); // 使能BANK
  214. }
  215. /**
  216. * @brief 以“字”为单位向sdram写入数据
  217. * @param pBuffer: 指向数据的指针
  218. * @param uwWriteAddress: 要写入的SRAM内部地址
  219. * @param uwBufferSize: 要写入数据大小
  220. * @retval None.
  221. */
  222. void SRAM_WriteBuffer(uint32_t* pBuffer, uint32_t uwWriteAddress, uint32_t uwBufferSize)
  223. {
  224. __IO uint32_t write_pointer = (uint32_t)uwWriteAddress;
  225. /* 循环写入数据 */
  226. for (; uwBufferSize != 0; uwBufferSize--)
  227. {
  228. /* 发送数据到SRAM */
  229. *(uint32_t *) (Bank1_SRAM3_ADDR + write_pointer) = *pBuffer++;
  230. /* 地址自增*/
  231. write_pointer += 4;
  232. }
  233. }
  234. /**
  235. * @brief 从SRAM中读取数据
  236. * @param pBuffer: 指向存储数据的buffer
  237. * @param ReadAddress: 要读取数据的地十
  238. * @param uwBufferSize: 要读取的数据大小
  239. * @retval None.
  240. */
  241. void SRAM_ReadBuffer(uint32_t* pBuffer, uint32_t uwReadAddress, uint32_t uwBufferSize)
  242. {
  243. __IO uint32_t write_pointer = (uint32_t)uwReadAddress;
  244. /*读取数据 */
  245. for(; uwBufferSize != 0x00; uwBufferSize--)
  246. {
  247. *pBuffer++ = *(__IO uint32_t *)(Bank1_SRAM3_ADDR + write_pointer );
  248. /* 地址自增*/
  249. write_pointer += 4;
  250. }
  251. }
  252. /**
  253. * @brief 测试SRAM是否正常
  254. * @param None
  255. * @retval 正常返回1,异常返回0
  256. */
  257. uint8_t SRAM_Test(void)
  258. {
  259. /*写入数据计数器*/
  260. uint32_t counter=0;
  261. /* 8位的数据 */
  262. uint8_t ubWritedata_8b = 0, ubReaddata_8b = 0;
  263. /* 16位的数据 */
  264. uint16_t uhWritedata_16b = 0, uhReaddata_16b = 0;
  265. SRAM_INFO("正在检测SRAM,以8位、16位的方式读写sram...");
  266. /*按8位格式读写数据,并校验*/
  267. /* 把SRAM数据全部重置为0 ,IS62WV51216_SIZE是以8位为单位的 */
  268. for (counter = 0x00; counter < IS62WV51216_SIZE; counter++)
  269. {
  270. *(__IO uint8_t*) (Bank1_SRAM3_ADDR + counter) = (uint8_t)0x0;
  271. }
  272. /* 向整个SRAM写入数据 8位 */
  273. for (counter = 0; counter < IS62WV51216_SIZE; counter++)
  274. {
  275. *(__IO uint8_t*) (Bank1_SRAM3_ADDR + counter) = (uint8_t)(ubWritedata_8b + counter);
  276. }
  277. /* 读取 SRAM 数据并检测*/
  278. for(counter = 0; counter<IS62WV51216_SIZE;counter++ )
  279. {
  280. ubReaddata_8b = *(__IO uint8_t*)(Bank1_SRAM3_ADDR + counter); //从该地址读出数据
  281. if(ubReaddata_8b != (uint8_t)(ubWritedata_8b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。
  282. {
  283. SRAM_ERROR("8位数据读写错误!");
  284. return 0;
  285. }
  286. }
  287. /*按16位格式读写数据,并检测*/
  288. /* 把SRAM数据全部重置为0 */
  289. for (counter = 0x00; counter < IS62WV51216_SIZE/2; counter++)
  290. {
  291. *(__IO uint16_t*) (Bank1_SRAM3_ADDR + 2*counter) = (uint16_t)0x00;
  292. }
  293. /* 向整个SRAM写入数据 16位 */
  294. for (counter = 0; counter < IS62WV51216_SIZE/2; counter++)
  295. {
  296. *(__IO uint16_t*) (Bank1_SRAM3_ADDR + 2*counter) = (uint16_t)(uhWritedata_16b + counter);
  297. }
  298. /* 读取 SRAM 数据并检测*/
  299. for(counter = 0; counter<IS62WV51216_SIZE/2;counter++ )
  300. {
  301. uhReaddata_16b = *(__IO uint16_t*)(Bank1_SRAM3_ADDR + 2*counter); //从该地址读出数据
  302. if(uhReaddata_16b != (uint16_t)(uhWritedata_16b + counter)) //检测数据,若不相等,跳出函数,返回检测失败结果。
  303. {
  304. SRAM_ERROR("16位数据读写错误!");
  305. return 0;
  306. }
  307. }
  308. SRAM_INFO("SRAM读写测试正常!");
  309. /*检测正常,return 1 */
  310. return 1;
  311. }
  312. /*********************************************END OF FILE**********************/

main.c

  1. /**
  2. ******************************************************************************
  3. * @file FSMC—外部SRAM
  4. * @author fire
  5. * @version V1.0
  6. * @date 2015-xx-xx
  7. * @brief sram应用例程
  8. ******************************************************************************
  9. * @attention
  10. *
  11. * 实验平台:野火 F103-霸道 STM32 开发板
  12. * 论坛 :http://www.firebbs.cn
  13. * 淘宝 :https://fire-stm32.taobao.com
  14. *
  15. ******************************************************************************
  16. */
  17. #include "stm32f10x.h"
  18. #include "./usart/bsp_usart.h"
  19. #include "./led/bsp_led.h"
  20. #include "./sram/bsp_sram.h"
  21. /*绝对定位方式访问SRAM,这种方式必须定义成全局变量*/
  22. uint8_t testValue __attribute__((at(Bank1_SRAM3_ADDR)));
  23. /**
  24. * @brief 主函数
  25. * @param 无
  26. * @retval 无
  27. */
  28. int main(void)
  29. {
  30. LED_GPIO_Config();
  31. //串口初始化
  32. USART_Config();
  33. //初始化外部SRAM
  34. FSMC_SRAM_Init();
  35. printf ( "\r\n野火外部 SRAM 测试\r\n" );
  36. /*蓝灯亮,表示正在读写SRAM测试*/
  37. LED_BLUE;
  38. /*对SRAM进行读写测试,检测SRAM是否正常*/
  39. if(SRAM_Test()==1)
  40. {
  41. //测试正常 绿灯亮
  42. LED_GREEN;
  43. }
  44. else
  45. {
  46. //测试失败 红灯亮
  47. LED_RED;
  48. }
  49. /*指针方式访问SRAM*/
  50. {
  51. uint32_t temp;
  52. printf("\r\n指针方式访问SRAM\r\n");
  53. /*向SRAM写入8位数据*/
  54. *( uint8_t*) (Bank1_SRAM3_ADDR ) = (uint8_t)0xAA;
  55. printf("\r\n指针访问SRAM,写入数据0xAA \r\n");
  56. /*从SRAM读取数据*/
  57. temp = *( uint8_t*) (Bank1_SRAM3_ADDR );
  58. printf("读取数据:0x%X \r\n",temp);
  59. /*写/读 16位数据*/
  60. *( uint16_t*) (Bank1_SRAM3_ADDR+10 ) = (uint16_t)0xBBBB;
  61. printf("指针访问SRAM,写入数据0xBBBB \r\n");
  62. temp = *( uint16_t*) (Bank1_SRAM3_ADDR+10 );
  63. printf("读取数据:0x%X \r\n",temp);
  64. /*写/读 32位数据*/
  65. *( uint32_t*) (Bank1_SRAM3_ADDR+20 ) = (uint32_t)0xCCCCCCCC;
  66. printf("指针访问SRAM,写入数据0xCCCCCCCC \r\n");
  67. temp = *( uint32_t*) (Bank1_SRAM3_ADDR+20 );
  68. printf("读取数据:0x%X \r\n",temp);
  69. }
  70. /*绝对定位方式访问SRAM,这种方式必须定义成全局变量*/
  71. {
  72. testValue = 0xDD;
  73. printf("\r\n绝对定位访问SRAM,写入数据0xDD,读出数据0x%X,变量地址为%X\r\n",testValue,(uint32_t )&testValue);
  74. }
  75. }
  76. /*********************************************END OF FILE**********************/

可执行程序:FSMC—外部SRAM.zip

FSMC—外部SRAM(内存管理)

bsp_malloc.h

  1. #ifndef __BSP_MALLOC_H
  2. #define __BSP_MALLOC_H
  3. #include "stm32f10x.h"
  4. #ifndef NULL
  5. #define NULL 0
  6. #endif
  7. //定义两个内存池
  8. #define SRAMIN 0 //内部内存池
  9. #define SRAMEX 1 //外部内存池
  10. #define SRAMBANK 2 //定义支持的SRAM块数.
  11. //mem1内存参数设定.mem1完全处于内部SRAM里面.
  12. #define MEM1_BLOCK_SIZE 32 //内存块大小为32字节
  13. #define MEM1_MAX_SIZE 40*1024 //最大管理内存 40K
  14. #define MEM1_ALLOC_TABLE_SIZE MEM1_MAX_SIZE/MEM1_BLOCK_SIZE //内存表大小
  15. //mem2内存参数设定.mem2的内存池处于外部SRAM里面
  16. #define MEM2_BLOCK_SIZE 32 //内存块大小为32字节
  17. #define MEM2_MAX_SIZE 960 *1024 //最大管理内存960K
  18. #define MEM2_ALLOC_TABLE_SIZE MEM2_MAX_SIZE/MEM2_BLOCK_SIZE //内存表大小
  19. //内存管理控制器
  20. struct _m_mallco_dev
  21. {
  22. void ( * init ) ( uint8_t ); //初始化
  23. uint8_t ( * perused ) ( uint8_t ); //内存使用率
  24. uint8_t * membase [ SRAMBANK ]; //内存池 管理SRAMBANK个区域的内存
  25. uint16_t * memmap [ SRAMBANK ]; //内存管理状态表
  26. uint8_t memrdy [ SRAMBANK ]; //内存管理是否就绪
  27. };
  28. extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定义
  29. void mymemset(void *s,uint8_t c,uint32_t count); //设置内存
  30. void mymemcpy(void *des,void *src,uint32_t n); //复制内存
  31. void my_mem_init(uint8_t memx); //内存管理初始化函数(外/内部调用)
  32. uint32_t my_mem_malloc(uint8_t memx,uint32_t size); //内存分配(内部调用)
  33. uint8_t my_mem_free(uint8_t memx,uint32_t offset); //内存释放(内部调用)
  34. uint8_t my_mem_perused(uint8_t memx); //获得内存使用率(外/内部调用)
  35. //用户调用函数
  36. void myfree(uint8_t memx,void *ptr); //内存释放(外部调用)
  37. void *mymalloc(uint8_t memx,uint32_t size); //内存分配(外部调用)
  38. void *myrealloc(uint8_t memx,void *ptr,uint32_t size); //重新分配内存(外部调用)
  39. #endif // __BSP_MALLOC_H

bsp_malloc.c

  1. #include "bsp_malloc.h"
  2. //内存池(32字节对齐)
  3. __align(32) uint8_t mem1base[MEM1_MAX_SIZE]; //内部SRAM内存池
  4. __align(32) uint8_t mem2base[MEM2_MAX_SIZE] __attribute__((at(0X68000000))); //外部SRAM内存池
  5. //内存管理表
  6. uint16_t mem1mapbase[MEM1_ALLOC_TABLE_SIZE]; //内部SRAM内存池MAP
  7. uint16_t mem2mapbase[MEM2_ALLOC_TABLE_SIZE] __attribute__((at(0X68000000+MEM2_MAX_SIZE))); //外部SRAM内存池MAP
  8. //内存管理参数
  9. const uint32_t memtblsize[SRAMBANK]={MEM1_ALLOC_TABLE_SIZE,MEM2_ALLOC_TABLE_SIZE}; //内存表大小
  10. const uint32_t memblksize[SRAMBANK]={MEM1_BLOCK_SIZE,MEM2_BLOCK_SIZE}; //内存分块大小
  11. const uint32_t memsize[SRAMBANK]={MEM1_MAX_SIZE,MEM2_MAX_SIZE}; //内存总大小
  12. //内存管理控制器
  13. struct _m_mallco_dev mallco_dev=
  14. {
  15. my_mem_init, //内存初始化
  16. my_mem_perused, //内存使用率
  17. mem1base,mem2base, //内存池
  18. mem1mapbase,mem2mapbase, //内存管理状态表
  19. 0,0, //内存管理未就绪
  20. };
  21. //复制内存
  22. //*des:目的地址
  23. //*src:源地址
  24. //n:需要复制的内存长度(字节为单位)
  25. void mymemcpy(void *des,void *src,uint32_t n)
  26. {
  27. uint8_t *xdes=des;
  28. uint8_t *xsrc=src;
  29. while(n--)*xdes++=*xsrc++;
  30. }
  31. //设置内存
  32. //*s:内存首地址
  33. //c :要设置的值
  34. //count:需要设置的内存大小(字节为单位)
  35. void mymemset(void *s,uint8_t c,uint32_t count)
  36. {
  37. uint8_t *xs = s;
  38. while(count--)*xs++=c;
  39. }
  40. //内存管理初始化
  41. //memx:所属内存块
  42. void my_mem_init(uint8_t memx)
  43. {
  44. mymemset(mallco_dev.memmap[memx], 0,memtblsize[memx]*2);//内存状态表数据清零
  45. mymemset(mallco_dev.membase[memx], 0,memsize[memx]); //内存池所有数据清零
  46. mallco_dev.memrdy[memx]=1; //内存管理初始化OK
  47. }
  48. //获取内存使用率
  49. //memx:所属内存块
  50. //返回值:使用率(0~100)
  51. uint8_t my_mem_perused(uint8_t memx)
  52. {
  53. uint32_t used=0;
  54. uint32_t i;
  55. for(i=0;i<memtblsize[memx];i++)
  56. {
  57. if(mallco_dev.memmap[memx][i])used++;
  58. }
  59. return (used*100)/(memtblsize[memx]);
  60. }
  61. //内存分配(内部调用)
  62. //memx:所属内存块
  63. //size:要分配的内存大小(字节)
  64. //返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
  65. uint32_t my_mem_malloc(uint8_t memx,uint32_t size)
  66. {
  67. signed long offset=0;
  68. uint32_t nmemb; //需要的内存块数
  69. uint32_t cmemb=0;//连续空内存块数
  70. uint32_t i;
  71. if(!mallco_dev.memrdy[memx])mallco_dev.init(memx);//未初始化,先执行初始化
  72. if(size==0)
  73. return 0XFFFFFFFF;//不需要分配
  74. nmemb=size/memblksize[memx]; //获取需要分配的连续内存块数
  75. if(size%memblksize[memx])nmemb++;
  76. for(offset=memtblsize[memx]-1;offset>=0;offset--)//搜索整个内存控制区
  77. {
  78. if(!mallco_dev.memmap[memx][offset])cmemb++;//连续空内存块数增加
  79. else cmemb=0; //连续内存块清零
  80. if(cmemb==nmemb) //找到了连续nmemb个空内存块
  81. {
  82. for(i=0;i<nmemb;i++) //标注内存块非空
  83. {
  84. mallco_dev.memmap[memx][offset+i]=nmemb;
  85. }
  86. return (offset*memblksize[memx]);//返回偏移地址
  87. }
  88. }
  89. return 0XFFFFFFFF;//未找到符合分配条件的内存块
  90. }
  91. //释放内存(内部调用)
  92. //memx:所属内存块
  93. //offset:内存地址偏移
  94. //返回值:0,释放成功;1,释放失败;
  95. uint8_t my_mem_free(uint8_t memx,uint32_t offset)
  96. {
  97. int i;
  98. if(!mallco_dev.memrdy[memx])//未初始化,先执行初始化
  99. {
  100. mallco_dev.init(memx);
  101. return 1;//未初始化
  102. }
  103. if(offset<memsize[memx])//偏移在内存池内.
  104. {
  105. int index=offset/memblksize[memx]; //偏移所在内存块号码
  106. int nmemb=mallco_dev.memmap[memx][index]; //内存块数量
  107. for(i=0;i<nmemb;i++) //内存块清零
  108. {
  109. mallco_dev.memmap[memx][index+i]=0;
  110. }
  111. return 0;
  112. }
  113. else
  114. return 2;//偏移超区了.
  115. }
  116. //释放内存(外部调用)
  117. //memx:所属内存块
  118. //ptr:内存首地址
  119. void myfree(uint8_t memx,void *ptr)
  120. {
  121. uint32_t offset;
  122. if(ptr==NULL)return;//地址为0.
  123. offset=(uint32_t)ptr-(uint32_t)mallco_dev.membase[memx];
  124. my_mem_free(memx,offset); //释放内存
  125. }
  126. //分配内存(外部调用)
  127. //memx:所属内存块
  128. //size:内存大小(字节)
  129. //返回值:分配到的内存首地址.
  130. void *mymalloc(uint8_t memx,uint32_t size)
  131. {
  132. uint32_t offset;
  133. offset=my_mem_malloc(memx,size);
  134. if(offset==0XFFFFFFFF)return NULL;
  135. else return (void*)((uint32_t)mallco_dev.membase[memx]+offset);
  136. }
  137. //重新分配内存(外部调用)
  138. //memx:所属内存块
  139. //*ptr:旧内存首地址
  140. //size:要分配的内存大小(字节)
  141. //返回值:新分配到的内存首地址.
  142. void *myrealloc(uint8_t memx,void *ptr,uint32_t size)
  143. {
  144. uint32_t offset;
  145. offset=my_mem_malloc(memx,size);
  146. if(offset==0XFFFFFFFF)return NULL;
  147. else
  148. { //拷贝旧内存内容到新内存
  149. mymemcpy((void*)((uint32_t)mallco_dev.membase[memx]+offset),ptr,size);
  150. //释放旧内存
  151. myfree(memx,ptr);
  152. //返回新内存首地址
  153. return (void*)((uint32_t)mallco_dev.membase[memx]+offset);
  154. }
  155. }

main.c

  1. /**
  2. ******************************************************************************
  3. * @file FSMC—外部SRAM(内存管理)
  4. * @author fire
  5. * @version V1.0
  6. * @date 2015-xx-xx
  7. * @brief sram应用例程
  8. ******************************************************************************
  9. * @attention
  10. *
  11. * 实验平台:野火 F103-霸道 STM32 开发板
  12. * 论坛 :http://www.firebbs.cn
  13. * 淘宝 :https://fire-stm32.taobao.com
  14. *
  15. ******************************************************************************
  16. */
  17. #include "stm32f10x.h"
  18. #include "./usart/bsp_usart.h"
  19. #include "./led/bsp_led.h"
  20. #include "./sram/bsp_sram.h"
  21. #include "bsp_malloc.h"
  22. int main(void)
  23. {
  24. u8 *p=0;
  25. u8 sramx=0; //默认为内部sram
  26. USART_Config(); //串口初始化为115200
  27. FSMC_SRAM_Init(); //初始化外部SRAM
  28. my_mem_init(SRAMIN); //初始化内部内存池
  29. my_mem_init(SRAMEX); //初始化外部内存池
  30. printf ( "\r\n野火内存管理\r\n" );
  31. printf ( "\r\n分配内存\r\n" );
  32. p = mymalloc ( sramx, 1024 *2 );//申请2K字节
  33. sprintf((char*)p,"Memory Malloc");//使用申请空间存储内容
  34. printf ( "SRAMIN USED:%d%%\r\n", my_mem_perused(SRAMIN) );//显示内部内存使用率
  35. printf ( "SRAMEX USED:%d%%\r\n", my_mem_perused(SRAMEX) );//显示外部内存使用率
  36. myfree(sramx,p); //释放内存
  37. p=0; //指向空地址
  38. printf ( "\r\n释放内存\r\n" );
  39. printf ( "SRAMIN USED:%d%%\r\n", my_mem_perused(SRAMIN) );//显示内部内存使用率
  40. printf ( "SRAMEX USED:%d%%\r\n", my_mem_perused(SRAMEX) );//显示外部内存使用率
  41. while(1);
  42. }
  43. /*********************************************END OF FILE**********************/

可执行程序:FSMC—外部SRAM(内存管理).zip