FSMC模拟8080时序及地址的计算

 一.简述

        在stm32单片机中对ili9341的8080通讯接口提供了一种特殊的办法——用FSMC接口来实现8080时序。在stm32单片机中FSMC外设是用来管理扩展存储器的,而lcd液晶显示屏中正好有显存这个东西,这与控制存储器的方式十分的相似,所以在这里我们利用FSMC模拟8080时序来控制液晶屏。

二.FSMC的存储器驱动简介

        STM32F1 系列芯片使用 FSMC 外设来管理扩展的存储器, FSMC 是 Flexible Static Memory Controller 的缩写,译为灵活的静态存储控制器。它可以用于驱动包括 SRAM、 NOR FLASH 以及 NAND FLSAH 类型的存储器。

FSMC的外设结构图

 如上图所示右边是FSMC外设相关功能的控制引脚。在本章中,我们利用STM32的FSMC外设,在NOR/PSRAM模式下,特别是借鉴了NOR_FLASH类型的模式B的时序配置,来模拟ILI9341液晶屏所需的8080接口时序,从而实现对液晶屏的控制。


NOR_FLASH 的信号线的信号名
FSMC的信号名信号方向功能
CLK输出时钟(同步突发模式使用)
A[ 25:0 ]输出地址总线
D[ 15:0 ]输入/输出双向数据总线
NE[ X ]输出片选,x=1...4
NOE输出输出使能
NWE输出写使能
NWAIT输入NOR闪存要求FSMC等待的信号
NADV输出地址,数据线复用时作锁存信号

STM32的FSMC外设来模拟LCD显示屏(如ILI9341)的8080接口时序时,一个重要的概念是“异步通信”。在FSMC的配置中,虽然它支持多种模式,包括那些可能会使用到clk(时钟)、nwait(等待信号)、nadv(地址选通)等引脚的同步或特定类型的异步模式,但在模拟8080时序时,我们实际上并不需要这些引脚。原因很简单:8080接口本身就是一个基于控制信号而非时钟信号的并行接口。因此,在FSMC的设置中,我们可以将这些引脚配置为未使用或忽略它们,因为它们对于模拟8080时序来说并不是必需的。

其 中 比 较 特 殊 的 FSMC_NE 是 用 于 控 制 存 储 器 芯 片 的 片 选 控 制 信 号 线, STM32 具 有 FSMC_NE1/2/3/4 号引脚,不同的引脚对应 STM32 内部不同的地址区域。例如,当 STM32 访
问 0x68000000-0x6BFFFFFF 地址空间时, FSMC_NE3 引脚会自动设置为低电平,由于它一般连
接到外部存储器的片选引脚且低电平有效,所以外部存储器的片选被使能,而访问 0x60000000-
0x63FFFFFF 地址时, FSMC_NE1 会输出低电平。
         不同类型的引脚是连接到 FSMC 内部对应的存储控制器中的 。 控制 NOR FLASH 的FSMC_BCR1/2/3/4 控制寄存器、FSMC_BTR1/2/3/4 片选时序寄存器以及,FSMC_BWTR1/2/3/4 写时序寄存器。每种寄存器都有 4 个,分别对应于 4 个不同的存储区域,各种寄存器介绍如下:
• FSMC_BCR 控制寄存器可配置要控制的存储器类型、数据线宽度以及信号有效极性能参数。
• FMC_BTR 时序寄存器用于配置 SRAM 访问时的各种时间延迟,如数据保持时间、地址保
• FMC_BWTR 写时序寄存器与 FMC_BTR 寄存器控制的参数类似,它专门用于控制写时序
的时间参数。

FSMC的内部存储器读取方式

        FSMC访问存储器地址的方式与用i2c访问eeprom及spi访问flash的方式并不一样。后者是通过总线给存储器发送地址获得数据,这个方式在程序里地址和数据都要分开使用不同的变量存储,在访问时同时需要用代码控制发送读写命令。前者是FSMC外接存储器,而存储器的存储单元是映射到stm32的内部寻址空间的,此时在程序里只要定义指向该地址的指针,就可以直接通过指针直接修改该存储单元的内容,FSMC外设会自动完成数据的访问过程。


FSMC的地址映射

上面就是将外部地址映射到stm32单片机的地址映射图。在这里FSMC会自动输出地址和数据。 在图的左边是stm32的存储空间的分配,右侧是stm32 FSMC外设的地址映射。在这里FSMC的NOR/PSRAM/SRAM/NAND FLASH以及PC卡的地址都在External RAM地址空间内。

FSMC将External RAM存储区域分为4个bank区域,并给对应的存储器类型分配了其地址范围。而每个bank的内部又分成了4个小块,每个小块有对应的控制引脚连接片选信号。比如FSMC_NE[4:1]信号线可以用来选择bank1内的4小块地址区域如下图所示,当stm32访问0x6c000000-0xfffffff地址空间时,就会访问bank1的第1小块区域,相应的FSMC_NE1信号线会输出控制信号。

三.FSMC 控制异步NOR FLASH的时序简介

        在上一节里面我们宏观的介绍了FSMC如何驱动存储器,在这一节里我们就要从微观的视角来了解FSMC控制异步NORFLASH的时序。FSMC外设支持输出多种不同的时序来控制不同的存储器,它具有ABCD4种模式。而我们只用到了B模式的功能,这里我们仅针对模式B进行讲解。


FSMC写NOR_FLASH的时序图

在stm32发出访问某个指向外部存储器地址时。FSMC外设会根据控制信号线产生时序访问存储器,上图就是访问外部异步NORFLASH(模式B)时FSMC外设的读写时序。以右图读时序为例,该图由一个存储器操作周期由地址建立周期(ADDSET),数据建立周期(DATAST),和2个HCLK周期组成。在地址建立周期的过程中,地址线发出要访问的地址,数据信号线指示要读取地址的高低字节部分,片选信号使能存储器芯片。地址建立的周期结束以后,读使能信号线发出读使能信号,接着存储器通过数据信号线把目标数据传输给FSMC,FSMC将其交给内核。

        根据stm32对寻址空间的地址映射,地址0x60000000~0x9FFFFFFF是映射到外部存储器的,

将这些地址分配给NORFALSH,PSAM这类可直接寻址的器件。假如FSMC外设被配置成正常工作的形式,并且外接了NORFALSH时,若向0x60000000地址写入数据如0xABCD,FSMC会自动在各信号线上产生相应的电平信号写入数据。FSMC会控制片选信号NE1选择相应的NOR芯片,然后使用地址线A[25:0]输出0x60000000,在NWE使能信号线上发出低电平的写使能信号,而要写的数据信号0xABCD则从数据线D[15:0]输出,然后数据就被保存到NORFLASH中了。

四.用FSMC模拟8080时序

        上一节我们讲解了FSMC是如何控制异步NORFLASH的时序的,其与8080时序十分的相似,只有FSMC的地址线与8080的D/CX线不一样。


FSMC的NOR和8080信号线对比

在上面的表格里我们可以看到,FSMC和8080的前4种信号线都是完全一样的,只有FSMC的地址信号线A[25:0]和8080的数据/命令选择线D/CX有区别。

D/CX线:它为高电平的时候表示数值,低电平的时候表示命令

所以我们只要修改A地址线不同情况产生对应的电平,就可以用FSMC来产生8080接口所要的时序了。 


FSMC模拟8080时序的操作

        模拟8080时序,我们将FSMC的A0地址线(可以使用A1/A2等地址线)和ili9341芯片8080接口的D/CX信号线连接,当A0为高电平时(即D/CX为高电平)数据线D[15:0]的信号会被ili9341理解为数值,当A0为低电平时(即D/CX为低电平)信号会被理解为命令。

        因为FSMC会自动产生地址信号,所以当FSMC向0x6xxxxxx1,0x6xxxxxx3,0x6xxxxxx5等这些 奇数 地址写入数据时,地址最低位的值均为1,所以它会控制地址线A0(D/CX)输出高电平,此时通过数据线传输的信号就会被理解为数值。当向0x6xxxxxx0,0x6xxxxxx2,0x6xxxxxx4等这些偶数地址写入数据时,地址最低位的值均为0,所以它会控制地址线A0(D/CX)输出低电平,这个时候通过数据线传输的信号会被理解为命令。

 有了这个基础,只要配置好 FSMC 外设,然后在代码中利用指针变量,向不同的地址单元写入数 据,就能够由 FSMC 模拟出的 8080 接口向 ILI9341 写入控制命令或 GRAM 的数据了。

五.代码详解

        FSMC的初始化配置重点是将FSMC配置成异步MORFLSH使用的模式B,还要注意FSMC的时钟的配置。在异步的时序里只有地址与数据建立时间是有效的,在这里1个HCLK的时钟周期的时钟频率为72MHZ。


 FSMC的初始化配置的相关代码


ili9341的时序参数图和ili9341的时序要求参数图

由上图我们可以知道ili9341的写周期最小twc=66ns,而读周期最小为trdl+trod=45+20=65ns。(对应读周期表中有参数要一个要求为trcfm和trc分别为450ns及160ns,但经过测试并不需要按照他们的指标要求)


FSMC的读写时序

         我们结合ili9341的时序要求和FSMC的配置图,代码中按照读写时序周期均要求至少66ns来计算,配置为ADDSET=1和DATST=4,把时间单位1/72微秒(即1000/72纳秒)代入。

读写周期的时间配置:

注意:将这两个参数值写入到FSMC后,其控制的读写周期 都比ili9341的最低要求值大。(这两个参数值可以适当的减小)

把计算得的参数赋值到时序结构体中的 FSMC_AddressSetupTime (即 ADDSET 的值)及
FSMC_DataSetupTime (即 DATAST 的值)中,然后再把时序结构体作为指针赋值到下面的 FSMC
初始化结构体中,作为读写的时序参数,最后再调用 FSMC_NORSRAMInit 函数即可把参数写入
到相应的寄存器中。

计算控制液晶屏使用时的地址

        当FSMC初始化完成后,FSMC模拟8080时序访问地址时,对应FSMC_Ax引脚会输出高电平(表示传输的是数据),FSMC_Ax引脚会输出低电平(表示传输的是命令)。


FSMC和8080的连接简图

计算地址的过程

        1.确定地址范围,当访问0x60000000~0x63FFFFFF地址时,FSMC会对外产生片选有效的访问时序(FSMC_NE1作为8080_CS片选信号)。

        2.在以上地址范围内,FSMC_A16输出高电平地址——数据;FSMC_A16输出低电平地址——命令(FSMC_A16作为数据/命令选择RS信号)。

要使 FSMC_A16 地址线为高电平,实质是输出地址信号的第 16 位为 1 即可,
使用 0X6000 0000~0X63FF FFFF 内的任意地址,作如下运算:
设置地址的第 16 位为 1 0X6000 0000 |= (1«16) = 0x6001 0000
不完全正确
要使 FSMC_A16 地址线为低电平,实质是输出地址信号的第 16 位为 0 即可,
使用 0X6000 0000~0X63FF FFFF 内的任意地址,作如下运算:
设置地址的第 16 位为 0 0X6000 0000 &= ~ (1«16) = 0x6000 0000
(不完全正确)        
注意:以上地址的计算并不完全正确,stm32 内部访问地址时使用的是内部 HADDR 总
线,它是需要转换到外部存储器的内部 AHB 地址线,它是字节地址 (8 ) ,而存储器访问不都
是按字节访问,因此接到存储器的地址线依存储器的数据宽度有所不同。

所以 HADDR FSMC_A 的地址线连接关系会左移 一位,如 HADDR1 FSMC_A0 对应、 HADDR2 FSMC_A1 对应。因此,当 FSMC_A0 地址线 为 1 时,实际上内部地址的第 1 位为 1 FSMC_A1 地址线为 1 时,实际上内部地址的第 2 位为 1。同样地,当希望 FSMC_A16 地址输出高电平或低电平时,需要重新调整计算公式:
要使 FSMC_A16 地址线为高电平,实质是访问内部 HADDR 地址的第 (16+1) 位 1 即可,
使用 0X6000 0000~0X63FF FFFF 内的任意地址,作如下运算:
使 FSMC_A16 地址线为高电平: 0X6000 0000 |= (1«(16+1)) = 0x6002 0000
要使 FSMC_A16 地址线为低电平,实质是访问内部 HADDR 地址的第 (16+1) 位 0 即可,
使用 0X6000 0000~0X63FF FFFF 内的任意地址,作如下运算:
使 FSMC_A16 地址线为低电平: 0X6000 0000 &= ~ (1«(16+1)) = 0x6000 0000

上述计算在工程代码中的应用

当 STM32 访问内部的 0x6002 0000 地址时,FSMC 自动输出 时序,且使得与液晶屏的数据/命令选择线 RS(D/CX) 相连的 FSMC_A16 输出高电平,使得液 晶屏会把传输过程理解为数据输;类似地,当 STM32 访问内部的 0X60000000 地址时,FSMC 自动输出时序,且使得与液晶屏的数据/命令选择线 RS(D/CX) 相连的 FSMC_A16 输出低电平, 使得液晶屏会把传输过程理解为命令传输。


使用 FSMC 访问数据及访问命令的地址

利用这样的宏,再使用指针的形式访问其地址,即可控制 FSMC 产生相应的时序,工程代码中把
发送命令及发送数据的操作封装成了内联函数,方便后面调用。
向液晶屏发送命令及发送数据的操作

需要写操作时,只要把要发送的命令代码或数据作为参数输入到函数然后调用即可,对于液晶屏
的读操作,把向指针赋值的过程改为读取指针内容即可。
向液晶屏写入初始化配置

以上列出的代码中省略了大量的配置内容,本质上它们都是使用 ILI9341_Write_Cmd 发送代码,
然后使用 ILI9341_Write_Data 函数发送命令对应的参数对液晶屏进行配置。
这个初始化过程中发送的代码及参数主要是配置了液晶屏的上电过程、显示屏的伽玛参数、分
辨率、像素格式等内容,这些配置主要由液晶屏生产厂家提供。

设置坐标显示窗口0X2A和0X2B

/********** ILI934 命令 ********************************/
#define   CMD_SetCoordinateX    0x2A
// 设置 X 坐标
#define   CMD_SetCoordinateY    0x2B
// 设置 Y 坐标
/** * @brief ILI9341 显示器上开辟一个窗口
* @param usX :在特定扫描方向下窗口的起点 X 坐标
* @param usY :在特定扫描方向下窗口的起点 Y 坐标
* @param usWidth :窗口的宽度
* @param usHeight :窗口的高度
* @retval
*/
void ILI9341_OpenWindow ( uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight )
{
        ILI9341_Write_Cmd ( CMD_SetCoordinateX ); /* 设置 X 坐标 */
        ILI9341_Write_Data ( usX >> 8 ); /* 先高 8 位,然后低 8 */
        ILI9341_Write_Data ( usX & 0xff ); /* 设置起始点和结束点 */
        ILI9341_Write_Data ( ( usX + usWidth - 1 ) >> 8 );
        ILI9341_Write_Data ( ( usX + usWidth - 1 ) & 0xff );
        ILI9341_Write_Cmd ( CMD_SetCoordinateY ); /* 设置 Y 坐标 */
        ILI9341_Write_Data ( usY >> 8 );
        ILI9341_Write_Data ( usY & 0xff );
        ILI9341_Write_Data ( ( usY + usHeight - 1 ) >> 8 );
        ILI9341_Write_Data ( ( usY + usHeight - 1 ) & 0xff );
}
        代码中定义的 ILI9341_OpenWindow 函数实现了图 设置显示窗口的 X 坐标 及图 设置液晶显示窗 口的 Y 坐标 0x2A 0x2B 命令,它们分别用于设置显示窗口的起始及结束的 X 坐标和 Y 坐 标,每个命令后包含 4 8 位的参数,这些参数组合后成起始坐标和结束坐标各 1 个用 16 位表示的值。ILI9341_OpenWindow 把它的四个函数输入参数 X Y 起始坐标,宽度、高度转化成命令参数的格式,写入到液晶屏中,从而设置出一个显示窗口。

这些代码的本质起始就是对存储器地址内容修改,但是我们要注意的是数据和命令一个要高电平一个要低电平。

//    uint32_t temp = 0x6C000000;
//    uint16_t lcd_read_temp;
    

//    //向LCD发送命令
//    *ILI9341_CMD_ADDR = 0xABCD;
//    *( uint16_t*)(0x60000000) = 0xABCD;
//    
//    //向LCD发送数据
//    *ILI9341_DATA_ADDR = 0x1234;
//    *( uint16_t*)(0x60020000) = 0xABCD;
//    
//    //从液晶屏读取数据
//    lcd_read_temp = *ILI9341_DATA_ADDR;
//    lcd_read_temp = *( uint16_t*)(0x60020000);
//    
//    
//    这里是设置高电平选择命令,低电平数据位的选择
//    temp =temp | (1<<(23+1));    
//    
//    printf("\r\nA23为高电平,地址=0x%x",temp);
//    
//    temp = 0x6C000000;
//    
//    temp &=  ~(1<<(23+1));
//    
//    printf("\r\nA23为低电平,地址=0x%x",temp);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值