Beginner trying to use littlevGL on stm32f103 and OLED monochrome 128 * 64 pixels

Description

What MCU/Processor/Board and compiler are you using?

stm32f103 with arm-none-eabi-gcc from ac6’s systemworkbench

What do you want to achieve?

I want to achieve a minimal display (due to the limited flash and ram) just a bar that eventually will change

What have you tried so far?

I tried to follow the tutorials “Porting LittlevGL for monochrome display” and the blog post “LittlevGL on a Monochrome OLED” as well as reading the GetStarted articles
I am using the lv_port_disp_init() in the renamed lv_port_display.c. I am calling the filled-in disp_init() and using the one buffer sized #define BUFFERSIZE (LV_HOR_RES_MAX * LV_VER_RES_MAX / 8). The disp_flush() I filled in with a simple copy all the bytes out to the display.
When the lv_disp_drv_register( &disp_drv) runs at the end of lv_port_disp_init(), I am getting a null disp.

What pretty please did I forget to initialize?

Code to reproduce

Add the relevant code snippets here.

The code block(s) should be between ```c and ``` tags:

/*You code here*/
    lv_disp_t * disp = lv_ll_ins_head(&LV_GC_ROOT(_lv_disp_ll));
    if(!disp) {
        lv_mem_assert(disp);
        return NULL;
    }

Please show your disp_init function.

Do you call lv_init before registering your driver?

Exellent question! I don’t think I’m calling lv_init()! Now I’ve added it and I get some output (that looks like I need to zero my display buffer.

/* Initialize your display and the required peripherals. */
static void disp_init(void)
{
ssd1306_spi_init();
ssd1306_Init();
}

This is the code in my main():that I’m trying to get the bar

lv_init();

lv_port_disp_init();
lv_obj_t *scr = lv_disp_get_scr_act( NULL );
lv_obj_t *bar = lv_bar_create( scr, NULL );

while (1)
{
   lv_task_handler();
   lv_tick_inc(1);
   delay_ms(1);
}

And what is the problem?

The first problem was what you diagnosed - a missing call to lv_init()
IMG_0189

The picture is the output I’m getting. The 8 stripes are the chunks of 128 that my flush_cb() is pushing. I wonder if the stuff at the beginning is the “bar” that would have been in the middle if I had used the area info

I think I introduced the problem here, that the buffer pointed-to by disp_drv isn’t filled in yet. The code in there looks like I need to follow the color_p pointer for the display data. Is that a correct analysis?

static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/The most simple case (but also the slowest) to put all pixels to the screen one-by-one/
ssd1306FlushToScreen( disp_drv->buffer );

#if 0
int32_t x;
int32_t y;
for(y = area->y1; y <= area->y2; y++) {
for(x = area->x1; x <= area->x2; x++) {
/* Put a pixel to the display. For example: /
/
put_px(x, y, color_p)/
color_p++;
}
}
#endif

/* IMPORTANT!!!
 * Inform the graphics library that you are ready with the flushing
 * */
lv_disp_flush_ready( disp_drv );

}

Don’t be investigating the contents of the lv_disp_drv_t structure. :wink: That’s reserved for the implementation.

Yes. You can convert each of the values in color_p to an appropriate color format with the lv_color_to series of functions (e.g. lv_color_to1, lv_color_to8):

for(y = area->y1; y <= area->y2; y++) {
    for(x = area->x1; x <= area->x2; x++) {
        put_px(x, y, lv_color_to1(*color_p));
        color_p++;
    }
}

Thanks EmbeddedT, now I’m translating the lv_color_t union using the full member to test for my monochrome display. I’m puzzling over the x and y in terms of my display, do they map directly to offsets from (0,0)

For portability it’s best to use the functions like I mentioned.

Yes.

Hi embeddedt,
Thanks for your help! I’m debugging my display and and it seems like I’m only getting the 1 level of color, I don’t ever get a 0 level. I do have the LV_COLOR_DEPTH set to 1 color level.
I get area (0,0) (127,7) and all the pixels are color 1, then the same for area(0,8)(127,15) and the successive areas through (0,56)(127,64) Do you have any idea what I may be doing wrong? I am expecting to see bar in the drawing color, and a dark background.
Thanks again,
Larry

:

Can you show me your current loop?

Here’s a DUH question, should I be drawing the bar repeatedly in a task ?

This is what I am currently doing:

I meant the loop to draw pixels in disp_flush.

No. That’s not how LittlevGL works. You just need to create the object once and it will always be drawn until you delete it.

tatic void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/The most simple case (but also the slowest) to put all pixels to the screen one-by-one/
int32_t x;
int32_t y;
SSD1306_COLOR color;

for(y = area->y1; y <= area->y2; y++) {
    for(x = area->x1; x <= area->x2; x++) {

       // Translate the passed in color value to our black or white
       if ( color_p->full == 0 )
       {
          color = BLACK;
       }   
       else  // color is white
       {
          color = WHITE;
       }   

       /* Put a pixel to the display. */
       ssd1306_DrawPixel( x, y, color );

       // Next pixel
       color_p++;
    }
}

ssd1306_UpdateScreen();

/* IMPORTANT!!!
 * Inform the graphics library that you are ready with the flushing
 * */
lv_disp_flush_ready( disp_drv );

}

Hi embeddedt,

Do you think I could be running out of memory: my stm32f103 has 128 KBytes of flash, 20KBytes RAM of which I am using about 87K right now, and I don’t see my code getting to the disp_flush() call back.

Thanks,

Larry

Can you step through it and find where it hangs? Also, for best results, you shouldn’t be calling lv_tick_inc in the same loop as lv_task_handler (use an interrupt or OS task).