summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJoaquim <joaquim.org@gmail.com>2021-04-10 19:09:33 +0100
committerJoaquim <joaquim.org@gmail.com>2021-04-10 19:09:33 +0100
commit012c246e401c0745d4b6765217ce7137680070da (patch)
treef5ac127917689dd57a36d7152f44bb923e2a9e9e /src
parenteb769fb60ecb8f96ecf6901082ec3f0610842af8 (diff)
0.16.0 TWI problems fix
More memory for freertos heap and timer stack Fix warning in watchface Fix number of bytes read by cst816 Debug app to show freertos tasks Increased the number of bytes of the twi write buffer
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