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布线。
不是什么LCD都能被FlexBus驱动,只有兼容8080或8600时序的LCD才可以被驱动,例如RUSH Kinetis开发板所用的LCD,其控制器型号是ILI9320,就可以直接被FlexBus驱动。本节将到的关于FlexBus驱动ILI9320的内容同样适用于其他类似型号的控制器。
下图是从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引脚进行控制,至于为什么这样做下面会讲到。[attach]53270[/attach]
在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驱动是无关的了。
和单片机内部的RAM一样,SRAM是一种临时存储数据的设备,一旦掉电数据就不复存在。但是他的读写速度都要比ROM、Flash快很多。很多应用在使用大数组存储图像或其他数据时,常常会受限于单片机内部的小RAM的牵制,这时候外扩一个大容量的RAM会是一个不错的选择。在RUSH Kinetis的开发板上,内置了一个2Mbit大小的SRAM,他相比与SDRAM,读写速度要更加迅速。
与LCD相比,SRAM的连接更加复杂一点,具体电路原理图如下图所示。在RUSH Kinetis开发板上,采用型号为IS61WV12816DBLL的SRAM,芯片上的Ax为地址引脚,IOx为数据引脚,OE、WE、CE分别是读使能、写使能和片选,LB和UB分别是选择16位数据的低8位和高8位。在与FlexBus的实际连接中,我们用FB_AD0~FB_AD17这18个引脚作为SRAM的地址总线,但是你会发现A0实际上是由FB_AD1控制的,那么FB_AD0去哪了呢?原来这里我们采用了AD0来控制高低8位的选择,将AD0直接连接至LB,再将通过非门的AD0_B连接至UB,可以达到控制16位数据中高低8位数据选择的目的。这样就使得本来是16位数据寻址的SRAM变为了8位数据寻址。再看IOx的16个数据引脚,由于通过控制LB和UB可实现单次8位数据的读写,因此这里只需要FB_AD24~FB_AD31这8个信号来读写数据了。为了能使FlexBus总线在LCD与SRAM之间复用,在SRAM的连接中采用FB_CS1作为该器件的片选引脚。
[attach]53272[/attach]
同样的,OSKinetis库函数中提供了SRAM的驱动函数,该驱动函数在DEV_SRAM.c中实现,下面看一下SRAM中的初始化代码(例程“LPLD_SDRAM”):
01 | FB_InitTypeDef fb_init; |
02 | fb_init.FB_Fbx = FB1; |
03 | fb_init.FB_ChipSelAddress = SDRAM_ADDRESS; |
04 | fb_init.FB_AutoAckEnable = TRUE; |
05 | fb_init.FB_IsRightJustied = FALSE; |
06 | fb_init.FB_WateStates = 0x02; |
07 | fb_init.FB_PortSize = FB_SIZE_8BIT; |
08 | fb_init.FB_AddressSpace = FB_SPACE_KB(SDRAM_SIZE); |
09 | fb_init.FB_ReadAddrHold = 0; |
10 | fb_init.FB_WriteAddrHold = 0; |
11 | LPLD_FlexBus_Init(fb_init); |
Line 3:配置SRAM的片选地址为SDRAM_ADDRESS,该宏定义的值为(0×70000000),在FlexBus的预留空间范围内。
Line 5:配置FB_IsRightJustied成员变量为FALSE,也就是说不使用右对齐方式,即FB1模块的数据由FB_ADx总线的最高位开始输入输出,即左对齐。
Line 7:配置数据位宽为FB_SIZE_8BIT,即8位位宽,因此SRAM的8位数据会从FB的AD31~AD24这8个口进行传输。而其余的AD0~AD17则作为FlexBus的地址总线传输地址数据。
Line 8:配置FB1的寻址空间大小为SDRAM_SIZE,该宏定义的值为(256),即SRAM的大小为2 Mbit=256 KByte。
初始化完毕后,你就可以直接用以SDRAM_ADDRESS为地址开始的变量进行数据的存储了,使用方法和上面介绍的LCD的方法一样。当然,SDRAM_ADDRESS仅仅是一个SRAM寻址空间的基地址,也就是说SDRAM_ADDRESS只能存1个字节,如果你要再存第二个字节,需要在SDRAM_ADDRESS的地址上+1。为了方便开发,OSKinetis提供了SRAM的动态内存分配函数,这些函数的使用方法和malloc()、free()等函数一样,只不过分配的内存空间均在外部SRAM内。具体的使用方法请见例程“LPLD_SDRAM”。
1 | //初始化SDRAM所需的FlexBus |
2 | void LPLD_SDRAM_Init(void); |
3 | //在SDRAM中动态分配一段空间 |
4 | void *LPLD_SDRAM_Malloc(unsigned); |
5 | //释放在SDRAM中动态分配的空间 |
6 | void LPLD_SDRAM_Free(void *); |
欢迎光临 智能车制作 (http://111.231.132.190/) | Powered by Discuz! X3.2 |