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 */