[MCU] 平頭哥RVB2601測評:OLED與LVGL移植介紹

xiyue521 樓主
2021-8-31 23:31

一、OLED介紹:

我們的屏幕采用的是128*64的分辨率的,驅動ic應該是SSD1306,這個剛好支持129*64的,但是就是單色屏,用的是spi接口。

image-20210831232254-1.png

 


   

 首先初始化io口:

csi_gpio_pin_t pin_clk;
csi_gpio_pin_t pin_mosi;
csi_gpio_pin_t pin_cs;
csi_gpio_pin_t pin_miso;

static void oled_pinmux_init()
{
    csi_pin_set_mux(PA28, PIN_FUNC_GPIO); //clk
    csi_pin_set_mux(PA29, PIN_FUNC_GPIO); //mosi
    csi_pin_set_mux(PA27, PIN_FUNC_GPIO); //cs
    csi_pin_set_mux(PA30, PIN_FUNC_GPIO); //miso

}



static void oled_gpio_init()
{
 

    csi_gpio_pin_init(&pin_clk, PA28);
    csi_gpio_pin_dir(&pin_clk, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_init(&pin_mosi, PA29);
    csi_gpio_pin_dir(&pin_mosi, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_init(&pin_cs, PA27);
    csi_gpio_pin_dir(&pin_cs, GPIO_DIRECTION_OUTPUT);
    csi_gpio_pin_init(&pin_miso, PA30); //dc
    csi_gpio_pin_dir(&pin_miso, GPIO_DIRECTION_OUTPUT);
}



然后寫命令、數據函數

void Write_Command(unsigned char Data)
{

    unsigned char i;

    lcd_cs(0);
    lcd_dc(0);
    for (i = 0; i < 8; i++) {
        lcd_sclk(0);
        lcd_sdin((Data & 0x80) >> 7);
        Data = Data << 1;
        lcd_sclk(1);
    }
    lcd_dc(1);
    lcd_cs(1);
}


void Write_Data(unsigned char Data)
{
    unsigned char i;
    lcd_cs(0);
   lcd_dc(1);
    for (i = 0; i < 8; i++) {
        lcd_sclk(0);
        lcd_sdin((Data & 0x80) >> 7);
        Data = Data << 1;
        lcd_sclk(1);
   }
    lcd_dc(1);
    lcd_cs(1);

}

對于這種單色屏,我們直接開一個緩沖區就行:
uint8_t g_oled_ram[8][128];
畫點就是修改緩存區的內容:

void oled_draw_point(uint8_t r, uint8_t c, uint8_t t)
{
    if (t) {
       SET_BIT(g_oled_ram[r / 8][c], ((r % 8)));
    } else {
        CLR_BIT(g_oled_ram[r / 8][c], (r % 8));
    }
}

最后要調用刷新函數來修改一整個屏幕:
void oled_reflesh()
{
    unsigned char i, j;
    for (i = 0; i < 8; i++) {
        Set_Start_Page(i);
        Set_Start_Column(0x00);
        for (j = 0; j < 128; j++) {
            Write_Data(g_oled_ram[j]);

        }
    }
}

屏幕初始化:

static void oled_initialize()
{

    Set_Command_Lock(0x12);           // Unlock Driver IC (0x12/0x16)
    Set_Display_On_Off(0xAE);         // Display Off (0xAE/0xAF)
    Set_Display_Clock(0xA0);          // Set Clock as 116 Frames/Sec
    Set_Multiplex_Ratio(0x3F);        // 1/64 Duty (0x0F~0x3F)
    Set_Display_Offset(0x00);         // Shift Mapping RAM Counter (0x00~0x3F)
    Set_Start_Line(0x00);             // Set Mapping RAM Display Start Line (0x00~0x3F)
    Set_Low_Power(0x04);              // Set Normal Power Mode (0x04/0x05)
    Set_Addressing_Mode(0x02);        // Set Page Addressing Mode (0x00/0x01/0x02)
    Set_Segment_Remap(0xA1);          // Set SEG/Column Mapping (0xA0/0xA1)
    Set_Common_Remap(0xC8);           // Set COM/Row Scan Direction (0xC0/0xC8)
    Set_Common_Config(0x12);          // Set Alternative Configuration (0x02/0x12)
    Set_Contrast_Control(Brightness); // Set SEG Output Current
    Set_Precharge_Period(0x82);       // Set Pre-Charge as 8 Clocks & Discharge as 2 Clocks
    Set_VCOMH(0x34);                  // Set VCOM Deselect Level
    Set_Entire_Display(0xA4);         // Disable Entire Display On (0xA4/0xA5)
    Set_Inverse_Display(0xA6);        // Disable Inverse Display On (0xA6/0xA7)
    Fill_RAM(0x00); // Clear Screen
    Set_Display_On_Off(0xAF); // Display On (0xAE/0xAF)

}

 

如果要顯示圖片看借助取模軟件來更改緩沖區:

image-20210831232254-2.png

 

二、LVGL的移植:

littlevgl是一個小型開源嵌入式 GUI (簡稱LVGL),界面精美,消耗資源小,可移植度高,支持響應式布局,全庫采用純 c 語言開發,移植上手簡單。

• 具有非常豐富的內置控件,buttons, charts, lists, sliders, images

• 高級圖形效果:動畫,反鋸齒,透明度,平滑滾動

• 支持多種輸入設備,touchpad, mouse, keyboard, encoder

• 支持多語言的 UTF-8 編碼

• 支持多個和多種顯示設備,例如同步顯示在多個彩色屏或單色屏上

• 完全自定制的圖形元素

• 硬件獨立于任何微控制器或顯示器

• 可以縮小到最小內存 (64 kB Flash, 16 kB RAM)

• 支持操作系統、外部儲存和 GPU(非必須)

• 僅僅單個幀緩沖設備就可以呈現高級視覺特效

• 使用 C 編寫以獲得最大兼容性(兼容 C++)

• 支持 PC 模擬器

• 為加速 GUI 設計,提供教程,案例和主題,支持響應式布局

 

這是我以前寫的基于LVGL的溫度測試顯示界面,有點丑。。:

 

image-20210831232254-3.png

 

image-20210831232254-4.png

 

image-20210831232254-5.png

 

 

image-20210831232254-6.png

 

Src就是一些源文件:

image-20210831232254-7.png

 

    兩個重要的API:

一個是事務處理函數:

        lv_task_handler();

一個是LVGL心跳

        lv_tick_inc(1);

兩個都要周期調傭。

 

比較重要移植相關的就是porting這個文件了:

image-20210831232254-8.png

第一個就是顯示接口:
 

 



//lvgl顯示接口初始化
void lv_port_disp_init(void)
{

static lv_disp_buf_t disp_buf;
//顯示緩沖區初始化
lv_disp_buf_init(&disp_buf, color_buf, NULL, COLOR_BUF_SIZE);
//顯示驅動默認值初始化   
lv_disp_drv_t disp_drv;                         
lv_disp_drv_init(&disp_drv);                 
/設置屏幕的顯示大小,我這里是為了支持正點原子的多個屏幕,采用動態獲取的方式
//如果你是用于實際項目的話,可以不用設置,那么其默認值就是lv_conf.h中LV_HOR_RES_MAX和LV_VER_RES_MAX宏定義的值
disp_drv.hor_res = lcddev.width;
disp_drv.ver_res = lcddev.height;
//注冊顯示驅動回調
disp_drv.flush_cb = disp_flush;
//注冊顯示緩沖區
disp_drv.buffer = &disp_buf;
#if LV_USE_GPU
//可選的,只要當使用到GPU時,才需要實現gpu_blend和gpu_fill接口
//使用透明度混合倆個顏色數組時需要用到gpu_blend接口
disp_drv.gpu_blend = gpu_blend;

//用一個顏色填充一個內存數組時需要用到gpu_fill接口

disp_drv.gpu_fill = gpu_fill;

#endif

//注冊顯示驅動到lvgl中
lv_disp_drv_register(&disp_drv);

}
//把指定區域的顯示緩沖區內容寫入到屏幕上,你可以使用DMA或者其他的硬件加速器在后臺去完成這個操作
//但是在完成之后,你必須得調用lv_disp_flush_ready()
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
//把指定區域的顯示緩沖區內容寫入到屏幕
LCD_Color_Fill(area->x1,area->y1,area->x2,area->y2,(u16*)color_p);
//最后必須得調用,通知lvgl庫你已經flushing拷貝完成了
lv_disp_flush_ready(disp_drv);

}

主要是顯示緩沖區,還有打點函數的適配。

23就是觸摸和文件相關的操作:

//lvgl的輸入設備初始化
void lv_port_indev_init(void)
{

    lv_indev_drv_t indev_drv;
    //lvgl支持很多種輸入設備,但是我們一般常用的就是觸摸屏,也就是Touchpad
    lv_indev_drv_init(&indev_drv);
    indev_drv.type = LV_INDEV_TYPE_POINTER;
    indev_drv.read_cb = touchpad_read;
    lv_indev_drv_register(&indev_drv);

}

//將會被lvgl周期性調用,周期值是通過lv_conf.h中的LV_INDEV_DEF_READ_PERIOD宏來定義的
//此值不要設置的太大,否則會感覺觸摸不靈敏,默認值為30ms
static bool touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static uint16_t last_x = 0;
static uint16_t last_y = 0;
if(tp_dev.sta&TP_PRES_DOWN)//觸摸按下了
{
last_x = tp_dev.x[0];
last_y = tp_dev.y[0];
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_PR;
}else{//觸摸松開了
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_REL;
}

//返回false代表沒有緩沖的數據
    return false;
}

其實也就是把坐標值賦值給他內部的數據結構,然后修改狀態就行了,但是我們的板子沒有觸摸,可惜了很多功能都用不了。

    最后就要跟我們剛才實際OLED接口函數對上,這里我們用的是雙緩存速度快:                                

static void oled_flush(lv_disp_drv_t *disp_drv, const lv_area_t *area, lv_color_t *color_p)
{
    oled_draw_frame((uint8_t(*)[Max_Column])color_p);
    oled_reflesh();
    lv_disp_flush_ready(disp_drv);
}

static lv_disp_buf_t disp_buf1;
static lv_color_t    buf1[64 * 128];
static lv_color_t    buf2[64 * 128];
void oled_init()
{
    oled_pinmux_init();
    oled_gpio_init();
    oled_initialize();
    lv_disp_buf_init(&disp_buf1, buf1, buf2, 64 * 128);
    lv_disp_drv_t disp_drv;
    lv_disp_drv_init(&disp_drv); 
    disp_drv.buffer   = &disp_buf1;
    disp_drv.flush_cb = oled_flush;
    disp_drv.rotated  = 0;
    lv_disp_drv_register(&disp_drv);
}

 

最后按例創建一個GUI任務:

static void gui_label_create(void)
{
    lv_obj_t *p = lv_label_create(lv_scr_act(), NULL);
    lv_label_set_long_mode(p, LV_LABEL_LONG_BREAK);
    lv_label_set_align(p, LV_LABEL_ALIGN_CENTER);
    lv_obj_set_pos(p, 0, 4);
    lv_obj_set_size(p, 128, 60);
    lv_label_set_text(p, "THEAD RISC-V\nGUI TEST\nEEWORLD NB!!");

}

static void gui_lvgl_task(void *arg)
{

    lv_init();
    oled_init();
    gui_label_create();
    while (1) {
        /* Periodically call the lv_task handler.

         * It could be done in a timer interrupt or an OS task too.*/
        lv_task_handler();
        aos_msleep(5);
        lv_tick_inc(1);

    }

}

image-20210831232254-9.png

 

 

 

 

 

 

 

回復評論 (6)

沙發 Jacktang

2021-9-1 08:33

樓主的OLED與LVGL移植挺順利的,最后展示的雙緩存速度確實快

板凳 soso

2021-9-1 09:22

哈哈 看到屏幕顯示文字,厲害。

不管是哪年,都要加油!繼續為中國電子行業做出小小的貢獻吧! 扣扣 1206973913

4樓 annysky2012

2021-9-1 10:23

l厲害厲害,一次性完成呀

沒有什么不可以,我就是我,不一樣的煙火! 

5樓 freebsder

2021-9-1 17:28

厲害了,謝謝分享!

默認摸魚

6樓 xiyue521

2021-9-1 21:38

以前學過,版本是6.x的現在都更新到8.0.2了,增加了圖形旋轉變換還有格式解碼,顏色也換成了css風格了,就是沒有上位機不好弄

7樓 littleshrimp

2021-9-2 21:02

下邊這個界面挺酷的,是上RVB2601上顯示的還是以前的設備上?

image.png

蝦扯蛋,蛋扯蝦,蝦扯蛋扯蝦
電子工程世界版權所有 京B2-20211791 京ICP備10001474號-1 京公網安備 11010802033920號
    我也要說兩句
    發送
    評論
    萝卜大香蕉