打印
[应用相关]

【转】分享关于STM32-FSMC 问题解决方法

[复制链接]
5258|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
android2|  楼主 | 2018-5-27 19:07 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
现在我用stm32f103ve, 配置fsmc, 驱动TFT, 只能配置成 psram模式, 如果配置其他模式,就会出现 fsmc总线没反应情况(当配置成sram,nor模式, 运行到 FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); ,就出现没有响应)

配置成psram模式, 读写模式B, 写数据可以, 当运行读数据时候, 就出现fsmc总线没有反应, 不知还有哪些设置影响 fsmc的配置.

可以确认,外部连线电路都正常,用i/0模拟总线方式, 可以读写,tft驱动都正常,

不知道哪位大大有解决方法,不胜感激,

tft fsmc
cs ne1(pd7)
RS A16
wr wr
rd rd
d0-d15 d0-d15

命令地址 0x60020000
数据地址 0x60000000

fsmc 配置
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef p;
/* FSMC_Bank1_NORSRAM1 timing configuration */
p.FSMC_AddressSetupTime = 15; /*地址建立时间期限*/
p.FSMC_AddressHoldTime = 15; /*地址的持续时间*/
p.FSMC_DataSetupTime = 100; /*设定数据时间期限*/
p.FSMC_BusTurnAroundDuration = 0; /*总线转向时间*/
p.FSMC_CLKDivision = 2; /*CLK时钟输出信号的HCLK周期数表示时间???*/
p.FSMC_DataLatency = 1; /*指定在获得第一个数据前的时钟周期*/
p.FSMC_AccessMode = FSMC_AccessMode_B;
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; /*指定的FSMC块*/
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; /*地址和数据值不复用的数据总线*/
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_PSRAM; /*外部存储器的类型*/
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; /*数据宽度*/
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; /* 禁用突发访问模式*/
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;/*指定等待信号的极性*/
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; /*Enables or disables the Wrapped burst access mode for Flash*/
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; /*启用指定的FSMC的写操作*/
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable; /*扩展模式*/
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; /*禁用写突发操作*/
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;

FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
/* Enable FSMC Bank1_SRAM Bank */
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);



有多个思路可以考虑。
1.看看库是不是太老了
2.不用库,而直接操作寄存器,我经常这么做。
3.FSMC用到的GPIO时钟 是否打开? 相关的引脚(特别要检查/RD或者说 /OE)设置了AF功能吗?

4.“只能配置成 psram模式, 如果配置其他模式,就会出现 fsmc总线没反应情况(当配置成sram,nor模式, 运行到 FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure); ,就出现没有响应”
这是不正常的症状,说明有潜在的问题。 配置成sram模式,以此为突破口,把潜在的问题解决掉。


十分感谢ijk, 现在终于读写正常了, 我把调试步骤写下来,

1. 当设置为psram模式,可以正常,其他模式不正常,经分析, 是初始化问题,
具体什么问题,分析完之后,我总结
2. 设置一些参数之后, sram,nor模式正常写了,但读不正常,也是初始化问题

3. 经过楼上 ijk的提醒, 我仔细研究了一下 datasheet, 经过仿真跟踪,
发现 fsmc的 faccen(bit6) 是0, datasheet表示此 bit 不用管
因为我设置为模式A, 扩展模式使能, 是模式A,不是模式1,
当我手动把faccen 设置成 1, 运行下去, 奇迹出现了,发现可以读了, 一时之间感觉天地都对我在笑
困扰了我近2个星期的问题终于拨开云雾了, 我看了下库函数,发现没有设置faccen的参数
第一感觉,ST库函数有bug,被我发现了,是不是可以向ST那边要些奖励(偷笑), 后来想想不对,
那么多人用fsmc,为什么就我发现问题,其他人都没发现, 我的代码也是参考别人成功应用的,
不应该有问题, 那么是什么问题导致FSMC不能读, 翻了库函数里面关于norsram初始化部分,
看到一个函数FSMC_NORSRAMStructInit, 突然感觉来灵感了,感觉找到问题点了,
因为我定义了初始化的变量,可能有部分参数没有初始化,设置参数时候,出现错误参数,按照这个
思路, 我把程序增加了 FSMC_NORSRAMStructInit 调用, 定义完变量之后,就调用这个函数
然后其他保持不变, 奇迹出现了, 发现一切正常了, 即使 faccen一直为0, 也能读了,我更改模式b,
调节了读写时间参数, 都能正常工作,

最后的结论就是, 初始化出问题了, 虽然问题解决了, 但是我奇怪很多例程都没调用FSMC_NORSRAMStructInit也能正常工作, 不知道是什么原因.
我用的编译器 iar 6.30,

如果有类似的问题的人, 有问题了,首先从寄存器入手, 看看寄存器的数值是不是你所需要的,

非常感谢ijk给的思路, 解决了问题!

下边贴出来FSMC初始化部分

//===============================================
FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
FSMC_NORSRAMTimingInitTypeDef p;
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
FSMC_NORSRAMStructInit(&FSMC_NORSRAMInitStructure);
/* FSMC_Bank1_NORSRAM1 timing configuration */
p.FSMC_AddressSetupTime = 0; /*地址建立时间期限*/
p.FSMC_AddressHoldTime = 0; /*地址的持续时间*/
p.FSMC_DataSetupTime = 2; /*设定数据时间期限*/
p.FSMC_BusTurnAroundDuration = 0; /*总线转向时间*/
p.FSMC_CLKDivision = 0; /*CLK时钟输出信号的HCLK周期数表示时间???*/
p.FSMC_DataLatency = 0; /*指定在获得第一个数据前的时钟周期*/
p.FSMC_AccessMode = FSMC_AccessMode_A;
FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM1; /*指定的FSMC块*/
FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable; /*地址和数据值不复用的数据总线*/
FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_SRAM; /*外部存储器的类型*/
FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b; /*数据宽度*/
FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable; /*禁用突发访问模式*/
FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;/*指定等待信号的极性*/
FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable; /*Enables or disables the Wrapped burst access mode for Flash*/
FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable; /*启用指定的FSMC块的写操作*/
FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable; /*扩展模式*/
FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable; /*禁用写突发操作*/
FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &p;
FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &p;
FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);
/* Enable FSMC Bank1_SRAM Bank */
FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM1, ENABLE);
//======================================================
沙发
xixi2017| | 2018-5-27 19:25 | 只看该作者
有一个模式有反应,能正常用吗

使用特权

评论回复
板凳
zhuomuniao110| | 2018-5-27 23:41 | 只看该作者
多谢分享。我也找个分享来。

使用特权

评论回复
地板
zhuomuniao110| | 2018-5-27 23:42 | 只看该作者
LCD有如下控制线:
CS:Chip Select 片选,低电平有效
RS:Register Select 寄存器选择
WR:Write 写信号,低电平有效
RD:Read 读信号,低电平有效
RESET:重启信号,低电平有效
DB0-DB15:数据线
假如这些线,全部用普通IO口控制。根据LCD控制芯片手册(大部分控制芯片时序差不多):
如果情况如下:
DB0-DB15的IO全部为1(表示数据0xff),也可以为其他任意值,这里以0xff为例。
CS为0(表示选上芯片,CS拉低时,芯片对传入的数据才会有效)
RS为1(表示DB0-15上传递的是要被写到寄存器的值),如果为0,表示传递的是数据。(这里原作者应该是搞反了,应该是:RS = 0时,表示读写寄存器;RS = 1表示读写数据RAM。)
WR为0,RD为1(表示是写动作),反过来就是读动作。
RESET一直为高,如果RESET为低,会导致芯片重启。
这种情况,会导致一个值0xff被传入芯片,被LCD控制芯片当作写寄存器值去解析。LCD控制芯片收到DB0-15上的值之后,根据其他控制线的情况,它得出结论,这个0xff是用来设置寄存器的。一般情况下,LCD控制芯片会把传入的寄存器值的高8位当做寄存器地址(因为芯片内部肯定不止一个寄存器),低8位当做真正的要赋给对应寄存器值。这样,就完成了一个写LCD控制芯片内部寄存器的时序。
如果上述情况不变,只将RS置低,那么得到的情况如下:LCD控制芯片会把DB0-15上的数据当做单纯的数据值来处理。那么假如LCD处在画图状态,这个传入的值0xff,就会被显示到对应的点上,0xffff就表示白色,那么对应的点就是白色。在这个数据值传递过来之前,程序肯定会通过设置寄存器值,告诉LCD控制芯片要写的点的位置在哪里。
如果上述两种情况都不变,分别把WR和RD的信号反过来(WR=1,RD=0),那么写信号就会被变成读信号。读信号下,主控芯片需要去读DB0-15的值,而LCD控制芯片就会去设置DB0-15的值,从而完成读数据的时序。
读寄存器的时序麻烦一点。第一步,先要将WR和RD都置低,主控芯片通过DB0-15传入寄存器地址。第二步就和前面读数据一样,将WR置高,RD置低,读出DB0-15的值即可。在这整个的过程中,RS一直为低。
好了,上面就是IO直接控制LCD的方法。假如放到STM32里面,用IO直接控制显得效率很低。STM32有FSMC(其实其他芯片基本都有类似的总线功能),FSMC的好处就是你一旦设置好之后,WR、RD、DB0-DB15这些控制线和数据线,都是FSMC自动控制的。打个比方,当你在程序中写到:
*(volatile unsigned short int *)(0x60000000)=val;
那么FSMC就会自动执行一个写的操作,其对应的主控芯片的WE、RD这些脚,就会呈现出写的时序出来(即WE=0,RD=1),数据val的值也会通过DB0-15自动呈现出来(即FSMC-D0:FSMC-D15=val)。地址0x60000000会被呈现在数据线上(即A0-A25=0,地址线的对应最麻烦,要根据具体情况来,好好看看FSMC手册)。
那么在硬件上面,我们需要做的,仅仅是MCU和LCD控制芯片的连接关系:
WE-WR,均为低电平有效
RD-RD,均为低电平有效
FSMC-D0-15接LCD DB0-15
连接好之后,读写时序都会被FSMC自动完成。但是还有一个很关键的问题,就是RS没有接,CS没有接。因为在FSMC里面,根本就没有对应RS和CS的脚。怎么办呢?这个时候,有一个好方法,就是用某一根地址线来接RS。比如我们选择了A16这根地址线来接,那么当我们要写寄存器的时候,我们需要RS,也就是A16置高。软件中怎么做呢?也就是将FSMC要写的地址改成0x60020000,如下:
*(volatile unsigned short int *)(0x60020000)=val;
这个时候,A16在执行其他FSMC的同时会被拉高,因为A0-A18要呈现出地址0x60020000。0x60020000里面的Bit17=1,就会导致A16为1。
当要读数据时,地址由0x60020000改为了0x60000000,这个时候A16就为0了。
那么有朋友就会有疑问,第一,为什么地址是0x6xxxxxxx而不是0x0xxxxxxx;第二,CS怎么接;第三,为什么Bit17对应A16?
先来看前两个问题,大家找到STM32的FSMC手册,在FSMC手册里面,我们很容易找到,FSMC将0x60000000-0x6fffffff的地址用作NOR/PRAM(共256M地址范围)。而这个存储块,又被分成了四部分,每部分64M地址范围。当对其中某个存储块进行读写时,对应的NEx就会置低。这里,就解决了我们两个问题,第一,LCD的操作时序,和NOR/PRAM是一样的(为什么一样自己找找NOR/PRAM的时序看看),所以我们选择0x6xxxxxxx这个地址范围(选择这个地址范围,操作这个地址时,FSMC就会呈现出NOR/PRAM的时序)。第二,我们可以将NEx连接到LCD的CS,只要我们操作的地址是第一个存储块内即可(即0-0x3ffffff地址范围)。
第三个问题再来看一看FSMC手册关于存储器字宽的描述,我们发现,当外部存储器是16位时,硬件管脚A0-A24表示的是地址线A1-A25的值,所以我们要位移一下,Bit17的值,实际会被反应到A16这根IO来。关于数据宽度及位移的问题,初学的朋友可能会比较疑惑,当你接触了多NOR/PRAM这样的器件后,你会发现,很多芯片的总线,都是这样设计的,为的是节省地址线。

PS:看到这里还是不明白,于是查了下手册,有这么一个图,大意是若外部设备的地址宽度是8位的,则HADDR[25:0]与STM32的CPU引脚FSMC_A[25:0]一一对应,最大可以访问64M字节的空间。若外部设备的地址宽度是16位的,则是HADDR[25:1]与STM32的CPU引脚FSMC_A[24:0]一一对应。

HADDR

FSMC_A

25

·

·

1

24

·

·

0

就是上图这个意思,这里的HADDR是需要转换到外部设备的内部AHB地址线,每个地址对应一个字节单元。所以我的理解是:上面出现的地址0x60020000,是工作于CPU内部的地址,体现在HADDR上面是17脚,但是转换到硬件引脚上就是FSMC_A16脚了(因为从上图看来,地址正好是差1,虽然HADDR的地址0并没有,但是可以虚构一下,就当它有了,呵呵),与液晶屏的RS脚相连。

                                                  ——纯粹个人瞎理解,老是感觉再看的时候跟新的一样,还是用自己的话记录一下吧

那么上面就完全解决了LCD驱动如何接FSMC的问题,如果读者没懂,建议将上述文字抄上一遍,FSMC手册对应NOR/PRAM的章节抄一遍。还没懂,就继续抄一遍,抄到懂为止。
虽然上述只是针对LCD讲解了FSMC,但是其实对NOR和外部RAM的操作也是类似的,只不过多了些地址线来寻址而已。

使用特权

评论回复
5
wing.yang| | 2019-2-16 10:55 | 只看该作者
本帖最后由 wing.yang 于 2019-2-16 11:09 编辑


按楼主的代码刷出来是花屏,刷RGB也刷不出来,有人遇到同样情况吗?

使用特权

评论回复
6
wing.yang| | 2019-2-16 18:13 | 只看该作者
找到原因了,LCD初始化代码错了

使用特权

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

本版积分规则

137

主题

784

帖子

0

粉丝