Fix race conditions during sleep/wakeup, where SPI/TWI could be disabled while transaction were in progress (https://github.com/JF002/Pinetime/issues/60).

This commit is contained in:
JF 2020-09-13 21:26:44 +02:00
parent d757344f1b
commit 20f5b0ffba
3 changed files with 34 additions and 18 deletions

View file

@ -105,22 +105,33 @@ void SystemTask::Work() {
Messages message = static_cast<Messages >(msg); Messages message = static_cast<Messages >(msg);
switch(message) { switch(message) {
case Messages::GoToRunning: case Messages::GoToRunning:
isSleeping = false; spi.Wakeup();
twiMaster.Wakeup();
spiNorFlash.Wakeup();
lcd.Wakeup();
touchPanel.Wakeup();
displayApp->PushMessage(Applications::DisplayApp::Messages::GoToRunning);
displayApp->PushMessage(Applications::DisplayApp::Messages::UpdateBatteryLevel);
xTimerStart(idleTimer, 0); xTimerStart(idleTimer, 0);
nimbleController.StartAdvertising(); nimbleController.StartAdvertising();
isSleeping = false;
isWakingUp = false;
break; break;
case Messages::GoToSleep: case Messages::GoToSleep:
isGoingToSleep = true;
NRF_LOG_INFO("[SystemTask] Going to sleep"); NRF_LOG_INFO("[SystemTask] Going to sleep");
xTimerStop(idleTimer, 0); xTimerStop(idleTimer, 0);
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::GoToSleep);
isSleeping = true;
break; break;
case Messages::OnNewTime: case Messages::OnNewTime:
ReloadIdleTimer(); ReloadIdleTimer();
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateDateTime); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::UpdateDateTime);
break; break;
case Messages::OnNewNotification: case Messages::OnNewNotification:
if(isSleeping) GoToRunning(); if(isSleeping && !isWakingUp) GoToRunning();
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::NewNotification); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::NewNotification);
break; break;
case Messages::BleConnected: case Messages::BleConnected:
@ -130,7 +141,7 @@ void SystemTask::Work() {
break; break;
case Messages::BleFirmwareUpdateStarted: case Messages::BleFirmwareUpdateStarted:
doNotGoToSleep = true; doNotGoToSleep = true;
if(isSleeping) GoToRunning(); if(isSleeping && !isWakingUp) GoToRunning();
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateStarted); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::BleFirmwareUpdateStarted);
break; break;
case Messages::BleFirmwareUpdateFinished: case Messages::BleFirmwareUpdateFinished:
@ -152,6 +163,8 @@ void SystemTask::Work() {
spi.Sleep(); spi.Sleep();
twiMaster.Sleep(); twiMaster.Sleep();
isSleeping = true;
isGoingToSleep = false;
break; break;
default: break; default: break;
} }
@ -180,31 +193,27 @@ void SystemTask::Work() {
} }
void SystemTask::OnButtonPushed() { void SystemTask::OnButtonPushed() {
if(isGoingToSleep) return;
if(!isSleeping) { if(!isSleeping) {
NRF_LOG_INFO("[SystemTask] Button pushed"); NRF_LOG_INFO("[SystemTask] Button pushed");
PushMessage(Messages::OnButtonEvent); PushMessage(Messages::OnButtonEvent);
displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::ButtonPushed); displayApp->PushMessage(Pinetime::Applications::DisplayApp::Messages::ButtonPushed);
} }
else { else {
NRF_LOG_INFO("[SystemTask] Button pushed, waking up"); if(!isWakingUp) {
GoToRunning(); NRF_LOG_INFO("[SystemTask] Button pushed, waking up");
GoToRunning();
}
} }
} }
void SystemTask::GoToRunning() { void SystemTask::GoToRunning() {
isWakingUp = true;
PushMessage(Messages::GoToRunning); PushMessage(Messages::GoToRunning);
spi.Wakeup();
twiMaster.Wakeup();
spiNorFlash.Wakeup();
lcd.Wakeup();
touchPanel.Wakeup();
displayApp->PushMessage(Applications::DisplayApp::Messages::GoToRunning);
displayApp->PushMessage(Applications::DisplayApp::Messages::UpdateBatteryLevel);
} }
void SystemTask::OnTouchEvent() { void SystemTask::OnTouchEvent() {
if(isGoingToSleep) return ;
NRF_LOG_INFO("[SystemTask] Touch event"); NRF_LOG_INFO("[SystemTask] Touch event");
if(!isSleeping) { if(!isSleeping) {
PushMessage(Messages::OnTouchEvent); PushMessage(Messages::OnTouchEvent);
@ -213,6 +222,9 @@ void SystemTask::OnTouchEvent() {
} }
void SystemTask::PushMessage(SystemTask::Messages msg) { void SystemTask::PushMessage(SystemTask::Messages msg) {
if(msg == Messages::GoToSleep) {
isGoingToSleep = true;
}
BaseType_t xHigherPriorityTaskWoken; BaseType_t xHigherPriorityTaskWoken;
xHigherPriorityTaskWoken = pdFALSE; xHigherPriorityTaskWoken = pdFALSE;
xQueueSendFromISR(systemTaksMsgQueue, &msg, &xHigherPriorityTaskWoken); xQueueSendFromISR(systemTaksMsgQueue, &msg, &xHigherPriorityTaskWoken);
@ -229,6 +241,6 @@ void SystemTask::OnIdle() {
} }
void SystemTask::ReloadIdleTimer() const { void SystemTask::ReloadIdleTimer() const {
if(isSleeping) return; if(isSleeping || isGoingToSleep) return;
xTimerReset(idleTimer, 0); xTimerReset(idleTimer, 0);
} }

View file

@ -54,7 +54,9 @@ namespace Pinetime {
Pinetime::Controllers::Ble& bleController; Pinetime::Controllers::Ble& bleController;
Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::DateTime& dateTimeController;
QueueHandle_t systemTaksMsgQueue; QueueHandle_t systemTaksMsgQueue;
bool isSleeping = false; std::atomic<bool> isSleeping{false};
std::atomic<bool> isGoingToSleep{false};
std::atomic<bool> isWakingUp{false};
Pinetime::Drivers::Watchdog watchdog; Pinetime::Drivers::Watchdog watchdog;
Pinetime::Drivers::WatchdogView watchdogView; Pinetime::Drivers::WatchdogView watchdogView;
Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::NotificationManager& notificationManager;

View file

@ -140,9 +140,11 @@ void TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, b
} }
void TwiMaster::Sleep() { void TwiMaster::Sleep() {
while(twiBaseAddress->ENABLE != 0) {
twiBaseAddress->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos);
}
nrf_gpio_cfg_default(6); nrf_gpio_cfg_default(6);
nrf_gpio_cfg_default(7); nrf_gpio_cfg_default(7);
twiBaseAddress->ENABLE = 0;
NRF_LOG_INFO("[TWIMASTER] Sleep"); NRF_LOG_INFO("[TWIMASTER] Sleep");
} }