LCD驱动模块前端设计流程
需求分析
- 使用Verilog代码完成LCD1602型号的液晶显示屏驱动设计
- LCD驱动模块的上位机为主控系统,下位机为LCD1602液晶显示屏;
- 要求LCD驱动模块与主控系统交互时使用APB接口(APB时钟采用64MHz) ;
- 该驱动模块工作时钟使用外部时钟(工作时钟采用50MHz) ;
- 该模块初始化完成后,它所驱动的LCD1602液晶显示屏默认输出“ABCD至MNOP abcd至mnop”共16*2个英文字符,主控系统可通过APB总线控制液晶显示屏输出的字符;
- 该模块内部需要设计使能寄存器,模块每次向LCD1602液晶显示屏输出新的字符时,均需要通过APB总线配置使能寄存器;
- 该模块内部需要设计BUSY寄存器,主控系统可以通过APB总线读取驱动模块的忙或不忙状态(16*2个字符正在向显示屏输出,则模块处于忙状态,否则处于不忙状态)﹔
- 本设计只向LCD液晶显示屏写入数据,不对其进行读操作。
- 字符型的显示原理
- 用LCD显示一个字符时比较复杂,因为一个字符由6×8或8×8点阵组成,既要找到和显示屏幕上某几个位置对应的显示RAM区的8字节,还要使每字节的不同位为”1”,其它的为”0”,为”1”的点亮,为”0”的不亮。这样一来就组成某个字符。
- 内带字符发生器的控制器来说,显示字符就比较简单了,可以让控制器工作在文本方式,根据在LCD上开始显示的行列号及每行的列数找出显示RAM对应的地址,设立光标,在此送上该字符对应的代码即可。
- RAM形式的标准字库
液晶显示模块是一个慢显示器件,所以在执行每条指令之前一定要确认模块的忙标志为低电平,表示不忙,否则此指令失效(通过LCD读时序发送指令9)。要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,如图是1602的内部显示地址
功能架构
LCD驱动模块的上位机为主控系统,下位机为LCD1602液晶显示屏
功能划分
硬件实现
该模块初始化完成后,它所驱动的LCD1602液晶显示屏默认输出“ABCD至MNOP abcd至mnop”共16*2个英文字符,主控系统可通过APB总线控制液晶显示屏输出的字符;
软件实现
- 该模块内部需要设计使能寄存器,模块每次向LCD1602液晶显示屏输出新的字符时,均需要通过APB总线配置使能寄存器;
- 该模块内部需要设计BUSY寄存器,主控系统可以通过APB总线读取驱动模块的忙或不忙状态(16*2个字符正在向显示屏输出,则模块处于忙状态,否则处于不忙状态);
接口协议
LCD1602液晶模块内部的控制器共有11条控制指令,如下表所示:
序号 | 指令 | RS | R/W | D7 | D6 | D5 | D4 | D3 | D2 | D1 | D0 |
---|---|---|---|---|---|---|---|---|---|---|---|
1 | 清显示 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
2 | 光标返回 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | * |
3 | 置输入模式 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | I/D | S |
4 | 显示开/关控制 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | D | C | B |
5 | 光标或字符移位 | 0 | 0 | 0 | 0 | 0 | 1 | S/C | R/L | * | * |
6 | 置功能 | 0 | 0 | 0 | 0 | 1 | DL | N | F | * | * |
7 | 置字符发生存储器地址 | 0 | 0 | 0 | 1 | 字符发生存储器地址 | |||||
8 | 置数据存储器地址 | 0 | 0 | 1 | 显示数据存储器地址 | ||||||
9 | 读忙标志或地址 | 0 | 1 | BF | 计数器地址 | ||||||
10 | 写数到CGRAM或DDRAM | 1 | 0 | 要写的数据内容 | |||||||
11 | 从CGRAM或DDRAM读数 | 1 | 1 | 读出的数据内容 |
指令1:清显示,指令码01H,光标复位到地址00H位置。
指令2:光标复位,光标返回到地址00H。
指令3:光标和显示模式设置VD:光标移动方向,高电平右移,低电平左移S:屏幕所有文字是否左移或者右移。高电平表示有效,低电平则无效。
指令4:显示开关控制。D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示C:控制光标的开与关,高电平表示有光标,低电平表示无光标B:控制光标是否闪烁,高电平闪烁,低电平不闪烁。
指令5:光标或显示移位S/C:高电平时移动显示的文字,低电平时移动光标。
指令6:功能设置命令DL;高电平时为4位总线,低电平时为8位总线N;低电平时为单行显示,高电平时双行显示F:低电平时显示57的点阵字符,高电平时显示510的点阵字符。
指令7:字符发生器RAM地址设置。
指令8:DDRAM地址设置。
指令9:读忙信号和光标地址BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据。
指令11:读数据。
接口时序
APB写时序
如图所示,地址(PADDR)、写信号(PWRITE)、选择信号(PSEL)、写数据(PWDATA)在时钟上升沿到来时有效。表明一次写传输的开始,传输的第一个时钟周期称为SETUP周期。在第二个时钟上升沿使能信号(PENABLE)有效,进入ENABLE周期。而地址、写数据和控制信号需要在此期间保持有效。传输在ENABLE周期结束时完成,此时PENABLE变为低电平,PSEL也变为低电平。
APB读时序
由图所示,地址(PADDR)、写信号(PWRITE)、选择信号(PSEL)、写数据(PWDATA)在时钟上升沿到来时有效。在读传输时,从设备必须在ENABLE周期提供数据,读数据在ENABLE周期结束的时钟上升沿被主设备采样。
LCD写操作时序
如图所示,在LCD写操作时序中,RS引脚和R/W引脚先变化,其中R/W引脚先置高,变化了tAS时间后使能引脚E从低电平变为高电平,然后上位机写入DB数据,写完之后,使能信号E从高变低。
Item | Symbol | Min | Typ | Max | Unit |
---|---|---|---|---|---|
Enable cycle time | tcycE | 500 | - | - | ns |
Enable pulse width(high level) | PWEH | 230 | - | - | ns |
Enable rise/fall time | tEr,tEf | - | - | 20 | ns |
Address set-up time(RS,R/W to E) | tAS | 40 | - | - | ns |
Address hold time | tAH | 10 | - | - | ns |
Data set-up time | tDSW | 80 | - | - | ns |
Data hold time | tH | 10 | - | - | ns |
LCD读操作时序
如图所示,RS和R/W引脚先变化,因为是读操作R/W引脚首先置为高电平经过tAS时间后,使能引脚E才从低电平变到高电平,经过tD时间后,我们进行数据读取,读取完成后,再把使能E拉低,经过一段时间后,可以继续下一次读写操作。
图6 LCD读操作时序
Item | Symbol | Min | Typ | Max | Unit |
---|---|---|---|---|---|
Enable cycle time | tcycE | 500 | - | - | ns |
Enable pulse width(high level) | PWEH | 230 | - | - | ns |
Enable rise/fall time | tEr,tEf | - | - | 20 | ns |
Address set-up time(RS,R/W to E) | tAS | 40 | - | - | ns |
Address hold time | tAH | 10 | - | - | ns |
Data delay time | tDDR | - | - | 100 | ns |
Data hold time | tDHR | 5 | - | - | ns |
功能分解
结构框架
- 设计框架主要由APB、LCD接口,内部寄存器模块,LCD主状态机控制模块构成
- 数据或命令内部寄存使用多组寄存器来设计,每组寄存器对应4个字符,一个字符8bit数据
- LCD主状态机控制可灵活设计,包括打开功能设置、关闭显示、清显示、设置为输入模式、打开显示、光标跳至1行1列、光标跳至2行1列命令以及显示数据等状态,要满足驱动模块通过控制HD44780芯片,来实现LCD显示的目的
- LCD驱动模块的复位通过外部复位信号控制
- LCD时序只需要设计写操作即可
APB接口和LCD接口
- APB接口模块要设计为从机接口,时钟采用64MHz,地址数据位宽均为32bit,此接口可以使用ready,也可以不使用。
- LCD接口模块要设计为主机接口,时钟采用50MHz,data7-0值包含数据和命令。
读状态 输入 RS=L,R/W=H,E=H 输出 D0-D7=状态字 写指令 输入 RS=L,R/W=L,D0-D7=指令码,E=高脉冲 输出 无 读数据 输入 RS=H,R/W=H,E=H 输出 D7-D0=数据 写数据 输入 RS=H,R/W=L,D0-D7=数据,E=高脉冲 输出 无
寄存器功能
- 字符显示寄存器:主控系统通过APB总线对LCD驱动模块的寄存器进行读写,将字符对应的十六进制码(可通过工具生成)写入字符寄存器
- 使能寄存器:写入字符寄存器后,打开使能控制寄存器,LCD驱动对LCD1602液晶显示屏进行写字符操作
- BUSY寄存器:主控系统对整个驱动流程可通过APB总线来查询驱动模块是否处于忙状态
初始化(复位)过程
在LCD驱动初始化功能
驱动上电完成后延时15ms
写指令38H(不检测忙信号)
延时5ms
写指令38H(不检测忙信号)
延时5ms
写指令38H(不检测忙信号)
以后每次写指令、读/写数据操作均需要检测忙信号(以下指令在每帧的LCD字符重新输出时,都要执行)
写指令38H:显示模式设置
写指令08H:显示关闭
写指令01H:显示清屏
写指令06H:显示光标移动设置
写指令0CH:显示开及光标设置LCD驱动初始化完成驱动LCD液晶显示屏显示“ABCD至MNOP abcd至mnop”共16*2个英文字符
主状态机功能
- 主状态机主要实现向LCD1602内置的HD44780芯片发送命令,用于控制屏幕显示、关闭,控制光标的位置与移动字符显示。
- 在字符显示状态时,首先要输出显示地址,即光标的位置,之后输出要显示字符的十六进制数据,此时LCD1602的光标会自动后移。
- 在光标移动到每一行的最后位置时,需要通过命令调正光标回到下一行的首列。
功能设计
时钟、复位
模块中使用一个外部50MHz工作时钟和64MHz的APB时钟,复位使用外部复位,低电平复位有效,高电平释放复位,采用异步复位同步释放。
字符写入过程
- 写入显示地址时要求最高位D7恒定为高电平1,例如第二行第一个字符的地址是40H,实际写入的数据应该是01000000B (40H) +10000000B(80H) = 11000000B(C0H)。
- 在液晶模块显示字符时光标是自动右移的,无需人工干预。
- 1602液晶模块内部的字符发生存储器(CGROM)已经存储了160个不同的点阵字符图形,这些字符有:阿拉伯数字、英文字母的大小写、常用的符号、和日文假名等,每一个字符都有一个固定的代码,比如大写的英文字母“A”的代码是01000001B(41H),显示时模块把地址41H中的点阵字符图形显示出来,我们就能看到字母“A”。
主状态机
- 状态共分为打开功能设置(发送38H)、关闭显示(发送08H)、清显示(发送01H)、设置为输入模式(发送06H)、打开显示(发送OCH)、光标跳至1行1列(发送80H)、发送字符(发送数据)、光标跳至2行1列(发送COH)、发送字符(发送数据)命令。
- 输出只和状态有关而与输入无关,故采用Moore状态机。
显示流程
功能仿真
- 将写好的rtl代码使用make命令运行,其中Makefile文件中包含
- 打开图形界面后,选中顶层点击Dump,然后进行仿真,并查看run.log。
- 将顶层文件中的端口添加到波形窗口查看波形。
从上图我们可以看出LCD驱动模块初始化之后,会先对液晶显示屏输入命令做初始化设置,再驱动LCD液晶显示屏显示“ABCD至MNOP abcd至mnop”共16*2个英文字符。
上图为APB接口波形图,此时上位机通过APB接口先配置显示使能寄存器,再配置字符寄存器。
上图为上位机配置内部寄存器以后,LCD驱动模块驱动下位机重新显示字符的波形图,从波形图上来看,配置寄存器以后驱动模块依然能正常向下位机LCD1602液晶显示屏发送数据,符合功能设计需求。
LCD驱动模块后端流程
逻辑综合
逻辑综合将 RTL 编码转换为特定时序约束下的门级网表和约束,具体操作使用DC软件完成。
- 在工作空间target中建立目录树
- 创建.synopsys_dc.setup文件,此文件在启动DC初始化环境的时候自动调用,该文件配置库文件的搜索路径,指定target library和link library的工艺库文件。其中target library中包含了cell的库文件以生成网表,link library中包含了设计网表中的cell。
- 启动DC
- 在work目录中启动dc_shell
- 使用source ../analyze_source_file.tcl读入需要综合的RTL代码文件
- 使用elaborate lcd1602声明顶层模块
- 使用link查看是否缺少子模块,返回值为1则说明文件完整
- 设计约束文件
- 在clock部分我们创建端口时钟和一个虚拟时钟,设置周期和占空比以及建立保持时间。
- 在con部分我们给所有的输入输出端口(除时钟外)设置输入输出延时。
- 在DRC部分我们给当前设计设置了最大转换时间和最大扇出,始终设置最大转换时间
- 在timing部分我们给输入输出端口设置建立保持时间约束。
- 编译并输出
- 使用compile命令对当前的设计进行逻辑综合
- 编译完成后我们需要输出后面的时序约束文件和网表文件,使用change_names -hierarchy -rules verilog更改变量名使之符合Verilog语法规则。
- 使用write -format verilog -hierarchy -output ../output/lcd1602.v命令输出网表文件
- 使用write_sdc ../output/lcd1602.sdc输出时序约束文件
布局布线
布局布线将区域内的cell安置在相应的位置并用金属层进行连接,具体操作利用ICC完成。
- 配置ICC环境并启动
- 首先我们在target工作目录中新建PR文件夹,在PR文件夹中同样需要.sysnopsy_dc.setup配置文件,内容和SYM中的一致。
- 使用icc_shell启动ICC。
- 使用create_mw_lib XXX(设计库名称) -open -technology XXX(工艺库路径+名称) - mw_reference_library XXX(参考库路径+名称)命令创建milkway设计库
- 使用read_verilog ../SYM/output/lcd1602.v读入综合生成的网表文件。
- 使用link命令将网表中的的单元和参考库中的单元连接起来,然后使用check_design。
- 使用read_sdc ../SYM/output/lcd1602.sdc读入综合生成的约束文件。
- 使用check_timing检查约束文件是否导入。
- 使用set_tlu_plus_files -max_tluplus XXX(路径+max.tluplus) -min_tluplus XXX(路径+min.tluplus) -tech2itf_map XXX(路径+tluplus.map)命令导入寄生参数文件,然后使用check_tlu_plus_file检查tlu文件是否导入。
- 打开图形界面并进行布局布线
- 使用start_gui命令打开ICC的图形界面,然后再工具栏点击creat floorplan创建平面图。
- 选择工具栏Preroute中Create Power Straps在进行引脚和网络的连接。
- 选择工具栏Preroute中Create Power Straps在图形界面中画出六、五、四层金属电源线(VDD和VSS)。
- 选择工具栏Preroute中Preoute standard cells中的fill empty rows,填充空行,并在DRC中布置M1-M4的power rail。
- 选择工具栏中Floorplan中的create placement blockage工具,遮住标准单元的第一行和最后一行,然后选择工具栏Finishing中的add tap cell array将标准单元N阱和衬底接电源和地,防止闩锁效应。
- 在终端使用check_physical_design -stage pre_place_opt和check_physical_constraints命令检查设计和约束。
- 在终端里使用place_opt命令进行自动布局,使用report_qor评估布局质量。
- 使用set_propagated_clock [all_clocks]命令进行设置时钟,使用clock_opt命令进行时钟树综合。
- 使用route_opt进行自动布线。
- 时序检查、DRC检查和违例修正
- 使用reqort_qor查看时序报告,检查建立/保持时间的违例。使用verify_drc做DRC检查。
- 使用report_timing -transition_time检查建立/保持时间的违例。
- 使用size_cell u_apbif/U355 AND3_X2M_A7TULL命令修改对应建立时间违例。
- 如果有保持时间违例,可以使用insert_buffer添加到路径中,直到时序正常。
- 使用legalize_placement -incremental和route_zrt_eco命令重新进行布局布线。
- 使用verify_zrt_route进行DRC检查。
- 检查没有任何违例之后使用save_design命令保存设计并退出。