【STM32备忘录】二、FSMC做LCD控制器,使用stm32cube配置示例
创始人
2024-02-25 05:14:18
0

文章目录

    • 1. FSMC框图
    • 2. 配置示例
      • (1) cube配置
      • (2) 代码参考
      • *疑问

1. FSMC框图

在这里插入图片描述
在这里插入图片描述

  • 如果屏幕接口8位数据宽度访问,地址线FSMC_A[25:0], 一共26位,一个块226=67108864Byte=64MB,
  • 如果屏幕接口16位数据宽度访问,地址线FSMC_A[25:0], 一共26位,但在内部会右移一位变成25位!!!所以225 *(16/8)=226=67108864Byte=64MB, 此时FSMC_A[25:0]内部将弃用FSMC_A[0],然后将FSMC_A[25:1]映射到FSMC_A[24:0],所以外部FSMC_A[0]仍需要连接。需要注意的是HADDR是需要转换到外部存储器的内部AHB地址线
    在这里插入图片描述
  • 0x6000 0000 - 0x6fff ffff 为NOR/PSRAM区,LCD控制使用该区域,其又被分为4个64MB的块, 一个块大小为0x400 0000,每个块通过FSMC_NE[4:1]映射, 使用那个块就把对应的FSMC_NEx当作LCD控制器的CS
  • 对命令和数据选择,通过地址位实现,比如寄存器选择使用了A16, 那么通过向置位该地址位的地址写入数据即为写入寄存器命令,需要注意的是,如果数据宽度为16位,因为内部地址右移了一位,如果使用NE1,则该地址为0x6000000|(0x00010000<<1) = 0x60020000
  • 典型的LCD接口引脚
主要引脚功能
CS片选,0有效
RS指令/数据选择,0: 控制,1: 数据
RD读动作, RD = 0, WR = 1
WR写动作, RD = 1, WR = 0
D0-D15数据引脚
次要引脚功能
RESET0复位
LIGHT背光
  • 典型的读写时序
    在这里插入图片描述
    在这里插入图片描述

2. 配置示例

(1) cube配置

我使用的是NE1,软件好像只有这个选项,,有LCD接口模式,这里选择的LCD Register Select(命令数据选择RS)是A16,下面配置默认即可用,但默认参数很大,刷新会比较慢,Extended mode扩展模式使能可以使用写时序寄存器单独配置,否则读写时序使用相同寄存器
在这里插入图片描述

  • 这个配置也可以,刷新会提高N倍,我并未测试极限参数,后面有时间可以优化
    在这里插入图片描述

(2) 代码参考

  • 读屏幕ID,使用的开发板是众想科技的大黄蜂(现在这个企业好像改名了),丝印ILI9325,读出来是9328,应该是同系列产品
extern SRAM_HandleTypeDef hsram1;#define ILI_ADDR_CMD 	0x60000000
#define ILI_ADDR_DATA  	0x60020000uint16_t get_lcd_id(void)
{uint16_t id;*(__IO uint16_t *)(ILI_ADDR_CMD) = 0x00;id = *(__IO uint16_t *)(ILI_ADDR_DATA);return id;
}
  • 写寄存器
static void write_reg(uint8_t cmd, uint16_t dat)
{*(__IO uint16_t *)(ILI_ADDR_CMD) = cmd;*(__IO uint16_t *)(ILI_ADDR_DATA) = dat;
}
  • 写显示数据
static void write_gram(uint16_t dat)
{*(__IO uint16_t *)(ILI_ADDR_DATA) = dat;
}
  • ili9325/9328一个可用的测试初始化序列
	write_reg(0x01,0x0100);	//Driver Output Contral.	write_reg(0x02,0x0700);	//LCD Driver Waveform Contral.write_reg(0x03,0x1030);	//Entry Mode Set.write_reg(0x04,0x0000);	//Scalling Contral.			write_reg(0x08,0x0202);	//Display Contral 2.(0x0207)		write_reg(0x09,0x0000);	//Display Contral 3.(0x0000)write_reg(0x0A,0x0000);	//Frame Cycle Contal.(0x0000)write_reg(0x0C,0x0000);	write_reg(0x0D,0x0000);	//Frame Maker Position.write_reg(0x0F,0x0000);	//Extern Display Interface Contral 2.write_reg(0x10,0x0000);	write_reg(0x11,0x0007);	//Power Control 2.(0x0001)	//Power Control 3.(0x0138)write_reg(0x12,0x0000);	write_reg(0x13,0x0000);								//Power Control 4.write_reg(0x07,0x0001);								//Power Control 7.HAL_Delay(50);write_reg(0x10,0x1690);write_reg(0x11,0x0227);HAL_Delay(50);write_reg(0x12,0x009D);HAL_Delay(50);write_reg(0x13,0x1900);	HAL_Delay(50);write_reg(0x29,0x0025);	write_reg(0x2B,0x000D);HAL_Delay(50);write_reg(0x20,0x0000);	write_reg(0x21,0x0000);HAL_Delay(50);write_reg(0x30,0x0007);	write_reg(0x31,0x0303);	write_reg(0x32,0x0003);	write_reg(0x35,0x0206);	write_reg(0x36,0x0008);	write_reg(0x37,0x0406);	write_reg(0x38,0x0304);write_reg(0x39,0x0007);	write_reg(0x3C,0x0601);	write_reg(0x3D,0x0008);			write_reg(0x50,0x0000);	write_reg(0x51,0x00EF);	write_reg(0x52,0x0000);	write_reg(0x53,0x013F);	write_reg(0x60,0xA700);	write_reg(0x61,0x0001);	write_reg(0x6A,0x0000);	write_reg(0x80,0x0000);	//Display Position? Partial Display 1.write_reg(0x81,0x0000);	//RAM Address Start? Partial Display 1.write_reg(0x82,0x0000);	//RAM Address End-Partial Display 1.write_reg(0x83,0x0000);	//Displsy Position? Partial Display 2.write_reg(0x84,0x0000);	//RAM Address Start? Partial Display 2.write_reg(0x85,0x0000);	//RAM Address End? Partial Display 2.write_reg(0x90,0x0010);	write_reg(0x92,0x0600);	//Panel Interface Contral 2.(0x0000)write_reg(0x07,0x0133);	//(0x0173
  • 方块填充测试
/* --------------------------------------------------------------------------*/
/*** @Synopsis  设置当前坐标** @Param x 	(x,y)当前点的坐标* @Param y*/
/* --------------------------------------------------------------------------*/
void ILI9325_Set_Pointer(uint16_t x,uint16_t y)
{write_reg(0x20,x);write_reg(0x21,y);
}/* --------------------------------------------------------------------------*/
/*** @Synopsis  设置显示区域** @Param x1* @Param y1* @Param x2* @Param y2*/
/* --------------------------------------------------------------------------*/
void ILI9325_Set_Window(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{ILI9325_Set_Window_Area(x1,y1,x2,y2);ILI9325_Set_Pointer(x1,y1);
}/* --------------------------------------------------------------------------*/
/*** @Synopsis  区域刷屏** @Param x1* @Param y1* @Param x2* @Param y2* @Param color*/
/* --------------------------------------------------------------------------*/
void ILI9325_Print_Rectangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color)
{ILI9325_Set_Window(x1,y1,x2,y2);write_reg_cmd(0x0022);for(uint16_t i = y1;i<=y2;i++){for(uint16_t j = x1;j<=x2;j++){write_gram(color);	}}
}

*疑问

  • 有些点还是不理解,比如使用HAL库提供的操作SRAM接口,HAL_SRAM_Write_16b()并不是只写一次16位数据(即使使用16位数据宽度),并且还需要读一次。。。因为HAL库提供的SRAM读写函数,无论8位,16位,32位,都是按字(32位)操作的,而按32位访问会被分割成两次访问
    在这里插入图片描述
      下图是使用HAL_SRAM_Write_16b()写lcd GRAM时序(写一次颜色数据),仿真只执行一次,但时序显示读了一次,写了两次,多读一次可能会导致地址的一次跳过(不确定命令字地址是否自动增加?),而多写一次会导致一半数据异常(地址自动增加,多写了16位),暂时不了解,感觉这些函数不能用在LCD上面?有清楚的大佬希望可以评论指点下。
HAL_SRAM_Write_16b(&HANDLE_SRAM,(uint32_t*)ILI_ADDR_DATA, &dat, 1);

在这里插入图片描述

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...