LVGL Support

ChibiOS public support forum for topics related to the STMicroelectronics STM32 family of micro-controllers.

Moderators: barthess, RoccoMarco

dynfer
Posts: 6
Joined: Sun Aug 25, 2024 6:11 pm
Been thanked: 1 time

LVGL Support

Postby dynfer » Sun Apr 13, 2025 9:09 pm

Hello,

Im currently playing around with LVGL on ChibiOS, I wanted to ask some professional minds if im adapting the required RTOS functions correctly. I've based my code on the present FreeRTOS implementation in LVGL.

Code below:

Code: Select all

/**
 * @file lv_chibios.h
 */

 #ifndef LV_CHIBIOS_H
 #define LV_CHIBIOS_H
 
 #include "hal.h"
 #include "ch.h"
 #include "lvgl/src/osal/lv_os.h"

 typedef struct {
     void (*pvStartRoutine)(void *);   /**< Application thread function */
     void * pTaskArg;                  /**< Argument to the thread function */
     thread_t * thread;                /**< Pointer to the created thread */
     void * stack;                     /**< Pointer to dynamically allocated stack memory */
 } lv_thread_t;

 typedef struct {
     bool xIsInitialized;        /**< pdTRUE if the mutex is initialized */
     mutex_t   xMutex;                 /**< Underlying ChibiOS mutex object */
     thread_t * owner;                 /**< The current owner (if any) */
     uint32_t  rec_count;              /**< Recursion count */
 } lv_mutex_t;

 typedef struct {
     bool xIsInitialized;            /**< pdTRUE if the condition variable is initialized */
     bool xSyncSignal;               /**< pdTRUE if a signal has been sent */
     semaphore_t xCondWaitSemaphore;       /**< Semaphore on which threads wait */
     uint32_t ulWaitingThreads;            /**< Count of threads waiting on the condition */
     mutex_t xSyncMutex;                   /**< Mutex to protect access to the condition variable */
 } lv_thread_sync_t;

 #endif /* LV_CHIBIOS_H */
 


Code: Select all

/**
 * @file lv_chibios.c
 */
/*********************
 *      INCLUDES
 *********************/
#include "hal.h"
#include "ch.h"
#include "lvgl/src/osal/lv_os.h"
#include "lvgl/src/misc/lv_log.h"
#include "lvgl/src/core/lv_global.h"

#define globals LV_GLOBAL_DEFAULT()
static msg_t prvRunThread(void * arg);

static void prvMutexInit(lv_mutex_t * pxMutex);
static void prvCheckMutexInit(lv_mutex_t * pxMutex);

static void prvCondInit(lv_thread_sync_t * pxCond);
static void prvCheckCondInit(lv_thread_sync_t * pxCond);
static void prvCheckCondInitIsr(lv_thread_sync_t * pxCond);
lv_result_t lv_thread_init(lv_thread_t * pxThread, const char * const name,
                           lv_thread_prio_t xSchedPriority,
                           void (*pvStartRoutine)(void *), size_t usStackSize,
                           void * xAttr)
{
    pxThread->pTaskArg = xAttr;
    pxThread->pvStartRoutine = pvStartRoutine;

    pxThread->stack = chHeapAlloc(NULL, usStackSize);
    if(pxThread->stack == NULL) {
        LV_LOG_ERROR("chHeapAlloc failed!");
        return LV_RESULT_INVALID;
    }
    pxThread->thread = chThdCreateFromHeap(NULL, usStackSize, name, xSchedPriority,
                                           prvRunThread, pxThread);
    if(pxThread->thread == NULL) {
        LV_LOG_ERROR("chThdCreateFromHeap failed!");
        chHeapFree(pxThread->stack);
        return LV_RESULT_INVALID;
    }

    return LV_RESULT_OK;
}

lv_result_t lv_thread_delete(lv_thread_t * pxThread)
{
    chThdTerminate(pxThread->thread);
    chHeapFree(pxThread->stack);
    return LV_RESULT_OK;
}

lv_result_t lv_mutex_init(lv_mutex_t * pxMutex)
{
    prvCheckMutexInit(pxMutex);
    return LV_RESULT_OK;
}

lv_result_t lv_mutex_lock(lv_mutex_t * pxMutex)
{
    prvCheckMutexInit(pxMutex);
    thread_t * current = chThdGetSelfX();
    /* If the current thread already owns the mutex, increase the recursion count */
    if(pxMutex->owner == current) {
        pxMutex->rec_count++;
        return LV_RESULT_OK;
    }
    chMtxLock(&pxMutex->xMutex);
    pxMutex->owner = current;
    pxMutex->rec_count = 1;
    return LV_RESULT_OK;
}

lv_result_t lv_mutex_lock_isr(lv_mutex_t * pxMutex)
{
    LV_LOG_ERROR("lv_mutex_lock_isr not supported in ChibiOS");
    return LV_RESULT_INVALID;
}

lv_result_t lv_mutex_unlock(lv_mutex_t * pxMutex)
{
    prvCheckMutexInit(pxMutex);
    thread_t * current = chThdGetSelfX();
    if(pxMutex->owner != current) {
        LV_LOG_ERROR("Mutex unlock called by non-owner");
        return LV_RESULT_INVALID;
    }
    if(pxMutex->rec_count > 1) {
        pxMutex->rec_count--;
    }
    else {
        pxMutex->owner = NULL;
        pxMutex->rec_count = 0;
        chMtxUnlock(&pxMutex->xMutex);
    }
    return LV_RESULT_OK;
}

lv_result_t lv_mutex_delete(lv_mutex_t * pxMutex)
{
    if(pxMutex->xIsInitialized == FALSE){
        return LV_RESULT_INVALID;
    }
    /* No explicit deletion needed because the mutex is allocated as part of the struct. */
    pxMutex->xIsInitialized = FALSE;
    return LV_RESULT_OK;
}

/*------------------------------
 * Condition variable functions
 *------------------------------*/
lv_result_t lv_thread_sync_init(lv_thread_sync_t * pxCond)
{
    prvCheckCondInit(pxCond);
    return LV_RESULT_OK;
}

lv_result_t lv_thread_sync_wait(lv_thread_sync_t * pxCond)
{
    lv_result_t lvRes = LV_RESULT_OK;
    prvCheckCondInit(pxCond);
   
    chMtxLock(&pxCond->xSyncMutex);
    while(pxCond->xSyncSignal == FALSE) {
        pxCond->ulWaitingThreads++;
        chMtxUnlock(&pxCond->xSyncMutex);
        chSemWait(&pxCond->xCondWaitSemaphore);
        chMtxLock(&pxCond->xSyncMutex);
    }
    /* Reset the signal after waking up */
    pxCond->xSyncSignal = FALSE;
    chMtxUnlock(&pxCond->xSyncMutex);
    return lvRes;
}

lv_result_t lv_thread_sync_signal(lv_thread_sync_t * pxCond)
{
    prvCheckCondInit(pxCond);
    chMtxLock(&pxCond->xSyncMutex);
    pxCond->xSyncSignal = TRUE;
    uint32_t waiting = pxCond->ulWaitingThreads;
    pxCond->ulWaitingThreads = 0;
    chMtxUnlock(&pxCond->xSyncMutex);

    /* Unblock all waiting threads by releasing the semaphore */
    for(uint32_t i = 0; i < waiting; i++) {
        chSemSignal(&pxCond->xCondWaitSemaphore);
    }
    return LV_RESULT_OK;
}

lv_result_t lv_thread_sync_delete(lv_thread_sync_t * pxCond)
{
    pxCond->xIsInitialized = FALSE;
    return LV_RESULT_OK;
}

lv_result_t lv_thread_sync_signal_isr(lv_thread_sync_t * pxCond)
{
    pxCond->xSyncSignal = TRUE;
    uint32_t waiting = pxCond->ulWaitingThreads;
    pxCond->ulWaitingThreads = 0;
    chSysLockFromISR();
    for(uint32_t i = 0; i < waiting; i++) {
        chSemSignalI(&pxCond->xCondWaitSemaphore);
    }
    chSysUnlockFromISR();
    return LV_RESULT_OK;
}

static msg_t prvRunThread(void * arg)
{
    lv_thread_t * pxThread = (lv_thread_t *)arg;
    pxThread->pvStartRoutine(pxThread->pTaskArg);
    chThdExit(MSG_OK);
    return MSG_OK; /* Not reached */
}

static void prvMutexInit(lv_mutex_t * pxMutex)
{
    chMtxObjectInit(&pxMutex->xMutex);
    pxMutex->owner = NULL;
    pxMutex->rec_count = 0;
    pxMutex->xIsInitialized = TRUE;
}

static void prvCheckMutexInit(lv_mutex_t * pxMutex)
{
    if(pxMutex->xIsInitialized == FALSE) {
        chSysLock();
        prvMutexInit(pxMutex);
        chSysUnlock();
    }
}

static void prvCondInit(lv_thread_sync_t * pxCond)
{
    pxCond->xIsInitialized = TRUE;
    pxCond->xSyncSignal = FALSE;
    chSemObjectInit(&pxCond->xCondWaitSemaphore, 0);
    chMtxObjectInit(&pxCond->xSyncMutex);
    pxCond->ulWaitingThreads = 0;
}

static void prvCheckCondInit(lv_thread_sync_t * pxCond)
{
    if(pxCond->xIsInitialized == FALSE) {
        chSysLock();
        prvCondInit(pxCond);
        chSysUnlock();
    }
}

static void prvCheckCondInitIsr(lv_thread_sync_t * pxCond)
{
    if(pxCond->xIsInitialized == FALSE) {
        chSysLockFromISR();
        prvCondInit(pxCond);
        chSysUnlockFromISR();
    }
}

Return to “STM32 Support”

Who is online

Users browsing this forum: No registered users and 51 guests