查看了很多关于STM32 FSMC连接TFT LCD (ILI9320)的讨论,还是困惑中。。。
我用GPIO方式已经可以正确的驱动LCD了,但FSMC方式一直不成功,所以请教各位。
下面是我的程序:
#define FSMC_BCR1 *((long int*)0xA0000000)
#define FSMC_BTR1 *((long int*)0xA0000004)
#define LCD_Data_Address *((unsigned int*)0x60020000)
#define LCD_CMD_Address *((unsigned int*)0x60000000)
void LCD_Write2REG(unsigned int COM_Index, unsigned int COM_Dat) //就是这个函数的时序总是不对。
{
LCD_CS_Low();
LCD_CMD_Address = COM_Index;
__nop();
__nop();
__nop();
LCD_Data_Address = COM_Dat;
__nop();
__nop();
__nop();
LCD_CS_High();
}
void FSMC_init(void) //FSMC的设置
{
FSMC_BCR1 = 0x00001010;
FSMC_BTR1 = 0x00000501;
FSMC_BWTR1 = 0xFFFFFFFF;
FSMC_BCR1 |= 0x00000001;
}
我用示波器测量了以下/WR信号,感觉不对,虽然在/CS为低时,/WR输出两次,但在/CS信号为高时,仍然输出两次低有效,搞不懂是哪来的?另外地址A16接LCD的RS信号,测量发现A16也输出不正常,很奇怪的变化。
/CS信号为高时,对于你的设备,其它信号线上的任何电平都是没有意义的,你必须用/CS信号来控制你的设备,是否需要解释其它信号线上信号。
我很奇怪在/CS为高时为什么会有/WR输出呢?
一开始我将/CS以FSMC方式输出的,但时序总是不对,所以我改成了GPIO方式输出了。今天又折腾了一天还是没收获。
为什么/CS为高时不能有/WR输出呢?/WR信号是所有设备共享的呀。
如果按照你的逻辑,/CS为高时不能有/WR输出,那么/CS还有多少意义呢?岂不是直接用/WR也可以实现/CS的功能了?
LZ,
/CS是片选,意思是选中这个芯片。
而选中这个芯片却可以有多种情况:
1、写
2、读
3、传送地址(SDRAM等,这里没用到)
而/WR是给大家用的,只有/CS和/WR同时有效时你这个芯片才会被选中执行,明白吗?
而你的/CS无效时,别的挂在总线上的芯片当然还可以操作(读、写),当然也会有/WR信号,很明显,这时你是不应该响应的。
那这么才能不响应呢?
——最基本的逻辑:与、或、非,或者组合一下就可以了,自己去想想吧
当然,
如果没有任何操作而总线有动作,一种原因是使用了片外存储器;另一种原因那就是见鬼了
而如果操作时总线数据、逻辑不对,那就得检查自己的逻辑、原理是否对了,然后检查实际的硬件是不是对!
大家误会了,我的意思是FSMC上我只挂了一个LCD而没有其他设备,并且只有LCD_Write2REG()函数里有
LCD_CMD_Address = COM_Index;
LCD_Data_Address = COM_Dat;
向FSMC写数据!
所以,我才奇怪在/CS为高时为什么会有/WR输出?! 包括/CS以GPIO方式和FSMC都有观察到!而且输出的时序与我设置的模式A根本不对!
GPIO设置:
GPIOD_CRL = 0xB4BB2BBB;
GPIOD_CRH = 0xBB82BBBB;
GPIOD_ODR = 0x0000FFFF;
GPIOE_CRL = 0xB4222888;
GPIOE_CRH = 0xBBBBBBBB;
GPIOE_ODR = 0x0000FFFF;
FSMC设置:
void FSMC_init(void)
{
FSMC_BCR1 = 0x00001010; //WREN: 0 允许FSMC对存储器的写操作;这是复位后的默认状态
//MWID: 01 存储器数据总线宽度16位
//MBKEN 1 启用对应的存储器
FSMC_BTR1 = 0x00000501;
FSMC_BWTR1 = 0xFFFFFFFF;
FSMC_BCR1 |= 0x00000001;
}
即使这样设置,用示波器量/CS和/WR时序也和模式A对不上呀。还有就是A16(PD11)的时序也不对!
要测量总线 应该把数据+CS+RD+WR+必要的ADDR全部接在逻辑分析仪上面
当然,可以先省掉,数据线,但是CS+RD+WR+地址线是一定要的
真要用示波器测 也起码要3-4通道的 CS+RD/WR(只会有一个出现,坏了除外)+地址
不知道你的程序中是否还依然是:
- LCD_Data_Address = COM_Dat;
- __nop();
- __nop();
- __nop();
- LCD_CS_High();
复制代码如果是,你还是换回IO模拟吧
请楼主在图中标出你认为有问题的地方,我没有看到你说的问题。
经过这量天测试,重新总结一下:
1)GPIO方式没有问题。
2)FSMC方式有问题。通过示波器结论如下:
设置FSMC总线宽度为16位时,定义
#define LCD_Data_Address *((unsigned int*)0x60020000)
#define LCD_CMD_Address *((unsigned int*)0x60000000)
当执行LCD_CMD_Address = COM_Index; COM_Index定义为unsigned int. 模式A时序,则
应该是在/CS信号为低有效时,只应该有一个/WR低有效信号输出,但实际测量发现是有两个WR低有效信号输出,如上图TEK00002.JPG所示。就象输出分两次以16位数据总线输出了一个32位的数据。我做了个试验,把FSMC总线宽度设为8位时,则在/CS信号为低有效时,有四个/WR低有效信号输出。假设我定义#define LCD_Data_Address *((unsigned char*)0x60020000) 并且设置16位FSMC总线。执行LCD_CMD_Address = COM_Index; COM_Index定义为unsigned int. 模式A时序,则在/CS信号为低有效时,就只有1个/WR低有效信号输出了。所以很奇怪不知道为什么。
我看了一下汇编程序,LCD_CMD_Address = COM_Index编译为:
MOVS R2, #0x60000000
STR R0, [R2]
是不是默认输出就是32位的数据了?
问题就出在你对数据宽度没有足够的理解。这样的定义决定的:
#define LCD_Data_Address *((unsigned int*)0x60020000)
#define LCD_CMD_Address *((unsigned int*)0x60000000)
unsigned int的数据宽度是32位,你定义LCD_Data_Address和LCD_CMD_Address为32位的数据,当设置FSMC总线宽度为16位时,相当于把32位的数据通过16位的通道送出,FSMC当然需要执行2次操作了。
下图是STM32参考手册上的一张图,我用红线标出的那一行,清楚地说明了你这种情况需要分成2次FSMC访问。
你只要把数据宽度和通道的宽度定义为相同就可以了。
呵呵 果然,大家都没注意到...
原因在于,也许大家潜意识中就认为楼主写的是正确的
#define LCD_Data_Address *((unsigned int*)0x60020000)
#define LCD_CMD_Address *((unsigned int*)0x60000000)
改成
#define LCD_Data_Address *((unsigned short int*)0x60020000)
#define LCD_CMD_Address *((unsigned short int*)0x60000000)
就好了。
这个地方真没注意
谢谢大家!