本帖最后由 洋葱圈 于 2013-12-9 14:01 编辑
FlexBus是一种多功能的外部总线接口,在Kinetis K60芯片上,你见过最多的引脚可能就是FB_xx标号的了,这个就是FlexBus模块的复用功能引脚。FlexBus能干什么,它能够驱动各种从机设备,例如:外部ROM、RAM、FLash内存、可编程逻辑器件或其他器件(LCD控制器)…
接下来的内容,我们将针对OSKinetis固件库中的FlexBus库函数做详细讲解,如果你要了解FlexBus的具体功能、寄存器编程,建议你百度一下FlexBus,有几篇文章写的是不错的,如果你英文够好,那么更墙裂推荐看一下官网的应用文档AN4393-《Using FlexBus Interface for Kinetis Microcontrollers》-by: Carlos Musich and Alejandro Lozano.该文档针对Kinetis的FlexBus接口做了详尽的描述,包括外部RAM、LCD的应用实例、寄存器编程甚至PCB布线。 FlexBus驱动LCD不是什么LCD都能被FlexBus驱动,只有兼容8080或8600时序的LCD才可以被驱动,例如RUSH Kinetis开发板所用的LCD,其控制器型号是ILI9320,就可以直接被FlexBus驱动。本节将到的关于FlexBus驱动ILI9320的内容同样适用于其他类似型号的控制器。
FlexBus与LCD之间的连接下图是从ILI9320的技术文档中截取的,其中红框圈出的部分就是LCD与K60的FlexBus总线引脚实际需要连接的部分。由于是LCD控制器的文档,因此该图并未标出单片机一边的具体引脚。System Interface可以看做是K60的FlexBus引脚,ILI9320一边是LCD上的引脚。其中nCS是LCD控制器的使能信号(片选),它由K60的FB_CS0引脚控制;nWR是写使能信号 ,它由FB_RW引脚控制;nRD是读使能信号,它由FB_OE引脚控制,DB[17:0]是数据\命令总线,他们负责传输数据或者命令,方向是双向的,由于RUSH Kinetis开发板的LCD是16位数据传输的,因此只用到了ILI9320的DB[15:0],他们分别由FlexBus 的FB_AD15~FB_AD0控制;最后还有一个RS信号,他是LCD控制器的命令\数据选择信号,由于FlexBus没有特殊的这样一个引脚,因此我们采用FB_AD16引脚进行控制,至于为什么这样做下面会讲到。
FlexBus的LCD驱动编程在OSKinetis固件库中,既提供了FlexBus的底层库函数,又提供了LCD的驱动函数,其中LCD的驱动函数是基于FlexBux底层库函数封装的,如果你想用FlexBus库函数驱动其他设备,可以直接参考LCD驱动的写法。LCD的驱动函数在DEV文件夹下,名为DEV_LCD.h和DEV_LCD.c;FlexBus的库函数则在HW文件夹下。
下面具体看下LCD中关于FlexBus的初始化的代码是如何实现的,打开例程“LPLD_LCD”,打开lib\LPLD\DEV\DEV_LCD.c这个文件,可以看到函数LPLD_LCD_FLEXBUS_Init()
01 | FB_InitTypeDef fb_init; | 02 | fb_init.FB_Fbx = FB0; | 03 | fb_init.FB_ChipSelAddress = LCD_CMD_ADDRESS; | 04 | fb_init.FB_AutoAckEnable = TRUE; | 05 | fb_init.FB_IsRightJustied = TRUE; | 06 | fb_init.FB_WateStates = 0x02; | 07 | fb_init.FB_PortSize = FB_SIZE_16BIT; | 08 | fb_init.FB_AddressSpace = FB_SPACE_KB(128); //128K | 09 | fb_init.FB_ReadAddrHold = 0; | 10 | fb_init.FB_WriteAddrHold = 0; | 11 | LPLD_FlexBus_Init(fb_init); |
Line 1:首先还是初始化一个FlexBus结构体变量。
Line 2:选择使用FB0模块,这里有一点要注意,Kinetis内部有6个FB模块可用,FB0~FB5。但是只有在FB_CS0被使用的情况下,其他FB的片选才能使用。因此无论如何,用几个FBx都要先使能FB0……
Line 3:这里配置成员变量FB_ChipSelAddress来设置外部设备的片选地址,这里的LCD_CMD_ADDRESS是宏定义,其值是(0×60000000)。首先,这个值是有一定范围的,不能随便设置,Kinetis内部寻址空间给FlexBus划定的区域是(0x6000_0000至0xDFFF_FFFF),因此超过这个区域的地址都是不合法的。其次,你可能注意到了,这里的宏定义名字中带有CMD,这是我们起名的时候的一个Tip,代表这个地址是LCD控制器的命令总线地址,在操作LCD的时候我们要写入或读出各种命令,就直接往LCD_CMD_ADDRESS中去读写就可以了。你可能还会注意到在.h文件中定义了一个LCD_DATA_ADDRESS,没错,这个是LCD的数据总线地址,他的值是(0×60010000)。有没有注意到他比命令总线地址多了0×10000,这里的1出现在了地址的第16位,也就是说当使用这个地址时,FB_AD16这个信号会置1,即RS信号位高,代表写入数据。而其他的数据,不管是CMD数据还是DATA数据都走FB_0至FB_15这16位。
Line 4:使能FlexBus的自动应答产生。
Line 5:配置成员变量FB_IsRightJustied来设置数据右对齐,也就说,FlexBus上的有效数的最低位将出现在从FB_AD0上,例如LCD控制器是16位数据,那么他的读写数据就从FB_AD0~FB_AD15上出现,其余的引脚为地址信号,如FB_AD16。加入这里配置为FALSE,也就是说左对齐,那么LCD的16位数据就要从FB_AD31~FB_AD16上上出现,其余的位为地址信号。
Line 6:配置FB_WateStates在产生内部应答前加入的等待个数为2个。这个主要是配合具体的从设别而定,如果从设备运行速度较慢,则要多插入几个等待周期。
Line 7:配置FB_PortSize,设置FB总线的数据位宽为16位。
Line 8:配置寻址空间大小为128k,通过配置这个变量,FB库函数会自动初始化需要用到的FB_AD引脚个数、基地址掩码等参数,但是这个数字是如何确定的呢。原来我们总共使用了17个FB_AD引脚,因此2的16次方是就是128*1024这么大。当然一个LCD控制器可能实际用不了这么多地址,但是它不是一个RAM,我们无法确定他的寻址空间真正大小,只能通过它用到的引脚数来确定寻址空间大小。如果你使用的2Mbit的SRAM,就可以直接配置为256了,因为256K Byte=2M bit。
Line 9~10:配置读地址和写地址保持时间为0,即在CS使能之前保持时间为0。 以上就可以个以ILI9320为控制器的LCD液晶屏接口的初始化函数,当然这个仅仅是接口的初始化,代表初始化完成后你可以正常操作LCD命令和数据的读写操作,要想使LCD正常显示出图像,还需要进一步写入不同的命令和数据。这个过程就跟使用单片机内部的变量一样简单了,具体看下面一段代码:
1 | static void LPLD_LCD_WriteIndex(uint16 index) | 2 | { | 3 | *(vuint16*)LCD_CMD_ADDRESS = index; //write | 4 | } |
这是一个LCD驱动的内部函数LPLD_LCD_WriteIndex(),用来给LCD写控制命令,你可以看到我们可以直接把index的值给LCD_CMD_ADDRESS这个地址,就像给普通变量赋值一样简单,这样做的话Kinetis就会自动把index的这个16位数据,直接呈现在FB_AD0~FB_AD15上了,并且将RS置0,告诉LCD现在输出的是给你的控制命令。当然在代码中要做小小的设置,就是告诉编译器LCD_CMD_ADDRESS是一个16位数据的地址变量,在前面加强制转换“*(vuint16*)”。 剩下的读写数据函数和这个代码类似,大家可以自行浏览,然后其他的LCD屏幕初始化、绘图函数就全部通用了,即与FlexBus驱动是无关的了。
|