代码改变世界

话说stm32f10x-FSMC的配置与频率

2013-08-28 10:56  居安  阅读(5149)  评论(0编辑  收藏  举报

1.存储器,从例子说起
  存储器读写,cpu与芯片同步等等都需要参考设备的读写时序,并通过参考cpu系统时钟,给出合理的读写周期。
  这里以stm32f103zeT6读写外部CSRAM为例子加以说明。
选用用的CSRAM芯片的读写模式为同步非复用,频率为36MHz,芯片挂在cpu的FSMC的BANK1 SRAM4区,其同步非复用
模式就不多讲,具体参考《STM32F103ZET6》p51~p52。至于这个36MHz则需要进行对FSMC的读写时序进行控制。如何
控制呢?网上很多资料在这里都没有详细的说明,估计是很多网友觉得这个比较容易吧。但是当时我真是被这个问题
给搞的半死不活。后来沉下心来悉心研究了一段时间,终于知道是怎么配置这个36MHz了。
 首先需要明确的是,stm32f10x固件库提供了简便的FSMC配置过程,我们可以利用一个结构体就进行配置,而不用
对具体的寄存器进行一位一位的填写。具体的配置如下:
  FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;
 FSMC_NORSRAMTimingInitTypeDef  FSMC_NORSRAMTimingInitStructure;
 //
 FSMC_NORSRAMTimingInitStructure.FSMC_AddressSetupTime = 1; 
 FSMC_NORSRAMTimingInitStructure.FSMC_AddressHoldTime = 0;  
 FSMC_NORSRAMTimingInitStructure.FSMC_DataSetupTime = 2;
 FSMC_NORSRAMTimingInitStructure.FSMC_BusTurnAroundDuration = 0;   //总线恢复时间-19:16

 /*系统选用PLL作为时钟输出源,而PLL频率为72MHz,CRAM读写频率为36MHz,所以采用2分频*/
 FSMC_NORSRAMTimingInitStructure.FSMC_CLKDivision = 1; //bit-23:20,分频比为1,则存储器读写周期为 1/2 SYSCLK

 FSMC_NORSRAMTimingInitStructure.FSMC_DataLatency = 0;    //bit27:24,(数据保持时间)对于CRAM这个参数必须为0
 FSMC_NORSRAMTimingInitStructure.FSMC_AccessMode = FSMC_AccessMode_A;  //访问模式-只对FSMC_BCR1中EXTMOD位为1时起作用
 
   //以下是配置FSMC_BCR1寄存器的各个位
 FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4; 
 FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; //非复用MUXEN:bit1
 FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM; //MTYP-bit3:2存储器类型 
 FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;  //存储器数据总线宽度-bit5:4
 FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;//BURSTEN-bit8 成组模式使能
 FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait = FSMC_AsynchronousWait_Disable; //bit15这一位手册里面保留...
 FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;  //WAITPOL-bit9-等待信号极性
 FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; //WRAPMOD-bit10是否支持费对其成组模式
 FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState; //WAITCFG-bit11
 FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; //WREN-bit12
 FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;  //WAITEN-bit13-等待使能
 FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;  //EXTMOD-bit14 读写时序不一致时设置
 FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Enable;     //同步写-CBURSTRW(bit19)
 FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &FSMC_NORSRAMTimingInitStructure; 
 FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &FSMC_NORSRAMTimingInitStructure;

 FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
 /* Enable FSMC Bank1_SRAM4 Bank */
 //根据PCB原理图 CSRAM的片选信号ARM_325T_CS与PG12连接,而PG12则是FSMC_NE4
 FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);
 
 上面的配置大部分都给出了明确的解释,有些解释比较书面化,如不能理解透彻还是参照《STM32F10XXX参考手册》18章具体的
寄存器说明进行查阅。
   这里只重点讲下,时钟配置,FSMC_NORSRAMTimingInitStructure.FSMC_CLKDivision = 1;这条语句,为什么配置为1?首先知
道这条命令的含义。FSMC_CLKDivision表示分频比,而这个分频的参考是SYSCLK,而我的初始化程序中将系统时钟设置为72MHZ。
而这里CRAM读写频率是36MHZ,所以要进行二分频,根据手册,二分频则需要将FSMC_BTRx寄存器的CLKDIV(bit23~bit20)位配置为
1,即FSMC_NORSRAMTimingInitStructure.FSMC_CLKDivision = 1;这样就ok了~

 

2.时钟,从启动程序说起
 另外要说的是,我的开发工具是keil-uVersion4+rt-thread,这个非常好用,boot程序都已经写好了的。查看其启动程序,发现中
断向量表的第二个向量放的是复位中断,片段如下:
__Vectors       DCD     __initial_sp                    ; Top of Stack
                DCD     Reset_Handler                   ; Reset Handler //复位中断
系统一旦复位便进入复位中断,并调用复位中断处理程序,处理如下:
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP
                
 我们可以看到,复位中断处理首先调用的是SystemIint程序,再调用c库函数_main,SystemInit也就是初始化我们的板子的运行环境,
包括时钟,SRAM,FLASH等等,主要是时钟这一块。这个函数对HSE,HSI,PLL,以及系统时钟进行配置。
 这里只列出关于PLL和系统时钟的配置
 /* 
   硬件电路中HSE给的是12MHz(其实默认是8MHz,在stm32f10x中其取值范围为4~16MHz,具体参考《STM32F103ZET6中文》p42)

 */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
                                        RCC_CFGR_PLLMULL));
 
  //PLL 时钟配置: PLLCLK = HSE * 6 = 72 MHz
 RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL6);
 
 系统复位后,HSI被选为系统时钟(HSI),而我们这里要选择PLL作为SYSCLK的时钟源,代码如下:
  /* Select PLL as system clock source */
    RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
    RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;  
 这样系统时钟就是72MHz。