Skip to content
Snippets Groups Projects
Verified Commit 2e00c2b3 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 6109df47
Branches
No related tags found
No related merge requests found
...@@ -60,6 +60,7 @@ int main(void) ...@@ -60,6 +60,7 @@ int main(void)
fatfs_init(); fatfs_init();
api_interrupt_init(); api_interrupt_init();
stream_init(); stream_init();
i2c_init();
LOG_INFO("startup", "Initializing tasks ..."); LOG_INFO("startup", "Initializing tasks ...");
......
...@@ -115,7 +115,8 @@ int epic_bhi160_enable_sensor( ...@@ -115,7 +115,8 @@ int epic_bhi160_enable_sensor(
return -ENODEV; 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]; struct stream_info *stream = &bhi160_streams[sensor_type];
stream->item_size = bhi160_lookup_data_size(sensor_type); stream->item_size = bhi160_lookup_data_size(sensor_type);
/* TODO: Sanity check length */ /* TODO: Sanity check length */
...@@ -138,6 +139,7 @@ int epic_bhi160_enable_sensor( ...@@ -138,6 +139,7 @@ int epic_bhi160_enable_sensor(
0, 0,
config->dynamic_range /* dynamic range is sensor dependent */ config->dynamic_range /* dynamic range is sensor dependent */
); );
i2c_unlock();
xSemaphoreGive(bhi160_mutex); xSemaphoreGive(bhi160_mutex);
} else { } else {
return -EBUSY; return -EBUSY;
...@@ -153,13 +155,15 @@ int epic_bhi160_disable_sensor(enum bhi160_sensor_type sensor_type) ...@@ -153,13 +155,15 @@ int epic_bhi160_disable_sensor(enum bhi160_sensor_type sensor_type)
return -ENODEV; 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]; struct stream_info *stream = &bhi160_streams[sensor_type];
stream_deregister(bhi160_lookup_sd(sensor_type), stream); stream_deregister(bhi160_lookup_sd(sensor_type), stream);
vQueueDelete(stream->queue); vQueueDelete(stream->queue);
stream->queue = NULL; stream->queue = NULL;
bhy_disable_virtual_sensor(vs_id, VS_WAKEUP); bhy_disable_virtual_sensor(vs_id, VS_WAKEUP);
i2c_unlock();
xSemaphoreGive(bhi160_mutex); xSemaphoreGive(bhi160_mutex);
} else { } else {
return -EBUSY; return -EBUSY;
...@@ -233,7 +237,8 @@ static int bhi160_fetch_fifo(void) ...@@ -233,7 +237,8 @@ static int bhi160_fetch_fifo(void)
/* Number of bytes left in BHI160's FIFO buffer */ /* Number of bytes left in BHI160's FIFO buffer */
uint16_t bytes_left_in_fifo = 1; 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; return -EBUSY;
} }
...@@ -282,6 +287,7 @@ static int bhi160_fetch_fifo(void) ...@@ -282,6 +287,7 @@ static int bhi160_fetch_fifo(void)
} }
xSemaphoreGive(bhi160_mutex); xSemaphoreGive(bhi160_mutex);
i2c_unlock();
return 0; return 0;
} }
...@@ -310,8 +316,8 @@ void vBhi160Task(void *pvParameters) ...@@ -310,8 +316,8 @@ void vBhi160Task(void *pvParameters)
bhi160_mutex = xSemaphoreCreateMutexStatic(&bhi160_mutex_data); bhi160_mutex = xSemaphoreCreateMutexStatic(&bhi160_mutex_data);
/* Take Mutex during initialization, just in case */ /* Take Mutex during initialization, just in case */
if (xSemaphoreTake(bhi160_mutex, 0) != pdTRUE) { if (i2c_lock() < 0 || xSemaphoreTake(bhi160_mutex, 0) != pdTRUE) {
LOG_CRIT("bhi160", "Failed to acquire BHI160 mutex!"); LOG_CRIT("bhi160", "Failed to acquire BHI160/i2c mutex!");
vTaskDelay(portMAX_DELAY); vTaskDelay(portMAX_DELAY);
} }
...@@ -336,8 +342,7 @@ void vBhi160Task(void *pvParameters) ...@@ -336,8 +342,7 @@ void vBhi160Task(void *pvParameters)
vTaskDelay(portMAX_DELAY); vTaskDelay(portMAX_DELAY);
} }
/* Wait for first two interrupts */ /* Wait for first interrupt */
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100)); ulTaskNotifyTake(pdTRUE, pdMS_TO_TICKS(100));
/* Remap axes to match card10 layout */ /* Remap axes to match card10 layout */
...@@ -356,6 +361,8 @@ void vBhi160Task(void *pvParameters) ...@@ -356,6 +361,8 @@ void vBhi160Task(void *pvParameters)
xSemaphoreGive(bhi160_mutex); xSemaphoreGive(bhi160_mutex);
i2c_unlock();
/* ----------------------------------------- */ /* ----------------------------------------- */
while (1) { 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");
}
}
...@@ -3,6 +3,7 @@ module_sources = files( ...@@ -3,6 +3,7 @@ module_sources = files(
'display.c', 'display.c',
'fatfs.c', 'fatfs.c',
'fatfs_fileops.c', 'fatfs_fileops.c',
'i2c.c',
'leds.c', 'leds.c',
'log.c', 'log.c',
'pmic.c', 'pmic.c',
......
...@@ -26,6 +26,11 @@ void vPmicTask(void *pvParameters); ...@@ -26,6 +26,11 @@ void vPmicTask(void *pvParameters);
#define BHI160_MUTEX_WAIT_MS 50 #define BHI160_MUTEX_WAIT_MS 50
void vBhi160Task(void *pvParameters); void vBhi160Task(void *pvParameters);
/* ---------- I2C ---------------------------------------------------------- */
int i2c_init(void);
int i2c_lock(void);
void i2c_unlock(void);
// Forces an unlock of the display. Only to be used in epicardium // Forces an unlock of the display. Only to be used in epicardium
void disp_forcelock(); void disp_forcelock();
#endif /* MODULES_H */ #endif /* MODULES_H */
...@@ -43,7 +43,13 @@ void vPmicTask(void *pvParameters) ...@@ -43,7 +43,13 @@ void vPmicTask(void *pvParameters)
MAX77650_setSFT_RST(0x2); 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(); uint8_t int_flag = MAX77650_getINT_GLBL();
i2c_unlock();
if (int_flag & MAX77650_INT_nEN_F) { if (int_flag & MAX77650_INT_nEN_F) {
/* Button was pressed */ /* Button was pressed */
...@@ -62,8 +68,11 @@ void vPmicTask(void *pvParameters) ...@@ -62,8 +68,11 @@ void vPmicTask(void *pvParameters)
/* TODO: Remove when all interrupts are handled */ /* TODO: Remove when all interrupts are handled */
if (int_flag & ~(MAX77650_INT_nEN_F | MAX77650_INT_nEN_R)) { if (int_flag & ~(MAX77650_INT_nEN_F | MAX77650_INT_nEN_R)) {
LOG_WARN("pmic", "Unhandled PMIC Interrupt: %x", LOG_WARN(
int_flag); "pmic",
"Unhandled PMIC Interrupt: %x",
int_flag
);
} }
if (delay != portMAX_DELAY) { if (delay != portMAX_DELAY) {
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment