卡死在lvgl定时器中
官方提供的lvgl的demo在gui_main函数中如下设置定时器并调用window_manager_init函数初始化各个界面:
/* Implement and register a function which can read an input device. E.g. for a touch pad */
static lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
lv_indev_drv_init ( &indev_drv ); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
lv_indev_drv_register ( &indev_drv ); /*Finally register the driver*/
//timer_reinit();
__SYSTEM_TIMER_CLK_ENABLE();
timer_init ( Timer0, system_get_clock_config() * 1000 * LV_TICK_COUNT, TIMER_DIV_NONE );
timer_start ( Timer0 );
NVIC_SetPriority ( TIMER0_IRQn, 5 );
NVIC_EnableIRQ ( TIMER0_IRQn );
// os_timer_init(&lv_schedule_timer, lv_schedule_timer_handler, NULL);
// os_timer_start(&lv_schedule_timer, 20, true);
timer_init ( Timer1, system_get_clock_config() * 1000 * 100, TIMER_DIV_NONE );
timer_start ( Timer1 );
NVIC_SetPriority ( TIMER1_IRQn, 6 );
NVIC_EnableIRQ ( TIMER1_IRQn );
//init display menu
window_manager_init();
通过分析timer1中断回调函数可以看到该中断回调函数中是有调用lvgl的lv_timer_handler函数的,也就是说涉及到lvgl的相关流程:
__attribute__ ( ( section ( "ram_code" ) ) ) void timer1_handler ( void )
{
uint32_t tick;
timer_int_clear ( Timer1 );
timer_stop ( Timer1 );
tick = lv_timer_handler();
timer_init ( Timer1, system_get_clock_config() * 1000 * tick, TIMER_DIV_NONE );
timer_start ( Timer1 );
}
static void lv_schedule_timer_handler ( void *arg )
{
lv_timer_handler();
}
/**
* Call it periodically to handle lv_timers.
* @return the time after which it must be called again
*/
LV_ATTRIBUTE_TIMER_HANDLER uint32_t lv_timer_handler(void)
{
TIMER_TRACE("begin");
/*Avoid concurrent running of the timer handler*/
static bool already_running = false;
if(already_running) {
TIMER_TRACE("already running, concurrent calls are not allow, returning");
return 1;
}
already_running = true;
if(lv_timer_run == false) {
already_running = false; /*Release mutex*/
return 1;
}
static uint32_t idle_period_start = 0;
static uint32_t busy_time = 0;
uint32_t handler_start = lv_tick_get();
if(handler_start == 0) {
static uint32_t run_cnt = 0;
run_cnt++;
if(run_cnt > 100) {
run_cnt = 0;
LV_LOG_WARN("It seems lv_tick_inc() is not called.");
}
}
/*Run all timer from the list*/
lv_timer_t * next;
do {
timer_deleted = false;
timer_created = false;
LV_GC_ROOT(_lv_timer_act) = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
while(LV_GC_ROOT(_lv_timer_act)) {
/*The timer might be deleted if it runs only once ('repeat_count = 1')
*So get next element until the current is surely valid*/
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), LV_GC_ROOT(_lv_timer_act));
if(lv_timer_exec(LV_GC_ROOT(_lv_timer_act))) {
/*If a timer was created or deleted then this or the next item might be corrupted*/
if(timer_created || timer_deleted) {
TIMER_TRACE("Start from the first timer again because a timer was created or deleted");
break;
}
}
LV_GC_ROOT(_lv_timer_act) = next; /*Load the next timer*/
}
} while(LV_GC_ROOT(_lv_timer_act));
uint32_t time_till_next = LV_NO_TIMER_READY;
next = _lv_ll_get_head(&LV_GC_ROOT(_lv_timer_ll));
while(next) {
if(!next->paused) {
uint32_t delay = lv_timer_time_remaining(next);
if(delay < time_till_next)
time_till_next = delay;
}
next = _lv_ll_get_next(&LV_GC_ROOT(_lv_timer_ll), next); /*Find the next timer*/
}
busy_time += lv_tick_elaps(handler_start);
uint32_t idle_period_time = lv_tick_elaps(idle_period_start);
if(idle_period_time >= IDLE_MEAS_PERIOD) {
idle_last = (busy_time * 100) / idle_period_time; /*Calculate the busy percentage*/
idle_last = idle_last > 100 ? 0 : 100 - idle_last; /*But we need idle time*/
busy_time = 0;
idle_period_start = lv_tick_get();
}
already_running = false; /*Release the mutex*/
TIMER_TRACE("finished (%d ms until the next timer call)", time_till_next);
return time_till_next;
}
按照上面的代码,很容易出现卡死在Timer1中断函数中的现象,这个现象并不是必现的,复位十次基本有3次能够出现:
lv_mem_buf_get
0x10028474: 2800 .( CMP r0,#0
0x10028476: bf08 .. IT EQ
0x10028478: 4770 pG BXEQ lr
0x1002847a: e92d41f0 -..A PUSH {r4-r8,lr}
0x1002847e: 2100 .! MOVS r1,#0
0x10028480: 4e32 2N LDR r6,[pc,#200] ; [0x1002854c] = 0x11009904
0x10028482: b088 .. SUB sp,sp,#0x20
0x10028484: 4605 .F MOV r5,r0
0x10028486: f04f32ff O..2 MOV r2,#0xffffffff
0x1002848a: 2701 .' MOVS r7,#1
0x1002848c: eb0603c1 .... ADD r3,r6,r1,LSL #3
0x10028490: 7998 .y LDRB r0,[r3,#6]
0x10028492: f0100f01 .... TST r0,#1
0x10028496: d113 .. BNE 0x100284c0 ; lv_mem_buf_get + 76
0x10028498: 889b .. LDRH r3,[r3,#4]
0x1002849a: 42ab .B CMP r3,r5
0x1002849c: d310 .. BCC 0x100284c0 ; lv_mem_buf_get + 76
0x1002849e: d107 .. BNE 0x100284b0 ; lv_mem_buf_get + 60
0x100284a0: eb0600c1 .... ADD r0,r6,r1,LSL #3
0x100284a4: 7187 .q STRB r7,[r0,#6]
0x100284a6: f8560031 V.1. LDR r0,[r6,r1,LSL #3]
0x100284aa: b008 .. ADD sp,sp,#0x20
0x100284ac: e8bd81f0 .... POP {r4-r8,pc}
0x100284b0: 2a00 .* CMP r2,#0
0x100284b2: db04 .. BLT 0x100284be ; lv_mem_buf_get + 74
0x100284b4: eb0600c2 .... ADD r0,r6,r2,LSL #3
0x100284b8: 8880 .. LDRH r0,[r0,#4]
0x100284ba: 4283 .B CMP r3,r0
0x100284bc: d200 .. BCS 0x100284c0 ; lv_mem_buf_get + 76
0x100284be: b24a J. SXTB r2,r1
0x100284c0: 1c48 H. ADDS r0,r1,#1
0x100284c2: b2c1 .. UXTB r1,r0
0x100284c4: 2910 .) CMP r1,#0x10
0x100284c6: d3e1 .. BCC 0x1002848c ; lv_mem_buf_get + 24
0x100284c8: 2a00 .* CMP r2,#0
0x100284ca: bfb8 .. IT LT
0x100284cc: 2400 .$ MOVLT r4,#0
0x100284ce: db07 .. BLT 0x100284e0 ; lv_mem_buf_get + 108
0x100284d0: eb0600c2 .... ADD r0,r6,r2,LSL #3
0x100284d4: 7187 .q STRB r7,[r0,#6]
0x100284d6: f8560032 V.2. LDR r0,[r6,r2,LSL #3]
0x100284da: b008 .. ADD sp,sp,#0x20
0x100284dc: e8bd81f0 .... POP {r4-r8,pc}
0x100284e0: eb0600c4 .... ADD r0,r6,r4,LSL #3
0x100284e4: 7980 .y LDRB r0,[r0,#6]
0x100284e6: f0100f01 .... TST r0,#1
0x100284ea: d004 .. BEQ 0x100284f6 ; lv_mem_buf_get + 130
0x100284ec: 1c60 `. ADDS r0,r4,#1
0x100284ee: b2c4 .. UXTB r4,r0
0x100284f0: 2c10 ., CMP r4,#0x10
0x100284f2: d3f5 .. BCC 0x100284e0 ; lv_mem_buf_get + 108
0x100284f4: e7fe .. B 0x100284f4 ; lv_mem_buf_get + 128
0x100284f6: 4816 .H LDR r0,[pc,#88] ; [0x10028550] = 0x11007a94
0x100284f8: f8561034 V.4. LDR r1,[r6,r4,LSL #3]
0x100284fc: f8df8050 ..P. LDR r8,[pc,#80] ; [0x10028550] = 0x11007a94
0x10028500: 6840 @h LDR r0,[r0,#4]
0x10028502: 002a *. MOVS r2,r5
0x10028504: d00b .. BEQ 0x1002851e ; lv_mem_buf_get + 170
0x10028506: 4541 AE CMP r1,r8
0x10028508: d10f .. BNE 0x1002852a ; lv_mem_buf_get + 182
0x1002850a: 4629 )F MOV r1,r5
0x1002850c: f008fca6 .... BL lv_tlsf_malloc ; 0x10030e5c
0x10028510: ea5f0800 _... MOVS r8,r0
0x10028514: bf04 .. ITT EQ
0x10028516: 4668 hF MOVEQ r0,sp
0x10028518: f000f848 ..H. BLEQ lv_mem_monitor ; 0x100285ac
0x1002851c: e008 .. B 0x10028530 ; lv_mem_buf_get + 188
0x1002851e: 4541 AE CMP r1,r8
0x10028520: bf1c .. ITT NE
0x10028522: 2900 .) CMPNE r1,#0
0x10028524: f008fc4a ..J. BLNE lv_tlsf_free ; 0x10030dbc
0x10028528: e002 .. B 0x10028530 ; lv_mem_buf_get + 188
0x1002852a: f008fcb0 .... BL lv_tlsf_realloc ; 0x10030e8e
0x1002852e: 4680 .F MOV r8,r0
0x10028530: f1b80f00 .... CMP r8,#0
0x10028534: d009 .. BEQ 0x1002854a ; lv_mem_buf_get + 214
0x10028536: eb0600c4 .... ADD r0,r6,r4,LSL #3
0x1002853a: 7187 .q STRB r7,[r0,#6]
0x1002853c: 8085 .. STRH r5,[r0,#4]
0x1002853e: f8468034 F.4. STR r8,[r6,r4,LSL #3]
0x10028542: b008 .. ADD sp,sp,#0x20
0x10028544: 4640 @F MOV r0,r8
0x10028546: e8bd81f0 .... POP {r4-r8,pc}
0x1002854a: e7fe .. B 0x1002854a ; lv_mem_buf_get + 214
$d
这时候把window_manager_init函数放到定时器初始化之前就能够解决这个问题:
/* Implement and register a function which can read an input device. E.g. for a touch pad */
static lv_indev_drv_t indev_drv; /*Descriptor of a input device driver*/
lv_indev_drv_init ( &indev_drv ); /*Basic initialization*/
indev_drv.type = LV_INDEV_TYPE_POINTER; /*Touch pad is a pointer-like device*/
indev_drv.read_cb = my_touchpad_read; /*Set your driver function*/
lv_indev_drv_register ( &indev_drv ); /*Finally register the driver*/
//init display menu
window_manager_init();
//timer_reinit();
__SYSTEM_TIMER_CLK_ENABLE();
timer_init ( Timer0, system_get_clock_config() * 1000 * LV_TICK_COUNT, TIMER_DIV_NONE );
timer_start ( Timer0 );
NVIC_SetPriority ( TIMER0_IRQn, 5 );
NVIC_EnableIRQ ( TIMER0_IRQn );
// os_timer_init(&lv_schedule_timer, lv_schedule_timer_handler, NULL);
// os_timer_start(&lv_schedule_timer, 20, true);
timer_init ( Timer1, system_get_clock_config() * 1000 * 100, TIMER_DIV_NONE );
timer_start ( Timer1 );
NVIC_SetPriority ( TIMER1_IRQn, 6 );
NVIC_EnableIRQ ( TIMER1_IRQn );
这样改虽然不会死机了,但是会出现表盘界面表针出来很晚的现象,这个后期再想办法优化:
lvgl表盘界面表针晚出现
未修改前的效果请看文章:https://blog.csdn.net/cheng___yi/article/details/128622148
SWD接口配置
我们从官方提供的硬件参考资料可以得到SWD占用如下管脚:
通过和技术支持沟通知道这两个管脚默认是SWD功能(未确定),但是我这里依旧在proj_init函数中做了如下配置:文章来源:https://www.toymoban.com/news/detail-468266.html
// configure PSRAM pin and init PSRAM
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_0, PORTC0_FUNC_QSPI0_IO3 );
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_1, PORTC1_FUNC_QSPI0_SCLK0 );
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_2, PORTC2_FUNC_QSPI0_CSN0 );
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_3, PORTC3_FUNC_QSPI0_IO1 );
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_4, PORTC4_FUNC_QSPI0_IO2 );
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_5, PORTC5_FUNC_QSPI0_IO0 );
psram_init();
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_6, PORTC6_FUNC_SW_TCK );
system_set_port_mux ( GPIO_PORT_C, GPIO_BIT_7, PORTC7_FUNC_SW_DIO );
经过测试依旧没有什么作用,SWD依旧连接不上,原厂说SWD要连接不上有如下可能:要么进睡眠了,要么IO被复用其他功能了
但是我都没有这方面的设置,无语了,最后原厂说让我擦除一下芯片再用JLINK连接看看,我擦除后发现确实可以连接上,然后我重新烧录代码和flash,发现竟然可以连接了,无语!应该是原来芯片做了相关设置造成不能够连接,我擦除重新烧录后就可以了!这个问题最终都没有找到根本原因!文章来源地址https://www.toymoban.com/news/detail-468266.html
到了这里,关于富芮坤fr8008gp lvgl遇坑和解法:卡死在lvgl定时器中;SWD接口配置;的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!