summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/FreeRTOSConfig.h4
-rw-r--r--src/displayapp/Apps.h2
-rw-r--r--src/displayapp/DisplayApp.cpp5
-rw-r--r--src/displayapp/lv_pinetime_theme.c10
-rw-r--r--src/displayapp/screens/ApplicationList.cpp2
-rw-r--r--src/displayapp/screens/Tasks.cpp77
-rw-r--r--src/displayapp/screens/Tasks.h31
-rw-r--r--src/displayapp/screens/WatchFaceDigital.cpp12
-rw-r--r--src/drivers/Bma421.cpp2
-rw-r--r--src/drivers/Cst816s.cpp3
-rw-r--r--src/drivers/Cst816s.h2
-rw-r--r--src/drivers/TwiMaster.cpp203
-rw-r--r--src/drivers/TwiMaster.h14
14 files changed, 301 insertions, 67 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 9dacf378..d8d92432 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -406,6 +406,7 @@ list(APPEND SOURCE_FILES
displayapp/screens/FlashLight.cpp
displayapp/screens/List.cpp
displayapp/screens/BatteryInfo.cpp
+ displayapp/screens/Tasks.cpp
## Settings
displayapp/screens/settings/QuickSettings.cpp
diff --git a/src/FreeRTOSConfig.h b/src/FreeRTOSConfig.h
index 3ba7faa0..b4de26fa 100644
--- a/src/FreeRTOSConfig.h
+++ b/src/FreeRTOSConfig.h
@@ -63,7 +63,7 @@
#define configTICK_RATE_HZ 1024
#define configMAX_PRIORITIES ( 3 )
#define configMINIMAL_STACK_SIZE ( 120 )
-#define configTOTAL_HEAP_SIZE ( 1024*15 )
+#define configTOTAL_HEAP_SIZE ( 1024*16 )
#define configMAX_TASK_NAME_LEN ( 4 )
#define configUSE_16_BIT_TICKS 0
#define configIDLE_SHOULD_YIELD 1
@@ -96,7 +96,7 @@
#define configUSE_TIMERS 1
#define configTIMER_TASK_PRIORITY ( 0 )
#define configTIMER_QUEUE_LENGTH 32
-#define configTIMER_TASK_STACK_DEPTH ( 200 )
+#define configTIMER_TASK_STACK_DEPTH ( 300 )
/* Tickless Idle configuration. */
#define configEXPECTED_IDLE_TIME_BEFORE_SLEEP 2
diff --git a/src/displayapp/Apps.h b/src/displayapp/Apps.h
index 358ea1f7..5daa82ff 100644
--- a/src/displayapp/Apps.h
+++ b/src/displayapp/Apps.h
@@ -4,7 +4,7 @@ namespace Pinetime {
namespace Applications {
enum class Apps {
None, Launcher, Clock, SysInfo, FirmwareUpdate, FirmwareValidation, NotificationsPreview, Notifications, FlashLight, BatteryInfo,
- Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion,
+ Music, Paint, Paddle, Twos, HeartRate, Navigation, StopWatch, Motion, Tasks,
QuickSettings, Settings, SettingWatchFace, SettingTimeFormat, SettingDisplay, SettingWakeUp
};
}
diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp
index 9aaf77a6..eab4e3b3 100644
--- a/src/displayapp/DisplayApp.cpp
+++ b/src/displayapp/DisplayApp.cpp
@@ -24,6 +24,7 @@
#include "displayapp/screens/Twos.h"
#include "displayapp/screens/FlashLight.h"
#include "displayapp/screens/BatteryInfo.h"
+#include "displayapp/screens/Tasks.h"
#include "drivers/Cst816s.h"
#include "drivers/St7789.h"
#include "drivers/Watchdog.h"
@@ -307,6 +308,10 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction)
case Apps::Motion:
currentScreen = std::make_unique<Screens::Motion>(this, motionController);
break;
+ case Apps::Tasks:
+ currentScreen = std::make_unique<Screens::Tasks>(this);
+ returnApp(Apps::Launcher, FullRefreshDirections::Down, TouchEvents::SwipeDown);
+ break;
}
currentApp = app;
diff --git a/src/displayapp/lv_pinetime_theme.c b/src/displayapp/lv_pinetime_theme.c
index 99ea9c8a..c153e42d 100644
--- a/src/displayapp/lv_pinetime_theme.c
+++ b/src/displayapp/lv_pinetime_theme.c
@@ -246,10 +246,10 @@ static void basic_init(void)
lv_style_set_border_color(&style_table_cell, LV_STATE_DEFAULT, LV_PINETIME_GRAY);
lv_style_set_border_width(&style_table_cell, LV_STATE_DEFAULT, 1);
lv_style_set_border_side(&style_table_cell, LV_STATE_DEFAULT, LV_BORDER_SIDE_FULL);
- lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 12);
- lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 12);
- lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 12);
- lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 12);
+ lv_style_set_pad_left(&style_table_cell, LV_STATE_DEFAULT, 5);
+ lv_style_set_pad_right(&style_table_cell, LV_STATE_DEFAULT, 5);
+ lv_style_set_pad_top(&style_table_cell, LV_STATE_DEFAULT, 2);
+ lv_style_set_pad_bottom(&style_table_cell, LV_STATE_DEFAULT, 2);
style_init_reset(&style_pad_small);
lv_style_int_t pad_small_value = 10;
@@ -356,6 +356,7 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
lv_obj_clean_style_list(obj, LV_OBJ_PART_MAIN);
list = lv_obj_get_style_list(obj, LV_OBJ_PART_MAIN);
_lv_style_list_add_style(list, &style_bg);
+ _lv_style_list_add_style(list, &style_label_white);
break;
case LV_THEME_OBJ:
@@ -499,6 +500,7 @@ static void theme_apply(lv_obj_t * obj, lv_theme_style_t name)
for(; idx <= LV_TABLE_CELL_STYLE_CNT; idx ++) {
list = lv_obj_get_style_list(obj, idx);
_lv_style_list_add_style(list, &style_table_cell);
+ _lv_style_list_add_style(list, &style_label_white);
}
break;
diff --git a/src/displayapp/screens/ApplicationList.cpp b/src/displayapp/screens/ApplicationList.cpp
index 056d128c..ccbd8ca4 100644
--- a/src/displayapp/screens/ApplicationList.cpp
+++ b/src/displayapp/screens/ApplicationList.cpp
@@ -49,7 +49,7 @@ std::unique_ptr<Screen> ApplicationList::CreateScreen1() {
{Symbols::map, Apps::Navigation},
{Symbols::shoe, Apps::Motion},
{Symbols::heartBeat, Apps::HeartRate},
- {"", Apps::None},
+ {"Tasks", Apps::Tasks},
}
};
diff --git a/src/displayapp/screens/Tasks.cpp b/src/displayapp/screens/Tasks.cpp
new file mode 100644
index 00000000..7bd6c09d
--- /dev/null
+++ b/src/displayapp/screens/Tasks.cpp
@@ -0,0 +1,77 @@
+#include <FreeRTOS.h>
+#include <task.h>
+#include "Tasks.h"
+#include <lvgl/lvgl.h>
+#include "../DisplayApp.h"
+#include <string>
+#include <algorithm>
+
+using namespace Pinetime::Applications::Screens;
+
+static void lv_update_task(struct _lv_task_t *task) {
+ auto user_data = static_cast<Tasks *>(task->user_data);
+ user_data->UpdateScreen();
+}
+
+Tasks::Tasks(
+ Pinetime::Applications::DisplayApp *app) :
+ Screen(app)
+{
+
+ table = lv_table_create(lv_scr_act(), NULL);
+ lv_table_set_col_cnt(table, 3);
+ lv_table_set_row_cnt(table, 8);
+ //lv_obj_align(table, NULL, LV_ALIGN_CENTER, 0, 0);
+ lv_obj_set_size(table, 240, 240);
+ lv_obj_set_pos(table, 0, 0);
+
+ /*lv_table_set_cell_type(table, 0, 0, 1);
+ lv_table_set_cell_type(table, 0, 1, 1);
+ lv_table_set_cell_type(table, 0, 2, 1);
+ lv_table_set_cell_type(table, 0, 3, 1);*/
+
+ lv_table_set_cell_value(table, 0, 0, "#");
+ lv_table_set_col_width(table, 0, 50);
+ lv_table_set_cell_value(table, 0, 1, "Task");
+ lv_table_set_col_width(table, 1, 80);
+ lv_table_set_cell_value(table, 0, 2, "Free");
+ lv_table_set_col_width(table, 2, 80);
+
+ lv_obj_t * backgroundLabel = lv_label_create(lv_scr_act(), nullptr);
+ lv_label_set_long_mode(backgroundLabel, LV_LABEL_LONG_CROP);
+ lv_obj_set_size(backgroundLabel, 240, 240);
+ lv_obj_set_pos(backgroundLabel, 0, 0);
+ lv_label_set_text_static(backgroundLabel, "");
+
+ UpdateScreen();
+ taskUpdate = lv_task_create(lv_update_task, 100000, LV_TASK_PRIO_LOW, this);
+
+}
+
+Tasks::~Tasks() {
+ lv_task_del(taskUpdate);
+ lv_obj_clean(lv_scr_act());
+}
+
+bool sortById(const TaskStatus_t &lhs, const TaskStatus_t &rhs) { return lhs.xTaskNumber < rhs.xTaskNumber; }
+
+void Tasks::UpdateScreen() {
+ auto nb = uxTaskGetSystemState(tasksStatus, 7, nullptr);
+ std::sort(tasksStatus, tasksStatus + nb, sortById);
+ for (uint8_t i = 0; i < nb; i++) {
+
+ lv_table_set_cell_value(table, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str());
+ lv_table_set_cell_value(table, i + 1, 1, tasksStatus[i].pcTaskName);
+ if (tasksStatus[i].usStackHighWaterMark < 20) {
+ std::string str1 = std::to_string(tasksStatus[i].usStackHighWaterMark) + " low";
+ lv_table_set_cell_value(table, i + 1, 2, str1.c_str());
+ } else {
+ lv_table_set_cell_value(table, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str());
+ }
+
+ }
+}
+
+bool Tasks::Refresh() {
+ return running;
+} \ No newline at end of file
diff --git a/src/displayapp/screens/Tasks.h b/src/displayapp/screens/Tasks.h
new file mode 100644
index 00000000..e9a49db4
--- /dev/null
+++ b/src/displayapp/screens/Tasks.h
@@ -0,0 +1,31 @@
+#pragma once
+#include <FreeRTOS.h>
+#include <task.h>
+#include <cstdint>
+#include <lvgl/lvgl.h>
+#include <timers.h>
+#include "Screen.h"
+
+namespace Pinetime {
+
+ namespace Applications {
+ namespace Screens {
+
+ class Tasks : public Screen{
+ public:
+ Tasks(DisplayApp* app);
+ ~Tasks() override;
+
+ bool Refresh() override;
+ void UpdateScreen();
+
+ private:
+ mutable TaskStatus_t tasksStatus[7];
+
+ lv_task_t* taskUpdate;
+ lv_obj_t * table;
+
+ };
+ }
+ }
+}
diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp
index c085b0b4..b1e21924 100644
--- a/src/displayapp/screens/WatchFaceDigital.cpp
+++ b/src/displayapp/screens/WatchFaceDigital.cpp
@@ -227,12 +227,10 @@ bool WatchFaceDigital::Refresh() {
heartbeat = heartRateController.HeartRate();
heartbeatRunning = heartRateController.State() != Controllers::HeartRateController::States::Stopped;
if(heartbeat.IsUpdated() || heartbeatRunning.IsUpdated()) {
- char heartbeatBuffer[4];
if(heartbeatRunning.Get())
- sprintf(heartbeatBuffer, "%d", heartbeat.Get());
+ lv_label_set_text_fmt(heartbeatValue, "%d", heartbeat.Get());
else
- sprintf(heartbeatBuffer, "---");
-
+ lv_label_set_text_static(heartbeatValue, "---");
lv_label_set_text(heartbeatValue, heartbeatBuffer);
lv_obj_align(heartbeatIcon, lv_scr_act(), LV_ALIGN_IN_BOTTOM_LEFT, 5, -2);
lv_obj_align(heartbeatValue, heartbeatIcon, LV_ALIGN_OUT_RIGHT_MID, 5, 0);
@@ -242,11 +240,7 @@ bool WatchFaceDigital::Refresh() {
stepCount = motionController.NbSteps();
motionSensorOk = motionController.IsSensorOk();
if(stepCount.IsUpdated() || motionSensorOk.IsUpdated()) {
- char stepBuffer[5];
- if(motionSensorOk.Get())
- sprintf(stepBuffer, "%lu", stepCount.Get());
- else
- sprintf(stepBuffer, "---", stepCount.Get());
+ lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get());
lv_label_set_text(stepValue, stepBuffer);
lv_obj_align(stepValue, lv_scr_act(), LV_ALIGN_IN_BOTTOM_RIGHT, -5, -2);
lv_obj_align(stepIcon, stepValue, LV_ALIGN_OUT_LEFT_MID, -5, 0);
diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp
index ea705d8e..d7a59cf0 100644
--- a/src/drivers/Bma421.cpp
+++ b/src/drivers/Bma421.cpp
@@ -31,7 +31,7 @@ Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster{twiMaster},
bma.variant = BMA42X_VARIANT;
bma.intf_ptr = this;
bma.delay_us = user_delay;
- bma.read_write_len = 8;
+ bma.read_write_len = 16;
}
void Bma421::Init() {
diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp
index 03da76ce..e3a37b1b 100644
--- a/src/drivers/Cst816s.cpp
+++ b/src/drivers/Cst816s.cpp
@@ -31,7 +31,8 @@ void Cst816S::Init() {
twiMaster.Read(twiAddress, 0x15, &dummy, 1);
vTaskDelay(5);
twiMaster.Read(twiAddress, 0xa7, &dummy, 1);
-
+ vTaskDelay(5);
+
/*
[2] EnConLR - Continuous operation can slide around
[1] EnConUD - Slide up and down to enable continuous operation
diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h
index b7876b88..63007860 100644
--- a/src/drivers/Cst816s.h
+++ b/src/drivers/Cst816s.h
@@ -53,7 +53,7 @@ namespace Pinetime {
static constexpr uint8_t touchStep = 6;
static constexpr uint8_t gestureIndex = 1;
- uint8_t touchData[63];
+ uint8_t touchData[10];
TwiMaster& twiMaster;
uint8_t twiAddress;
};
diff --git a/src/drivers/TwiMaster.cpp b/src/drivers/TwiMaster.cpp
index 646823d0..271b714f 100644
--- a/src/drivers/TwiMaster.cpp
+++ b/src/drivers/TwiMaster.cpp
@@ -2,77 +2,167 @@
#include <cstring>
#include <hal/nrf_gpio.h>
#include <nrfx_log.h>
-#include <nrfx_twim.h>
-#include <nrf_drv_twi.h>
+
using namespace Pinetime::Drivers;
// TODO use shortcut to automatically send STOP when receive LastTX, for example
// TODO use DMA/IRQ
-TwiMaster::TwiMaster(const Modules module, const Parameters& params) : module{module}, params{params}, mutex{xSemaphoreCreateBinary()} {
- ASSERT(mutex != nullptr);
+TwiMaster::TwiMaster(const Modules module, const Parameters& params) : module{module}, params{params} {
+ mutex = xSemaphoreCreateBinary();
+}
+
+void TwiMaster::Init() {
+ NRF_GPIO->PIN_CNF[params.pinScl] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
+
+ NRF_GPIO->PIN_CNF[params.pinSda] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0D1 << GPIO_PIN_CNF_DRIVE_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
+
switch(module) {
- case Modules::TWIM1:
+ case Modules::TWIM1: twiBaseAddress = NRF_TWIM1; break;
default:
- twim = NRFX_TWIM_INSTANCE(1);
- break;
+ return;
}
-}
-void TwiMaster::Init() {
- nrfx_twim_config_t config;
- config.frequency = static_cast<nrf_twim_frequency_t>(params.frequency);
- config.hold_bus_uninit = false;
- config.interrupt_priority = 0;
- config.scl = params.pinScl;
- config.sda = params.pinSda;
- nrfx_twim_init(&twim,
- &config,
- nullptr,
- nullptr);
- nrfx_twim_enable(&twim);
+ switch(static_cast<Frequencies>(params.frequency)) {
+ case Frequencies::Khz100 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K100; break;
+ case Frequencies::Khz250 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K250; break;
+ case Frequencies::Khz400 : twiBaseAddress->FREQUENCY = TWIM_FREQUENCY_FREQUENCY_K400; break;
+ }
+
+ twiBaseAddress->PSEL.SCL = params.pinScl;
+ twiBaseAddress->PSEL.SDA = params.pinSda;
+ twiBaseAddress->EVENTS_LASTRX = 0;
+ twiBaseAddress->EVENTS_STOPPED = 0;
+ twiBaseAddress->EVENTS_LASTTX = 0;
+ twiBaseAddress->EVENTS_ERROR = 0;
+ twiBaseAddress->EVENTS_RXSTARTED = 0;
+ twiBaseAddress->EVENTS_SUSPENDED = 0;
+ twiBaseAddress->EVENTS_TXSTARTED = 0;
+
+ twiBaseAddress->ENABLE = (TWIM_ENABLE_ENABLE_Enabled << TWIM_ENABLE_ENABLE_Pos);
+
+
+ /* // IRQ
+ NVIC_ClearPendingIRQ(_IRQn);
+ NVIC_SetPriority(_IRQn, 2);
+ NVIC_EnableIRQ(_IRQn);
+ */
xSemaphoreGive(mutex);
+
}
TwiMaster::ErrorCodes TwiMaster::Read(uint8_t deviceAddress, uint8_t registerAddress, uint8_t *data, size_t size) {
xSemaphoreTake(mutex, portMAX_DELAY);
- TwiMaster::ErrorCodes ret;
+ auto ret = Write(deviceAddress, &registerAddress, 1, false);
+ ret = Read(deviceAddress, data, size, true);
+ xSemaphoreGive(mutex);
+ return ret;
+}
+
+TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
+ ASSERT(size <= maxDataSize);
+ xSemaphoreTake(mutex, portMAX_DELAY);
+ internalBuffer[0] = registerAddress;
+ std::memcpy(internalBuffer + 1, data, size);
+ auto ret = Write(deviceAddress, internalBuffer, size + 1, true);
+ xSemaphoreGive(mutex);
+ return ret;
+}
+
+TwiMaster::ErrorCodes TwiMaster::Read(uint8_t deviceAddress, uint8_t *buffer, size_t size, bool stop) {
+ twiBaseAddress->ADDRESS = deviceAddress;
+ twiBaseAddress->TASKS_RESUME = 0x1UL;
+ twiBaseAddress->RXD.PTR = (uint32_t)buffer;
+ twiBaseAddress->RXD.MAXCNT = size;
- auto err = nrfx_twim_tx(&twim, deviceAddress, &registerAddress, 1, false);
- if(err != 0) {
- return TwiMaster::ErrorCodes::TransactionFailed;
+ twiBaseAddress->TASKS_STARTRX = 1;
+
+ while(!twiBaseAddress->EVENTS_RXSTARTED && !twiBaseAddress->EVENTS_ERROR);
+ twiBaseAddress->EVENTS_RXSTARTED = 0x0UL;
+
+ txStartedCycleCount = DWT->CYCCNT;
+ uint32_t currentCycleCount;
+ while(!twiBaseAddress->EVENTS_LASTRX && !twiBaseAddress->EVENTS_ERROR) {
+ currentCycleCount = DWT->CYCCNT;
+ if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
+ FixHwFreezed();
+ return ErrorCodes::TransactionFailed;
+ }
}
+ twiBaseAddress->EVENTS_LASTRX = 0x0UL;
- err = nrfx_twim_rx(&twim, deviceAddress, data, size);
- if(err != 0) {
- return TwiMaster::ErrorCodes::TransactionFailed;
+ if (stop || twiBaseAddress->EVENTS_ERROR) {
+ twiBaseAddress->TASKS_STOP = 0x1UL;
+ while(!twiBaseAddress->EVENTS_STOPPED);
+ twiBaseAddress->EVENTS_STOPPED = 0x0UL;
+ }
+ else {
+ twiBaseAddress->TASKS_SUSPEND = 0x1UL;
+ while(!twiBaseAddress->EVENTS_SUSPENDED);
+ twiBaseAddress->EVENTS_SUSPENDED = 0x0UL;
}
- xSemaphoreGive(mutex);
- return TwiMaster::ErrorCodes::NoError;
+ if (twiBaseAddress->EVENTS_ERROR) {
+ twiBaseAddress->EVENTS_ERROR = 0x0UL;
+ }
+ return ErrorCodes::NoError;
}
-TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, uint8_t registerAddress, const uint8_t *data, size_t size) {
- ASSERT(size <= maxDataSize);
- xSemaphoreTake(mutex, portMAX_DELAY);
- TwiMaster::ErrorCodes ret;
+TwiMaster::ErrorCodes TwiMaster::Write(uint8_t deviceAddress, const uint8_t *data, size_t size, bool stop) {
+ twiBaseAddress->ADDRESS = deviceAddress;
+ twiBaseAddress->TASKS_RESUME = 0x1UL;
+ twiBaseAddress->TXD.PTR = (uint32_t)data;
+ twiBaseAddress->TXD.MAXCNT = size;
- internalBuffer[0] = registerAddress;
- std::memcpy(internalBuffer+1, data, size);
- auto err = nrfx_twim_tx(&twim, deviceAddress, internalBuffer , size+1, false);
- if(err != 0){
- return TwiMaster::ErrorCodes::TransactionFailed;
+ twiBaseAddress->TASKS_STARTTX = 1;
+
+ while(!twiBaseAddress->EVENTS_TXSTARTED && !twiBaseAddress->EVENTS_ERROR);
+ twiBaseAddress->EVENTS_TXSTARTED = 0x0UL;
+
+ txStartedCycleCount = DWT->CYCCNT;
+ uint32_t currentCycleCount;
+ while(!twiBaseAddress->EVENTS_LASTTX && !twiBaseAddress->EVENTS_ERROR) {
+ currentCycleCount = DWT->CYCCNT;
+ if ((currentCycleCount-txStartedCycleCount) > HwFreezedDelay) {
+ FixHwFreezed();
+ return ErrorCodes::TransactionFailed;
+ }
}
+ twiBaseAddress->EVENTS_LASTTX = 0x0UL;
- xSemaphoreGive(mutex);
- return TwiMaster::ErrorCodes::NoError;
+ if (stop || twiBaseAddress->EVENTS_ERROR) {
+ twiBaseAddress->TASKS_STOP = 0x1UL;
+ while(!twiBaseAddress->EVENTS_STOPPED);
+ twiBaseAddress->EVENTS_STOPPED = 0x0UL;
+ }
+ else {
+ twiBaseAddress->TASKS_SUSPEND = 0x1UL;
+ while(!twiBaseAddress->EVENTS_SUSPENDED);
+ twiBaseAddress->EVENTS_SUSPENDED = 0x0UL;
+ }
+
+ if (twiBaseAddress->EVENTS_ERROR) {
+ twiBaseAddress->EVENTS_ERROR = 0x0UL;
+ uint32_t error = twiBaseAddress->ERRORSRC;
+ twiBaseAddress->ERRORSRC = error;
+ }
+
+ return ErrorCodes::NoError;
}
void TwiMaster::Sleep() {
- nrfx_twim_disable(&twim);
- nrfx_twim_uninit(&twim);
-
+ while(twiBaseAddress->ENABLE != 0) {
+ twiBaseAddress->ENABLE = (TWIM_ENABLE_ENABLE_Disabled << TWIM_ENABLE_ENABLE_Pos);
+ }
nrf_gpio_cfg_default(6);
nrf_gpio_cfg_default(7);
NRF_LOG_INFO("[TWIMASTER] Sleep");
@@ -82,3 +172,30 @@ void TwiMaster::Wakeup() {
Init();
NRF_LOG_INFO("[TWIMASTER] Wakeup");
}
+
+/* Sometimes, the TWIM device just freeze and never set the event EVENTS_LASTTX.
+ * This method disable and re-enable the peripheral so that it works again.
+ * This is just a workaround, and it would be better if we could find a way to prevent
+ * this issue from happening.
+ * */
+void TwiMaster::FixHwFreezed() {
+ NRF_LOG_INFO("I2C device frozen, reinitializing it!");
+ // Disable I²C
+ uint32_t twi_state = NRF_TWI1->ENABLE;
+ twiBaseAddress->ENABLE = TWIM_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
+
+ NRF_GPIO->PIN_CNF[params.pinScl] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
+
+ NRF_GPIO->PIN_CNF[params.pinSda] = ((uint32_t)GPIO_PIN_CNF_DIR_Input << GPIO_PIN_CNF_DIR_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_INPUT_Connect << GPIO_PIN_CNF_INPUT_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_PULL_Pullup << GPIO_PIN_CNF_PULL_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_DRIVE_S0S1 << GPIO_PIN_CNF_DRIVE_Pos)
+ | ((uint32_t)GPIO_PIN_CNF_SENSE_Disabled << GPIO_PIN_CNF_SENSE_Pos);
+
+ // Re-enable I²C
+ twiBaseAddress->ENABLE = twi_state;
+} \ No newline at end of file
diff --git a/src/drivers/TwiMaster.h b/src/drivers/TwiMaster.h
index 6e3ff721..f3c87b0a 100644
--- a/src/drivers/TwiMaster.h
+++ b/src/drivers/TwiMaster.h
@@ -3,13 +3,13 @@
#include <semphr.h>
#include <drivers/include/nrfx_twi.h> // NRF_TWIM_Type
#include <cstdint>
-#include <nrfx_twim.h>
namespace Pinetime {
namespace Drivers {
class TwiMaster {
public:
enum class Modules { TWIM1 };
+ enum class Frequencies {Khz100, Khz250, Khz400};
enum class ErrorCodes {NoError, TransactionFailed};
struct Parameters {
uint32_t frequency;
@@ -27,13 +27,19 @@ namespace Pinetime {
void Wakeup();
private:
- nrfx_twim_t twim;
+
+ ErrorCodes Read(uint8_t deviceAddress, uint8_t* buffer, size_t size, bool stop);
+ ErrorCodes Write(uint8_t deviceAddress, const uint8_t* data, size_t size, bool stop);
+ void FixHwFreezed();
+ NRF_TWIM_Type* twiBaseAddress;
+ SemaphoreHandle_t mutex;
const Modules module;
const Parameters params;
- SemaphoreHandle_t mutex;
- static constexpr uint8_t maxDataSize{8};
+ static constexpr uint8_t maxDataSize{16};
static constexpr uint8_t registerSize{1};
uint8_t internalBuffer[maxDataSize + registerSize];
+ uint32_t txStartedCycleCount = 0;
+ static constexpr uint32_t HwFreezedDelay{161000};
};
}
} \ No newline at end of file