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/components/battery/BatteryController.cpp b/src/components/battery/BatteryController.cpp index 4a7a2345..99afa55c 100644 --- a/src/components/battery/BatteryController.cpp +++ b/src/components/battery/BatteryController.cpp @@ -23,12 +23,20 @@ void Battery::Update() { isCharging = !nrf_gpio_pin_read(chargingPin); isPowerPresent = !nrf_gpio_pin_read(powerPresentPin); + if ( isReading ) return; // Non blocking read - SaadcInit(); - nrfx_saadc_sample(); + samples = 0; + isReading = true; + SaadcInit(); + + nrfx_saadc_sample(); } +void Battery::adcCallbackStatic(nrfx_saadc_evt_t const *event) { + instance->SaadcEventHandler(event); +} + void Battery::SaadcInit() { nrfx_saadc_config_t adcConfig = NRFX_SAADC_DEFAULT_CONFIG; APP_ERROR_CHECK(nrfx_saadc_init(&adcConfig, adcCallbackStatic)); @@ -68,10 +76,13 @@ void Battery::SaadcEventHandler(nrfx_saadc_evt_t const * p_event) { percentRemainingBuffer.insert(percentRemaining); - nrfx_saadc_uninit(); + samples++; + if ( samples > percentRemainingSamples ) { + nrfx_saadc_uninit(); + isReading = false; + } else { + nrfx_saadc_sample(); + } } } -void Battery::adcCallbackStatic(nrfx_saadc_evt_t const *event) { - instance->SaadcEventHandler(event); -} diff --git a/src/components/battery/BatteryController.h b/src/components/battery/BatteryController.h index 2776687b..47d7a6d1 100644 --- a/src/components/battery/BatteryController.h +++ b/src/components/battery/BatteryController.h @@ -52,13 +52,13 @@ namespace Pinetime { float Voltage() const { return voltage; } bool IsCharging() const { return isCharging; } - bool IsPowerPresent() const { return isPowerPresent; } + bool IsPowerPresent() const { return isPowerPresent; } private: static Battery *instance; nrf_saadc_value_t saadc_value; - static constexpr uint8_t percentRemainingSamples = 10; + static constexpr uint8_t percentRemainingSamples = 5; CircBuffer percentRemainingBuffer {}; static constexpr uint32_t chargingPin = 12; @@ -74,6 +74,9 @@ namespace Pinetime { void SaadcEventHandler(nrfx_saadc_evt_t const * p_event); static void adcCallbackStatic(nrfx_saadc_evt_t const *event); + + bool isReading = false; + uint8_t samples = 0; }; } } \ No newline at end of file diff --git a/src/displayapp/DisplayApp.cpp b/src/displayapp/DisplayApp.cpp index 9aaf77a6..36f93a91 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 "drivers/Cst816s.h" #include "drivers/St7789.h" #include "drivers/Watchdog.h" @@ -131,7 +132,7 @@ void DisplayApp::Refresh() { // clockScreen.SetBleConnectionState(bleController.IsConnected() ? Screens::Clock::BleConnectionStates::Connected : Screens::Clock::BleConnectionStates::NotConnected); break; case Messages::UpdateBatteryLevel: -// clockScreen.SetBatteryPercentRemaining(batteryController.PercentRemaining()); + batteryController.Update(); break; case Messages::NewNotification: LoadApp( Apps::NotificationsPreview, DisplayApp::FullRefreshDirections::Down ); @@ -307,7 +308,6 @@ void DisplayApp::LoadApp(Apps app, DisplayApp::FullRefreshDirections direction) case Apps::Motion: currentScreen = std::make_unique(this, motionController); 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/BatteryInfo.cpp b/src/displayapp/screens/BatteryInfo.cpp index ae39138f..e616d67f 100644 --- a/src/displayapp/screens/BatteryInfo.cpp +++ b/src/displayapp/screens/BatteryInfo.cpp @@ -84,7 +84,7 @@ void BatteryInfo::UpdateAnim() { batteryPercent = batteryController.PercentRemaining(); if ( batteryPercent >= 0 ) { - if ( batteryController.IsCharging() ) { + if ( batteryController.IsCharging() and batteryPercent < 100 ) { animation +=1; if (animation >= 100) { animation = 0; @@ -111,12 +111,17 @@ void BatteryInfo::UpdateScreen() { batteryVoltage = batteryController.Voltage(); if ( batteryPercent >= 0 ) { - if ( batteryController.IsCharging() ) { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, lv_color_hex(0xFF0000)); + if ( batteryController.IsCharging() and batteryPercent < 100 ) { + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_RED); lv_label_set_text_static(status,"Battery charging"); - + } else if ( batteryPercent == 100 ) { + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_BLUE); + lv_label_set_text_static(status,"Battery is fully charged"); + } else if ( batteryPercent < 10 ) { + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_YELLOW); + lv_label_set_text_static(status,"Battery is low"); } else { - lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, lv_color_hex(0x00FF00)); + lv_obj_set_style_local_bg_color(charging_bar, LV_BAR_PART_INDIC , LV_STATE_DEFAULT, LV_COLOR_GREEN); lv_label_set_text_static(status,"Battery discharging"); } diff --git a/src/displayapp/screens/List.cpp b/src/displayapp/screens/List.cpp index 87cfa6db..82da4d4c 100644 --- a/src/displayapp/screens/List.cpp +++ b/src/displayapp/screens/List.cpp @@ -116,7 +116,7 @@ void List::OnButtonEvent(lv_obj_t * object, lv_event_t event) { if ( event == LV_EVENT_RELEASED ) { for(int i = 0; i < MAXLISTITEMS; i++) { if ( apps[i] != Apps::None && object == itemApps[i] ) { - app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Down); + app->StartApp(apps[i], DisplayApp::FullRefreshDirections::Up); running = false; return; } diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index f3ac7490..48dba547 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -26,7 +26,8 @@ SystemInfo::SystemInfo(Pinetime::Applications::DisplayApp *app, [this]() -> std::unique_ptr { return CreateScreen1(); }, [this]() -> std::unique_ptr { return CreateScreen2(); }, [this]() -> std::unique_ptr { return CreateScreen3(); }, - [this]() -> std::unique_ptr { return CreateScreen4(); } + [this]() -> std::unique_ptr { return CreateScreen4(); }, + [this]() -> std::unique_ptr { return CreateScreen5(); } }, Screens::ScreenListModes::UpDown } {} @@ -37,7 +38,9 @@ SystemInfo::~SystemInfo() { } bool SystemInfo::Refresh() { - screens.Refresh(); + if (running) { + screens.Refresh(); + } return running; } @@ -50,27 +53,8 @@ bool SystemInfo::OnTouchEvent(Pinetime::Applications::TouchEvents event) { return screens.OnTouchEvent(event); } -void SystemInfo::CreateContainer() { - - if ( container1 ) { - container1 = lv_cont_create(lv_scr_act(), nullptr); - - lv_obj_set_style_local_bg_opa(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, LV_OPA_TRANSP); - lv_obj_set_style_local_pad_all(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 10); - lv_obj_set_style_local_pad_inner(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 5); - lv_obj_set_style_local_border_width(container1, LV_CONT_PART_MAIN, LV_STATE_DEFAULT, 0); - - lv_obj_set_pos(container1, 0, 0); - lv_obj_set_width(container1, LV_HOR_RES - 10); - lv_obj_set_height(container1, LV_VER_RES); - lv_cont_set_layout(container1, LV_LAYOUT_CENTER); - } -} - std::unique_ptr SystemInfo::CreateScreen1() { - CreateContainer(); - - lv_obj_t * label = lv_label_create(container1, nullptr); + lv_obj_t * label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); lv_label_set_text_fmt(label, "#FFFF00 InfiniTime#\n\n" @@ -81,12 +65,11 @@ std::unique_ptr SystemInfo::CreateScreen1() { Version::Major(), Version::Minor(), Version::Patch(), __DATE__, __TIME__); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); - return std::unique_ptr(new Screens::Label(0, 4, app, label)); + lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + return std::unique_ptr(new Screens::Label(0, 5, app, label)); } std::unique_ptr SystemInfo::CreateScreen2() { - CreateContainer(); - auto batteryPercent = static_cast(batteryController.PercentRemaining()); float batteryVoltage = batteryController.Voltage(); @@ -126,7 +109,7 @@ std::unique_ptr SystemInfo::CreateScreen2() { batteryVoltageBytes[0] = static_cast((batteryVoltage - batteryVoltageBytes[1]) * 100); //remove whole part of flt and shift 2 places over // - lv_obj_t * label = lv_label_create(container1, nullptr); + lv_obj_t * label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); lv_label_set_text_fmt(label, "#444444 Date# %02d/%02d/%04d\n" @@ -140,6 +123,7 @@ std::unique_ptr SystemInfo::CreateScreen2() { uptimeDays, uptimeHours, uptimeMinutes, uptimeSeconds, batteryPercent, batteryVoltageBytes[1], batteryVoltageBytes[0], brightnessController.ToString(), resetReason ); + lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); return std::unique_ptr(new Screens::Label(1, 4, app, label)); } @@ -147,9 +131,8 @@ std::unique_ptr SystemInfo::CreateScreen2() { std::unique_ptr SystemInfo::CreateScreen3() { lv_mem_monitor_t mon; lv_mem_monitor(&mon); - CreateContainer(); - - lv_obj_t * label = lv_label_create(container1, nullptr); + + lv_obj_t * label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); auto& bleAddr = bleController.Address(); lv_label_set_text_fmt(label, @@ -169,13 +152,46 @@ std::unique_ptr SystemInfo::CreateScreen3() { (int)mon.free_biggest_size, 0 ); - - return std::unique_ptr(new Screens::Label(2, 4, app, label)); + lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + return std::unique_ptr(new Screens::Label(2, 5, app, label)); } + +bool sortById(const TaskStatus_t &lhs, const TaskStatus_t &rhs) { return lhs.xTaskNumber < rhs.xTaskNumber; } + std::unique_ptr SystemInfo::CreateScreen4() { - CreateContainer(); - lv_obj_t * label = lv_label_create(container1, nullptr); + TaskStatus_t tasksStatus[7]; + lv_obj_t * infoTask = lv_table_create(lv_scr_act(), NULL); + lv_table_set_col_cnt(infoTask, 3); + lv_table_set_row_cnt(infoTask, 8); + lv_obj_set_pos(infoTask, 10, 10); + + lv_table_set_cell_value(infoTask, 0, 0, "#"); + lv_table_set_col_width(infoTask, 0, 50); + lv_table_set_cell_value(infoTask, 0, 1, "Task"); + lv_table_set_col_width(infoTask, 1, 80); + lv_table_set_cell_value(infoTask, 0, 2, "Free"); + lv_table_set_col_width(infoTask, 2, 90); + + 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(infoTask, i + 1, 0, std::to_string(tasksStatus[i].xTaskNumber).c_str()); + lv_table_set_cell_value(infoTask, 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(infoTask, i + 1, 2, str1.c_str()); + } else { + lv_table_set_cell_value(infoTask, i + 1, 2, std::to_string(tasksStatus[i].usStackHighWaterMark).c_str()); + } + + } + return std::unique_ptr(new Screens::Label(3, 5, app, infoTask)); +} + +std::unique_ptr SystemInfo::CreateScreen5() { + lv_obj_t * label = lv_label_create(lv_scr_act(), nullptr); lv_label_set_recolor(label, true); lv_label_set_text_static(label, "Software Licensed\n" @@ -186,5 +202,6 @@ std::unique_ptr SystemInfo::CreateScreen4() { "#FFFF00 https://github.com/#\n" "#FFFF00 JF002/InfiniTime#"); lv_label_set_align(label, LV_LABEL_ALIGN_CENTER); - return std::unique_ptr(new Screens::Label(3, 4, app, label)); + lv_obj_align(label, lv_scr_act(), LV_ALIGN_CENTER, 0, 0); + return std::unique_ptr(new Screens::Label(4, 5, app, label)); } \ No newline at end of file diff --git a/src/displayapp/screens/SystemInfo.h b/src/displayapp/screens/SystemInfo.h index 574ded74..f5f50a42 100644 --- a/src/displayapp/screens/SystemInfo.h +++ b/src/displayapp/screens/SystemInfo.h @@ -35,21 +35,19 @@ namespace Pinetime { private: bool running = true; - lv_obj_t* container1; - Pinetime::Controllers::DateTime& dateTimeController; Pinetime::Controllers::Battery& batteryController; Pinetime::Controllers::BrightnessController& brightnessController; Pinetime::Controllers::Ble& bleController; Pinetime::Drivers::WatchdogView& watchdog; - ScreenList<4> screens; + ScreenList<5> screens; std::unique_ptr CreateScreen1(); std::unique_ptr CreateScreen2(); std::unique_ptr CreateScreen3(); std::unique_ptr CreateScreen4(); + std::unique_ptr CreateScreen5(); - void CreateContainer(); }; } } diff --git a/src/displayapp/screens/Tile.cpp b/src/displayapp/screens/Tile.cpp index 8fa7fd07..b1dfaf76 100644 --- a/src/displayapp/screens/Tile.cpp +++ b/src/displayapp/screens/Tile.cpp @@ -128,7 +128,7 @@ bool Tile::Refresh() { void Tile::OnObjectEvent(lv_obj_t *obj, lv_event_t event, uint32_t buttonId) { if(event == LV_EVENT_VALUE_CHANGED) { - app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Down); + app->StartApp(apps[buttonId], DisplayApp::FullRefreshDirections::Up); running = false; } } diff --git a/src/displayapp/screens/Twos.cpp b/src/displayapp/screens/Twos.cpp index 7a3ed1e4..bbee5e11 100644 --- a/src/displayapp/screens/Twos.cpp +++ b/src/displayapp/screens/Twos.cpp @@ -21,28 +21,33 @@ Twos::Twos(Pinetime::Applications::DisplayApp *app) : Screen(app) { lv_style_set_border_width(&style_cell1, LV_STATE_DEFAULT, 3); lv_style_set_bg_opa(&style_cell1, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&style_cell1, LV_STATE_DEFAULT, lv_color_hex(0xcdc0b4)); + lv_style_set_pad_top(&style_cell1, LV_STATE_DEFAULT, 25); + lv_style_set_text_color(&style_cell1, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_style_set_border_color(&style_cell2, LV_STATE_DEFAULT, lv_color_hex(0xbbada0)); lv_style_set_border_width(&style_cell2, LV_STATE_DEFAULT, 3); lv_style_set_bg_opa(&style_cell2, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&style_cell2, LV_STATE_DEFAULT, lv_color_hex(0xefdfc6)); + lv_style_set_pad_top(&style_cell2, LV_STATE_DEFAULT, 25); + lv_style_set_text_color(&style_cell2, LV_STATE_DEFAULT, LV_COLOR_BLACK); lv_style_set_border_color(&style_cell3, LV_STATE_DEFAULT, lv_color_hex(0xbbada0)); lv_style_set_border_width(&style_cell3, LV_STATE_DEFAULT, 3); lv_style_set_bg_opa(&style_cell3, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&style_cell3, LV_STATE_DEFAULT, lv_color_hex(0xef9263)); + lv_style_set_pad_top(&style_cell3, LV_STATE_DEFAULT, 25); lv_style_set_border_color(&style_cell4, LV_STATE_DEFAULT, lv_color_hex(0xbbada0)); lv_style_set_border_width(&style_cell4, LV_STATE_DEFAULT, 3); lv_style_set_bg_opa(&style_cell4, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&style_cell4, LV_STATE_DEFAULT, lv_color_hex(0xf76142)); - //lv_style_set_text_color(&style_cell4, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_pad_top(&style_cell4, LV_STATE_DEFAULT, 25); lv_style_set_border_color(&style_cell5, LV_STATE_DEFAULT, lv_color_hex(0xbbada0)); lv_style_set_border_width(&style_cell5, LV_STATE_DEFAULT, 3); lv_style_set_bg_opa(&style_cell5, LV_STATE_DEFAULT, LV_OPA_COVER); lv_style_set_bg_color(&style_cell5, LV_STATE_DEFAULT, lv_color_hex(0x007dc5)); - //lv_style_set_text_color(&style_cell5, LV_STATE_DEFAULT, LV_COLOR_WHITE); + lv_style_set_pad_top(&style_cell5, LV_STATE_DEFAULT, 25); // format grid display diff --git a/src/displayapp/screens/WatchFaceDigital.cpp b/src/displayapp/screens/WatchFaceDigital.cpp index c085b0b4..15f73e8b 100644 --- a/src/displayapp/screens/WatchFaceDigital.cpp +++ b/src/displayapp/screens/WatchFaceDigital.cpp @@ -227,13 +227,11 @@ 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(heartbeatValue, heartbeatBuffer); + lv_label_set_text_static(heartbeatValue, "---"); + 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); lv_obj_align(heartbeatBpm, heartbeatValue, LV_ALIGN_OUT_RIGHT_MID, 5, 0); @@ -242,12 +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(stepValue, stepBuffer); + lv_label_set_text_fmt(stepValue, "%lu", stepCount.Get()); 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 #include #include -#include -#include + 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); - switch(module) { - case Modules::TWIM1: - default: - twim = NRFX_TWIM_INSTANCE(1); - break; - } +TwiMaster::TwiMaster(const Modules module, const Parameters& params) : module{module}, params{params} { + mutex = xSemaphoreCreateBinary(); } void TwiMaster::Init() { - nrfx_twim_config_t config; - config.frequency = static_cast(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); + 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: twiBaseAddress = NRF_TWIM1; break; + default: + return; + } + + switch(static_cast(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 err = nrfx_twim_tx(&twim, deviceAddress, ®isterAddress, 1, false); - if(err != 0) { - return TwiMaster::ErrorCodes::TransactionFailed; - } - - err = nrfx_twim_rx(&twim, deviceAddress, data, size); - if(err != 0) { - return TwiMaster::ErrorCodes::TransactionFailed; - } + auto ret = Write(deviceAddress, ®isterAddress, 1, false); + ret = Read(deviceAddress, data, size, true); xSemaphoreGive(mutex); - - return TwiMaster::ErrorCodes::NoError; + 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); - TwiMaster::ErrorCodes ret; - 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; + 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; + + 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; + + 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, 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; + + 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; + + 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 #include // NRF_TWIM_Type #include -#include 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 diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index 42a4e844..b540fcd8 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -98,7 +98,6 @@ void SystemTask::Work() { heartRateController, settingsController, motionController); displayApp->Start(); - batteryController.Update(); displayApp->PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel); heartRateSensor.Init(); @@ -106,7 +105,6 @@ void SystemTask::Work() { heartRateApp = std::make_unique(heartRateSensor, heartRateController); heartRateApp->Start(); - nrf_gpio_cfg_sense_input(pinButton, (nrf_gpio_pin_pull_t)GPIO_PIN_CNF_PULL_Pulldown, (nrf_gpio_pin_sense_t)GPIO_PIN_CNF_SENSE_High); nrf_gpio_cfg_output(15); nrf_gpio_pin_set(15); @@ -141,7 +139,14 @@ void SystemTask::Work() { uint8_t msg; if (xQueueReceive(systemTasksMsgQueue, &msg, 100)) { + + // call the battery controller or use the MSG in DisplayApp to get the battery status ??? + // it is necessary to validate which is the most efficient batteryController.Update(); + //displayApp->PushMessage(Pinetime::Applications::Display::Messages::UpdateBatteryLevel); + // analyze a more efficient way to do this refreshment + // this and the UpdateMotion(); can be called on a timer to be independent of the main process ??? + Messages message = static_cast(msg); switch(message) { case Messages::EnableSleeping: