Skip to content
Snippets Groups Projects
Verified Commit a8c3b396 authored by rahix's avatar rahix
Browse files

feat(epicardium): Add a lock for i2c


Multiple tasks might access the i2c bus simultaneously.  To prevent
race conditions, this patch introduces a lock which tasks should
acquire before accessing the bus.

Signed-off-by: default avatarRahix <rahix@rahix.de>
parent 9f7a356d
No related branches found
No related tags found
No related merge requests found
......@@ -57,6 +57,7 @@ int main(void)
fatfs_init();
api_interrupt_init();
stream_init();
i2c_init();
LOG_INFO("startup", "Initializing tasks ...");
......
......@@ -115,7 +115,8 @@ int epic_bhi160_enable_sensor(
return -ENODEV;
}
if (xSemaphoreTake(bhi160_mutex, LOCK_WAIT) == pdTRUE) {
if (i2c_lock() == 0 &&
xSemaphoreTake(bhi160_mutex, LOCK_WAIT) == pdTRUE) {
struct stream_info *stream = &bhi160_streams[sensor_type];
stream->item_size = bhi160_lookup_data_size(sensor_type);
/* TODO: Sanity check length */
......@@ -138,6 +139,7 @@ int epic_bhi160_enable_sensor(
0,
config->dynamic_range /* dynamic range is sensor dependent */
);
i2c_unlock();
xSemaphoreGive(bhi160_mutex);
} else {
return -EBUSY;
......@@ -153,13 +155,15 @@ int epic_bhi160_disable_sensor(enum bhi160_sensor_type sensor_type)
return -ENODEV;
}
if (xSemaphoreTake(bhi160_mutex, LOCK_WAIT) == pdTRUE) {
if (i2c_lock() == 0 &&
xSemaphoreTake(bhi160_mutex, LOCK_WAIT) == pdTRUE) {
struct stream_info *stream = &bhi160_streams[sensor_type];
stream_deregister(bhi160_lookup_sd(sensor_type), stream);
vQueueDelete(stream->queue);
stream->queue = NULL;
bhy_disable_virtual_sensor(vs_id, VS_WAKEUP);
i2c_unlock();
xSemaphoreGive(bhi160_mutex);
} else {
return -EBUSY;
......@@ -233,7 +237,8 @@ static int bhi160_fetch_fifo(void)
/* Number of bytes left in BHI160's FIFO buffer */
uint16_t bytes_left_in_fifo = 1;
if (xSemaphoreTake(bhi160_mutex, LOCK_WAIT) != pdTRUE) {
if (i2c_lock() < 0 ||
xSemaphoreTake(bhi160_mutex, LOCK_WAIT) != pdTRUE) {
return -EBUSY;
}
......@@ -282,6 +287,7 @@ static int bhi160_fetch_fifo(void)
}
xSemaphoreGive(bhi160_mutex);
i2c_unlock();
return 0;
}
......@@ -310,8 +316,8 @@ void vBhi160Task(void *pvParameters)
bhi160_mutex = xSemaphoreCreateMutexStatic(&bhi160_mutex_data);
/* Take Mutex during initialization, just in case */
if (xSemaphoreTake(bhi160_mutex, 0) != pdTRUE) {
LOG_CRIT("bhi160", "Failed to acquire BHI160 mutex!");
if (i2c_lock() < 0 || xSemaphoreTake(bhi160_mutex, 0) != pdTRUE) {
LOG_CRIT("bhi160", "Failed to acquire BHI160/i2c mutex!");
vTaskDelay(portMAX_DELAY);
}
......@@ -336,8 +342,7 @@ void vBhi160Task(void *pvParameters)
vTaskDelay(portMAX_DELAY);
}
/* Wait for first two interrupts */
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
/* Wait for first interrupt */
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
/* Remap axes to match card10 layout */
......@@ -356,6 +361,8 @@ void vBhi160Task(void *pvParameters)
xSemaphoreGive(bhi160_mutex);
i2c_unlock();
/* ----------------------------------------- */
while (1) {
......
#include "modules/log.h"
#include "modules/modules.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include <errno.h>
static StaticSemaphore_t i2c_mutex_data;
static SemaphoreHandle_t i2c_mutex;
int i2c_init(void)
{
i2c_mutex = xSemaphoreCreateMutexStatic(&i2c_mutex_data);
return 0;
}
int i2c_lock(void)
{
if (xSemaphoreTake(i2c_mutex, pdMS_TO_TICKS(100)) != pdTRUE) {
LOG_WARN("i2c", "Mutex is busy");
return -EBUSY;
}
return 0;
}
void i2c_unlock(void)
{
if (xSemaphoreGive(i2c_mutex) != pdTRUE) {
LOG_ERR("i2c", "Mutex was not acquired correctly");
}
}
module_sources = files(
'bhi.c',
'fatfs.c',
'i2c.c',
'leds.c',
'log.c',
'pmic.c',
......
......@@ -19,4 +19,9 @@ void vPmicTask(void *pvParameters);
#define BHI160_MUTEX_WAIT_MS 50
void vBhi160Task(void *pvParameters);
/* ---------- I2C ---------------------------------------------------------- */
int i2c_init(void);
int i2c_lock(void);
void i2c_unlock(void);
#endif /* MODULES_H */
......@@ -26,9 +26,9 @@ void pmic_interrupt_callback(void *_)
void vPmicTask(void *pvParameters)
{
int count = 0;
int count = 0;
portTickType delay = portMAX_DELAY;
pmic_task_id = xTaskGetCurrentTaskHandle();
pmic_task_id = xTaskGetCurrentTaskHandle();
while (1) {
ulTaskNotifyTake(pdTRUE, delay);
......@@ -42,7 +42,13 @@ void vPmicTask(void *pvParameters)
MAX77650_setSFT_RST(0x2);
}
while (i2c_lock() < 0) {
LOG_WARN("pmic", "Failed to acquire i2c. Retrying.");
vTaskDelay(pdMS_TO_TICKS(500));
}
uint8_t int_flag = MAX77650_getINT_GLBL();
i2c_unlock();
if (int_flag & MAX77650_INT_nEN_F) {
/* Button was pressed */
......@@ -69,8 +75,11 @@ void vPmicTask(void *pvParameters)
/* TODO: Remove when all interrupts are handled */
if (int_flag & ~(MAX77650_INT_nEN_F | MAX77650_INT_nEN_R)) {
LOG_WARN("pmic", "Unhandled PMIC Interrupt: %x",
int_flag);
LOG_WARN(
"pmic",
"Unhandled PMIC Interrupt: %x",
int_flag
);
}
if (delay != portMAX_DELAY) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment