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();
}
}