diff --git a/epicardium/modules/hardware.c b/epicardium/modules/hardware.c index 3905ceb81811dc38c581d6ad99320c3dbadb16a5..75a995e9703456ea7ceaaa57922fc2ff4ee2c14e 100644 --- a/epicardium/modules/hardware.c +++ b/epicardium/modules/hardware.c @@ -150,6 +150,11 @@ int hardware_early_init(void) */ stream_init(); + /* + * Hardware/Peripheral Locks + */ + hwlock_init(); + return 0; } diff --git a/epicardium/modules/hw-lock.c b/epicardium/modules/hw-lock.c new file mode 100644 index 0000000000000000000000000000000000000000..f02a5882b1bdb2aabddeb2ccea77d59fe14939c4 --- /dev/null +++ b/epicardium/modules/hw-lock.c @@ -0,0 +1,62 @@ +#include "modules/log.h" +#include "modules/modules.h" + +#include "FreeRTOS.h" +#include "task.h" +#include "semphr.h" + +#include <errno.h> + +static StaticSemaphore_t hwlock_mutex_data[_HWLOCK_MAX]; +static SemaphoreHandle_t hwlock_mutex[_HWLOCK_MAX]; +/* Which task is holding the lock */ +static TaskHandle_t hwlock_tasks[_HWLOCK_MAX]; + +void hwlock_init(void) +{ + for (int i = 0; i < _HWLOCK_MAX; i++) { + hwlock_mutex[i] = + xSemaphoreCreateMutexStatic(&hwlock_mutex_data[i]); + } +} + +int hwlock_acquire(enum hwlock_periph p, TickType_t wait) +{ + if (p >= _HWLOCK_MAX) { + return -EINVAL; + } + + if (xSemaphoreTake(hwlock_mutex[p], wait) != pdTRUE) { + LOG_WARN("hwlock", "Lock %u is busy.", p); + return -EBUSY; + } + + hwlock_tasks[p] = xTaskGetCurrentTaskHandle(); + + return 0; +} + +int hwlock_release(enum hwlock_periph p) +{ + int ret = 0; + + if (p >= _HWLOCK_MAX) { + return -EINVAL; + } + + if (hwlock_tasks[p] != xTaskGetCurrentTaskHandle()) { + LOG_ERR("hwlock", + "Lock %u is released by task \"%s\" while it was acquired by \"%s\"", + p, + pcTaskGetName(NULL), + pcTaskGetName(hwlock_tasks[p])); + ret = -EACCES; + } + + if (xSemaphoreGive(hwlock_mutex[p]) != pdTRUE) { + LOG_ERR("hwlock", "Lock %u not released correctly.", p); + ret = -EINVAL; + } + + return ret; +} diff --git a/epicardium/modules/meson.build b/epicardium/modules/meson.build index 31e7f5c078a74f39425d70048ac0f57be28c67f5..4966be6c9122ed2333ca6a5ecf1b6fc5e5ceb988 100644 --- a/epicardium/modules/meson.build +++ b/epicardium/modules/meson.build @@ -5,6 +5,7 @@ module_sources = files( 'fileops.c', 'gpio.c', 'hardware.c', + 'hw-lock.c', 'leds.c', 'lifecycle.c', 'light_sensor.c', diff --git a/epicardium/modules/modules.h b/epicardium/modules/modules.h index 535dcf5c1d87072c6ca631189ea3aec6210c2258..abf1c770939884274538b5d68e64eed36b23f896 100644 --- a/epicardium/modules/modules.h +++ b/epicardium/modules/modules.h @@ -37,6 +37,17 @@ void vBleTask(void *pvParameters); bool ble_shall_start(void); void ble_uart_write(uint8_t *pValue, uint8_t len); +/* ---------- Hardware (Peripheral) Locks ---------------------------------- */ +void hwlock_init(void); + +enum hwlock_periph { + HWLOCK_I2C = 0, + _HWLOCK_MAX, +}; + +int hwlock_acquire(enum hwlock_periph p, TickType_t wait); +int hwlock_release(enum hwlock_periph p); + /* ---------- Display ------------------------------------------------------ */ /* Forces an unlock of the display. Only to be used in Epicardium */ void disp_forcelock(); diff --git a/epicardium/modules/pmic.c b/epicardium/modules/pmic.c index 492545bb3b47c33b5494351a6f321d0af376df2c..c02691dc25350723b04bd0059183bcf0522396ae 100644 --- a/epicardium/modules/pmic.c +++ b/epicardium/modules/pmic.c @@ -45,7 +45,13 @@ void vPmicTask(void *pvParameters) MAX77650_setSFT_RST(0x2); } + while (hwlock_acquire(HWLOCK_I2C, pdMS_TO_TICKS(500)) < 0) { + LOG_WARN("pmic", "Failed to acquire I2C. Retrying ..."); + vTaskDelay(pdMS_TO_TICKS(500)); + } + uint8_t int_flag = MAX77650_getINT_GLBL(); + hwlock_release(HWLOCK_I2C); if (int_flag & MAX77650_INT_nEN_F) { /* Button was pressed */