sam9x60 lcd 驱动小记
近期用maplab开发sam9x60,结果例程能点亮屏幕,新建工程无论如何都不行,模块图形化配置做的稀烂,mhc还卡的不行,待机久了甚至出现过10g内存占用。但还好还是功能齐全的ide(虽然我还不知道类似keil那些功能在哪里打开)。
通过调试模式发现程序卡在LCDC_WaitForSyncInProgress内部的死循环里。
打断点发现第一个LCDC_WaitForSyncInProgress并没有卡住,而是卡在第二个。一开始以为是硬件图层的时钟配置,但我发现所有的LCDC_SetLayerClockGatingDisable都注释之后还是卡在那。所以怀疑目光终于落在了lcd的pwm时钟上。
直接让ai读代码,给出功能解释,在代码量小的情况下ai还是没问题的。
/* LCDC initialization */
//1. Configure the LCD timing parameters
LCDC_WaitForSyncInProgress();
LCDC_SetPWMClockSourceSelection(LCDC_PWM_CLOCK_SOURCE);
LCDC_SetClockDivider(PIXEL_CLOCK_DIV);
//Disable all layers for now
LCDC_SetLayerClockGatingDisable(LCDC_LAYER_BASE, false);
LCDC_SetLayerClockGatingDisable(LCDC_LAYER_OVR1, false);
LCDC_SetLayerClockGatingDisable(LCDC_LAYER_OVR2, false);
LCDC_SetLayerClockGatingDisable(LCDC_LAYER_HEO, false);
LCDC_SetLayerClockGatingDisable(LCDC_LAYER_PP, false);
LCDC_WaitForSyncInProgress();//就是卡在这。
1. LCDC_WaitForSyncInProgress()
这个函数用于等待LCD控制器的同步过程完成。在配置LCD控制器寄存器之前,需要确保没有正在进行的同步操作,以避免配置冲突。
函数实现:
-
检查LCDC_LCDSR寄存器中的SIPSTS位(同步正在进行状态位)
-
当该位为0时,表示同步已完成,函数返回
-
如果同步正在进行,则等待直到完成
2. LCDC_SetPWMClockSourceSelection(LCDC_PWM_CLOCK_SOURCE)
设置LCD控制器PWM信号的时钟源。LCDC_PWM_SOURCE_SYSTEM,表示使用系统时钟作为PWM时钟源
函数实现:
-
修改LCDC_LCDCFG0寄存器中的CLKPWMSEL位
-
根据参数设置选择系统时钟或慢速时钟作为PWM时钟源
3. LCDC_SetClockDivider(PIXEL_CLOCK_DIV)
设置像素时钟分频器,用于生成LCD面板所需的像素时钟。
参数: PIXEL_CLOCK_DIV:在项目中定义为7
函数实现:
-
修改LCDC_LCDCFG0寄存器中的CLKDIV位
-
像素时钟频率 = 系统时钟频率 / (CLKDIV + 2)
-
因此,当PIXEL_CLOCK_DIV为7时,实际分频值为9(7+2)
像素时钟是LCD控制器生成的时钟信号,用于同步像素数据的传输。
所以这里的逻辑是:
-
等待LCD控制器当前的同步操作完成,确保可以安全地修改寄存器
-
设置PWM时钟源为系统时钟,这将用于背光控制
-
设置像素时钟分频器,确定LCD面板的像素时钟频率
这些配置是LCD正常显示的基础,必须在启用LCD控制器其他功能之前正确设置。
以上都是ai分析结果,知道啥意思就好办了,直接查这两个函数的传参对不对得上硬件规格。兴奋得对比了例程的配置(我的硬件跟例程是一样的),发现时钟源/频率/分频全都一模一样,一头冷水。但好在,在对比过程中发现,例程设置的时钟配置跟我的自建工程不一样,你这ide,都不能自动配置好自家开发板的lcd驱动初始化的吗??
人在生气的时候真的会笑出来(因为已经被ide在emac初始化,工程configuration丢失,图形化模块编辑链接关系丢失,用着用着卡死发现内存泄露ide占用10g导致爆内存。还有更多我不太记得的让人无语的小细节诸如模块版本更新导致例程无法打开mhc,想看例程具体配置就在mcc降低模块版本结果兼容性崩溃被迫重装一切,装低版本ide结果这个例程可以打开了那个例程又不兼容,我绝望的想得到如果我想通过例程了解模块配置参数那我每天都在卸载和重装中度过。当然我很快想通ide的配置也得有个文件存储参数,所以还是找到了。那么可以放弃mhc了,只用ide构建,用vsc来编辑,手动添加模块库,结果因为只有库没有对应的时钟和中断等可以参考,我还得看手册,不害意思不会看也没必要如此古法开发。还是得折腾mhc直到摸清如何选对驱动参数。跟同学吐槽,同学一句话点醒我,感谢这些印度人的不靠谱,让ai无法正确处理嵌入式开发。所以我们工作机会大大滴多啊(○| ̄|_)
这是例程的时钟配置,注意到
{ ID_LCDC, 1, 1, 0x3, 0}了吗?在我的自建工程里面,他是
{ ID_LCDC, 1, 0, 0, 0}。vsc通过clang,鼠标悬停显示了具体的参数含义,第一个1设备时钟是否使能,后面三个0具体就是gclk是否开启,时钟源选第几个,分频系数多少。
static void initPeriphClk(void)
{
const uint8_t EOL_MARKER = ((uint8_t)ID_PERIPH_MAX + 1U);
struct {
uint8_t id;
uint8_t clken;
uint8_t gclken;
uint8_t css;
uint8_t divv;
} periphList[] =
{
{ ID_PIOA, 1, 0, 0, 0},
{ ID_PIOB, 1, 0, 0, 0},
{ ID_PIOC, 1, 0, 0, 0},
{ ID_FLEXCOM0, 1, 0, 0, 0},
{ ID_TC0, 1, 0, 0, 0},
{ ID_EMAC0, 1, 0, 0, 0},
{ ID_LCDC, 1, 1, 0x3, 0},
{ ID_GFX2D, 1, 0, 0, 0},
{ ID_PIOD, 1, 0, 0, 0},
{ ID_DBGU, 1, 0, 0, 0},
{ EOL_MARKER, 0, 0, 0, 0}//end of list marker
};
好了,配置完这个总算点亮屏幕了吧。还不行,不过经验有了,就知道去驱动库找配置不一样的地方了。是的,这个ide的代码架构是把许多初始化配置直接写在驱动库里,改参数直接在lib里面各个文件去改。
最后因为lvgl本身不支持24位色深,而添加模块时候会因为PDA-TM5000 可以超频到24位而自动填写,这里跟点亮与否无关,实测只是会显示异常。同理还有颜色模式虽然支持rgba8888,但是lvgl不支持24位的rgba8888,所以也得改成rgb565.接下来还有重头戏,mhc支持rtos模块化添加(虽然是加到一个third_party文件夹里),但是实测直接添加rtos会导致中断异常。很容易跑进架构自带的中断异常死循环里。
检查发现,在FreeRTOS的移植代码portASM.S中,定义了处理SWI指令的函数:
.type FreeRTOS_SWI_Handler, %function
FreeRTOS_SWI_Handler:
FreeRTOS的portmacro.h文件中定义了portYIELD()宏
#define portYIELD() __asm volatile ( "SWI 0" );
在系统启动汇编代码cstartup.S中,异常向量表定义了软件中断处理函数,这是默认配置。
/* Software Interrupt */
ldr pc, =software_interrupt_irq_handler
/* Interrupt */
ldr pc, =IRQ_Handler
需要改成
/* Software Interrupt */
ldr pc, =FreeRTOS_SWI_Handler
/* Interrupt */
ldr pc, =FreeRTOS_IRQ_Handler
改完调试仍然跳转到未定义中断循环。ε=( o`ω′)ノ
再检查一下,呼。别怕,这是因为调试器自动把cstartup.S里的中断配置又改默认了。
重新改好直接构建下载就能点亮屏幕触摸正常。
也就是说用了freertos就没法调试了,除非我改在freertos让它可以使用默认中断,但是微芯厂商在添加rtos到mhc的时候怎么不做好适配。。他们自己是没有用过调试功能吗?(印度加尔各答的开发人员,估计真没调试)
也就是说以后用了rtos还想要调试,我还得自己修改rtos?有这精力,我为什么不把这个开发板的rtt studio硬件支持包做出来,用rtt来跑业务。。至少rtt的lvgl和tcp等都有了,不需要再费劲巴拉的适配。(事实上我已经买了 RA6M4-HMI开发板了,rtt 与瑞萨的联合产品,到手半小时点亮例程,让qwen随手改改ui就是新东西。就是瑞萨的框架没那么精简,但人家的硬件配置也高,不用这么扣扣嗖嗖)

浙公网安备 33010602011771号