历史上的今天
返回首页

历史上的今天

今天是:2025年02月11日(星期二)

正在发生

2020年02月11日 | 浅谈STM32的FSMC的TFT笔记

2020-02-11 来源:eefocus

1、FSMC初初了解:


FSMC 包括4个模块:



(1)AHB接口(包括FSMC配置寄存器)


(2)NOR闪存和PSRAM控制器(驱动LCD的时候LCD就好像一个PSRAM的里面只有2个16位的存储空间,一个是DATA RAM 一个是CMD RAM)


(3)NAND闪存和PC卡控制器


(4)外部设备接口


我们驱动TFT很明显用的是第二个模块:NOR闪存。


2、FSMC的外设地址选择


FSMC _Bank 用来选择外接存储器的地址,FSMC所控制的外存储器所映射的地址是0x6000 0000 ~ 0x9fff ffff


其中属于NOR FLASH 的是0x6000 0000 ~ 0x6fff ffff ,然后这部分的地址空间又被分为四份,每份64MB, 编号是BANK1 ~ BANK 4 ,每个BANK 都有一个片选引脚。


而这四个分存储块的片选,则使用NE[4:1]来选择。数据线/地址线/控制线是共享的。


NE1 ->Bank1   NE2->Bank2  NE3->Bank3  NE4->Bank4


第一块:6000 0000h--63ff ffffh 


第二块:6400 0000h--67ff ffffh


第三块:6800 0000h--6bff ffffh


第四块:6c00 0000h--6fff ffffh


3、FSMC 驱动LCD


FSMC提供了所有的LCD控制器的信号:


FSMC_D[16:0]:16bit的数据总线


FSMC NEx:分配给NOR的256M,再分为4个区,每个区用来分配一个外设,这四个外设的片选分为是NE1-NE4,对应的引脚为:PD7—NE1,PG9—NE2,PG10-NE3,PG12—NE4


FSMC NOE:输出使能,连接LCD的RD脚。


FSMC NWE:写使能,连接LCD的RW脚。


FSMC Ax:用在LCD显示RAM和寄存器之间进行选择的地址线,即该线用于选择LCD的RS脚,该线可用地址线的任意一根线,范围:FSMC_A[25:0]。


正如我们操作12864的命令/数据选择端口RS一样,对于FSMC驱动TFT :RS = 0时,表示读写寄存器;RS = 1表示读写数据RAM。


4、GPIO端口配置


由于是使用FSMC来驱动TFT的,所以除了背光用的PD13和复位用的PC1要设置为通用推挽输出之外,其他引脚都必须设置为复用推挽输出。然而,很奇怪的是。当我配置好PD13时,我发现程序下载进去后是一片漆黑的,后来再三检查是背光的PD13的问题。必须把PD13置高才可以亮,否则默认低电平,就是一片黑了。


5、 具体程序


/*******************************************************************************


* FuncTIon Name  : Lcd_ConfiguraTIon


* DescripTIon    : Configures LCD Control lines


* Input          : None


* Output         : None


* Return         : None


* AttenTIon  : None


*******************************************************************************/


static void LCD_Configuration(void)


{


GPIO_InitTypeDef GPIO_InitStructure;


/* Enable GPIOD and GPIOE clocks */


RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, ENABLE);  


/* PE.00(D0), PE.01(D1), PE.02(D2), PE.03(D3), PE.04(D4), PE.05(D5), PE.06(D6), PE.07(D7), PE.08(D8)


PE.09(D9), PE.10(D10), PE.11(D11), PE.12(D12), PE.13(D13), PE.14(D14), PE.15(D15)   */


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;


GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


GPIO_Init(GPIOE, &GPIO_InitStructure);


/* PD.13(RS), PD.14(WR), PD.15(RD) */


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;


GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


GPIO_Init(GPIOD, &GPIO_InitStructure);


/* PD.12(CS)*/


GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;


GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;


GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;


GPIO_Init(GPIOD, &GPIO_InitStructure);


}


/*******************************************************************************


* Function Name  : LCD_WriteReg


* Description    : LCD控制器寄存器地址


* Input          : - index: 寄存器地址


* Output         : None


* Return         : None


* Attention  : None


*******************************************************************************/


__inline void LCD_WriteIndex(uint16_t index)


{


Clr_Rs;


Set_nRd;


GPIOE->ODR = index;  /* GPIO_Write(GPIOE,index); */


Clr_nWr;


Set_nWr;


}


/*******************************************************************************


* Function Name  : LCD_WriteReg


* Description    : LCD寄存器数据


* Input          : - index: 寄存器数据


* Output         : None


* Return         : None


* Attention  : None


*******************************************************************************/


__inline void LCD_WriteData(uint16_t data)


{


Set_Rs;


GPIOE->ODR = data;  /* GPIO_Write(GPIOE,data); */


Clr_nWr;


Set_nWr;


}


/*******************************************************************************


* Function Name  : LCD_ReadData


* Description    : 读取控制器数据


* Input          : None


* Output         : None


* Return         : 返回读取到的数据


* Attention  : None


*******************************************************************************/


__inline uint16_t LCD_ReadData(void)



uint16_t value;


Set_Rs;


Set_nWr;


Clr_nRd;


GPIOE->CRH = 0x44444444;


GPIOE->CRL = 0x44444444;


value = GPIOE->IDR;


value = GPIOE->IDR;


GPIOE->CRH = 0x33333333;


GPIOE->CRL = 0x33333333;


Set_nRd;


return value;


}


__inline void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue)



/* Write 16-bit Index, then Write Reg */  


Clr_Cs;


LCD_WriteIndex(LCD_Reg);         


/* Write 16-bit Reg */


LCD_WriteData(LCD_RegValue);  


Set_Cs; 


}


__inline uint16_t LCD_ReadReg(uint16_t LCD_Reg)


{


uint16_t LCD_RAM;


/* Write 16-bit Index (then Read Reg) */


Clr_Cs;


LCD_WriteIndex(LCD_Reg);


/* Read 16-bit Reg */


LCD_RAM = LCD_ReadData();       


Set_Cs;


return LCD_RAM;


}


static void LCD_SetCursor( uint16_t Xpos, uint16_t Ypos )


{


#if  ( DISP_ORIENTATION == 90 ) || ( DISP_ORIENTATION == 270 )


uint16_t temp = Xpos;


Xpos = Ypos;


Ypos = ( MAX_X - 1 ) - temp;  


#elif  ( DISP_ORIENTATION == 0 ) || ( DISP_ORIENTATION == 180 )


#endif


LCD_WriteReg(0x004e, Xpos );      


LCD_WriteReg(0x004f, Ypos );          


}


static void delay_ms(uint16_t ms)    



uint16_t i,j; 


for( i = 0; i < ms; i++ )



for( j = 0; j < 1141; j++ );


}



void LCD_Initializtion(void)


{


LCD_Configuration();


// DeviceCode = LCD_ReadReg(0x0000);


/* 读取屏ID */


LCD_WriteReg(0x0000,0x0001);    delay_ms(50);   /* 打开晶振 ,内部晶振500k*/


LCD_WriteReg(0x0003,0xA8A4);    delay_ms(50);   


LCD_WriteReg(0x000C,0x0000);    delay_ms(50);   


LCD_WriteReg(0x000D,0x080C);    delay_ms(50);   


LCD_WriteReg(0x000E,0x2B00);    delay_ms(50);   


LCD_WriteReg(0x001E,0x00B0);    delay_ms(50);   


LCD_WriteReg(0x0001,0x2B3F);    delay_ms(50);   /* 驱动输出控制320*240 0x2B3F */


LCD_WriteReg(0x0002,0x0600);    delay_ms(50);


LCD_WriteReg(0x0010,0x0000);    delay_ms(50);


LCD_WriteReg(0x0011,0x6070);    delay_ms(50);   /* 定义数据格式 16位色 横屏 0x6070 */


LCD_WriteReg(0x0005,0x0000);    delay_ms(50);


LCD_WriteReg(0x0006,0x0000);    delay_ms(50);


LCD_WriteReg(0x0016,0xEF1C);    delay_ms(50);


LCD_WriteReg(0x0017,0x0003);    delay_ms(50);


LCD_WriteReg(0x0007,0x0133);    delay_ms(50);         


LCD_WriteReg(0x000B,0x0000);    delay_ms(50);


LCD_WriteReg(0x000F,0x0000);    delay_ms(50);   /* 扫描开始地址 */


LCD_WriteReg(0x0041,0x0000);    delay_ms(50);


LCD_WriteReg(0x0042,0x0000);    delay_ms(50);


LCD_WriteReg(0x0048,0x0000);    delay_ms(50);


LCD_WriteReg(0x0049,0x013F);    delay_ms(50);


LCD_WriteReg(0x004A,0x0000);    delay_ms(50);


LCD_WriteReg(0x004B,0x0000);    delay_ms(50);


LCD_WriteReg(0x0044,0xEF00);    delay_ms(50);


LCD_WriteReg(0x0045,0x0000);    delay_ms(50);


LCD_WriteReg(0x0046,0x013F);    delay_ms(50);


LCD_WriteReg(0x0030,0x0707);    delay_ms(50);


LCD_WriteReg(0x0031,0x0204);    delay_ms(50);


LCD_WriteReg(0x0032,0x0204);    delay_ms(50);


LCD_WriteReg(0x0033,0x0502);    delay_ms(50);


LCD_WriteReg(0x0034,0x0507);    delay_ms(50);


LCD_WriteReg(0x0035,0x0204);    delay_ms(50);


LCD_WriteReg(0x0036,0x0204);    delay_ms(50);


LCD_WriteReg(0x0037,0x0502);    delay_ms(50);


LCD_WriteReg(0x003A,0x0302);    delay_ms(50);


LCD_WriteReg(0x003B,0x0302);    delay_ms(50);


LCD_WriteReg(0x0023,0x0000);    delay_ms(50);


LCD_WriteReg(0x0024,0x0000);    delay_ms(50);


LCD_WriteReg(0x0025,0x8000);    delay_ms(50);


LCD_WriteReg(0x004f,0);        /* 行首址0 */


  LCD_WriteReg(0x004e,0); //列首址0


  }else if(DeviceCode==0x4531){


  LCD_WriteReg(0X00,0X0001);


  LCD_Delay(50);


  LCD_WriteReg(0X10,0X1628);


  LCD_WriteReg(0X12,0X000e);//0x0006


  LCD_WriteReg(0X13,0X0A39);


  LCD_Delay(10);


  LCD_WriteReg(0X11,0X0040);


  LCD_WriteReg(0X15,0X0050);


  LCD_Delay(40);


  LCD_WriteReg(0X12,0X001e);//16


  LCD_Delay(40);


  LCD_WriteReg(0X10,0X1620);


  LCD_WriteReg(0X13,0X2A39);


  LCD_Delay(10);


  LCD_WriteReg(0X01,0X0100);


  LCD_WriteReg(0X02,0X0300);


  LCD_WriteReg(0X03,0X1030);//改变方向的


  LCD_WriteReg(0X08,0X0202);


  LCD_WriteReg(0X0A,0X0008);


  LCD_WriteReg(0X30,0X0000);


  LCD_WriteReg(0X31,0X0402);


  LCD_WriteReg(0X32,0X0106);


  LCD_WriteReg(0X33,0X0503);


  LCD_WriteReg(0X34,0X0104);


  LCD_WriteReg(0X35,0X0301);


  LCD_WriteReg(0X36,0X0707);


  LCD_WriteReg(0X37,0X0305);


  LCD_WriteReg(0X38,0X0208);


  LCD_WriteReg(0X39,0X0F0B);


  LCD_WriteReg(0X41,0X0002);


  LCD_WriteReg(0X60,0X2700);


  LCD_WriteReg(0X61,0X0001);


  LCD_WriteReg(0X90,0X0210);


  LCD_WriteReg(0X92,0X010A);


  LCD_WriteReg(0X93,0X0004);


  LCD_WriteReg(0XA0,0X0100);


  LCD_WriteReg(0X07,0X0001);


  LCD_WriteReg(0X07,0X0021);


  LCD_WriteReg(0X07,0X0023);


  LCD_WriteReg(0X07,0X0033);


  LCD_WriteReg(0X07,0X0133);


  LCD_WriteReg(0XA0,0X0000);


  }


  LCD_Delay(5000);


  Set_LED;//点亮背光


  LCD_Clear(WHITE);


  }


  //清屏函数


  //Color:要清屏的填充色


  void LCD_Clear(u16 Color)


  {


  u32 index=0;


  LCD_SetCursor(0x00,0x0000);//设置光标位置


  LCD_WriteRAM_Prepare(); //开始写入GRAM


  for(index=0;index《76800;index++)


  {


  LCD_WR_DATA(Color); //向每个GRAM写入数据


  }


  }


  //在指定区域内填充指定颜色


  //区域大小:


  // (xend-xsta)*(yend-ysta)


  void LCD_Fill(u8 xsta,u16 ysta,u8 xend,u16 yend,u16 color)


  {


  #if USE_HORIZONTAL //横屏


  u16 colortemp=POINT_COLOR;


  u16 ytemp=ysta;


  POINT_COLOR=color;


  for(;xsta《=xend;xsta++)


  {


  for(;ysta《=yend;ysta++)LCD_DrawPoint(xsta,ysta);


  ysta=ytemp;


  }


  POINT_COLOR=colortemp;


  #else //竖屏


  u32 n;


  //设置窗口


  LCD_WriteReg(R80, xsta); //水平方向GRAM起始地址


  LCD_WriteReg(R81, xend); //水平方向GRAM结束地址


  LCD_WriteReg(R82, ysta); //垂直方向GRAM起始地址


  LCD_WriteReg(R83, yend); //垂直方向GRAM结束地址


  LCD_SetCursor(xsta,ysta);//设置光标位置


  LCD_WriteRAM_Prepare(); //开始写入GRAM


  n=(u32)(yend-ysta+1)*(xend-xsta+1);


  while(n--){LCD_WR_DATA(color);}//显示所填充的颜色。

推荐阅读

史海拾趣

DCCOM [ DC COMPONENTS ]公司的发展小趣事

在快速发展的过程中,DCCOM公司始终坚持品质至上的原则。公司建立了一套严格的质量控制体系,从原材料采购到产品生产的每一个环节都严格把关。这种对品质的执着追求,使得DCCOM的产品在市场上赢得了良好的口碑,客户回头率逐年攀升。

Eastron Corp公司的发展小趣事

面对日益激烈的国际竞争,Eastron Corp决定走全球化发展的道路。公司先后在亚洲、欧洲和北美等地设立了研发中心和生产基地,通过本地化生产和研发,快速响应市场需求。同时,Eastron还积极寻求与国际知名企业的合作,共同开发新技术和产品,提升了公司的国际竞争力。

Exar公司的发展小趣事

面对日益激烈的市场竞争和不断变化的市场需求,Exar公司始终坚持以创新为核心竞争力。公司不断投入研发资金,加强技术创新和产品研发力度,推出了一系列具有自主知识产权的新产品。同时,Exar还积极关注行业发展趋势和市场动态,不断调整和优化产品线,以适应市场的变化和发展。在未来,Exar将继续坚持创新驱动的发展战略,努力成为电子行业的领军企业。

请注意,以上故事框架仅供参考,具体的故事内容需要根据实际情况进行补充和完善。

Davies Molding公司的发展小趣事

Davies Molding公司深知,人才是企业发展的核心动力。因此,公司高度重视团队建设与人才培养。通过建立完善的培训体系,Davies Molding公司不断提升员工的技能和素质,打造了一支高素质、专业化的团队。这支团队不仅为公司的发展提供了有力保障,还为行业的进步做出了积极贡献。

American Technical Ceramics (ATC)公司的发展小趣事

Davies Molding公司在发展过程中,始终注重市场布局与拓展。公司不仅在美国中西部建立了稳固的市场地位,还积极开拓国际市场,将产品出口到全球多个国家和地区。通过与全球客户的合作,Davies Molding公司不仅提升了品牌影响力,还获得了更多的发展机遇。

Gowanda Electronics公司的发展小趣事

Davies Molding公司深知,人才是企业发展的核心动力。因此,公司高度重视团队建设与人才培养。通过建立完善的培训体系,Davies Molding公司不断提升员工的技能和素质,打造了一支高素质、专业化的团队。这支团队不仅为公司的发展提供了有力保障,还为行业的进步做出了积极贡献。

问答坊 | AI 解惑

【转】"如何正确使用保险丝"在线研讨会问答精粹

慢熔断保险丝与快熔断有什么不同的性能和应用;相同特性和额定电流的保险丝能直接替换吗;保险丝分断能力在实际应用中有什么意义;保险丝性能的影响因素;一次性保险丝和可恢复保险丝的异同;保险电阻能起到保险丝的作用吗?这些都是工程师在保险丝 ...…

查看全部问答>

我觉得裸奔也要带着操作系统思想裸奔

我程序一直都是裸体的,在裸体中发现了几个问题: (1)WARNING L15: MULTIPLE CALL TO SEGMENT --函数重入 其实这个问题实际上就是函数重入问题,在操作系统的多线程很常见。例如在主循环里调用了一个函数,而在中断服务中,你又一次调用了同样 ...…

查看全部问答>

我的小本系统是win7的,但装不了Protel 99se软件

我的小本系统是win7的,但装不了Protel 99se软件,装的是Protel 99se汉化中文第六版(含第二版),请各位友友帮帮忙…小弟我感激不尽……

查看全部问答>

SD卡的识别问题,一些卡无法识别。

SD卡驱动在很多情况下都可以正常的识别SD卡,但是有一些卡却无法识别。 查看log,可以看到一些初始化命令无法获得响应,总是超时。 请问大家遇到过类似的问题吗?可能是哪些方面的原因呢?…

查看全部问答>

ads中用jlink调试时 调试窗口看不到存储器变化? 但运行结果正常! 求救!!!

ads中用jlink调试时 调试窗口看不到存储器变化? 但运行结果正常! 求救!!!…

查看全部问答>

2440 camera 问题????--献上所有分

刚接触CE1个月 马上要在公司自己开发的主板上移植7645BF驱动了 还有些有关camera驱动问题还不是很清楚 希望高人解答!!! 比如 2440上 camera分配的是irq6 该irq可能由INTSUB_CAM_P、INTSUB_CAM_C或INT_CAM 被置一而引起,有的资料上说中断由VSYN ...…

查看全部问答>

大家觉得这个车架适合不适合做智能车!~

RT 在淘宝上看到的,就是价格稍高318元,但是相对飞思卡尔官方的车体价格还是便宜一点的!~   …

查看全部问答>

加载失败和运行不起来的原因

本帖最后由 dontium 于 2015-1-23 13:21 编辑 在我加载程序时,它提示我Data verification failed at address 0x48a0。Please  verify target memory and memory map.点我点确定后,又出现这个错误对话框,可地址改为ox6320了,当我打开 ...…

查看全部问答>

转贴:FreeRTOS port to eZ430-RF2500

FreeRTOS 在eZ430-RF2500 的移植,秒到eZ430-RF2500可以玩…

查看全部问答>

大神,求助?

    学习DSP真的让我学到了很多的东西,最开心的就是问题解决后高兴和满足,但是当困恼在一个地方的时候会很烦恼,但是这是一个学技术的历练。    最近在连接一个F28035和TOPWAY 的液晶屏,但是会出现一些问题,有的已经 ...…

查看全部问答>