注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
刘程的个人空间 https://home.eeworld.com.cn/space-uid-392437.html [收藏] [复制] [分享] [RSS]
日志

STM32 FSMC

已有 6739 次阅读2012-7-19 14:23 |

      今天总算把stm32的FSMC搞懂了一部分,成果时候成功的把一个8位的显示屏以总线的方式驱动了,下面小总结一下啊。


下面内容来自网友:

FSMC全称“静态存储器控制器”

使用FSMC控制器后,可以把FSMC提供的FSMC_A[25:0]作为地址线,而把FSMC提供的FSMC_D[15:0]作为数据总线。

(1)当存储数据设为8位时,(FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b)

    地址各位对应FSMC_A[25:0],数据位对应FSMC_D[7:0]

(2)当存储数据设为16位时,(FSMC_NANDInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b)

    地址各位对应FSMC_A[24:0],数据位对应FSMC_D[15:0]

FSMC 包括4个模块:

(1)AHB接口(包括FSMC配置寄存器)

(2)NOR闪存和PSRAM控制器(驱动LCD的时候LCD就好像一个PSRAM的里面只有2个16位的存储空间,一个是DATA RAM 一个是CMD RAM)

(3)NAND闪存和PC卡控制器

(4)外部设备接口

:FSMC可以请求AHB进行数据宽度的操作。如果AHB操作的数据宽度大于外部设备(NOR或NAND或LCD)的宽度,此时FSMC将AHB操作分割成几个连续的较小的数据宽度,以适应外部设备的数据宽度。


FSMC对外部设备的地址映像从0x6000 0000开始,到0x9FFF FFFF结束,共分4个地址块,每个地址块256M字节。可以看出,每个地址块又分为4个分地址块,大小64M。对NOR的地址映像来说,我们可以通过选择HADDR[27:26]来确定当前使用的是哪个64M的分地址块,如下页表格。而这四个分存储块的片选,则使用NE[4:1]来选择。数据线/地址线/控制线是共享的。

NE1 ->Bank1   NE2->Bank2  NE3->Bank3  NE4->Bank4

若 NE1 连接, 则

每小块NOR/PSRAM 64M

 第一块:6000 0000h--63ff ffffh (DATA长度为8位情况下,由地址线FSMC_A[25:0]决定;DATA长度为16位情况下,由地址线FSMC_A[24:0]决定)

 第二块:6400 0000h--67ff ffffh

 第二块:6800 0000h--6bff ffffh

 第三块:6c00 0000h--6fff ffffh

注:这里的HADDR是需要转换到外部设备的内部AHB地址线,每个地址对应一个字节单元。因此,若外部设备的地址宽度是8位的,则HADDR[25:0]与STM32的CPU引脚FSMC_A[25:0]一一对应,最大可以访问64M字节的空间。若外部设备的地址宽度是16位的,则是HADDR[25:1]与STM32的CPU引脚FSMC_A[24:0]一一对应。在应用的时候,可以将FSMC_A总线连接到存储器或其他外设的地址总线引脚上。


来自网友的结束、、、、


所谓总线方式,这和之前学51单片机驱动8255之类芯片是一样的,有地址线,片选,读写选择等。操作时直接像对内存读写一样,直接赋值即可,至于时序关系,在初始化时完成


引脚对应关系

CS ----NE4      片选信号,可决定该外设属于哪个地址段

RES---RESET  直接连接芯片的复位端

RS----FSMC_A0  相当于片内地址信号,决定是写命令还是写数据

RW---NWE   写使能

RD----NOE  读使能


typedef struct

{

  vu8 LCD_REG;

  vu8 LCD_RAM;

} LCD_TypeDef;


/* LCD is connected to the FSMC_Bank1_NOR/SRAM4 and NE4 is used as ship select signal */

#define LCD_BASE   ((u32)(0x60000000 | 0x0C000000))

#define LCD         ((LCD_TypeDef *) LCD_BASE)


这一部分差点被忽略到了,他它决定了该模块的地址,LCD_REG地址为0x60C000000,则LCD_RAM地址默认自动加一为0x60C000001,最后一位刚好对应上FSMC_A0,相当于直接对存储器的读写


下面为IO引脚配置,都被配置成GPIO_Mode_AF_PP,注意数据口只是用了8位,因为是8位的LCD

void InitIO(void)

{

  GPIO_InitTypeDef GPIO_InitStructure;


  /* Enable FSMC, GPIOD, GPIOE, GPIOF, GPIOG and AFIO clocks */

  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);


  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |

                         RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG |

                         RCC_APB2Periph_AFIO, ENABLE);


  /* Set PD.00(D2), PD.01(D3), PD.04(NOE), PD.05(NWE), PD.08(D13), PD.09(D14),

     PD.10(D15), PD.14(D0), PD.15(D1) as alternate 

     function push pull */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |

                                GPIO_Pin_14 | GPIO_Pin_15;

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  GPIO_Init(GPIOD, &GPIO_InitStructure);


  /* Set PE.07(D4), PE.08(D5), PE.09(D6), PE.10(D7), PE.11(D8), PE.12(D9), PE.13(D10),

     PE.14(D11), PE.15(D12) as alternate function push pull */

  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10;

  GPIO_Init(GPIOE, &GPIO_InitStructure);


  /* Set PF.00(A0 (RS)) as alternate function push pull */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

  GPIO_Init(GPIOF, &GPIO_InitStructure);


  /* Set PG.12(NE4 (LCD/CS)) as alternate function push pull - CE3(LCD /CS) */

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

  GPIO_Init(GPIOG, &GPIO_InitStructure);


  /* LEDs pins configuration */


  /* Set PD7 to disable NAND */

}


下面为最重要的FSMC的配置,至于时序是怎么配置出来的,看了文档也没整清楚,反正这样配置是可行的,个人经验是主要配置p.FSMC_AddressSetupTime 和 p.FSMC_DataSetupTime 这两参数,数值越大,时间越长,模式选用模式B,例程使用模式A,没搞清楚AB是什么关系,其他的相对例程只需要把FSMC_MemoryDataWidth_16b改成FSMC_MemoryDataWidth_8b就OK了。


void LCD_FSMCConfig(void)

{

  FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;

  FSMC_NORSRAMTimingInitTypeDef  p;


/*-- FSMC Configuration ------------------------------------------------------*/

/*----------------------- SRAM Bank 4 ----------------------------------------*/

  /* FSMC_Bank1_NORSRAM4 configuration 3.15*/

  p.FSMC_AddressSetupTime = 2;

  p.FSMC_AddressHoldTime = 0;

  p.FSMC_DataSetupTime = 5;

  p.FSMC_BusTurnAroundDuration = 0;

  p.FSMC_CLKDivision = 0;

  p.FSMC_DataLatency = 0;

  p.FSMC_AccessMode = FSMC_AccessMode_B;


  /* Color LCD configuration ------------------------------------

     LCD configured as follow:

        - Data/Address MUX = Disable

        - Memory Type = SRAM

        - Data Width = 8bit

        - Write Operation = Enable

        - Extended Mode = Enable

        - Asynchronous Wait = Disable */

  FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;

  FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;

  FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM;

  FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_8b;

  FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;

  FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;

  FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;

  FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;

  FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;

  FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;

  FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;

 //  FSMC_NORSRAMInitStructure.FSMC_AsyncWait = FSMC_AsyncWait_Disable;

  FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;

  FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;

  FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;


  FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);  


  /* BANK 4 (of NOR/SRAM Bank 1~4) is enabled */

  FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);

     

}


然后就是两个较为重要的函数了,由于该LCD显示需要输入的数据是16位的,故需要输入两次,只要对相应的地址写两个值就行了,然后就可以和用IO驱动的兼容啦


//====================== 写命令 ==========================//


void Write_Cmd(unsigned char DH,unsigned char DL)

{

  LCD->LCD_REG = DH;

LCD->LCD_REG = DL;

}


//===================== 写数据 ===========================//


void Write_Data(unsigned char DH,unsigned char DL)

{

 LCD->LCD_RAM = DH;

LCD->LCD_RAM = DL;

}


做这个简单的移植花另外一天的时间,虽然最后还是没搞清楚FSMC是怎么一回事,但好歹学会了一些基本操作,对以后的是个铺垫吧、、、

全部作者的其他最新日志
发表评论 评论 (1 个评论)
回复 郭震2010 2012-9-14 10:22
有疑问 呀

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章