BL808:【M1s DOCK開發板】與LVGL 使用體驗

2023-03-14 21:01:16

前言

念春時已夏,戀冬雪已融。
總是感嘆時光匆匆,便努力在在平凡中掙扎,在平庸中努力,在平淡中積累。奈何時代飛速發展,時間又被工作佔用,外加生活中的誘惑又太多了,很多想學、想做、想超越的事,都被拋之一旁,漸漸的跟不上時代了,當年對興趣愛好的激情,也下降了好多。
上一篇部落格還是幾年前的,雖然中間進步不少,但是卻少了許多當年寫部落格時的激情飛揚,真是感慨諸多。
按公司要求,以後需要每週交一篇知識分享檔案,索性就繼續寫一下部落格,算是總結,也算是對自己的積累。
由於檔案允許在大框架內自由發揮,所以決定在我的興趣點上找一些還說的過去的東西寫一寫,而不是單純的複製一些網上隨便就能找到的東西。
以後會努力在機械電機、三維重建、影象視覺、深度學習等興趣範圍內做一些比較綜合的整理,而不是僅限於嵌入式的方向。當然,他們的實現都離不開底層,所以肯定是包含嵌入式方向的。

一:說明

BL808晶片是三核異構的RISC-V CPU,引數如下:
三核異構RISC-V CPUs:

  • RV64GCV 480MHz
  • RV32GCP 320MHz
  • RV32EMC 160MHz

AI NN 通用硬體加速器 —— BLAI-100 用於視訊/音訊檢測/識別
內建 768KB SRAM + 64MB UHS PSRAM

編解碼:

  • MJPEG and H264(Baseline/Main)
  • 1920x1080@30fps + 640x480@30fps
    介面:
  • 攝像頭介面 :DVP 和 MIPI-CSI
  • 顯示介面:SPI、DBI、DPI(RGB)
    無線:
  • 支援 Wi-Fi 802.11 b/g/n
  • 支援 Bluetooth 5.x Dual-mode(BT+BLE)
  • 支援 Wi-Fi / 藍芽 共存
    USB 2.0 HS OTG (引出到 USB Type-C 介面)
    具體引數可以檢視Sipeed科技的 M1s DOCK 開發板 說明頁。
    可以看到,這款晶片的能力還是很強的,完全可以媲美之前非常火的入門級Linux晶片 F1C100S,另外,它支援FreeRTOS,所以可以當做裸機進行開發,代替微控制器。但是可能由於是新出的產品,或是由於其他原因,目前這款產品只有Sipeed科技生產的模組,沒有純晶片售賣。目前體驗裝置便是Sipeed科技推出的全功能測試開發板:【Sipeed M1s DOCK 開發板

開始使用體驗

1:環境搭建

  • --Linux開發環境搭建
    參考Sipeed科技的【上手使用】教學的1-4大節,搭建linux使用環境後,使用模擬U盤的方式將bin檔案拖拽進去即可體驗。如果有問題,請自行查詢解決辦法。
    這裡我使用VMware軟體執行ubuntu16.04環境進行測試。支援快速內外複製等功能。如果是別的虛擬機器器環境,自行判斷是否支援。
    由於購買時間較早,所以需要根據教學的 3.2【串列埠燒錄】 來更新板載BL702韌體來實現穩定的下載,在使用圖形化介面燒錄最新的韌體,來實現 3.1【U盤燒錄】。後面編譯生成的bin檔案都可以通過U盤燒錄來快速更新。
    目前主要測試程式都是基於三個核心中的C906核心的。
  • --SDK下載和編譯測試
    參考【上手使用】教學的第5大節,下載SDK並設定好編譯工具鏈,然後就可以編譯並下載程式測試。
    可以跟著操作一遍【lvge_demo】的編譯和下載操作,熟悉整個流程。
    新手小提示
    • 1:程式需要兩個資料夾,一個是 M1s_BL808_SDK ,另一個是 M1s_BL808_example ,可以用 VSCode 開啟這兩個資料夾所在的資料夾,就可以使用 【Ctrl + 單擊】需要了解的函數就能進行快速追蹤跳轉了。如果只開啟例子資料夾是不會跳轉的,或是文字會包含所在文字的資料夾地址。
    • 2:修改【lvgl_demo】的範例內容方法如下:在設定標頭檔案 M1s_BL808_SDK/compnets/lvgl/lvgl/lv_conf.h 中,LV_BUILD_EXAMPLES 設定部分進行範例切換,預設是 LV_USE_DEMO_BENCHMARK 例子。將想要的例子後面的0切換為1,其他的切換為0,然後在 M1s_BL808_example/c906_app/lvgl_demo/main.c 的主檔案中將之前的 lv_demo_benchmark() 函數遮蔽,更換為開啟的demo的函數,比如music例子是 M1s_BL808_SDK/compnets/lvgl/lvgl/demos/lv_demo_music.h中的lv_demo_music()函數,其他幾個例子類似,都在M1s_BL808_SDK/compnets/lvgl/lvgl/demos資料夾下對應的資料夾內。
    • 3:編譯其他幾個例子需要開啟對應的字型(具體開啟那些字型,可以按照報錯提示來),字型開關在設定標頭檔案 M1s_BL808_SDK/compnets/lvgl/lvgl/lv_conf.h 中,快速搜尋LV_FONT_MONTSERRAT_ 即可跳轉到,後面的數位是你需要開啟的字型包。
    • 4:export BL_SDK_PATH 這一步每次重開都要重新來一次,否則會找不到編譯鏈。有長效修改的方法,可自行搜尋嘗試。

2:LVGL體驗

  • LVGL是由來自匈牙利首都布達佩斯的 Gábor Kiss-Vámosi最早於2016年編寫並開源的一款可執行於低資源的MCU裝置上的開源嵌入式GUI庫(輕量級通用型圖形庫)。
  • 其GitHub地址為:【LVGL Git
  • LVGL當時叫 LittlevGL而不是LVGL,後來作者統一修改為 LVGL 甚至連倉庫地址都改了。目前最新版本已經發展到了 v9.0.0 版本,在6.0版本時,我還體驗過移植和簡單使用。當時還沒有拖拽式GUI設計軟體,所有介面都要手寫。如今,LVGL已經有了如SquareLine Studio、GUI-Guider等GUI設計軟體,可以直接PC上進行介面設計和模擬執行,得到【所見即所得】的方便效果。而且隨著LVGL的發展壯大,其中文教學資源等都有了極大的發展,比如【百問網】就有包含檔案和視訊教學在內的豐富的教學資源,而且以前【正點原子】就有編寫過專門的LVGL教學。
  • 現在,首先下載和體驗【SquareLine Studio】軟體。
    SquareLine Studio是LVGL官方提供的GUI設計軟體,可以在LVGL官網直接點選到下載頁面。目前最新版本是V1.2.1。按照官網的說明,它只有30天的全功能體驗時間。
    按照教學下載安裝後(具體安裝步驟可以參考其他網友的教學,很多的),即可新建一個工程進行GUI設計了。
    在新建介面,可以看到,SquareLine Studio支援的LVGL版本只有8.3.3和8.3.4兩個版本:

【M1s DOCK】開發板的螢幕是 1.69 寸 240x280 電容觸控式螢幕,所以我們需要在新建介面將Resolution設定為 (280,240) ,Color depth 要設定為 (16 bit swap)模式 。設定好名字和要儲存的地址後就可以點選 CREATE 新建工程了。其實也可以點選上方的 Example 來檢視官方提供的幾個比較豐富的demo範例,跑起來很絢麗。不過由於開發板官方提供的LVGL例程所使用的的版本是8.2的,而SquareLine Studio只能選擇兩個更高的版本,所以下載demo後,程式並不能正常執行。以後有時間再移植成最新的版本再測試吧。
GUI設計介面如圖:
(具體含義和操作可以自行搜尋教學使用,也可以自己摸索)
我們可以點選一個【Button】到介面。

然後點選左上角的【Export】,選擇【Export UI Files】生成程式碼到指定資料夾。
生成成功後,可以看到指定資料夾下有幾個生成的檔案:

將這幾個檔案複製到linux環境中的 M1s_BL808_example/c906_app/lvgl_demo/ 資料夾下(此資料夾下除了原本的 bouffalo.mk 和 main.c,其他的都可以刪掉)。
我用的是VMware虛擬機器器,所以支援win與ubuntu環境的快速複製。如果是別的虛擬機器器環境,自行處理檔案複製問題。
將 ui.h 檔案中的 #include "lvgl/lvgl.h" 改為 #include "lvgl.h",不然會報錯,據說這個是 SquareLine Studio 的BUG。
將 main.c中的 demo測試相關的程式碼替換為ui.h中的ui_init()函數。
編譯通過後,將開發板設定為U盤下載模式(USB插在OTG口,按住兩側按鍵再按RST按鍵),將 M1s_BL808_example/c906_app/build_out/lvgl_demo.bin 檔案拖拽到U盤中即可。
可以看到,所見即所得:

LVGL升級體驗

完成基礎範例後,既可以進行更復雜一些的基礎範例了。
首先進行一次頁面切換。
點選做下角的【Screen】圖示即可增加一個顯示介面了。
在介面2上增加一個【Arc】控制元件。

下面,就應該思考該如何做介面切換了。首先,計劃需要實現的功能:點選按鈕進入第二頁面,右劃第二介面回到第一頁面。
實現方法如下:

  • 選中第一頁面的按鈕,可以看到右邊的屬性設定欄,可以對按鈕進行各種屬性設定。

  • 點選最下面的【ADD EVENT】,可以看到,有幾個事件型別選項,我們做如下選擇:

    • 【Trigger】選擇 【CLICKED】,即點選事件
    • 【Action】選擇【CHANGE SCREEN】,即切換螢幕

      然後點選【ADD】,增加這個點選事件,然後就可以對此事件進一步設定:
    • 【Screen to】選擇【Screen2】,即切換到螢幕2(名稱可以自行修改,對應到自己的螢幕的名稱)
    • 其他選項預設(可自行測試功能,或是檢視手冊查詢功能說明)

      此時就算設定完成了第一步,實現點選按鈕切換螢幕。可以點選【執行】三角號按鈕進行模擬測試。
  • 後面可以進行同樣的設定,點選第二頁的螢幕,選中螢幕,右側進行設定
    * 【Trigger】選擇 【GESTURE_RIGHT】,即右劃事件
    * 【Screen to】選擇【Screen1】,即切換到螢幕1

    然後點選【ADD】,新增事件,進入到事件設定介面。
    * 【Screen to】選擇【Screen1】,即切換到螢幕1
    此時完成預定目標的設定,實現右劃切換回螢幕1,可以點選【執行】三角號按鈕進行模擬測試。

  • 點選【Export】->【Export UI Files】生成程式碼。

  • 複製替換生成的程式碼到linux對應環境下,然後編譯下載,進行實際執行檢視,可以看到實現了既定目標,在裝置上跑起來了,按鈕和滑動也能正常切換。

LVGL操控裝置

目前我們已經完成了LVGL的簡單繪製,基本事件繫結等體驗功能,但具體來說,也只是使用SquareLine Studio本身實現的,不需要編寫一行程式碼就能實現(需要移植好的裝置環境),並沒有涉及LVGL之外的互動。所以下面嘗試一下,將LVGL與硬體互動聯絡起來,然後就能舉一反三,實現完整複雜的邏輯功能了。

  • 首先,計劃需要實現的功能:將螢幕2上的【Arc】控制元件於裝置背面的LED的亮度繫結,實現拖拽【Arc】的角度就能控制LED的亮度。

  • 然後,我們來看一下LED的PWM驅動例子。
    開啟 M1s_BL808_example/c906_app/pwm_demo 中的main.c,檢視PWM的例子。
    可以看到,PWM操作背面的LED燈,只需要幾個特定的函數。

  • 再然後,我們考慮怎麼將LVGL的【Arc】拖動事件與PWM調值聯絡起來。

    • 選中螢幕2的【Arc】控制元件,點選右下角的【ADD EVENT】,增加一個事件。
    • 【Trigger】選擇 【VALUE_CHANGED】,即值改變事件
    • 【Action】選擇【CALL_FUNCTION】,即呼叫函數

    • 點選【ADD】,進入設定
    • 給呼叫函數起一個名字,在【Action】->【Function name】文字方塊中輸入起的名字,如[Arc_PWMControl] ,注意,名字要夠一定字數
      設定完成,開始生成檔案。
      將生成的檔案複製替換到linux環境下,開啟資料夾,可以看到 ui_events.c 中有一個函數:
void Arc_PWMControl(lv_event_t * e)
{
	// Your code here
}

裡面沒有任何功能。所以我們需要在本函數中新增回撥函數對應的處理,即獲取改變後的值,然後設定對應脈寬給PWM,實現調節亮度。
使用如下函數即可獲取到【Arc】控制元件的當前值:

int16_t ArcValue = 0;
lv_obj_t* arc = lv_event_get_target(e);//獲取目標控制元件指標
ArcValue = lv_arc_get_value(arc) ;//獲取目標值

然後就可以使用這個值,呼叫 pwm_demo 中的 m1s_xram_pwm_set_duty 函數進行佔空比設定。我們可以在main函數中整合一下PWM操作相關的函數,包括初始化和佔空比調節,進行呼叫。在main.c中增加如下兩個函數:

```
#include "m1s_c906_xram_pwm.h"
#define PWM_PORT (0)
#define PWM_PIN (8)
#define PWM_FREQ 2000  //PWM頻率設定
//PWM驅動LED初始化程式碼
void LED_PWMInit(int freq,int duty){
    m1s_xram_pwm_init(PWM_PORT, PWM_PIN, freq, duty);
    m1s_xram_pwm_start(PWM_PORT, PWM_PIN);
}
//設定佔空比
void LED_PWMDutySet(int duty){
    m1s_xram_pwm_set_duty(PWM_PORT, PWM_PIN, PWM_FREQ, duty);   
}
```

將LED_PWMInit()函數放置到main函數中,將LED_PWMDutySet()函數使用extern關鍵字參照到ui_events.c中。
檢視pwm_demo中的m1s_xram_pwm_set_duty()函數,可以看到,佔空比為0-99,我們的【Arc】範圍為0-100,所以需要限制【Arc】的範圍。兩種方法:

  • 1:是在【Arc】屬性設定控制元件中將【Range max】最大值屬性設定為99
  • 2:在程式中增加判斷,大於99的都設定為99
    也可以兩種都用上,增加保險。
    然後在Arc_PWMControl()函數中呼叫,將ArcValue 值傳給m1s_xram_pwm_set_duty()函數即可。
    另外,由於LED燈電路上的驅動電路的不同(高電平端控制或是低電平端控制),所以PWM脈寬與LED亮度不一定成正比,可以加上一句 ArcValue = 99-ArcValue; 來換算。
    具體程式如下(僅供參考):
    main.c:
/* FreeRTOS */
#include <FreeRTOS.h>
#include <task.h>

/* bl808 c906 std driver */
#include <bl808_glb.h>

#include "demos/lv_demos.h"
#include "lv_port_disp.h"
#include "lv_port_indev.h"
#include "lvgl.h"

#include "ui.h"
#include "m1s_c906_xram_pwm.h"
static void lvgl_task(void *param)
{
    while (1) {
        lv_task_handler();
        vTaskDelay(1);
    }
    vTaskDelete(NULL);
}

#define PWM_PORT (0)
#define PWM_PIN (8)
#define PWM_FREQ 2000

//PWM驅動LED初始化程式碼
void LED_PWMInit(int freq,int duty){
    m1s_xram_pwm_init(PWM_PORT, PWM_PIN, freq, duty);
    m1s_xram_pwm_start(PWM_PORT, PWM_PIN);
}
//設定佔空比
void LED_PWMDutySet(int duty){
    m1s_xram_pwm_set_duty(PWM_PORT, PWM_PIN, PWM_FREQ, duty);   
}

void main()
{
    LED_PWMInit(PWM_FREQ,99);//PWM初始化,預設佔空比設為99
    lv_init();
    lv_port_disp_init();
    lv_port_indev_init();//觸控相關
    ui_init();
    lv_task_handler();
    xTaskCreate(lvgl_task, (char *)"lvgl task", 512, NULL, 15, NULL);
}

ui_events.c中程式如下:

#include "ui.h"

extern void LED_PWMDutySet(int duty);

void Arc_PWMControl(lv_event_t * e)
{
	// Your code here
	int16_t ArcValue = 0;
	lv_obj_t* arc = lv_event_get_target(e);//獲取目標控制元件指標
	ArcValue = lv_arc_get_value(arc) ;//獲取目標值
	if(ArcValue>99)ArcValue=99;
	
	ArcValue = 99-ArcValue;//佔空比對應燈的亮度;由於LED驅動方式的不同,亮度與佔空比不一定是正比
							//這樣處理後便將亮度與佔空比換算為正比了
	
	LED_PWMDutySet(ArcValue); 
}

將程式編譯,然後將 build_out資料夾下生成的 lvgl_demo.bin 拖拽到模擬U盤中更新程式,可以看到已經實現了既定目標:

  • 點選【button】切換到第二頁面
  • 右劃第二頁面回到第一頁面
  • 拖拽【Arc】控制元件實現控制背面LED的亮度


(LED在背面,此處不再展示)

以上只是一些簡單的例程,用於實現LVGL的操作體驗和與硬體的互動實現的流程,更多功能便可以很輕鬆的拓展了。其實還有很多優化空間的,比如【Arc】控制元件的左右滑動會激發頁面滑動效果從而回到第一頁面,右下角的引數視窗沒去掉,點選指示圖示是一個USB圖示,SDK的lvgl版本與編輯器的版本不同導致複雜介面卡死等。這些都可以自行深入學習並完善。
關於LVGL深入的學習,還請自行檢視相關教學。而且例程是基於freertos嵌入式作業系統的,在main函數中可以看到,lv_task_handler()控制程式碼是在 lvgl_task 任務中迴圈執行的,所以可以建立其他執行緒執行lvgl之外的功能,而不是僅僅依靠lvgl控制元件的回撥函數實現。後面有時間會再寫一些好玩的東西,比如深入理解一下LVGL的移植,然後實現其他的繪相簿的移植,比如之前寫過的旋轉立方體:

或是基於此演演算法的旋轉時鐘:

  • 隨夢,隨心,隨願,恆執念,為夢執戰,執戰蒼天 ----執念執戰 (好久沒寫我這很中二的座右銘了,哈哈)