CKS32F103VE应用于前级效果器面板方案

项目方案概述

本应用来源于前级效果器面板项目(图1),由一方案商提供硬件,但没有原版软件程序,因此他们自己开发了一套替代方案,依然是使用雅特力415芯片,此芯片主频150MHz,SPI传输速率最高可达50Mb/s,经计算,如果使用SPI+DMA传输,理论上可以跑40帧左右且不占用太大的系统使用率,但可能受限于技术水平,方案商的替代方案效果并不理想。

而如果我们想要出替代方案,使用M4系列,其价格并不是很好的选择,因此选用了M3大容量的CKS32F103VET6。LCD驱动方面,受限于M3最高18Mb/s的SPI传输速率,我们选用了8080作为显示驱动接口,利用了MCU的FSMC功能,对比SPI一根线传输数据,FSMC可同时传输8位/16位数据,其速率实测连续单色刷屏可达百帧以上,本项目方案商提供了8位并口屏,如果选择16位速度可提升一倍。

系统菜单方面,原方案使用的是多级菜单,没有挂系统,多级菜单优劣势明显,优势是设计简单,把系统分成一个个的层级,通过按键轮询菜单就可以切换不同的界面,其缺点是可靠性不足,不足以承载复杂的系统,基于项目复杂性及可靠性评估,选择了移植LVGL作为本方案的开发系统,兼顾了系统稳定性、项目拓展性及成功率。

1.png

图1 前级效果器面板开发样机

方案主要设计核心思路

客户的核心诉求主要是刷屏效果要达到原版效果,原版效果应该在20帧以内,速度比较快但刷屏时依然可以看到刷屏线,另一个要求是功能跟原版功能一致。

刷屏效果优化

刷屏效果主要通过四种方式来优化:

(1)提高主频:我们103大容量运行频率可达144MHz,因此在软件的最开始,手动配置了升频函数,主要语句如下,配置PLL倍频12倍,即12M*12=144MHz,后使能PLL,另外Flash等待时间必须配置为5,因为主频增加了,要保证有足够的等待时间才能完成配置,实测等待时间2时,最高只能跑到120MHz主频。

FLASH_SetLatency(0x05);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_12);
RCC_PLLCmd(ENABLE);

(2)优化FSMC驱动:FSMC硬件连接方式如下表1所示,使用NE1作为片选,A16为写命令/写数据,D0-D7为8位的双向数据线,PD4读数据,PD5写数据。LCD的驱动时序,和FSMC模式A的时序基本一致,因此配置成模式A即可。为了最大化提高传输速率,FSMC的建立时间和数据保持时间都配置到最小。

表1 MCU与LCD屏接口硬件连接

2.png

(3)打点函数优化:MCU通过以上FSMC并口控制LCD显示芯片,其逻辑是MCU通过特定的地址把数据传到LCD驱动显示芯片相应的显存里面(需要此芯片的根本原因是MCU SRAM不足),驱动显示芯片再按照配置好的扫屏顺序,在显示屏上刷新一个个像素点(图2)。

3.png

图2 MCU与LCD屏的关系

而打点函数就是MCU用来传输数据到LCD驱动显示芯片的桥梁,一般传输一个像素点数据,都需要先发送命令,再发送数据,LCD驱动显示芯片才会知道你这个数据用来干什么,一般的打点函数,会对每一个像素点都进行写命令再发送数据,这样每次都会浪费2次8位数据的时间,整一个屏320*240个像素点,就会浪费大量的时间,因此优化了打点函数,如下文所示。每次先获得需要显示图像的XY轴开窗大小,然后写命令一次,就可以将所有像素点连续写入,只需要一次循环结束就可以完成打点函数。

void LCD_Draw_Picture(u16 sx,u16 sy,u16 ex,u16 ey,u16 *color)
{   
    u16 height,width;
    u16 i;
    width=ex-sx+1;                 //得到图片的宽度
    height=ey-sy+1;                //得到图片的高度
    Lcd_SetRegion(sx,sy,ex,ey);
    LCD_WriteRAM_Prepare();         //开始写入GRAM
    for(i=0;i<height*width;i++)
    {
        LCD->LCD_RAM=(*color)>>8;//写入颜色值
        LCD->LCD_RAM=(*color)&0XFF;
        color++;
    }
}

另外因为有LCD驱动显示芯片的中转存在,这里会产生一个问题,当LCD还没有刷新完屏幕一帧画面时(读显存),LCD驱动显示芯片就写入下一帧的画面,那这两帧之间,就会产生断纹,对应到人眼视觉上面,就会产生一个横向撕裂的短暂停留(图3)。 本方案解决这个问题的方式是通过读取驱动芯片的更新扫描线,读取到扫描线在屏幕以外,才开始写入,当然弊端是这个读取时间导致帧数降低,所以本方案在刷整屏的时候才会去等待扫描线,启用消除横向撕裂功能,小面积刷屏的时候几乎不会出现撕裂现象,这样的方案可以有效提高帧数。

4.png

图3 横向撕裂产生的原因,读和写的不同步

(4)LVGL系统级优化:LVGL作为一个轻量级GUI系统,并不是想要显示图像,就能马上发送打点函数,LVGL会有一个自己的心跳,根据显示区域的大小及缓存区域配置,缓存好一块图像再通过打点函数输出,这个缓存区域会极大的影响帧率,一般默认是每次缓存像素点的十分之一,就会存在10次缓存等待时间,因此选择优化这个次数,但是增大缓存区域会极大的占用SRAM,目前优化配置为缓存总像素点的四分之一,占用38K字节SRAM,帧数可达20帧左右。

当然,并不是只有这一种缓存方式,还可以选用双缓存或者DMA2D+LTDC加速,但前者需要大量的SRAM资源,相当于开辟双倍的缓存区域,一个负责渲染,一个负责绘制;后者LTDC则需要F429以上芯片才有。很明显我们不具有LTDC外设,并且实测同等SRAM占用下,双缓存不如单缓存显示效果好。

方案进行到这一步的时候才发现LVGL的弊端,并不能完全发挥我们FSMC传输速率,但好处是正因为轻量级系统的存在,令我们系统可靠性大大提升,不需要自行设计内存管理,配置后系统会帮你管理。

核心功能开发

经过刷屏效果优化后,已经能满足项目需求,接下来进行功能项开发。虽然本项目看起来不大,但涉及的内容非常多,共分为7大项:

1) 输入按键及旋钮开发

本项目所有输入分两种,第一种是ADC检测的按键,由一个ADC外设,来检测由分压电阻隔开的11个电平,共分11个按键,不同adc值得到特定按钮,本功能难点是adc检测滤波函数和无冲突按键逻辑,滤波函数如下文所示,由于要准确的命中键值,这里每次触发adc中断,会从DMA读取100个adc值,然后快速作一个排序,最后平均第49位和50位adc值,就可以得到可靠的按键值,这些设定在16ms内处理一次。能准确得到按键值后,因为处理时间很快,为了使重复按键不冲突,设定了第一次按键锁定以及锁定时间,按下第一个按键后一定时间内失能其他按键。

void filter(void)
{
    u16 tmp;
    u8 i = 0,j = 0;
    for(i=0; i<=100/2; i++)
    {
        for(j=0; j< 99-i; j++)
        {
            if(ADC_ConvertedValue[j+1] < ADC_ConvertedValue[j])
            {
                tmp = ADC_ConvertedValue[j+1];
                ADC_ConvertedValue[j+1] = ADC_ConvertedValue[j];
                ADC_ConvertedValue[j] = tmp;
            }
        }
    }
    After_filter=(ADC_ConvertedValue[49] + ADC_ConvertedValue[50])/2;
}

第二种输入是三组旋钮编码器,旋钮编码器比较特殊,正转和反转时,都会触发AB两个相的电平(图4),通过分辨电平触发的先后顺序来得到正反转。软件部分使用2个IO外部中断线触发,通过排序AB电平来临的顺序判断是正反转,需要触发多次判断,同时要兼顾软件防抖。三组编码器共用到6个IO外部线中断。

5.png

图4 编码器正反转波形及状态图

2)页面开发及页面切换

为了快速开发页面,本项目用到了NXP的一个软件GUI-guider,页面如图5所示,是一款以图像设计转换为LVGL代码的软件,通过配置模型和触发事件,能快速的帮你转化成代码。有众多使用方式,如新建文本框并给这个文本框触发事件、按键按下后触发文本框参数修改、聚焦时背景高亮、离焦后背景变回原色或切换下一页。

使用软件后,文本框功能只需要放置一个文本框图像,设定大小和文本内容,右键添加相关事件,最后会自动生成所有代码,大大减少开发难度,但最新版仍有一些bug,要自行按经验修改,如内存泄露,跳转后没有及时清理新建过的模型,导致内存一直累积,多次跳转后爆内存。本项目使用此软件快速生成页面和事件的模版,再按需求修改逻辑和bug,本项目高达20多个页面,200多个触发事件,使用此软件后工作量依然巨大。

6.png

图5 NXP的GUI-guider页面

3)参数切换开发

本项目参数切换页面如图6所示,这是其中一页的可调参数,通过旋钮来选择参数项,如选到输入选择,按下确认按键后,进入参数切换模式,再次转动旋钮将模拟1切换为模拟2、蓝牙、USB等字样。

软件层面来看,我们找到这个文本框事件,添加按下事件,触发这个事件会进入到修改参数的状态,不同参数切换有不同标志位,整个项目参数切换标志位多达200个,并且由于要修改参数的形式都不大一样,每种参数都需要一种函数处理,工作量很大,并且除了参数本身定义值以外,还要显示成字符串显示在屏幕上,占用的FLASH和SRAM也需要非常大,目前没有太好的方式,功能2和功能3都要花费大量的重复工作。

7.png

图6 MCU与LCD屏的关系

4)面板锁开发

面板功能要求带有面板锁,基本逻辑是开启面板锁后,一段时间自动回到主页并显示上锁符号,上锁后不能操作按键,仅能用旋钮调节音乐话筒效果等音量,按键后会进入解锁页面,输入正确密码后,回到主页并解除上锁符号,但一段时间不操作依旧会回到上锁页面,除非关闭面板锁。

软件设计了2种状态,一种是开启面板锁功能标志位,一种是完全上锁标志位,开启面板锁并不会马上进入第二种状态,不管当前是什么页面,只要一段时间不操作,就会跳转主页并完全上锁,完全上锁后只要按键,就会跳转解锁页面,密码匹配后方可退出完全上锁状态,然后开始倒数计数,每次按键都会复位计数值,倒数完毕后重回上锁状态,逻辑流程图如图7所示。

8.png

图7 面板锁软件逻辑流程图

5)保存命名/密码输入

本功能主要是对命名设计,模式保存后可以添加命名(图8a),一共可以保存16种配置,配置好后,使用效果器的人员,只需要调用相应序号及名字的模式,所有参数会自动切换到上次保存的配置。这个功能和参数切换类似,把每一位的名称都当成是独立的一个参数,由A-Z,a-z,0-9还有空格一共63个数组成的数组里面选择,总共10位组成一段命名,同时调整序号,会马上显示相应保存好的命名。面板锁密码页面(图8b)也是类似,只不过是从0-9,10个数字变化,另外增加原密码的对比,以及密码修改功能。这部分的难点在于要考虑全面,当保存命名/输入密码中途,插入其他操作,应该复位和保存相应的参数。

9.png

10.png

图8 a保存命名及b面板锁密码

6)配置保存读取/数据库修改开发

在项目的初期,原方案商并没有加入进来,没有获取到对方的数据库设定,因此设计将所有16组配置参数写入内部Flash,以及读取的一套验证方式,把写入内部Flash当成是发送到对方数据库内,用于所有参数的保存和读取,根据写入参数的大小,按顺序每8位写入到一位内存数组里,再从特定地址,顺序读回参数。

为了减少Flash占用空间,参数都使用数字简化代表字符串,再根据不同数字转换回字符串用于显示。虽然后期加入对方的数据库,存储数据在DSP内部,但这种方式也有效的设计了字符串转换的函数,减少了开发周期。

7) 事务优化

LVGL的特色是按照心跳自行输出画面,而众多的事务总会对画面做干预,但LVGL本身是不支持多线程操作的,在系统还没有输出完画面时,我们直接去干预,会造成系统卡死,因此可以利用LVGL的软件定时器,将所有事务都运行在里面,让LVGL自行顺序执行。

而MCU自身的ADC中断和外部IO检测中断,因为不能放在软件定时器内执行,我们尽可能的减少数据量处理,仅用于标志位触发判定,从而保证系统可靠。如果开发更大的系统,可以加入任务系统,来辅助线程操作。

软件定时器新建方式如下:

lvgl_task2 = lv_timer_create(OS_Handler, 10, 0);  
//创建软件定时器,后续直接调用void OS_Handler(lv_timer_t * tmr)

结语

以上是本项目核心的开发思路,详细开发过程中还会碰到很多问题,如字模替换、特殊显示逻辑、图片插入等。软件工程送样后添加了通讯协议和相关函数,上机连接DSP实测通讯控制没有问题。

整个方案,总的来说CKS32F103VE的FLASH和SRAM资源堪堪够用,可以看到LVGL虽然稳定可靠且使用方便,但在只用到文本框和标签模型的情况下,每页画面占用的资源在十多K字节左右,显示帧率也因为缓冲方式受限很大。FSMC优化后,能跑20帧左右,占用SRAM有38K字节,如果重新评估,同样显示功能, SPI+DMA+多级菜单的方案也是足够使用,当然现在图形化一直在发展,更加美观的GUI可拓展性更佳。

来源:中科芯MCU

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。