本例演示用的软硬件:
- 片内外设驱动库:STM32CubeF41.24.1的HAL库1.7.6,2019年4月12日
- IDE:MDK-ARM 5.28.0.0,2019年5月
- 开发板:片外SRAM挂在FSMC_NORPSRAM3,16bit×219=1MiB
本例的目的是让编程人员使用片外SRAM就像使用片内SRAM一样,即不用把任何变量声明到指定的RAM地址、连接器也能自动地把片外SRAM作为变量的存储空间
如果把所有需要被放到片外SRAM的变量用__attribute__((at()))、指针等声明到片外SRAM,那么完全不用像本例这样
执行main()前执行片内Flash上初始化FSMC及其GPIO的指令:
- 有些指令由启动文件的汇编代码生成,例如对于本例的STM32F407ZG来说这个启动文件就是startup_stm32f407xx.s(默认版本位于STM32CubeF4\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\arm)
- 有些函数在system_stm32f4xx.c(位于STM32CubeF4\Drivers\CMSIS\Device\ST\STM32F4xx\Source\Templates\)
对于本例的STM32F407来说修改上述的2个源文件的方法是:
1.换用官方的使用片外SRAM作运行内存的例程的启动文件
例如STM32CubeF4\Projects\STM324xG_EVAL\Examples\FSMC\FSMC_SRAM_DataMemory\MDK-ARM\startup_stm32f407xx.s
可以看到适用于使用片外SRAM运存的启动文件相较于默认版本的启动文件变化的地方有
- 第52行、第75行:定义用于初始化片外SRAM的栈
- 第191行~第192行:在执行main()前、执行完启动文件定义的指令后将栈顶指针恢复为默认值
52 __initial_spTop EQU 0x20000400 ; stack used for SystemInit & SystemInit_ExtMemCtl
75 __Vectors DCD __initial_spTop ; Top of Stack
177 __Vectors_End
178
179 __Vectors_Size EQU __Vectors_End - __Vectors
180
181 AREA |.text|, CODE, READONLY
182
183 ; Reset handler
184 Reset_Handler PROC
185 EXPORT Reset_Handler [WEAK]
186 IMPORT SystemInit
187 IMPORT __main
188
189 LDR R0, =SystemInit
190 BLX R0
191 LDR R0, =__initial_sp ; restore original stack pointer
192 MSR MSP, R0
193 LDR R0, =__main
194 BX R0
195 ENDP
2.取消注释system_stm32f4xx.c的第96行
91 /************************* Miscellaneous Configuration ************************/
92 /*!< Uncomment the following line if you need to use external SRAM or SDRAM as data memory */
93 #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
94 || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
95 || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
96 /* #define DATA_IN_ExtSRAM */
97 #endif /* STM32F40xxx || STM32F41xxx || STM32F42xxx || STM32F43xxx || STM32F469xx || STM32F479xx ||\
98 STM32F412Zx || STM32F412Vx */
那么system_stm32f4xx.c的
- 第662行~第716行
- 开启FSMC模块用到的GPIO的时钟(第662行)
- 配置相应GPIO口的模式、速度等信息(第667行~第712行)
- 开启FSMC模块的时钟(第716行))
- 第737行~第741行
- 配置FSMC_NORPSRAM的控制、时序(第739行~第741行)
都会被执行
655 #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
656 || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
657 || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
658
659 #if defined(DATA_IN_ExtSRAM)
660 /*-- GPIOs Configuration -----------------------------------------------------*/
661 /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
662 RCC->AHB1ENR |= 0x00000078;
663 /* Delay after an RCC peripheral clock enabling */
664 tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
665
666 /* Connect PDx pins to FMC Alternate function */
667 GPIOD->AFR[0] = 0x00CCC0CC;
668 GPIOD->AFR[1] = 0xCCCCCCCC;
669 /* Configure PDx pins in Alternate function mode */
670 GPIOD->MODER = 0xAAAA0A8A;
671 /* Configure PDx pins speed to 100 MHz */
672 GPIOD->OSPEEDR = 0xFFFF0FCF;
673 /* Configure PDx pins Output type to push-pull */
674 GPIOD->OTYPER = 0x00000000;
675 /* No pull-up, pull-down for PDx pins */
676 GPIOD->PUPDR = 0x00000000;
677
678 /* Connect PEx pins to FMC Alternate function */
679 GPIOE->AFR[0] = 0xC00CC0CC;
680 GPIOE->AFR[1] = 0xCCCCCCCC;
681 /* Configure PEx pins in Alternate function mode */
682 GPIOE->MODER = 0xAAAA828A;
683 /* Configure PEx pins speed to 100 MHz */
684 GPIOE->OSPEEDR = 0xFFFFC3CF;
685 /* Configure PEx pins Output type to push-pull */
686 GPIOE->OTYPER = 0x00000000;
687 /* No pull-up, pull-down for PEx pins */
688 GPIOE->PUPDR = 0x00000000;
689
690 /* Connect PFx pins to FMC Alternate function */
691 GPIOF->AFR[0] = 0x00CCCCCC;
692 GPIOF->AFR[1] = 0xCCCC0000;
693 /* Configure PFx pins in Alternate function mode */
694 GPIOF->MODER = 0xAA000AAA;
695 /* Configure PFx pins speed to 100 MHz */
696 GPIOF->OSPEEDR = 0xFF000FFF;
697 /* Configure PFx pins Output type to push-pull */
698 GPIOF->OTYPER = 0x00000000;
699 /* No pull-up, pull-down for PFx pins */
700 GPIOF->PUPDR = 0x00000000;
701
702 /* Connect PGx pins to FMC Alternate function */
703 GPIOG->AFR[0] = 0x00CCCCCC;
704 GPIOG->AFR[1] = 0x000000C0;
705 /* Configure PGx pins in Alternate function mode */
706 GPIOG->MODER = 0x00085AAA;
707 /* Configure PGx pins speed to 100 MHz */
708 GPIOG->OSPEEDR = 0x000CAFFF;
709 /* Configure PGx pins Output type to push-pull */
710 GPIOG->OTYPER = 0x00000000;
711 /* No pull-up, pull-down for PGx pins */
712 GPIOG->PUPDR = 0x00000000;
713
714 /*-- FMC/FSMC Configuration --------------------------------------------------*/
715 /* Enable the FMC/FSMC interface clock */
716 RCC->AHB3ENR |= 0x00000001;
734 #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
735 || defined(STM32F412Zx) || defined(STM32F412Vx)
736 /* Delay after an RCC peripheral clock enabling */
737 tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
738 /* Configure and enable Bank1_SRAM2 */
739 FSMC_Bank1->BTCR[2] = 0x00001011;
740 FSMC_Bank1->BTCR[3] = 0x00000201;
741 FSMC_Bank1E->BWTR[2] = 0x0FFFFFFF;
从system_stm32f4xx.c的第738行的注释可知,第739行~第741行分别配置的是FSMC_NORPSRAM2的控制寄存器、读写时序寄存器、写时序寄存器,而我使用的开发板的片外SRAM挂在FSMC_NORPSRAM3,所以需要修改system_stm32f4xx.c上述的写GPIO寄存器、FSMC寄存器的代码,获取正确的寄存器值的方法是核外片内外设只开启FSMC_NORPSRAM3及其GPIO,再在硬件调试过程中复制出相应的寄存器值
3.更正system_stm32f4xx.c的上述代码
(再次提醒没仔细读题的读者:下文的代码只被保证适用于( (STM32F407ZG) && (片外SRAM挂在FSMC_NORPSRAM3) && (片外SRAM是16bit×219=1MiB) )的情况,且应该根据你用的SRAM芯片、STM32的AHB总线时钟频率等信息修改第739行~第741行配置FSMC寄存器用的值。用上一段提到的方法获取适用于你的开发板的寄存器值,用本文初提到的方法获取适用于你的单片机的启动文件):
655 #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx) || defined(STM32F417xx)\
656 || defined(STM32F427xx) || defined(STM32F437xx) || defined(STM32F429xx) || defined(STM32F439xx)\
657 || defined(STM32F469xx) || defined(STM32F479xx) || defined(STM32F412Zx) || defined(STM32F412Vx)
658
659 #if defined(DATA_IN_ExtSRAM)
660 /*-- GPIOs Configuration -----------------------------------------------------*/
661 /* Enable GPIOD, GPIOE, GPIOF and GPIOG interface clock */
662 RCC->AHB1ENR |= 0x00000078;
663 /* Delay after an RCC peripheral clock enabling */
664 tmp = READ_BIT(RCC->AHB1ENR, RCC_AHB1ENR_GPIODEN);
665
666 /* Connect PDx pins to FMC Alternate function */
667 GPIOD->AFR[0] = 0x00CC00CC;
668 GPIOD->AFR[1] = 0xCCCCCCCC;
669 /* Configure PDx pins in Alternate function mode */
670 GPIOD->MODER = 0xAAAA0A0A;
671 /* Configure PDx pins speed to 100 MHz */
672 GPIOD->OSPEEDR = 0xFFFF0F0F;
673 /* Configure PDx pins Output type to push-pull */
674 GPIOD->OTYPER = 0x00000000;
675 /* No pull-up, pull-down for PDx pins */
676 GPIOD->PUPDR = 0x00000000;
677
678 /* Connect PEx pins to FMC Alternate function */
679 GPIOE->AFR[0] = 0xC00000CC;
680 GPIOE->AFR[1] = 0xCCCCCCCC;
681 /* Configure PEx pins in Alternate function mode */
682 GPIOE->MODER = 0xAAAA800A;
683 /* Configure PEx pins speed to 100 MHz */
684 GPIOE->OSPEEDR = 0xFFFFC00F;
685 /* Configure PEx pins Output type to push-pull */
686 GPIOE->OTYPER = 0x00000000;
687 /* No pull-up, pull-down for PEx pins */
688 GPIOE->PUPDR = 0x00000000;
689
690 /* Connect PFx pins to FMC Alternate function */
691 GPIOF->AFR[0] = 0x00CCCCCC;
692 GPIOF->AFR[1] = 0xCCCC0000;
693 /* Configure PFx pins in Alternate function mode */
694 GPIOF->MODER = 0xAA000AAA;
695 /* Configure PFx pins speed to 100 MHz */
696 GPIOF->OSPEEDR = 0xFF000FFF;
697 /* Configure PFx pins Output type to push-pull */
698 GPIOF->OTYPER = 0x00000000;
699 /* No pull-up, pull-down for PFx pins */
700 GPIOF->PUPDR = 0x00000000;
701
702 /* Connect PGx pins to FMC Alternate function */
703 GPIOG->AFR[0] = 0x00CCCCCC;
704 GPIOG->AFR[1] = 0x00000C00;
705 /* Configure PGx pins in Alternate function mode */
706 GPIOG->MODER = 0x00200AAA;
707 /* Configure PGx pins speed to 100 MHz */
708 GPIOG->OSPEEDR = 0x00300FFF;
709 /* Configure PGx pins Output type to push-pull */
710 GPIOG->OTYPER = 0x00000000;
711 /* No pull-up, pull-down for PGx pins */
712 GPIOG->PUPDR = 0x00000000;
713
714 /*-- FMC/FSMC Configuration --------------------------------------------------*/
715 /* Enable the FMC/FSMC interface clock */
716 RCC->AHB3ENR |= 0x00000001;
734 #if defined(STM32F405xx) || defined(STM32F415xx) || defined(STM32F407xx)|| defined(STM32F417xx)\
735 || defined(STM32F412Zx) || defined(STM32F412Vx)
736 /* Delay after an RCC peripheral clock enabling */
737 tmp = READ_BIT(RCC->AHB3ENR, RCC_AHB3ENR_FSMCEN);
738 /* Configure and enable Bank1_SRAM3 */
739 FSMC_Bank1->BTCR[4] = 0x00001091;
740 FSMC_Bank1->BTCR[5] = 0x00100222;
4.在MDK把FSMC_NORPSRAM3映射的地址范围0x68000000~0x6BFFFFFF的首1M设为运行内存
把0x68000000、0x100000分别填入下图窗口右下角的"Read/Write Memory Areas"的”off-chip“的任一行:
5.修改完后Reuild
(注意:如果你用MDK-ARM以外的软件修改了前述的2个源文件,那么MDK-ARM可能不知道你修改了那2个文件,所以如果仅Build,那么IDE可能会拿编译旧版本的源文件得到的目标文件进行连接
或者你手动让MDK-ARM知道你修改过那些文件再仅Build,比如在MDK-ARM打开前述的2个源文件,在里面随便找个地方加个字再删掉那个字了再Build)
从MAP文件可以看到,变量被分配到了片外SRAM映射的地址范围0x68000000~0x68100000中,且单片机程序能正常
Exec Addr Load Addr Size Type Attr Idx E Section Name Object
0x68000000 0x0800628c 0x00000008 Data RW 19 .data main.o
0x68000008 0x08006294 0x00000008 Data RW 247 .data stm32f4xx_hal_msp.o
0x68000010 0x0800629c 0x0000000c Data RW 1539 .data stm32f4xx_hal.o
0x6800001c 0x080062a8 0x00000004 Data RW 1772 .data system_stm32f4xx.o
0x68000020 0x080062ac 0x00000004 Data RW 1842 .data tftlcd.o
0x68000024 - 0x00000050 Zero RW 18 .bss main.o
0x68000074 - 0x0000000e Zero RW 1840 .bss tftlcd.o
0x68000082 0x080062b0 0x00000006 PAD
0x68000088 - 0x00000400 Zero RW 1 STACK startup_stm32f407xx.o
希望CubeMX以后的版本能自动将片外RAM设为运存
来源:oschina
链接:https://my.oschina.net/u/4383691/blog/4331798