OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7606|回复: 7

FSMC 配置及应用 LCD 显示问题

[复制链接]

3

主题

8

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2013-8-5
在线时间
0 小时
发表于 2013-12-25 12:42:02 | 显示全部楼层 |阅读模式

日期: 2013/12/25 12:31
主题: FSMC 配置及应用 LCD 显示问题
/*
*********************************************************************************************************
* 函 数 名: LCD_gpioFSMCInit
* 功能说明: 初始化LCD
* 形    参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void LCD_gpioFSMCInit(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    FSMC_NORSRAMTimingInitTypeDef  WriteTiming;
    FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOD 
                         | RCC_APB2Periph_GPIOE |RCC_APB2Periph_AFIO, ENABLE);

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
/* 设置 
T_PEN    A1
T_CS     PA4
T_SCK    A5
T_MISO   PA6
T_MOSI   PA7              为复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1| GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
/* 设置 
D0-D1  D14 PD15
D2-D3  D0  D1
D13-D15  D8-PD10
nOE      D4    
nWE      D5  
nCS2     PD7
RS       PD11(FSMC A16)  为复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 
                                | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_8
                                | GPIO_Pin_9 | GPIO_Pin_10|GPIO_Pin_11| GPIO_Pin_14| GPIO_Pin_15 ;
/*  */
    GPIO_Init(GPIOD, &GPIO_InitStructure);

/* 设置 
D4-D12  E7-PE15  为复用推挽输出 */
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
                     GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13| GPIO_Pin_14 |GPIO_Pin_15 ;
    GPIO_Init(GPIOE, &GPIO_InitStructure);
   /*
// PD11 推挽输出 复位、数据命令区分线
    GPIO_InitStructure.GPIO_Pin =GPIO_Pin_11;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_Init(GPIOD, &GPIO_InitStructure);
*/
 //   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);

    WriteTiming.FSMC_AddressSetupTime = 0x02;       //地址建立时间
    WriteTiming.FSMC_AddressHoldTime = 0x00;         //地址保持时间
    WriteTiming.FSMC_DataSetupTime = 0x05;         //数据建立时间
    WriteTiming.FSMC_BusTurnAroundDuration = 0x00; //总线恢复时间
    WriteTiming.FSMC_CLKDivision = 0x00;          //时钟分频
    WriteTiming.FSMC_DataLatency = 0x00;        //数据保持时间
    WriteTiming.FSMC_AccessMode = FSMC_AccessMode_A;   //在地址\数据线不复用的情况下,ABCD模式的区别不大

    FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;                                //NOR FLASH的BANK4
    FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;              //数据与地址总线不复用
    FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;                          //存储器类型NOR FLASH
    FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;                //数据宽度为16位
    FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;            //使用异步写模式,禁止突发模式
    FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;          //只在突发模式下有效,等待信号极性为低
    FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;                          //禁止非对齐性突发模式
    FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;  //仅在突发模式下有效,NWAIT信号在什么周期产生
    FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;               //写使能
    FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;                      //仅在突发模式下有效,禁用NWAIT信号
    FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;                  //禁止扩展模式,扩展模式可以使用独立的读、写模式
    FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;                      //禁止突发写操作
    FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &WriteTiming;                  //配置读写时序
    FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &WriteTiming;                         //配置写时序 

    FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);            //初始化FSMC配置
    FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);                                             //使能FSMC Bank1_SRAM Bank
}

/*-----------------------------------------------------------------------------------*/
 //LCD地址结构体
typedef struct
{
u16 LCD_REG;  //地址寄存器
u16 LCD_RAM;  //数据寄存器
} LCD_TypeDef;
/*
TFTLCD通过RS信号来决定传送的数据是数据还是命令,本质上可以理解为一个地址信号,
比如我们把RS接在A0上面,那么当FSMC控制器写地址0的时候,会使得A0变为0,对TFTLCD来说,就是写命令。而FSMC写地址1的时候,A0将会变为1,对TFTLCD来说,就是写数据了。这样,就把数据和命令区分开了,他们其实就是对应SRAM操作的两个连续地址。当然RS也可以接在其他地址线上,战舰STM32开发板是把RS连接在A10上面的。
BANK1 第一区 0x6000 0000  --0x63FF FFFF
      第二区 0x6400 0000  --0x64FF FFFF
      第三区 0x6800 0000  --0x68FF FFFF
      第四区 0x6C00 0000  --0x6CFF FFFF
BANK2 0x7000 0000 -- 0x7FFF FFFF   
BANK3 0x8000 0000 -- 0x8FFF FFFF      
BANK4 0x9000 0000 -- 0x9FFF FFFF      
其中LCD_BASE,必须根据我们外部电路的连接来确定,我们使用Bank1.sector4就是从地址0X6C000000开始,而0X000007FE,则是A10的偏移量。我们将这个地址强制转换为LCD_TypeDef结构体地址,那么可以得到LCD->LCD_REG的地址就是0X6C00,07FE,对应A10的状态为0(即RS=0),而LCD-> LCD_RAM的地址就是0X6C00,0800(结构体地址自增),对应A10的状态为1(即RS=1)。
所以,有了这个定义,当我们要往LCD写命令/数据的时候,可以这样写:
LCD->LCD_REG=CMD;  //写命令
LCD->LCD_RAM=DATA; //写数据
而读的时候反过来操作就可以了,如下所示:
CMD= LCD->LCD_REG;//读LCD寄存器
DATA = LCD->LCD_RAM;//读LCD数据
*/
#define LCD_BASE    ((u32)(0x6C000000|0x0001FFFE))    // A16
#define LCD             ((LCD_TypeDef *) LCD_BASE) // 对应LCD->LCD_REG 地址0x6C01 FFFE
                                                   //    LCD->LCD_RAM  地址0x6001FFFE 
/*-----------------------------------------------------------------------------------*/

//初始化lcd
//该初始化函数可以初始化各种ILI93XX液晶,但是其他函数是基于ILI9320的!!!
//在其他型号的驱动芯片上没有测试! 
void LCD_Init(void)
{


 LCD_gpioFSMCInit();
// mdelay(50);
// LCD_Reset();
 mdelay(50);//
// Light = 1;
// LCD_WriteRAM(0xffff);    //作用?????
DeviceCode=LCD_ReadReg(0X0000);
printf(" LCD ID:%x\n",DeviceCode); //打印LCD ID   十六进制
     。
     。
     。


问题: 全速运行时,设备ID为 0x0000 , 单步时位 0x FFFE 错误!
        原子哥能不能帮忙看看呢?  
         







正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

8

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2013-8-5
在线时间
0 小时
 楼主| 发表于 2013-12-25 12:47:46 | 显示全部楼层
圣诞了! 祝原子哥及各位朋友 学有所成,工作顺利!
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-12-25 17:32:58 | 显示全部楼层
回复【楼主位】温sir:
---------------------------------
LCD初始化那里,你先发个命令让LCD软件复位一下,等待50ms之后再去读取ID

问下,你的LCD是什么驱动IC的,用原子的例程读,看串口助手打印信息,原子哥的驱动兼容好几种IC的
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

头像被屏蔽

38

主题

382

帖子

0

精华

高级会员

Rank: 4

积分
596
金钱
596
注册时间
2012-12-5
在线时间
19 小时
发表于 2013-12-25 19:17:25 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

3

主题

8

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2013-8-5
在线时间
0 小时
 楼主| 发表于 2013-12-25 20:54:23 | 显示全部楼层
回复【3楼】Badu_Space:
---------------------------------
ILI9328 驱动,我这没有原子哥 FSMC总线控制的TFT屏例程(库函数)。 好像我的初始化没错,用你的方法,以及下一楼“toddchen”朋友的也没解决。

有点赖不住性了。  谢谢建议!
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-12-26 12:16:03 | 显示全部楼层
回复【5楼】温sir:
---------------------------------
我的方法和3楼这位兄台的差不多,初始化的时候你可以这样
delay_ms(50);     //等待相关寄存器完成初始化
      LCD_WriteRegisterData(0x0000, 0x0001);    //软件复位
      delay_ms(50);

      LCD_Manage.ID = LCD_ReadRegisterData(0x0000);      //读取LCD型号
这个很多LCD都支持的,可以试下

我的FSMC地址是这个,你可以参考下
#define LCD_REG_ADD           ((u32)(0x6c000000 | 0x00000000)) //寄存器地址,命令,RS = 0
      #define LCD_DAT_ADD           ((u32)(0x6c000000 | 0x00000800)) //显示数据地址,显示RAM,RS = 1

      #define LCD_WR_REG(index)     ((*(__IO u16 *)(LCD_REG_ADD)) = ((u16)index))
                                    //写LCD寄存器写入数值index
      #define LCD_WR_Data(val)      ((*(__IO u16 *)(LCD_DAT_ADD)) = ((u16)val))
                                    //往LCD的RAM写入数据val
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

3

主题

8

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2013-8-5
在线时间
0 小时
 楼主| 发表于 2013-12-28 11:37:34 | 显示全部楼层
回复【6楼】Badu_Space:
---------------------------------
问题已解决,能正常显示。 我把 #define(*(—IO u16 *)) 0x60000000 
                                      写成 #define(*(—IO u32 *)) 0x60000000 了,(错了!)

终其原因,指针没用好,不是很懂! 可以解释下么?
回复 支持 反对

使用道具 举报

120

主题

7878

帖子

13

精华

资深版主

Rank: 8Rank: 8

积分
12012
金钱
12012
注册时间
2013-9-10
在线时间
427 小时
发表于 2013-12-31 10:52:12 | 显示全部楼层
回复【7楼】温sir:
---------------------------------
不好意思啊,前些日子不小心推出账号了忘记登录密码,所以没及时回复你,不好意思啊

这个指针呢, #define(*(—IO u16 *)) 0x60000000这句的理解就是将指针指到0x60000000这个地址,放数据的时候就是往这个地址写数据,简单点的理解就是快递,今天有个手机货物快递寄给你,明天有个电脑快递给你,你的地址是不变的,但是快递公司不是同一家,这个指针就是这个意思,都是指向你的所在地址,马马虎虎的解析可能不对,望不要误导了,呵呵,能正确理解就好,我就是这么理解这个指针的,希望高手给指正
现在,程序把烂铜烂铁变得智能化了,人呢,一旦离开了这烂铜烂铁就不知道干啥了
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-6-11 07:11

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表