打印

关于STM32 FSMC再请教

[复制链接]
13654|24
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
jjl3|  楼主 | 2009-9-14 22:41 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
查看了很多关于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也输出不正常,很奇怪的变化。
沙发
香水城| | 2009-9-14 22:56 | 只看该作者
/CS信号为高时,对于你的设备,其它信号线上的任何电平都是没有意义的,你必须用/CS信号来控制你的设备,是否需要解释其它信号线上信号。

使用特权

评论回复
板凳
jjl3|  楼主 | 2009-9-15 19:58 | 只看该作者
我很奇怪在/CS为高时为什么会有/WR输出呢?
一开始我将/CS以FSMC方式输出的,但时序总是不对,所以我改成了GPIO方式输出了。今天又折腾了一天还是没收获。

使用特权

评论回复
地板
香水城| | 2009-9-15 21:40 | 只看该作者
为什么/CS为高时不能有/WR输出呢?/WR信号是所有设备共享的呀。

如果按照你的逻辑,/CS为高时不能有/WR输出,那么/CS还有多少意义呢?岂不是直接用/WR也可以实现/CS的功能了?

使用特权

评论回复
5
xwj| | 2009-9-15 21:54 | 只看该作者
LZ,
/CS是片选,意思是选中这个芯片。
而选中这个芯片却可以有多种情况:
1、写
2、读
3、传送地址(SDRAM等,这里没用到)

而/WR是给大家用的,只有/CS和/WR同时有效时你这个芯片才会被选中执行,明白吗?
而你的/CS无效时,别的挂在总线上的芯片当然还可以操作(读、写),当然也会有/WR信号,很明显,这时你是不应该响应的。

那这么才能不响应呢?
——最基本的逻辑:与、或、非,或者组合一下就可以了,自己去想想吧:)

使用特权

评论回复
6
xwj| | 2009-9-15 21:58 | 只看该作者
当然,
如果没有任何操作而总线有动作,一种原因是使用了片外存储器;另一种原因那就是见鬼了;P

而如果操作时总线数据、逻辑不对,那就得检查自己的逻辑、原理是否对了,然后检查实际的硬件是不是对!

使用特权

评论回复
7
jjl3|  楼主 | 2009-9-15 22:29 | 只看该作者
大家误会了,我的意思是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)的时序也不对!

使用特权

评论回复
8
aozima| | 2009-9-16 00:36 | 只看该作者
要测量总线 应该把数据+CS+RD+WR+必要的ADDR全部接在逻辑分析仪上面
当然,可以先省掉,数据线,但是CS+RD+WR+地址线是一定要的
真要用示波器测  也起码要3-4通道的  CS+RD/WR(只会有一个出现,坏了除外)+地址

不知道你的程序中是否还依然是:
LCD_Data_Address         = COM_Dat;
        __nop();
        __nop();
        __nop();
LCD_CS_High();
如果是,你还是换回IO模拟吧

使用特权

评论回复
9
jjl3|  楼主 | 2009-9-16 09:57 | 只看该作者
上个图,这样清楚些

TEK00001.JPG (57.48 KB )

TEK00001.JPG

TEK00002.JPG (94.28 KB )

TEK00002.JPG

使用特权

评论回复
10
香水城| | 2009-9-16 12:14 | 只看该作者
请楼主在图中标出你认为有问题的地方,我没有看到你说的问题。

使用特权

评论回复
11
jjl3|  楼主 | 2009-9-16 17:52 | 只看该作者
经过这量天测试,重新总结一下:
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低有效信号输出了。所以很奇怪不知道为什么。

使用特权

评论回复
12
jjl3|  楼主 | 2009-9-16 18:15 | 只看该作者
我看了一下汇编程序,LCD_CMD_Address          = COM_Index编译为:
MOVS R2, #0x60000000
STR R0, [R2]
是不是默认输出就是32位的数据了?

使用特权

评论回复
13
jjl3|  楼主 | 2009-9-16 19:06 | 只看该作者
这个问题好像不止我遇到
http://www.st.com/mcu/forums-cat-8487-23.html

使用特权

评论回复
14
香水城| | 2009-9-16 21:20 | 只看该作者
问题就出在你对数据宽度没有足够的理解。这样的定义决定的:
#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访问。

你只要把数据宽度和通道的宽度定义为相同就可以了。

STM32_FSMC_Memory_Support.GIF (26.91 KB )

STM32_FSMC_Memory_Support.GIF

使用特权

评论回复
15
aozima| | 2009-9-16 23:16 | 只看该作者
呵呵 果然,大家都没注意到...

原因在于,也许大家潜意识中就认为楼主写的是正确的:lol

使用特权

评论回复
16
jjl3|  楼主 | 2009-9-17 10:44 | 只看该作者
#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)
就好了。
这个地方真没注意
谢谢大家!

使用特权

评论回复
17
来与君| | 2012-2-9 17:39 | 只看该作者
围观一下,以后用上。

使用特权

评论回复
18
chenhou99| | 2012-2-10 08:36 | 只看该作者
仔细看资料

使用特权

评论回复
19
Xflyan| | 2012-2-10 09:27 | 只看该作者
mark!! 正准备在F4DISCOVERY上通过FSMC接LCD...

使用特权

评论回复
20
雨辰073| | 2012-3-13 09:59 | 只看该作者
正准备外接FPGA呢,mark!

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

43

主题

265

帖子

2

粉丝