mirror of
https://github.com/vicliu624/trail-mate.git
synced 2026-10-23 05:32:18 +00:00
fix(esp): harden shared SPI display locking
Make the T-Deck display SPI mutex recursive and track the owning task before releasing it, avoiding the FreeRTOS assert seen when loopTask tried to give a mutex held by gps_collect. Keep the display address-window update and pixel payload under one shared SPI lock so SD-backed map tile work cannot interleave between them and corrupt tile fills. Fixes #59
This commit is contained in:
1 parent
3f25e3d577
commit
fbed1b092e
3 files changed
+122
-15
No files matched your search
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "freertos/task.h"
|
||||
#include "platform/esp/common/shared_spi_lock.h"
|
||||
|
||||
#include <stddef.h>
|
||||
@@ -131,6 +132,14 @@ class LilyGoDispArduinoSPI
|
||||
const DispRotationConfig_t* _rotation_configs;
|
||||
DispTransferConfig_t _transfer_config{};
|
||||
SemaphoreHandle_t _lock = nullptr;
|
||||
TaskHandle_t _lock_owner = nullptr;
|
||||
uint32_t _lock_depth = 0;
|
||||
|
||||
void pushColorsLocked(uint16_t* data, uint32_t len);
|
||||
void writeParamsLocked(uint8_t cmd, uint8_t* data = nullptr, size_t length = 0);
|
||||
void writeDataLocked(uint8_t data);
|
||||
void writeCommandLocked(uint8_t cmd);
|
||||
void setAddrWindowLocked(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye);
|
||||
|
||||
public:
|
||||
uint16_t _width = 0;
|
||||
|
||||
@@ -31,12 +31,52 @@ void shared_spi_unlock()
|
||||
|
||||
bool LilyGoDispArduinoSPI::lock(TickType_t xTicksToWait)
|
||||
{
|
||||
return xSemaphoreTake(_lock, xTicksToWait) == pdTRUE;
|
||||
if (_lock == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (xSemaphoreTakeRecursive(_lock, xTicksToWait) != pdTRUE)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TaskHandle_t current = xTaskGetCurrentTaskHandle();
|
||||
if (_lock_owner == current)
|
||||
{
|
||||
_lock_depth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
_lock_owner = current;
|
||||
_lock_depth = 1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::unlock()
|
||||
{
|
||||
xSemaphoreGive(_lock);
|
||||
if (_lock == nullptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
TaskHandle_t current = xTaskGetCurrentTaskHandle();
|
||||
if (_lock_owner != current || _lock_depth == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (xSemaphoreGiveRecursive(_lock) != pdTRUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_lock_depth--;
|
||||
if (_lock_depth == 0)
|
||||
{
|
||||
_lock_owner = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::setBrightness(uint8_t level)
|
||||
@@ -54,7 +94,12 @@ bool LilyGoDispArduinoSPI::init(int sck,
|
||||
uint32_t freq_Mhz,
|
||||
SPIClass& spi)
|
||||
{
|
||||
_lock = xSemaphoreCreateMutex();
|
||||
_lock = xSemaphoreCreateRecursiveMutex();
|
||||
if (_lock == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_spi = &spi;
|
||||
g_display_spi = this;
|
||||
|
||||
@@ -107,7 +152,6 @@ bool LilyGoDispArduinoSPI::init(int sck,
|
||||
{
|
||||
digitalWrite(_backlight, (_brightness > 0) ? HIGH : LOW);
|
||||
}
|
||||
xSemaphoreGive(_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -135,7 +179,16 @@ void LilyGoDispArduinoSPI::setRotation(uint8_t rotation)
|
||||
|
||||
void LilyGoDispArduinoSPI::pushColors(uint16_t* data, uint32_t len)
|
||||
{
|
||||
xSemaphoreTake(_lock, portMAX_DELAY);
|
||||
if (!lock(portMAX_DELAY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
pushColorsLocked(data, len);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::pushColorsLocked(uint16_t* data, uint32_t len)
|
||||
{
|
||||
digitalWrite(_cs, LOW);
|
||||
_spi->beginTransaction(SPISettings(_spi_freq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_dc, HIGH);
|
||||
@@ -169,13 +222,17 @@ void LilyGoDispArduinoSPI::pushColors(uint16_t* data, uint32_t len)
|
||||
}
|
||||
_spi->endTransaction();
|
||||
digitalWrite(_cs, HIGH);
|
||||
xSemaphoreGive(_lock);
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::pushColors(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t* color)
|
||||
{
|
||||
setAddrWindow(x1, y1, x1 + x2 - 1, y1 + y2 - 1);
|
||||
pushColors(color, x2 * y2);
|
||||
if (!lock(portMAX_DELAY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setAddrWindowLocked(x1, y1, x1 + x2 - 1, y1 + y2 - 1);
|
||||
pushColorsLocked(color, x2 * y2);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::sleep()
|
||||
@@ -189,6 +246,16 @@ void LilyGoDispArduinoSPI::wakeup()
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::setAddrWindow(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye)
|
||||
{
|
||||
if (!lock(portMAX_DELAY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
setAddrWindowLocked(xs, ys, xe, ye);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::setAddrWindowLocked(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye)
|
||||
{
|
||||
xs += _offset_x;
|
||||
ys += _offset_y;
|
||||
@@ -201,13 +268,22 @@ void LilyGoDispArduinoSPI::setAddrWindow(uint16_t xs, uint16_t ys, uint16_t xe,
|
||||
};
|
||||
for (uint32_t i = 0; i < 3; i++)
|
||||
{
|
||||
writeParams(t[i].cmd, t[i].data, t[i].len);
|
||||
writeParamsLocked(t[i].cmd, t[i].data, t[i].len);
|
||||
}
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::writeCommand(uint8_t cmd)
|
||||
{
|
||||
xSemaphoreTake(_lock, portMAX_DELAY);
|
||||
if (!lock(portMAX_DELAY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
writeCommandLocked(cmd);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::writeCommandLocked(uint8_t cmd)
|
||||
{
|
||||
digitalWrite(_cs, LOW);
|
||||
_spi->beginTransaction(SPISettings(_spi_freq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_dc, LOW);
|
||||
@@ -215,29 +291,46 @@ void LilyGoDispArduinoSPI::writeCommand(uint8_t cmd)
|
||||
digitalWrite(_dc, HIGH);
|
||||
_spi->endTransaction();
|
||||
digitalWrite(_cs, HIGH);
|
||||
xSemaphoreGive(_lock);
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::writeData(uint8_t data)
|
||||
{
|
||||
xSemaphoreTake(_lock, portMAX_DELAY);
|
||||
if (!lock(portMAX_DELAY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
writeDataLocked(data);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::writeDataLocked(uint8_t data)
|
||||
{
|
||||
digitalWrite(_cs, LOW);
|
||||
_spi->beginTransaction(SPISettings(_spi_freq, MSBFIRST, SPI_MODE0));
|
||||
digitalWrite(_dc, HIGH);
|
||||
_spi->write(data);
|
||||
_spi->endTransaction();
|
||||
digitalWrite(_cs, HIGH);
|
||||
xSemaphoreGive(_lock);
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::writeParams(uint8_t cmd, uint8_t* data, size_t length)
|
||||
{
|
||||
writeCommand(cmd);
|
||||
if (!lock(portMAX_DELAY))
|
||||
{
|
||||
return;
|
||||
}
|
||||
writeParamsLocked(cmd, data, length);
|
||||
unlock();
|
||||
}
|
||||
|
||||
void LilyGoDispArduinoSPI::writeParamsLocked(uint8_t cmd, uint8_t* data, size_t length)
|
||||
{
|
||||
writeCommandLocked(cmd);
|
||||
if (data != nullptr)
|
||||
{
|
||||
for (size_t i = 0; i < length; i++)
|
||||
{
|
||||
writeData(data[i]);
|
||||
writeDataLocked(data[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,11 @@ class SharedSpiLockGuard
|
||||
{
|
||||
}
|
||||
|
||||
SharedSpiLockGuard(const SharedSpiLockGuard&) = delete;
|
||||
SharedSpiLockGuard& operator=(const SharedSpiLockGuard&) = delete;
|
||||
SharedSpiLockGuard(SharedSpiLockGuard&&) = delete;
|
||||
SharedSpiLockGuard& operator=(SharedSpiLockGuard&&) = delete;
|
||||
|
||||
~SharedSpiLockGuard()
|
||||
{
|
||||
if (locked_)
|
||||
|
||||
Reference in new issue
Block a user