发新帖本帖赏金 10.00元(功能说明)我要提问
12下一页
返回列表
[STM32F4]

【STM32F469I试用】+ LCD硬件加速应用 + 两个福利【申精】

[复制链接]
9787|30
手机看帖
扫描二维码
随时随地手机跟帖
deru_qq|  楼主 | 2015-12-20 00:45 | 显示全部楼层 |阅读模式
本帖最后由 deru_qq 于 2015-12-21 08:43 编辑

能申请到这块高大上的开发板,虽然之前很期待,但是看到自己的名字还是挺意外的,为了这块开发板值得拿出来一点有用的东西。
关于STM32F469I-DISCO,这篇帖子只介绍了使用液晶的BSP库,但是这个不是重点,重点是后面的福利——自己之前写的两个有用的模块:简单CUI(命令用户接口)模块,基于超级终端的外置键盘。本帖就分3个部分来讲
1. 使用液晶的BSP
STM32F469I-DISCO板的一大特点就是使用了一块高分屏,这篇帖子就来研究一下使用HAL库和BSP库来使用液晶屏的方法。
1.1 DSI模式简介
       STM32F469I-DISCO的液晶控制模块LTDC是和DSI模块一起使用的,DSI有两种模式CommandMode和Video mode
DSI(Video Mode)视频模式.
这种工作模式与传统RGB接口相似,主机需要持续刷新显示器。由于不使用专用的数据信号传输同步信息,控制信号和RGB数据是以报文的形式通过MIPI总线传输的。因为主机需要定期刷新显示器,显示器就不需要帧缓冲器。
DCS(Command mode)命令模式
MIPI总线控制器使用显示命令报文来向显示器发送像素数据流。显示器应该有一个全帧长的帧缓冲器来存储所有的像素数据。一旦数据被放在显示器的帧缓冲器中,定时控制器就从帧缓冲器中取出数据,并自动把它们显示在屏幕上。MIPI总线控制器不需要定期刷新显示器。
STM32F469使用命令模式时可以手动刷新显示器,也可以自动刷新(消除TearingEffect模式,TE)
如果想了解更多关于这两种模式的内容,可以看这个博客
见附件文档
如果想了解更多关于TE的内容,看下面这个博客
见附件文档
       在写这篇帖子的过程中对两种方式都进行了测试,发现Command Mode下在刷屏时屏幕上会雪花出现(刷完屏后显示一切正常),理论上来讲,在刷新显存之前,显存RAM内容的改变并不会表现在屏幕上,暂时没有精力去找原因了,帖子的工程中使用了Video Mode

1.2 工程建立
接下来开始建立工程,这个工程是从LCD_DSI_VideoMode_DoubleBuffering工程修改而来的
工程需要的库文件:
库文件.jpg


BSP的LCD库函数需要板载SDRAM,因为显存存放在从地址LCD_FB_START_ADDRESS(0xC0000000)开始的内存中,而这个地址就是SDRAM的起始地址
Main函数:
       Main函数开头的初始化都是直接调用库函数完成,初始化完成之后,就可以使用LCD的库函数了,包括了画点,画线,画图填充,写字符等函数。
初始化.jpg


2. 简易CUI模块
       PC上的cmd窗口就是CUI的一个例子,相对于GUI,它的实现简单,占用资源少,非常适合嵌入式,本例是一个简单的CUI演示,它有两个特点:软件光标和屏幕卷动。但是屏幕缓冲区只有一屏的内容,因此不能回看。

2.1 CUI界面配置
       CUI界面只支持字符显示,可以显示固定行数和列数的字符,并且字符只能顺序写入,不能设定光标的位置。
通过配置文件可以设置界面的行数,列数,字体样式,背景色和前景色。
模块配置.jpg
LCD_WIDTH,LCD_HEIGHT:只用来限制显示CUI界面的大小,不必等于真实液晶宽和高
CUI_FONT:font.c文件有几种字体可选,CUI_WIDTH和CUI_HEIGHT要和所选的字体一致。也可以添加其他字体,字体取模的格式为:纵向取模,从上到下(MSb在上),从左到右,不足8bit的LSb补0
CURSOR_HEIGHT:光标使用横向的格式,高度从1到FONT_HEIGHT都可以
CURSOR_BLINK_RATE:光标闪烁频率,这里设置的是1Hz,这个要求定时器中断周期为1ms
CUI_LINE,CUI_ROW:CUI显示的行数和列数,这两个值设定之后最好保证整个CUI界面小于LCD_WIDTH和LCD_HEIGHT所限定的区域,否则一部分字符会显示不出来

2.2 移植准备
移植CUI模块只要2个外部函数,Lcd_SetPixel()和Lcd_GetPixel(),在程序中是要用这两个函数实现画字符的功能,因此可以结合LCD控制器的特点进行优化。
另外,还需要将Cui_TimerProc()函数在1ms定时器中断程序中调用,用来实现软件光标。
2.3应用接口:
接口.jpg
接口函数只有4个,Cui_PutcCui_Puts可以像C标准库里的那样使用,重定位之后可以直接printf
2.4 基于STM32F469I-DISCO的优化
使用上面未优化的方法,移植到STM32F469I-DISCO,全屏幕时,屏幕卷动的速度很慢,因为屏幕卷动一次需要将当前屏幕整体往上移动一行字符的高度,未优化时,是直接重新给整个屏幕填充字符,一个字符一个字符画出来,当然消耗时间,如果有方法将整个屏幕整体拷贝,这个过程将提速N倍。MCU接口的LCD的驱动IC一般支持窗口函数,这种使用软件去描点就类似于这种拷贝了,但是RGB接口的显存都是线性的,无法实现这种方法,而STM32F469的硬件加速器正是为了这种拷贝而设计的,假如有一组图片数据,颜色格式为ARGB8888,但是图片大小是100x100的,现在要将图片拷贝到屏幕的(320,240)的位置,如果使用软件拷贝就要对每一行数据计算起始RAM地址,拷贝一行,接着计算下一行的起始RAM地址,拷贝下一行…,并且图片数据的格式和显存中的格式还不一样,拷贝之前还要先转换一下,但是使用DMA2D硬件加速器,这个过程变得非常简单迅速,设置一下图片数据的起始地址(源),在显存中存放的起始地址(目的),图片的颜色格式,图片的宽和高,启动DMA2D,然后等着硬件拷贝完成就行了。
       经过上面的分析,就知道了该怎样优化了,可以有两种方法优化:
优化1优化画字符的函数,这种方法对CUI的软件改变最小,但是要求取字模时,一个点要用4个字节表示,而不再是1bit,字模体积最大为原来的32倍,虽说STM32F469的Flash有2M,还有16M的QSPI,也不能这么任性,关键是如果屏幕颜色数据改变了,字模岂不是要随着改变,所以这个优化先排除掉
优化2在终端中输入字符时,只要当前屏幕未满,显示速度都是飞快的,毕竟只显示一个字符,但是如果是上面这种情况,那么,整个屏幕都要上移一行,未优化的方法都是重新写满屏数据,这个过程比较慢,但是如果能将当前屏幕从第二行开始拷贝到从第一行开始,再将最后一行清除,那么就相当于把整屏往上移动了一行,这就是这种优化的思想;
    遗憾的是,并没有发现可以将屏幕显存的一部分拷贝到另外一个位置的方法,例程中使用DMA2D的拷贝只是将一个图片数据拷贝到屏幕的某个位置,如果只拷贝图片的一部分,就不知道该怎么处理了,所以只能绕个路,每次拷贝一行像素,如果CUI界面占用了整个屏幕倒是可以整个拷贝。这种方法其实使用普通的DMA也可实现。
注1后来实际测试了一下普通的DMA,发现速度非常慢,显示效果还不如不用优化,也许是我没配置好,对这个结果不满意的坛友可以研究一下,看是不是可以更快。另外实测DMA从SDRAM拷贝到SDRAM所用时间大约是Flash到RAM时间的4~5倍。
       附件工程中提供了未优化和用DMA2D优化这两种方法,可以通过命令行启动或关闭加速,对比一下效果吧。

2调试程序时发现BSP库中关于BSP_LCD_ReadPixel()函数有一处错误:
库错误.jpg
红圈中的2应该改为4ARGB格式一个点占4个字节,不是两个










附件1_STM32F469I-DISCO_cui_demo.rar

73.21 KB

附件2_STLink_win7_32位精简版USB转串口解决方案.rar

566.26 KB

附件3_STM32F469-DISCO_CUI 超级终端外置键盘.pdf

615.2 KB

附件4_windows 7 超级终端 v1.01 绿色版.rar

239.97 KB

打赏榜单

21ic小喇叭 打赏了 10.00 元 2015-12-22

deru_qq|  楼主 | 2015-12-20 01:02 | 显示全部楼层
本帖最后由 deru_qq 于 2015-12-21 08:42 编辑

3 基于超级终端的外置键盘
       一般开发板只有有限的几个按键,有的甚至没有,想扩展键盘比较麻烦,使用也不方便,但是串口大多开发板都是有的,这部分就介绍如何使用串口配合PC的超级终端来外扩一个外置的键盘,有了这个键盘,几乎能输入电脑标准键盘上的所有按键,并且扩展非常方便,“即插即用”。在介绍这个模块之前,先做些铺垫。

3.1 MCU串行通信处理方法
先介绍一下自己经常用的一个串口通信处理方法和一个自定义的printf函数,这些都是从日本人chaN(FatFs的作者)那里得来的,使用非常方便。
要介绍的这种串口通信方法使用了软件FIFO
发送时:应用程序写要发送的数据到发送FIFO,TX中断函数查询发送FIFO,如果不为空就从里面读数据发送出去
接收时: RX中断函数将接收到的数据写入接收FIFO,应用程序查询接收FIFO,如果不为空,就可以将数据读出来。
使用这种处理,应用程序编程变得很方便;但是移植时,发送中断的处理需要结合MCU的中断触发机制。后面会结合STM32和51单片机讲一下怎样移植这个模块。

3.1.1 软件FIFO操作
       软件FIFO只需要提供MCU的开关中断的方法即可
关中断:FIFO_ENTER_CRITICAL()
开中断:FIFO_EXIT_CRITICAL()

3.1.2移植方法
串口初始化
串口的初始化不同的平台都不一样,但是初始化之后要开接收中断,发送中断要不要开根据平台决定,下面例子有说。
中断触发条件的设置
对于接收中断,一般设为只要有数据接收到就触发中断,大部分MCU都支持这个功能。要注意的是有些MCU的串口接收具有硬件FIFO功能,接收中断的触发条件可以设为FIFO满或者FIFO不空,这时要设为不空,否则会有一些接收数据存留在FIFO中。
对于发送中断,有的MCU是发送寄存器空触发,有的是发送完成触发,这两个本质是不一样的,下面分别根据51和STM32来介绍。
STM32
       初始化:初始化之后开接收中断,发送中断先不要开,接收中断触发条件是RXNE。
       Uart_Putc()函数:(阻塞)
void Uart_Putc(unsigned char c)
{
Fifo_Write(&TxFifo, c);
__HAL_UART_ENABLE_IT(&UartHandle, UART_IT_TXE);
}
将要发送的字节写入FIFO,开发送中断,发送中断的触发条件为TXE,即发送寄存器空触发中断,这时如果没有数据在发送,会立刻进入中断

Uart_Getc()函数(阻塞)
unsigned char Uart_Getc(void)
{
  returnFifo_Read(&RxFifo);
}
不用移植,注意这个函数是阻塞函数,如果需要非阻塞函数,可以先查询一下FIFO是否为空,如果为空,读取失败返回。

中断处理函数:
void USART3_IRQHandler(void)
{
  unsigned charc;

if(__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_RXNE)==1) {
    c =(unsigned char)((UartHandle.Instance)->DR);
   if(!Fifo_Full(&RxFifo))
     Fifo_Write(&RxFifo, c);
  }

if(__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_TXE)==1) {
   if(!Fifo_Empty(&TxFifo)) {
      c =Fifo_Read(&TxFifo);
     (UartHandle.Instance)->DR = (unsigned short)c;
    }
    else {
     __HAL_UART_DISABLE_IT(&UartHandle, UART_IT_TXE);
    }
  }
}
中断处理函数,对于接收中断,将接收到的数据写入接收FIFO即可,但是如果FIFO已满,接收到的数据将被丢弃;对于发送中断,如果FIFO不为空,读出数据发送,如果FIFO为空,注意要禁用发送中断,否则会一直进入中断。

51单片机
       初始化:
初始化之后,开中断,51的接收和发送是一个中断,只能同时使能或禁用
       Uart_Putc()函数:
       void Uart_Putc(unsigned char c)
{
Fifo_Write(&TxFifo, c);
  EA= 0;
if(!TxRun) {
     TxRun= 1;
     TI= 1;
}
  EA= 1;
}
先写数据到FIFO,51的发送中断是发送完成触发,并且可以软件置位标识位触发,这里就是将TI置1来触发软件中断;这里有一个TxRun变量,如果有数据要发送,要将这个变量置1,中断程序会在FIFO中所有数据接收完成之后将其清零,注意修改TxRun时要先关中断。
void UartISR(void) interrupt 4
{
  if(RI){
     Fifo_Write(&RxFifo,SBUF);
     RI= 0;      
  }
  else {
     TI= 0; //清除发送中断标志
     if(!Fifo_Empty(&TxFifo){
        SBUF = Fifo_Read(&TxFifo);
}
     else  {
        TxRun= 0;
     }
  }
}

3.1.3 非阻塞函数
      前面的getc和putc函数都是阻塞函数,但有时需要非阻塞函数,这时可以使用FIFO_Full()和FIFO_Empty()函数先判断一下,如果可以写或者读,就执行,然后返回成功,否则返回失败,这个功能配合定时器就可以实现带超时的非阻塞函数。
3.2 xprintf模块
       在串口输出时,如果将putc重定位,可以使用C标准库的printf函数,这对于调试意义重大,但重定向到标准的printf函数好像比较麻烦,编译出来的代码也会增加,RAM小的情况下也比较容易出问题(我自己没试过),所以一直以来都没用过,一直在用的是chaN的xprintf模块,这个模块基本上具备了printf的所有功能(不支持浮点数打印),还有sprintf,等等,代码编译之后大概2K,实现只需要stdarg.h头文件,这个头文件中都是一些宏操作,没什么消耗,它有几个好处:
       1. 使用方便:不需要移植,通过一个函数调用完成重定向,也可以将输出函数作为参数来实现临时的重定向
       2. 适合调试用:模块提供了xgetc, xgets,xatoi等函数,具有回显功能,可以方便从串口输入数据,完成字符串到整数的转换等,后面Demo程序会看到相关的用法。
模块使用
这个模块不用移植,可以直接使用,只需要调用两个函数:
xdev_out(Uart_Putc);
xdev_in(Uart_Getc);
这样就完成了重定向,虽说一般用于串口,其实这个模块可以用于任何字符输出设备,比如液晶。
chaN的网站上有很多值得学习的地方,电子爱好者不要错过
见附件文档
3.3 基于超级终端的外置键盘3.3.1设计思路:
       在PC的超级终端下,按下一个按键,会(不是所有按键都会)通过串口发送一个字符,有些功能键按下之后会发送3个字符,可以利用这个特性来用MCU的串口扩展一个外接键盘。
键盘扫描:
根据前面的介绍,串口接收到的字符都存放在接收FIFO中,这样隔一段时间去查询一下FIFO,如果有数据,将数据读出,就知道那个按键按下,然后执行相应的处理,而这个FIFO相当于键盘的缓冲区(本模块使用了单独的按键缓冲FIFO),有些功能键按下会一下发送3个字符,这三个字符如果分别读出会被误判为其他按键按下,如:UP键对应的键盘码为1B 5B 41,如果顺序读出来,会认为ESC(1B),“[”和“A”按下了,对于这种情况,可以用一个状态机来处理,如果接收到的字符是1B,那么延时5ms,再扫描,如果5ms之内又接收到了数据,认为新接收到的数据和将要接收到的数据是同一个按键的码值,如果5ms之内没接收到,说明按下的就是ESC键。
本模块在定时器中断中执行案件扫描,占用CPU时间很少,并且这个外接键盘有一个好处,就是免去了判断按键键值的麻烦,接收到的字符既是按键键值。
超级终端的高级用途:
超级终端除了可以按顺序输出打印的字符外,还可以在指定位置显示字符,改变背景颜色,字符颜色和显示模式等,完全可以当做一个简单的监控界面来使用,在要介绍的模块中,实现了几个简单的函数,想了解超级终端高级用途的可以参考这里:
见附件文档

3.3.2 模块移植
       这个模块的移植需要fifo.c,其他只需要提供一个非阻塞的串口接收函数
#define ht_getc_unblock(c)  Uart_Getc_Unblock(c)
如果接收FIFO为空,这个函数返回0,如果接收FIFO不为空,从接收FIFO中读出一个字节,将这个字节赋值给*c
3.3.3 接口函数
HT接口函数.jpg
KeyBuf_Proc():这个函数要放在1ms定时器中断服务函数中执行
HT_GetKey():从键盘缓冲中读取一个按键,如果读到的值为0,说明没有按键按下。
HT_KeyScan_Enable(),HT_KeyScan_Disable():键盘的扫描可以使能或禁用,使能键盘扫描时,串口接收FIFO中的数据会在KeyBuf_Proc()函数中读入键盘缓冲;禁用扫描时,键盘缓冲会被清除,KeyBuf_Proc()函数也不会执行按键扫描,超级终端可以当做普通的串口终端来使用。
       下面这几个函数属于超级终端的高级用法了
HT_ClearScreen():清除当前显示
HT_SetStyle():设置显示风格,可以是高亮,闪烁,带下划线等
HT_SetBackground():设置字符背景色
HT_SetForeground():设置字符前景色
HT_SetXY():设置光标位置(注意光标的原点位置坐标是(1,1)不是(0,0)
       在Demo程序中会看到相应的用法。



4. 综合DEMO程序
       前面讲了这么多,看得都没劲了,还是来个Demo程序来演示一下吧
硬件准备:
       将STM32F469I-DISCO通过STlink的USB接口连接到电脑,保证可以下载程序,并且虚拟串口可以使用(这个虚拟串口的驱动相当难装,我自己折腾了一个下午才装成功,后面会附上这个方法),下载程序。
超级终端演示:
HT初始.jpg

程序默认将输出函数定位到了串口上,超级终端会打印Hello World,并有“>”来提示输入命令,这个Demo程序支持几个命令,用于超级终端演示的有
“dir2lcd”:定位输出函数到液晶,如果输入这个命令,显示将会从超级终端切换到液晶。
ht_test”:进入外置键盘的测试程序,进入之后的界面是这样的:
HT测试.jpg
按下一个按键,将会在屏幕固定位置打印出按下的按键及其键值,按ESC键会退出测试模式。
液晶和CUI演示
       在超级终端中输入“dir2lcd”命令将输出重定向到LCD,这时要看LCD屏幕了,在LCD屏幕上可以有以下命令:
“dir2ht”:切换输出到超级终端
“opt_enable”:使能CUI的DMA2D硬件加速,上电默认是使能的
“opt_disable”:禁用CUI的DMA2D硬件加速
“cui_test”:输入这个命令会打印出来几行字符,多输入几次写满整个屏幕,可以看滚屏的效果,并且可以对比开优化和不开优化的效果。
晒图2.jpg


附录:关于附件中的DEMO工程
       cui_demo工程文件和STM32CUBEF4软件包的位置关系如下:
cui_demo路径.jpg
工程所需要的文件都在cui_demo/src文件夹下,串口驱动的HAL库太乱了,自己写了一个,比较简洁。

STM32CUBEF4软件包太大了就不上传了
src目录.jpg

使用特权

评论回复
deru_qq|  楼主 | 2015-12-20 01:04 | 显示全部楼层
今天图片上传个数已达上限了,明天把图片和附件3的文档(本帖的PDF版本)补上

使用特权

评论回复
wejoncy| | 2015-12-20 09:26 | 显示全部楼层

使用特权

评论回复
deru_qq|  楼主 | 2015-12-20 20:27 | 显示全部楼层

使用特权

评论回复
21ic小喇叭| | 2015-12-21 14:21 | 显示全部楼层
写得挺细,先关注着,明天打赏哦~

使用特权

评论回复
deru_qq|  楼主 | 2015-12-21 14:55 | 显示全部楼层
21ic小喇叭 发表于 2015-12-21 14:21
写得挺细,先关注着,明天打赏哦~

谢谢,;P

使用特权

评论回复
exson_2006| | 2015-12-23 16:12 | 显示全部楼层
感谢分享

使用特权

评论回复
bkn1860| | 2015-12-24 09:05 | 显示全部楼层
很不错

使用特权

评论回复
huaiqiao| | 2015-12-24 13:28 | 显示全部楼层
我来学习了,这个帖子的内容第一次见,很新颖的内容。

使用特权

评论回复
秋风式街球| | 2015-12-24 17:22 | 显示全部楼层
顶楼主

使用特权

评论回复
deru_qq|  楼主 | 2015-12-24 17:46 | 显示全部楼层

使用特权

评论回复
deru_qq|  楼主 | 2015-12-24 17:47 | 显示全部楼层
huaiqiao 发表于 2015-12-24 13:28
我来学习了,这个帖子的内容第一次见,很新颖的内容。

一起学习哈

使用特权

评论回复
huaiqiao| | 2015-12-24 20:06 | 显示全部楼层

呵呵,向您学习

使用特权

评论回复
Prague| | 2015-12-25 19:48 | 显示全部楼层

使用特权

评论回复
zhuotuzi| | 2015-12-25 21:42 | 显示全部楼层
楼主这个超级终端是XP上搞来的吧?可以用WIN10上吗?

使用特权

评论回复
zhuotuzi| | 2015-12-25 21:51 | 显示全部楼层
刚才试了一下,在WIN10上可以运行,但是卡着不动。

使用特权

评论回复
yiyigirl2014| | 2015-12-25 22:42 | 显示全部楼层
CUI界面只支持字符显示,可以显示固定行数和列数的字符,并且字符只能顺序写入,不能设定光标的位置

使用特权

评论回复
huangcunxiake| | 2015-12-25 23:31 | 显示全部楼层
CUI显示的行数和列数,这两个值设定之后最好保证整个CUI界面小于LCD_WIDTH和LCD_HEIGHT所限定的区域,否则一部分字符会显示不出来。这个CUI是GUI吗?是一种Windows操作吗

使用特权

评论回复
deru_qq|  楼主 | 2015-12-25 23:43 | 显示全部楼层
zhuotuzi 发表于 2015-12-25 21:42
楼主这个超级终端是XP上搞来的吧?可以用WIN10上吗?

Win7可以用的,win10没试过

使用特权

评论回复
发新帖 本帖赏金 10.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

10

主题

132

帖子

2

粉丝