From 03f60eb14d0fb6015898700f36739c8c89c897cf Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Thu, 19 May 2022 00:21:44 +0200 Subject: [PATCH 01/12] BMA421: Use internal FIFO for smoothing --- src/drivers/Bma421.cpp | 55 +++++++++++++++++++++++++++++++++--------- src/drivers/Bma421.h | 2 ++ 2 files changed, 45 insertions(+), 12 deletions(-) diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp index 539cc8d1d3..050a3a6fb1 100644 --- a/src/drivers/Bma421.cpp +++ b/src/drivers/Bma421.cpp @@ -32,16 +32,19 @@ Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster} bma.intf_ptr = this; bma.delay_us = user_delay; bma.read_write_len = 16; + bma.resolution = 12; } void Bma421::Init() { - if (not isResetOk) + if (!isResetOk) return; // Call SoftReset (and reset TWI device) first! + // Initialize interface auto ret = bma423_init(&bma); if (ret != BMA4_OK) return; + // Identify chip by ID. The driver code has been modified to handle BMA421 as BMA423 switch (bma.chip_id) { case BMA423_CHIP_ID: deviceType = DeviceTypes::BMA421; @@ -54,14 +57,12 @@ void Bma421::Init() { break; } + // Load proprietary firmware blob required for step counting engine ret = bma423_write_config_file(&bma); if (ret != BMA4_OK) return; - ret = bma4_set_interrupt_mode(BMA4_LATCH_MODE, &bma); - if (ret != BMA4_OK) - return; - + // Enable step counter and accelerometer, disable step detector ret = bma423_feature_enable(BMA423_STEP_CNTR, 1, &bma); if (ret != BMA4_OK) return; @@ -74,11 +75,21 @@ void Bma421::Init() { if (ret != BMA4_OK) return; + // Configure FIFO + ret = bma4_set_fifo_config(BMA4_FIFO_ACCEL, 1, &bma); + if (ret != BMA4_OK) + return; + fifo_frame.data = (uint8_t*) &fifo; + fifo_frame.length = sizeof(fifo); + fifo_frame.fifo_data_enable = BMA4_FIFO_A_ENABLE; + fifo_frame.fifo_header_enable = 0; + + // Configure accelerometer struct bma4_accel_config accel_conf; - accel_conf.odr = BMA4_OUTPUT_DATA_RATE_100HZ; + accel_conf.odr = BMA4_OUTPUT_DATA_RATE_200HZ; accel_conf.range = BMA4_ACCEL_RANGE_2G; accel_conf.bandwidth = BMA4_ACCEL_NORMAL_AVG4; - accel_conf.perf_mode = BMA4_CIC_AVG_MODE; + accel_conf.perf_mode = BMA4_CONTINUOUS_MODE; ret = bma4_set_accel_config(&accel_conf, &bma); if (ret != BMA4_OK) return; @@ -102,22 +113,42 @@ void Bma421::Write(uint8_t registerAddress, const uint8_t* data, size_t size) { Bma421::Values Bma421::Process() { if (not isOk) return {}; - struct bma4_accel data; - bma4_read_accel_xyz(&data, &bma); + // Dump entire FIFO into buffer + bma4_read_fifo_data(&fifo_frame, &bma); + // Decode FIFO frames in-place sequentially + uint16_t length = 32; // Should be about 20 (200 Hz ODR / 10 Hz main loop) + bma4_extract_accel((bma4_accel*) fifo, &length, &fifo_frame, &bma); + + // Read step counter engine uint32_t steps = 0; bma423_step_counter_output(&steps, &bma); - int32_t temperature; + // Read temperature sensor + int32_t temperature = 0; bma4_get_temperature(&temperature, BMA4_DEG, &bma); temperature = temperature / 1000; + // Read sport activity mode uint8_t activity = 0; bma423_activity_output(&activity, &bma); - // X and Y axis are swapped because of the way the sensor is mounted in the PineTime - return {steps, data.y, data.x, data.z}; + // Compute averages of FIFO + int16_t avgs[3] = {0}; + for (uint8_t i = 0; i < length; i++) { + // X and Y axis are swapped because of the way the sensor is mounted in the PineTime + int16_t swap = fifo[i][0]; + fifo[i][0] = fifo[i][1]; + fifo[i][1] = swap; + for (uint8_t j = 0; j < 3; j++) + avgs[j] += fifo[i][j]; + } + for (uint8_t j = 0; j < 3; j++) + avgs[j] /= length; + + return {steps, avgs[0], avgs[1], avgs[2]}; } + bool Bma421::IsOk() const { return isOk; } diff --git a/src/drivers/Bma421.h b/src/drivers/Bma421.h index ac5c707ffc..9345227245 100644 --- a/src/drivers/Bma421.h +++ b/src/drivers/Bma421.h @@ -38,6 +38,8 @@ namespace Pinetime { TwiMaster& twiMaster; uint8_t deviceAddress = 0x18; struct bma4_dev bma; + struct bma4_fifo_frame fifo_frame; + int16_t fifo[32][3] = {0}; bool isOk = false; bool isResetOk = false; DeviceTypes deviceType = DeviceTypes::Unknown; From de0fa1488b9ccb9a86a4d464200dcf46987922d4 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Tue, 10 May 2022 22:58:35 +0200 Subject: [PATCH 02/12] LVGL: Add SetNewTap to generate tap events This function sends a tap down and tap up event to LVGL, despite being called only once. --- src/displayapp/DummyLittleVgl.h | 2 ++ src/displayapp/LittleVgl.cpp | 14 ++++++++++++++ src/displayapp/LittleVgl.h | 2 ++ 3 files changed, 18 insertions(+) diff --git a/src/displayapp/DummyLittleVgl.h b/src/displayapp/DummyLittleVgl.h index 05355a9730..cf105cc504 100644 --- a/src/displayapp/DummyLittleVgl.h +++ b/src/displayapp/DummyLittleVgl.h @@ -33,6 +33,8 @@ namespace Pinetime { } void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) { } + void SetNewTap(uint16_t x, uint16_t y) { + } }; } } diff --git a/src/displayapp/LittleVgl.cpp b/src/displayapp/LittleVgl.cpp index d5f31848c4..75e069c524 100644 --- a/src/displayapp/LittleVgl.cpp +++ b/src/displayapp/LittleVgl.cpp @@ -180,6 +180,14 @@ void LittleVgl::SetNewTouchPoint(uint16_t x, uint16_t y, bool contact) { tap_x = x; tap_y = y; tapped = contact; + simulate_tap_release = false; +} + +void LittleVgl::SetNewTap(uint16_t x, uint16_t y) { + tap_x = x; + tap_y = y; + tapped = true; + simulate_tap_release = true; } bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) { @@ -187,6 +195,12 @@ bool LittleVgl::GetTouchPadInfo(lv_indev_data_t* ptr) { ptr->point.y = tap_y; if (tapped) { ptr->state = LV_INDEV_STATE_PR; + if (simulate_tap_release) { + // If a tap consists of only a single event, enqueue a synthetic release state update + tapped = false; + simulate_tap_release = false; + return true; + } } else { ptr->state = LV_INDEV_STATE_REL; } diff --git a/src/displayapp/LittleVgl.h b/src/displayapp/LittleVgl.h index 4582616533..e35da7fbbb 100644 --- a/src/displayapp/LittleVgl.h +++ b/src/displayapp/LittleVgl.h @@ -25,6 +25,7 @@ namespace Pinetime { bool GetTouchPadInfo(lv_indev_data_t* ptr); void SetFullRefresh(FullRefreshDirections direction); void SetNewTouchPoint(uint16_t x, uint16_t y, bool contact); + void SetNewTap(uint16_t x, uint16_t y); bool GetFullRefresh() { bool returnValue = fullRefresh; @@ -62,6 +63,7 @@ namespace Pinetime { uint16_t tap_x = 0; uint16_t tap_y = 0; bool tapped = false; + bool simulate_tap_release = false; }; } } From 6f1b5023eee581d20f750c3982b9dc93aa6fb4c2 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Tue, 10 May 2022 23:05:23 +0200 Subject: [PATCH 03/12] CST816S: Add register description header file --- src/CMakeLists.txt | 1 + src/drivers/Cst816s_registers.h | 162 ++++++++++++++++++++++++++++++++ 2 files changed, 163 insertions(+) create mode 100644 src/drivers/Cst816s_registers.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e59c0d814b..2748ceb23d 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -656,6 +656,7 @@ set(INCLUDE_FILES components/timer/TimerController.h components/alarm/AlarmController.h drivers/Cst816s.h + drivers/Cst816s_registers.h FreeRTOS/portmacro.h FreeRTOS/portmacro_cmsis.h libs/date/include/date/tz.h diff --git a/src/drivers/Cst816s_registers.h b/src/drivers/Cst816s_registers.h new file mode 100644 index 0000000000..edec944fde --- /dev/null +++ b/src/drivers/Cst816s_registers.h @@ -0,0 +1,162 @@ +#pragma once + +// CST816(S) / CST716 High-performance self-capacitive touch chip +// Hynitron, www.hynitron.com + +// Manually assembled from auto-translated incomplete datasheets and documents. + +// The device contains an embedded firmware, behaviour may differ. +// Code fragments on how to update the internal firmware exist, but not much is know about +// the internal architecture. No verified compatible binary firmware has been found yet. + +// The "S" suffix stands for speed, i.e. double the sample rate (>100 Hz instead of ~50 Hz (?)). + +// The CST816S has an auto-sleep low-power mode, from which it can wake via a touch event. +// In low-power sleep, the I2C interface is inactive. +// It sends a gesture event while the gesture is still being performed. + +// The CST716 has no auto-sleep functionality, and sends a gesture event after the gesture has been completed. +// Its I2C interface is always active, as it stays in normal mode. + +// Both chips are able to enter a deep-sleep mode, from which they can only wake via a signal on the reset pin. + +// Registers + +// * = Works only on chips which have not been preconfigured (fused) in the factory. +// CST716 are probably always fused, default: reporting mode. +// CST816S can be reconfigureable, but can be fused as well. Some fused ones report with a CST716 chip ID. + +// ** = Auto-sleep related registers. Only on the CST816S. + +#define DEV_MODE 0x00 // readonly. Always 0. +#define GESTURE_ID 0x01 // readonly. Which gesture was detected. +#define TD_STATUS 0x02 // readonly. Number of touch points. (0 - 2). + +#define P1_X_POS_H 0x03 // readonly. Point 1: X touch event flag + X touch coordinate MSB. +#define P1_X_POS_L 0x04 // readonly. Point 1: X touch coordinate LSB. +#define P1_Y_POS_H 0x05 // readonly. Point 1: Y touch event flag + Y touch coordinate MSB. +#define P1_Y_POS_L 0x06 // readonly. Point 1: Y touch coordinate LSB. +#define P1_WEIGHT 0x07 // readonly. Point 1: Touch weight. +#define P1_MISC 0x08 // readonly. Point 1: Touch area. + +#define P2_X_POS_H 0x09 // readonly. Point 2: X touch event flag + X touch coordinate MSB. +#define P2_X_POS_L 0x0A // readonly. Point 2: X touch coordinate LSB. +#define P2_Y_POS_H 0x0B // readonly. Point 2: Y touch event flag + Y touch coordinate MSB. +#define P2_Y_POS_L 0x0C // readonly. Point 2: Y touch coordinate LSB. +#define P2_WEIGHT 0x0D // readonly. Point 2: Touch weight. +#define P2_MISC 0x0E // readonly. Point 2: Touch area. + +#define BPC0_H 0xB0 // unknown. BPC0 value MSB. +#define BPC0_L 0xB1 // unknown. BPC0 value LSB. +#define BPC1_H 0xB2 // unknown. BPC1 value MSB. +#define BPC1_L 0xB3 // unknown. BPC1 value LSB. + +#define CHIP_ID 0xA7 // readonly. Chip / firmware type ID. +#define PROJ_ID 0xA8 // readonly. Vendor / project ID. +#define FW_VERSION 0xA9 // readonly. Firmware version. + +#define MOTION_MASK 0xEC // read-write*. Motion configuration. +#define IRQ_PULSE_WIDTH 0xED // read-write. Interrupt low pulse output width. Unit 0.1ms, possible value: 1~200. The default value is 10. +// read-write. Normal fast detection cycle. This value affects LpAutoWakeTime and AutoSleepTime. Unit 10ms, possible value: 1~30. The +// default value is 1. +#define NOR_SCAN_PER 0xEE +// read-write. Gesture detection sliding partition angle control. Angle=tan(c)*10. c is the angle based on the positive direction of +// the x-axis. +#define MOTION_S1_ANGLE 0xEF + +#define LP_SCAN_RAW1_H 0xF0 // readonly**. Low power scan, MSB of the reference value of channel 1. +#define LP_SCAN_RAW1_L 0xF1 // readonly**. Low power scan, LSB of the reference value of channel 1. +#define LP_SCAN_RAW2_H 0xF2 // readonly**. Low power scan, MSB of the reference value of channel 2. +#define LP_SCAN_RAW2_L 0xF3 // readonly**. Low power scan, LSB of the reference value of channel 2. +// read-write**. Automatic recalibration cycle in low power mode. The unit is 1 minute, and the possible value is 1 to 5. The default +// value is 5. +#define LP_AUTO_WAKE_TIME 0xF4 +// read-write**. Low-power scan wake-up threshold. The smaller the more sensitive. Possible values: 1 to 255. The default value +// is 48. +#define LP_SCAN_TH 0xF5 +// read-write**. Low power scan range. The larger the more sensitive, the higher the power consumption. Possible values: 0, 1, 2, 3. +// The default value is 3. +#define LP_SCAN_WIN 0xF6 +// read-write**. Low power scan frequency. The smaller the more sensitive. Possible values: 1 to 255. The default value is 7. +#define LP_SCAN_FREQ 0xF7 +#define LP_SCAN_I_DAC 0xF8 // read-write**. Low power scan current. The smaller the more sensitive. Possible values: 1 to 255. +// read-write**. Automatically enter low power mode when there is no touch for x seconds. The unit is 1s, the default value is 2. +#define AUTO_SLEEP_TIME 0xF9 +// read-write*. Interrupt configuration. 0x60 = report mode, 0x11 = gesture mode, 0x71 = both. +#define IRQ_CTL 0xFA +// read-write. Automatic reset (cancel) when there is a touch but no valid gesture within x seconds. The unit is 1s. When it is 0, +// this function is not enabled. Default is 5. +#define AUTO_RESET 0xFB +// read-write. Automatic reset (cancel) after long press for x seconds. The unit is 1s. When it is 0, this function is not enabled. +// Default is 10. +#define LONG_PRESS_TIME 0xFC +// read-write. Pin IO configuration. +#define IO_CTL 0xFD +// read-write**. The default is 0, enabling automatic entry into low power mode. When it is a non-zero value, automatic entry into +// low power mode is disabled. +#define DIS_AUTO_SLEEP 0xFE + +#define PWR_MODE_CST816S 0xE5 // read-write. Power state for the CST816S. +#define PWR_MODE_CST716 0xA5 // read-write. Power state for the CST716. + +// Data fields + +// GESTURE_ID + +#define GESTURE_ID_NONE 0x00 +#define GESTURE_ID_SLIDE_DOWN 0x01 +#define GESTURE_ID_SLIDE_UP 0x02 +#define GESTURE_ID_SLIDE_LEFT 0x03 +#define GESTURE_ID_SLIDE_RIGHT 0x04 +#define GESTURE_ID_SINGLE_TAP 0x05 +#define GESTURE_ID_DOUBLE_TAP 0x0B +#define GESTURE_ID_LONG_PRESS 0x0C + +// TD_STATUS + +#define TD_STATUS_MASK 0x0F + +// *_POS_H + +#define POS_H_POS_MASK 0x0F + +#define POS_H_EVENT_MASK 0xC0 +#define POS_H_EVENT0 (1 << 6) +#define POS_H_EVENT1 (1 << 7) + +#define POS_H_EVENT_DOWN (0 << 6) +#define POS_H_EVENT_UP (1 << 6) +#define POS_H_EVENT_CONTACT (2 << 6) +#define POS_H_EVENT_NONE (3 << 6) + +// CHIP_ID + +#define CHIP_ID_CST816S 0xB4 +#define CHIP_ID_CST716 0x20 + +// Control register configurations + +// MOTION_MASK + +#define MOTION_MASK_EN_DCLICK (1 << 0) // Enable double click action +#define MOTION_MASK_EN_CON_UD (1 << 1) // Enable continuous up-down sliding action +#define MOTION_MASK_EN_CON_LR (1 << 2) // Enable continuous left-right sliding action + +// IRQ_CTL + +#define IRQ_CTL_ONCE_WLP (1 << 0) // The long press gesture only emits a low pulse signal. +#define IRQ_CTL_EN_MOTION (1 << 4) // When a gesture is detected, a low pulse is emitted. +#define IRQ_CTL_EN_CHANGE (1 << 5) // A low pulse is emitted when a touch state change is detected. +#define IRQ_CTL_EN_TOUCH (1 << 6) // Periodically emit low pulses when a touch is detected. +#define IRQ_CTL_EN_TEST (1 << 7) // Interrupt pin test, automatically and periodically send low pulses after enabling. + +// IO_CTL + +#define IO_CTL_EN_1V8 (1 << 0) // I2C and IRQ pin voltage level selection, the default is VDD level. 0: VDD, 1: 1.8V. +#define IO_CTL_IIC_OD (1 << 1) // I2C pin drive mode, the default is resistor pull-up. 0: Resistor pull-up 1: OD. +#define IO_CTL_SOFT_RST (1 << 2) // Enable soft reset by pulling down the IRQ pin. 0: Soft reset is disabled. 1: Enable soft reset. + +// PWR_MODE_* + +#define PWR_MODE_ACTIVE 0x00 // Normal state of execution +#define PWR_MODE_DEEP_SLEEP 0x03 // Deep-sleep mode. Touch to wakeup and I2C are disabled. From 48123d94a31505f4fb3f2a23a8d99f45d9058cd1 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Tue, 10 May 2022 23:12:28 +0200 Subject: [PATCH 04/12] Add CST716 touch support and fused mode support The P8 smartwatches use the CST716 or CST816S chips in various modes. The device ID of these chips cannot be used for runtime detection, because it does not give the hardware revision / firmware configuration. --- src/CMakeLists.txt | 5 + src/drivers/Cst816s.cpp | 151 +++++++++++++----------------- src/drivers/Cst816s.h | 35 +++---- src/systemtask/SystemTask.cpp | 8 +- src/touchhandler/TouchHandler.cpp | 38 +++++++- 5 files changed, 123 insertions(+), 114 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 2748ceb23d..0b6b2a3f7b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -799,23 +799,28 @@ add_definitions(-DTARGET_DEVICE_NAME="${TARGET_DEVICE}") if(TARGET_DEVICE STREQUAL "PINETIME") add_definitions(-DDRIVER_PINMAP_PINETIME) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_TOUCH_DYNAMIC) elseif(TARGET_DEVICE STREQUAL "MOY-TFK5") # P8a add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_TOUCH_GESTURE) elseif(TARGET_DEVICE STREQUAL "MOY-TIN5") # P8a variant 2 add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_TOUCH_GESTURE) elseif(TARGET_DEVICE STREQUAL "MOY-TON5") # P8b add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) + add_definitions(-DDRIVER_TOUCH_REPORT) elseif(TARGET_DEVICE STREQUAL "MOY-UNK") # P8b mirrored add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) add_definitions(-DDRIVER_DISPLAY_MIRROR) + add_definitions(-DDRIVER_TOUCH_REPORT) else() message(FATAL_ERROR "Invalid TARGET_DEVICE") endif() diff --git a/src/drivers/Cst816s.cpp b/src/drivers/Cst816s.cpp index cf10c895f5..4fba71d135 100644 --- a/src/drivers/Cst816s.cpp +++ b/src/drivers/Cst816s.cpp @@ -1,108 +1,103 @@ #include "drivers/Cst816s.h" +#include "drivers/PinMap.h" #include #include #include #include -#include "drivers/PinMap.h" using namespace Pinetime::Drivers; -/* References : +/* + * References : * This implementation is based on this article : * https://medium.com/@ly.lee/building-a-rust-driver-for-pinetimes-touch-controller-cbc1a5d5d3e9 Touch panel datasheet (weird chinese * translation) : https://wiki.pine64.org/images/5/51/CST816S%E6%95%B0%E6%8D%AE%E6%89%8B%E5%86%8CV1.1.en.pdf * - * TODO : we need a complete datasheet and protocol reference! + * TODO: We need a complete datasheet and protocol reference! + * For register desciptions, see Cst816s_registers.h. Information was collected from various chinese datasheets and documents. * */ Cst816S::Cst816S(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} { } bool Cst816S::Init() { + // Reset the touch driver nrf_gpio_cfg_output(PinMap::Cst816sReset); nrf_gpio_pin_clear(PinMap::Cst816sReset); - vTaskDelay(5); + vTaskDelay(10); nrf_gpio_pin_set(PinMap::Cst816sReset); vTaskDelay(50); - // Wake the touchpanel up - uint8_t dummy; - twiMaster.Read(twiAddress, 0x15, &dummy, 1); - vTaskDelay(5); - twiMaster.Read(twiAddress, 0xa7, &dummy, 1); - vTaskDelay(5); - - // TODO This function check that the device IDs from the controller are equal to the ones - // we expect. However, it seems to return false positive (probably in case of communication issue). - // Also, it seems that some users have pinetimes that works correctly but that report different device IDs - // Until we know more about this, we'll just read the IDs but not take any action in case they are not 'valid' - CheckDeviceIds(); - - /* - [2] EnConLR - Continuous operation can slide around - [1] EnConUD - Slide up and down to enable continuous operation - [0] EnDClick - Enable Double-click action - */ - static constexpr uint8_t motionMask = 0b00000101; - twiMaster.Write(twiAddress, 0xEC, &motionMask, 1); - - /* - [7] EnTest - Interrupt pin to test, enable automatic periodic issued after a low pulse. - [6] EnTouch - When a touch is detected, a periodic pulsed Low. - [5] EnChange - Upon detecting a touch state changes, pulsed Low. - [4] EnMotion - When the detected gesture is pulsed Low. - [0] OnceWLP - Press gesture only issue a pulse signal is low. - */ - static constexpr uint8_t irqCtl = 0b01110000; - twiMaster.Write(twiAddress, 0xFA, &irqCtl, 1); + // Chip ID is suspected to be dependent on embedded firmware and factory configuration, + // and not (just) on hardware type and revision. + if (twiMaster.Read(twiAddress, CHIP_ID, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + chipId = 0xFF; + } + // Vendor / project ID and firmware version can vary between devices. + if (twiMaster.Read(twiAddress, PROJ_ID, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + vendorId = 0xFF; + } + if (twiMaster.Read(twiAddress, FW_VERSION, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) { + fwVersion = 0xFF; + } + + // These configuration settings will be ignored by chips which were + // fused / pre-configured in the factory (GESTURE and REPORT settings). + // This mainly applies to CST716, however there may be CST816S with static configurations as well. + // The other, freely configureable ones (DYNAMIC), are configured in reporting mode here. + + // Configure motion behaviour + static constexpr uint8_t motionMask = MOTION_MASK_EN_DCLICK | MOTION_MASK_EN_CON_UD | MOTION_MASK_EN_CON_LR; + twiMaster.Write(twiAddress, MOTION_MASK, &motionMask, 1); + + // Configure interrupt generating events + static constexpr uint8_t irqCtl = IRQ_CTL_EN_MOTION | IRQ_CTL_EN_CHANGE | IRQ_CTL_EN_TOUCH; + twiMaster.Write(twiAddress, IRQ_CTL, &irqCtl, 1); return true; } Cst816S::TouchInfos Cst816S::GetTouchInfo() { - Cst816S::TouchInfos info; - uint8_t touchData[7]; - - auto ret = twiMaster.Read(twiAddress, 0, touchData, sizeof(touchData)); - if (ret != TwiMaster::ErrorCodes::NoError) { - info.isValid = false; - return info; + // Some chips fail to wake up even though the reset pin has been toggled. + // They only provide an I2C communication window after a touch interrupt, + // so the first touch interrupt is used to force initialisation. + if (firstEvent) { + Init(); + firstEvent = false; + // The data registers should now be reset, so this touch event will be detected as invalid. } - // This can only be 0 or 1 - uint8_t nbTouchPoints = touchData[touchPointNumIndex] & 0x0f; - uint8_t xHigh = touchData[touchXHighIndex] & 0x0f; - uint8_t xLow = touchData[touchXLowIndex]; - uint16_t x = (xHigh << 8) | xLow; - uint8_t yHigh = touchData[touchYHighIndex] & 0x0f; - uint8_t yLow = touchData[touchYLowIndex]; - uint16_t y = (yHigh << 8) | yLow; - Gestures gesture = static_cast(touchData[gestureIndex]); - - // Validity check - if (x >= maxX || y >= maxY || - (gesture != Gestures::None && gesture != Gestures::SlideDown && gesture != Gestures::SlideUp && gesture != Gestures::SlideLeft && - gesture != Gestures::SlideRight && gesture != Gestures::SingleTap && gesture != Gestures::DoubleTap && - gesture != Gestures::LongPress)) { - info.isValid = false; + // Read gesture metadata and first touch point coordinate block + Cst816S::TouchInfos info; + uint8_t touchData[P1_Y_POS_L + 1]; + auto ret = twiMaster.Read(twiAddress, 0x00, touchData, sizeof(touchData)); + if (ret != TwiMaster::ErrorCodes::NoError) return info; - } - info.x = x; - info.y = y; - info.touching = (nbTouchPoints > 0); - info.gesture = gesture; - info.isValid = true; + // Assemble 12 bit point coordinates from lower 8 bits and higher 4 bits + info.x = ((touchData[P1_X_POS_H] & POS_H_POS_MASK) << 8) | touchData[P1_X_POS_L]; + info.y = ((touchData[P1_Y_POS_H] & POS_H_POS_MASK) << 8) | touchData[P1_Y_POS_L]; + // Evaluate number of touch points + info.touching = (touchData[TD_STATUS] & TD_STATUS_MASK) > 0; + // Decode gesture ID + info.gesture = static_cast(touchData[GESTURE_ID]); + + // Validity check, verify value ranges + info.isValid = (info.x < maxX && info.y < maxY && + (info.gesture == Gestures::None || info.gesture == Gestures::SlideDown || info.gesture == Gestures::SlideUp || + info.gesture == Gestures::SlideLeft || info.gesture == Gestures::SlideRight || info.gesture == Gestures::SingleTap || + info.gesture == Gestures::DoubleTap || info.gesture == Gestures::LongPress)); + return info; } void Cst816S::Sleep() { - nrf_gpio_pin_clear(PinMap::Cst816sReset); - vTaskDelay(5); - nrf_gpio_pin_set(PinMap::Cst816sReset); - vTaskDelay(50); - static constexpr uint8_t sleepValue = 0x03; - twiMaster.Write(twiAddress, 0xA5, &sleepValue, 1); + // This only controls the CST716, the CST816S will ignore this register. + // The CST816S power state is managed using auto-sleep. + + static constexpr uint8_t sleepValue = PWR_MODE_DEEP_SLEEP; + twiMaster.Write(twiAddress, PWR_MODE_CST716, &sleepValue, 1); + NRF_LOG_INFO("[TOUCHPANEL] Sleep"); } @@ -110,21 +105,3 @@ void Cst816S::Wakeup() { Init(); NRF_LOG_INFO("[TOUCHPANEL] Wakeup"); } - -bool Cst816S::CheckDeviceIds() { - // There's mixed information about which register contains which information - if (twiMaster.Read(twiAddress, 0xA7, &chipId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { - chipId = 0xFF; - return false; - } - if (twiMaster.Read(twiAddress, 0xA8, &vendorId, 1) == TwiMaster::ErrorCodes::TransactionFailed) { - vendorId = 0xFF; - return false; - } - if (twiMaster.Read(twiAddress, 0xA9, &fwVersion, 1) == TwiMaster::ErrorCodes::TransactionFailed) { - fwVersion = 0xFF; - return false; - } - - return chipId == 0xb4 && vendorId == 0 && fwVersion == 1; -} diff --git a/src/drivers/Cst816s.h b/src/drivers/Cst816s.h index 9d426c9db9..fde7149f04 100644 --- a/src/drivers/Cst816s.h +++ b/src/drivers/Cst816s.h @@ -1,5 +1,6 @@ #pragma once +#include "drivers/Cst816s_registers.h" #include "drivers/TwiMaster.h" namespace Pinetime { @@ -7,14 +8,15 @@ namespace Pinetime { class Cst816S { public: enum class Gestures : uint8_t { - None = 0x00, - SlideDown = 0x01, - SlideUp = 0x02, - SlideLeft = 0x03, - SlideRight = 0x04, - SingleTap = 0x05, - DoubleTap = 0x0B, - LongPress = 0x0C + None = GESTURE_ID_NONE, + SlideDown = GESTURE_ID_SLIDE_DOWN, + SlideUp = GESTURE_ID_SLIDE_UP, + SlideLeft = GESTURE_ID_SLIDE_LEFT, + SlideRight = GESTURE_ID_SLIDE_RIGHT, + SingleTap = GESTURE_ID_SINGLE_TAP, + DoubleTap = GESTURE_ID_DOUBLE_TAP, + LongPress = GESTURE_ID_LONG_PRESS, + Invalid = 0xFF }; struct TouchInfos { uint16_t x = 0; @@ -46,21 +48,6 @@ namespace Pinetime { } private: - bool CheckDeviceIds(); - - // Unused/Unavailable commented out - static constexpr uint8_t gestureIndex = 1; - static constexpr uint8_t touchPointNumIndex = 2; - // static constexpr uint8_t touchEventIndex = 3; - static constexpr uint8_t touchXHighIndex = 3; - static constexpr uint8_t touchXLowIndex = 4; - // static constexpr uint8_t touchIdIndex = 5; - static constexpr uint8_t touchYHighIndex = 5; - static constexpr uint8_t touchYLowIndex = 6; - // static constexpr uint8_t touchStep = 6; - // static constexpr uint8_t touchXYIndex = 7; - // static constexpr uint8_t touchMiscIndex = 8; - static constexpr uint8_t maxX = 240; static constexpr uint8_t maxY = 240; @@ -70,6 +57,8 @@ namespace Pinetime { uint8_t chipId; uint8_t vendorId; uint8_t fwVersion; + + bool firstEvent = true; }; } diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index ef631af74e..4f58ea6d73 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -377,7 +377,13 @@ void SystemTask::Work() { // Double Tap needs the touch screen to be in normal mode if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::DoubleTap)) { - touchPanel.Sleep(); +// REPORT and GESTURE mode sensors must be normal mode for single tap as well +#if !defined(DRIVER_TOUCH_DYNAMIC) + if (!settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::SingleTap)) +#endif + { + touchPanel.Sleep(); + } } state = SystemTaskState::Sleeping; diff --git a/src/touchhandler/TouchHandler.cpp b/src/touchhandler/TouchHandler.cpp index 0e4fb5414a..8fef817d7d 100644 --- a/src/touchhandler/TouchHandler.cpp +++ b/src/touchhandler/TouchHandler.cpp @@ -50,11 +50,36 @@ Pinetime::Applications::TouchEvents TouchHandler::GestureGet() { bool TouchHandler::GetNewTouchInfo() { info = touchPanel.GetTouchInfo(); - - if (!info.isValid) { + if (!info.isValid) return false; - } + // REPORT configurations (P8b variants) of the fused (usually) Cst716 + // generate multiple "none" gesture events with info.touching == true during the physical gesture. + // The last event is a e.g. "slide" event with info.touching == true. + // gestureReleased state does not have to be computed manually, instead it occurs when event != "none". + + // GESTURE configurations (P8a variants) of the fused (usually) Cst716 generate no events during the physical gesture. + // The only event is a e.g. "slide" event with info.touching == true. + // gestureReleased state does not have to be computed manually, instead it occurs everytime. + + // DYNAMIC configurations (PineTime) are configured in reporting mode during initialisation. + // Usually based on the Cst816s, they generate multiple e.g. "slide" gesture events with info.touching == true during the physical + // gesture. The last of these e.g. "slide" events has info.touching == false. gestureReleased state is computed manually by checking for + // the transition to info.touching == false. + + // Unfortunately, there is no way to reliably obtain which configuration is used at runtime. + // In all cases, the event is bubbled up once the gesture is released. + +#if defined(DRIVER_TOUCH_REPORT) + if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { + gesture = ConvertGesture(info.gesture); + info.touching = false; + } +#elif defined(DRIVER_TOUCH_GESTURE) + if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { + gesture = ConvertGesture(info.gesture); + } +#elif defined(DRIVER_TOUCH_DYNAMIC) if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { if (gestureReleased) { if (info.gesture == Pinetime::Drivers::Cst816S::Gestures::SlideDown || @@ -75,15 +100,22 @@ bool TouchHandler::GetNewTouchInfo() { if (!info.touching) { gestureReleased = true; } +#endif return true; } void TouchHandler::UpdateLvglTouchPoint() { if (info.touching) { +#if defined(DRIVER_TOUCH_GESTURE) + // GESTURE config only generates a single event / state change + // so the LVGL wrapper is used to generate a successive release state update + lvgl.SetNewTap(info.x, info.y); +#else if (!isCancelled) { lvgl.SetNewTouchPoint(info.x, info.y, true); } +#endif } else { if (isCancelled) { lvgl.SetNewTouchPoint(-1, -1, false); From 1d92f8e72a07448c4a78767d48395f1f710ce9f3 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Tue, 10 May 2022 23:55:47 +0200 Subject: [PATCH 05/12] Acceleration: Abstract sensors into common interface The AccelerationSensor base class provides a unified interface to access both the BMA421 as well as the SC7A20 chip. --- src/CMakeLists.txt | 3 ++ src/components/motion/MotionController.cpp | 17 +++----- src/components/motion/MotionController.h | 12 ++---- src/displayapp/screens/SystemInfo.cpp | 10 +++-- src/drivers/AccelerationSensor.cpp | 39 ++++++++++++++++++ src/drivers/AccelerationSensor.h | 47 ++++++++++++++++++++++ src/main.cpp | 14 ++++++- src/systemtask/SystemTask.cpp | 4 +- src/systemtask/SystemTask.h | 6 +-- 9 files changed, 120 insertions(+), 32 deletions(-) create mode 100644 src/drivers/AccelerationSensor.cpp create mode 100644 src/drivers/AccelerationSensor.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e59c0d814b..439a240981 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -443,6 +443,7 @@ list(APPEND SOURCE_FILES drivers/DebugPins.cpp drivers/InternalFlash.cpp drivers/Hrs3300.cpp + drivers/AccelerationSensor.cpp drivers/Bma421.cpp drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c @@ -510,6 +511,7 @@ list(APPEND RECOVERY_SOURCE_FILES drivers/DebugPins.cpp drivers/InternalFlash.cpp drivers/Hrs3300.cpp + drivers/AccelerationSensor.cpp drivers/Bma421.cpp drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c @@ -626,6 +628,7 @@ set(INCLUDE_FILES drivers/InternalFlash.h drivers/Hrs3300.h drivers/PinMap.h + drivers/AccelerationSensor.h drivers/Bma421.h drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp index 7dd321271c..19b239c206 100644 --- a/src/components/motion/MotionController.cpp +++ b/src/components/motion/MotionController.cpp @@ -62,6 +62,7 @@ bool MotionController::Should_ShakeWake(uint16_t thresh) { lastZForShake = z; return wake; } + int32_t MotionController::currentShakeSpeed() { return accumulatedspeed; } @@ -69,19 +70,11 @@ int32_t MotionController::currentShakeSpeed() { void MotionController::IsSensorOk(bool isOk) { isSensorOk = isOk; } -void MotionController::Init(Pinetime::Drivers::Bma421::DeviceTypes types) { - switch (types) { - case Drivers::Bma421::DeviceTypes::BMA421: - this->deviceType = DeviceTypes::BMA421; - break; - case Drivers::Bma421::DeviceTypes::BMA425: - this->deviceType = DeviceTypes::BMA425; - break; - default: - this->deviceType = DeviceTypes::Unknown; - break; - } + +void MotionController::Init(Pinetime::Drivers::AccelerationDeviceTypes types) { + this->deviceType = types; } + void MotionController::SetService(Pinetime::Controllers::MotionService* service) { this->service = service; } diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index f80b11b994..4ddc1af8bc 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -8,12 +8,6 @@ namespace Pinetime { namespace Controllers { class MotionController { public: - enum class DeviceTypes { - Unknown, - BMA421, - BMA425, - }; - void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps); int16_t X() const { @@ -44,11 +38,11 @@ namespace Pinetime { return isSensorOk; } - DeviceTypes DeviceType() const { + Pinetime::Drivers::AccelerationDeviceTypes DeviceType() const { return deviceType; } - void Init(Pinetime::Drivers::Bma421::DeviceTypes types); + void Init(Pinetime::Drivers::AccelerationDeviceTypes types); void SetService(Pinetime::Controllers::MotionService* service); private: @@ -59,7 +53,7 @@ namespace Pinetime { int16_t z; int16_t lastYForWakeUp = 0; bool isSensorOk = false; - DeviceTypes deviceType = DeviceTypes::Unknown; + Pinetime::Drivers::AccelerationDeviceTypes deviceType = Pinetime::Drivers::AccelerationDeviceTypes::Unknown; Pinetime::Controllers::MotionService* service = nullptr; int16_t lastXForShake = 0; diff --git a/src/displayapp/screens/SystemInfo.cpp b/src/displayapp/screens/SystemInfo.cpp index 01c351955e..eaf33c688d 100644 --- a/src/displayapp/screens/SystemInfo.cpp +++ b/src/displayapp/screens/SystemInfo.cpp @@ -17,13 +17,15 @@ using namespace Pinetime::Applications::Screens; namespace { - const char* ToString(const Pinetime::Controllers::MotionController::DeviceTypes deviceType) { + const char* ToString(const Pinetime::Drivers::AccelerationDeviceTypes deviceType) { switch (deviceType) { - case Pinetime::Controllers::MotionController::DeviceTypes::BMA421: + case Pinetime::Drivers::AccelerationDeviceTypes::BMA421: return "BMA421"; - case Pinetime::Controllers::MotionController::DeviceTypes::BMA425: + case Pinetime::Drivers::AccelerationDeviceTypes::BMA425: return "BMA425"; - case Pinetime::Controllers::MotionController::DeviceTypes::Unknown: + case Pinetime::Drivers::AccelerationDeviceTypes::SC7A20: + return "SC7A20"; + case Pinetime::Drivers::AccelerationDeviceTypes::Unknown: return "???"; } return "???"; diff --git a/src/drivers/AccelerationSensor.cpp b/src/drivers/AccelerationSensor.cpp new file mode 100644 index 0000000000..c0d2bda168 --- /dev/null +++ b/src/drivers/AccelerationSensor.cpp @@ -0,0 +1,39 @@ +#include "AccelerationSensor.h" + +namespace Pinetime { + namespace Drivers { + + AccelerationSensor::AccelerationSensor(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster(twiMaster), deviceAddress(twiAddress) { + } + + void AccelerationSensor::SoftReset() { + } + + void AccelerationSensor::Init() { + } + + AccelerationValues AccelerationSensor::Process() { + return {0}; + } + + void AccelerationSensor::ResetStepCounter() { + } + + void AccelerationSensor::Read(uint8_t registerAddress, uint8_t* buffer, size_t size) { + twiMaster.Read(deviceAddress, registerAddress, buffer, size); + } + + void AccelerationSensor::Write(uint8_t registerAddress, const uint8_t* data, size_t size) { + twiMaster.Write(deviceAddress, registerAddress, data, size); + } + + AccelerationDeviceTypes AccelerationSensor::DeviceType() const { + return deviceType; + } + + bool AccelerationSensor::IsInitialized() const { + return isInitialized; + } + + } +} diff --git a/src/drivers/AccelerationSensor.h b/src/drivers/AccelerationSensor.h new file mode 100644 index 0000000000..428948c20f --- /dev/null +++ b/src/drivers/AccelerationSensor.h @@ -0,0 +1,47 @@ +#pragma once + +#include "drivers/TwiMaster.h" + +namespace Pinetime { + namespace Drivers { + + enum class AccelerationDeviceTypes : uint8_t { Unknown, BMA421, BMA425, SC7A20 }; + + struct AccelerationValues { + uint32_t steps; + int16_t x; + int16_t y; + int16_t z; + int16_t* samples = nullptr; + uint16_t samples_length = 0; + }; + + class AccelerationSensor { + public: + AccelerationSensor(TwiMaster& twiMaster, uint8_t twiAddress); + AccelerationSensor(const AccelerationSensor&) = delete; + AccelerationSensor& operator=(const AccelerationSensor&) = delete; + AccelerationSensor(AccelerationSensor&&) = delete; + AccelerationSensor& operator=(AccelerationSensor&&) = delete; + + virtual void SoftReset(); + virtual void Init(); + virtual AccelerationValues Process(); + virtual void ResetStepCounter(); + + void Read(uint8_t registerAddress, uint8_t* buffer, size_t size); + void Write(uint8_t registerAddress, const uint8_t* data, size_t size); + + bool IsInitialized() const; + AccelerationDeviceTypes DeviceType() const; + + protected: + TwiMaster& twiMaster; + uint8_t deviceAddress; + bool isInitialized = false; + AccelerationDeviceTypes deviceType = AccelerationDeviceTypes::Unknown; + int16_t fifo[32][3] = {0}; + }; + + } +} diff --git a/src/main.cpp b/src/main.cpp index ad7a07dc98..fddec544ac 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include "BootloaderVersion.h" #include "components/battery/BatteryController.h" @@ -58,7 +57,6 @@ Pinetime::Logging::DummyLogger logger; #endif static constexpr uint8_t touchPanelTwiAddress = 0x15; -static constexpr uint8_t motionSensorTwiAddress = 0x18; static constexpr uint8_t heartRateSensorTwiAddress = 0x44; Pinetime::Drivers::SpiMaster spi {Pinetime::Drivers::SpiMaster::SpiModule::SPI0, @@ -90,7 +88,19 @@ Pinetime::Drivers::Cst816S touchPanel {twiMaster, touchPanelTwiAddress}; #endif Pinetime::Components::LittleVgl lvgl {lcd, touchPanel}; +#if (defined DRIVER_ACC_SC7A20) +#include + static constexpr uint8_t motionSensorTwiAddress = 0x18; +Pinetime::Drivers::SC7A20 motionSensor {twiMaster, motionSensorTwiAddress}; +#else +// Assume DRIVER_ACC_BMA421, +// this is needed for the LVGL simulator, +// which does not set any target hardware configuration variables + #include +static constexpr uint8_t motionSensorTwiAddress = 0x18; Pinetime::Drivers::Bma421 motionSensor {twiMaster, motionSensorTwiAddress}; +#endif + Pinetime::Drivers::Hrs3300 heartRateSensor {twiMaster, heartRateSensorTwiAddress}; TimerHandle_t debounceTimer; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index ef631af74e..d86b6320b2 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -62,7 +62,7 @@ SystemTask::SystemTask(Drivers::SpiMaster& spi, Pinetime::Controllers::MotorController& motorController, Pinetime::Drivers::Hrs3300& heartRateSensor, Pinetime::Controllers::MotionController& motionController, - Pinetime::Drivers::Bma421& motionSensor, + Pinetime::Drivers::AccelerationSensor& motionSensor, Controllers::Settings& settingsController, Pinetime::Controllers::HeartRateController& heartRateController, Pinetime::Applications::DisplayApp& displayApp, @@ -483,7 +483,7 @@ void SystemTask::UpdateMotion() { auto motionValues = motionSensor.Process(); - motionController.IsSensorOk(motionSensor.IsOk()); + motionController.IsSensorOk(motionSensor.IsInitialized()); motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps); if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) { diff --git a/src/systemtask/SystemTask.h b/src/systemtask/SystemTask.h index d1e4a004f9..1439e3a80a 100644 --- a/src/systemtask/SystemTask.h +++ b/src/systemtask/SystemTask.h @@ -8,7 +8,7 @@ #include #include #include -#include +#include #include #include @@ -70,7 +70,7 @@ namespace Pinetime { Pinetime::Controllers::MotorController& motorController, Pinetime::Drivers::Hrs3300& heartRateSensor, Pinetime::Controllers::MotionController& motionController, - Pinetime::Drivers::Bma421& motionSensor, + Pinetime::Drivers::AccelerationSensor& motionSensor, Controllers::Settings& settingsController, Pinetime::Controllers::HeartRateController& heartRateController, Pinetime::Applications::DisplayApp& displayApp, @@ -115,7 +115,7 @@ namespace Pinetime { Pinetime::Controllers::NotificationManager& notificationManager; Pinetime::Controllers::MotorController& motorController; Pinetime::Drivers::Hrs3300& heartRateSensor; - Pinetime::Drivers::Bma421& motionSensor; + Pinetime::Drivers::AccelerationSensor& motionSensor; Pinetime::Controllers::Settings& settingsController; Pinetime::Controllers::HeartRateController& heartRateController; Pinetime::Controllers::MotionController& motionController; From 49da67a3137ccb67a9b24e29c067a972931ccb0e Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Tue, 10 May 2022 23:56:12 +0200 Subject: [PATCH 06/12] BMA421: Use AccelerationSensor base class --- src/drivers/Bma421.cpp | 53 +++++++++++++----------------------------- src/drivers/Bma421.h | 30 +++++------------------- 2 files changed, 22 insertions(+), 61 deletions(-) diff --git a/src/drivers/Bma421.cpp b/src/drivers/Bma421.cpp index 539cc8d1d3..043aef2b51 100644 --- a/src/drivers/Bma421.cpp +++ b/src/drivers/Bma421.cpp @@ -1,11 +1,9 @@ #include "drivers/Bma421.h" -#include -#include #include "drivers/TwiMaster.h" #include +#include using namespace Pinetime::Drivers; - namespace { int8_t user_i2c_read(uint8_t reg_addr, uint8_t* reg_data, uint32_t length, void* intf_ptr) { auto bma421 = static_cast(intf_ptr); @@ -24,7 +22,7 @@ namespace { } } -Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, deviceAddress {twiAddress} { +Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : AccelerationSensor(twiMaster, twiAddress) { bma.intf = BMA4_I2C_INTF; bma.bus_read = user_i2c_read; bma.bus_write = user_i2c_write; @@ -35,45 +33,44 @@ Bma421::Bma421(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster} } void Bma421::Init() { - if (not isResetOk) + if (!isResetOk) return; // Call SoftReset (and reset TWI device) first! + // Initialize interface auto ret = bma423_init(&bma); if (ret != BMA4_OK) return; + // Identify chip by ID. The driver code has been modified to handle BMA421 as BMA423 switch (bma.chip_id) { case BMA423_CHIP_ID: - deviceType = DeviceTypes::BMA421; + deviceType = AccelerationDeviceTypes::BMA421; break; case BMA425_CHIP_ID: - deviceType = DeviceTypes::BMA425; + deviceType = AccelerationDeviceTypes::BMA425; break; default: - deviceType = DeviceTypes::Unknown; + deviceType = AccelerationDeviceTypes::Unknown; break; } + // Load proprietary firmware blob required for step counting engine ret = bma423_write_config_file(&bma); if (ret != BMA4_OK) return; - ret = bma4_set_interrupt_mode(BMA4_LATCH_MODE, &bma); - if (ret != BMA4_OK) - return; - + // Enable step counter and accelerometer, disable step detector ret = bma423_feature_enable(BMA423_STEP_CNTR, 1, &bma); if (ret != BMA4_OK) return; - ret = bma423_step_detector_enable(0, &bma); if (ret != BMA4_OK) return; - ret = bma4_set_accel_enable(1, &bma); if (ret != BMA4_OK) return; + // Configure accelerometer struct bma4_accel_config accel_conf; accel_conf.odr = BMA4_OUTPUT_DATA_RATE_100HZ; accel_conf.range = BMA4_ACCEL_RANGE_2G; @@ -83,25 +80,13 @@ void Bma421::Init() { if (ret != BMA4_OK) return; - isOk = true; + isInitialized = true; } -void Bma421::Reset() { - uint8_t data = 0xb6; - twiMaster.Write(deviceAddress, 0x7E, &data, 1); -} - -void Bma421::Read(uint8_t registerAddress, uint8_t* buffer, size_t size) { - twiMaster.Read(deviceAddress, registerAddress, buffer, size); -} - -void Bma421::Write(uint8_t registerAddress, const uint8_t* data, size_t size) { - twiMaster.Write(deviceAddress, registerAddress, data, size); -} - -Bma421::Values Bma421::Process() { - if (not isOk) +AccelerationValues Bma421::Process() { + if (!isInitialized) return {}; + struct bma4_accel data; bma4_read_accel_xyz(&data, &bma); @@ -116,10 +101,7 @@ Bma421::Values Bma421::Process() { bma423_activity_output(&activity, &bma); // X and Y axis are swapped because of the way the sensor is mounted in the PineTime - return {steps, data.y, data.x, data.z}; -} -bool Bma421::IsOk() const { - return isOk; + return {steps, data.y, data.x, data.z, (int16_t*) fifo, 0}; } void Bma421::ResetStepCounter() { @@ -133,6 +115,3 @@ void Bma421::SoftReset() { nrf_delay_ms(1); } } -Bma421::DeviceTypes Bma421::DeviceType() const { - return deviceType; -} diff --git a/src/drivers/Bma421.h b/src/drivers/Bma421.h index ac5c707ffc..7ecf7bfef4 100644 --- a/src/drivers/Bma421.h +++ b/src/drivers/Bma421.h @@ -1,18 +1,12 @@ #pragma once + +#include "drivers/AccelerationSensor.h" #include namespace Pinetime { namespace Drivers { - class TwiMaster; - class Bma421 { + class Bma421 : public AccelerationSensor { public: - enum class DeviceTypes : uint8_t { Unknown, BMA421, BMA425 }; - struct Values { - uint32_t steps; - int16_t x; - int16_t y; - int16_t z; - }; Bma421(TwiMaster& twiMaster, uint8_t twiAddress); Bma421(const Bma421&) = delete; Bma421& operator=(const Bma421&) = delete; @@ -23,24 +17,12 @@ namespace Pinetime { /// Init() method to allow the caller to uninit and then reinit the TWI device after the softreset. void SoftReset(); void Init(); - Values Process(); + AccelerationValues Process(); void ResetStepCounter(); - void Read(uint8_t registerAddress, uint8_t* buffer, size_t size); - void Write(uint8_t registerAddress, const uint8_t* data, size_t size); - - bool IsOk() const; - DeviceTypes DeviceType() const; - private: - void Reset(); - - TwiMaster& twiMaster; - uint8_t deviceAddress = 0x18; - struct bma4_dev bma; - bool isOk = false; bool isResetOk = false; - DeviceTypes deviceType = DeviceTypes::Unknown; + struct bma4_dev bma; }; } -} \ No newline at end of file +} From 8e6c3007729f160b2b2432d9529d297992cda10f Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Tue, 10 May 2022 23:57:16 +0200 Subject: [PATCH 07/12] Acceleration: Add support for SC7A20 chip The FIFO buffer is used as well --- src/CMakeLists.txt | 4 + src/drivers/SC7A20.cpp | 89 +++++++ src/drivers/SC7A20.h | 19 ++ src/drivers/SC7A20_registers.h | 423 +++++++++++++++++++++++++++++++++ 4 files changed, 535 insertions(+) create mode 100644 src/drivers/SC7A20.cpp create mode 100644 src/drivers/SC7A20.h create mode 100644 src/drivers/SC7A20_registers.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 439a240981..a58f9b61cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -447,6 +447,7 @@ list(APPEND SOURCE_FILES drivers/Bma421.cpp drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c + drivers/SC7A20.cpp components/battery/BatteryController.cpp components/ble/BleController.cpp components/ble/NotificationManager.cpp @@ -515,6 +516,7 @@ list(APPEND RECOVERY_SOURCE_FILES drivers/Bma421.cpp drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c + drivers/SC7A20.cpp components/battery/BatteryController.cpp components/ble/BleController.cpp components/ble/NotificationManager.cpp @@ -632,6 +634,8 @@ set(INCLUDE_FILES drivers/Bma421.h drivers/Bma421_C/bma4.c drivers/Bma421_C/bma423.c + drivers/SC7A20.h + drivers/SC7A20_registers.h components/battery/BatteryController.h components/ble/BleController.h components/ble/NotificationManager.h diff --git a/src/drivers/SC7A20.cpp b/src/drivers/SC7A20.cpp new file mode 100644 index 0000000000..4e75d24465 --- /dev/null +++ b/src/drivers/SC7A20.cpp @@ -0,0 +1,89 @@ +#include "drivers/SC7A20.h" +#include "drivers/SC7A20_registers.h" +#include +#include + +using namespace Pinetime::Drivers; + +SC7A20::SC7A20(TwiMaster& twiMaster, uint8_t twiAddress) : AccelerationSensor(twiMaster, twiAddress) { +} + +void SC7A20::Init() { + // Reset internal memory + uint8_t data = CTRL_REG5_BOOT; + Write(CTRL_REG5, &data, 1); + vTaskDelay(5); + data = 0; + Write(CTRL_REG5, &data, 1); + + // Read Chip ID + Read(WHO_AM_I, &data, 1); + if (data == 17) { + deviceType = AccelerationDeviceTypes::SC7A20; + } else { + deviceType = AccelerationDeviceTypes::Unknown; + return; + } + + // Configure resolution to be +-2g + data = CTRL_REG4_FS_2G; + Write(CTRL_REG4, &data, 1); + + // Enable block update, configure 12 bit resolution mode + data = CTRL_REG4_BDU | CTRL_REG4_HR; + Write(CTRL_REG4, &data, 1); + + // Use FIFO for batch data + data = CTRL_REG5_FIFO_EN; + Write(CTRL_REG5, &data, 1); + data = FIFO_CTRL_REG_FIFO; + Write(FIFO_CTRL_REG, &data, 1); + + // Set 200 Hz sample rate, enable all axes + data = CTRL_REG1_ODR_200HZ | CTRL_REG1_X_EN | CTRL_REG1_Y_EN | CTRL_REG1_Z_EN; + Write(CTRL_REG1, &data, 1); + + isInitialized = true; +} + +AccelerationValues SC7A20::Process() { + if (!isInitialized) + return {}; + + // Read FIFO size, should be about 20 (200 Hz ODR / 10 Hz main loop) + uint8_t length = 0; + Read(FIFO_SRC_REG, &length, 1); + length &= FIFO_SRC_REG_FSS_MASK; + + // Read FIFO samples one by one (full read does not work) + for (uint8_t i = 0; i < length; i++) { + // Set the most significant bit of the sub-address field for block read + Read(0x80 | OUT_X_L, (uint8_t*) &fifo[i], sizeof(int16_t) * 3); + // Shift because value is left-justified + for (uint8_t j = 0; j < 3; j++) + fifo[i][j] >>= (16 - 12); + // X and Y axis are swapped because of the way the sensor is mounted in the P8 + int16_t swap = fifo[i][0]; + fifo[i][0] = fifo[i][1]; + fifo[i][1] = swap; + } + + // Restart FIFO + uint8_t data = FIFO_CTRL_REG_BYPASS; + Write(FIFO_CTRL_REG, &data, 1); + data = FIFO_CTRL_REG_FIFO; + Write(FIFO_CTRL_REG, &data, 1); + + // Compute averages of FIFO + int16_t avgs[3] = {0}; + // 2g range in n bits + for (uint8_t i = 0; i < length; i++) + for (uint8_t j = 0; j < 3; j++) { + avgs[j] += ((fifo[i][j] * 2000) / (1 << (12 - 1))); + } + for (uint8_t j = 0; j < 3; j++) + avgs[j] /= length; + + // Step counting is not implemented + return {0, avgs[0], avgs[1], avgs[2], (int16_t*) fifo, length}; +} diff --git a/src/drivers/SC7A20.h b/src/drivers/SC7A20.h new file mode 100644 index 0000000000..9716a57098 --- /dev/null +++ b/src/drivers/SC7A20.h @@ -0,0 +1,19 @@ +#pragma once + +#include "drivers/AccelerationSensor.h" + +namespace Pinetime { + namespace Drivers { + class SC7A20 : public AccelerationSensor { + public: + SC7A20(TwiMaster& twiMaster, uint8_t twiAddress); + SC7A20(const SC7A20&) = delete; + SC7A20& operator=(const SC7A20&) = delete; + SC7A20(SC7A20&&) = delete; + SC7A20& operator=(SC7A20&&) = delete; + + void Init(); + AccelerationValues Process(); + }; + } +} diff --git a/src/drivers/SC7A20_registers.h b/src/drivers/SC7A20_registers.h new file mode 100644 index 0000000000..9b3464a1ef --- /dev/null +++ b/src/drivers/SC7A20_registers.h @@ -0,0 +1,423 @@ +#pragma once + +// SC7A20 ±2G/±4G/±8G/±16G Three-axis micromachined digital accelerometer +// Hangzhou Silan Microelectronics Co., Ltd. www.silan.com.cn + +// Manually assembled from an auto-translated incomplete datasheet +// This chips behaves nearly the same as a ST LIS2DH, the rest was added from the ST datasheet + +// Registers + +#define OUT_TEMP_L 0x0C // readonly +#define OUT_TEMP_H 0x0D // readonly +#define WHO_AM_I 0x0F // readonly +#define USER_CAL 0x13 // read-write +#define NVM_WR 0x1E // read-write +#define TEMP_CFG 0x1F // read-write +#define CTRL_REG1 0x20 // read-write. Control register 1. +#define CTRL_REG2 0x21 // read-write. Control register 2. +#define CTRL_REG3 0x22 // read-write. Control register 3. +#define CTRL_REG4 0x23 // read-write. Control register 4. +#define CTRL_REG5 0x24 // read-write. Control register 5. +#define CTRL_REG6 0x25 // read-write. Control register 6. +#define REFERENCE 0x26 // read-write +#define STATUS_REG 0x27 // read-write. Status register. +#define OUT_X_L 0x28 // readonly. X Axis accelerometer value. This value starts with 2 output in two's complement form. +#define OUT_X_H 0x29 // readonly +#define OUT_Y_L 0x2A // readonly. Y Axis accelerometer value. This value starts with 2 output in two's complement form. +#define OUT_Y_H 0x2B // readonly +#define OUT_Z_L 0x2C // readonly. Z Axis accelerometer value. This value starts with 2 output in two's complement form. +#define OUT_Z_H 0x2D // readonly +#define FIFO_CTRL_REG 0x2E // read-write +#define FIFO_SRC_REG 0x2F // readonly +#define INT1_CFG 0x30 // read-write. Interrupt 1 configuration. +#define INT1_SOURCE 0x31 // readonly. Interrupt 1 source / status. +#define INT1_THS 0x32 // read-write. Interrupt 1 treshold. +#define INT1_DURATION 0x33 // read-write. Interrupt 1 duration. +#define INT2_CFG 0x34 // read-write. Interrupt 2 configuration. +#define INT2_SOURCE 0x35 // readonly. Interrupt 2 source / status. +#define INT2_THS 0x36 // read-write. Interrupt 2 treshold. +#define INT2_DURATION 0x37 // read-write. Interrupt 1 duration. +#define CLICK_CFG 0x38 // read-write +#define CLICK_SRC 0x39 // readonly +#define CLICK_THS 0x3A // read-write +#define TIME_LIMIT 0x3B // read-write +#define TIME_LATENCY 0x3C // read-write +#define TIME_WINDOW 0x3D // read-write +#define ACT_THS 0x3E // read-write +#define ACT_DURATION 0x3F // read-write + +// Control register configurations + +// CTRL_REG1 + +#define CTRL_REG1_X_EN (1 << 0) // XAxis enable, default is 1. (0: Xaxis disabled, 1: Xaxis enabled) +#define CTRL_REG1_Y_EN (1 << 1) // YAxis enable, default is 1. (0: Yaxis disabled, 1: Yaxis enabled) +#define CTRL_REG1_Z_EN (1 << 2) // ZAxis enable, default is 1. (0: Zaxis disabled, 1: Zaxis enabled) +#define CTRL_REG1_LP_EN (1 << 3) // Low power enable, the default value is 0. (0: normal working mode, 1: low power mode) +#define CTRL_REG1_ODR0 (1 << 4) // Data rate selection, default: 0000 +#define CTRL_REG1_ODR1 (1 << 5) +#define CTRL_REG1_ODR2 (1 << 6) +#define CTRL_REG1_ODR3 (1 << 7) + +#define CTRL_REG1_ODR_POWERDOWN (0 << 4) // Power down mode +#define CTRL_REG1_ODR_1HZ (1 << 4) // Normal / Low power mode (1 Hz) +#define CTRL_REG1_ODR_10HZ (2 << 4) // Normal / Low power mode (10 Hz) +#define CTRL_REG1_ODR_25HZ (3 << 4) // Normal / Low power mode (25 Hz) +#define CTRL_REG1_ODR_50HZ (4 << 4) // Normal / Low power mode (50 Hz) +#define CTRL_REG1_ODR_100HZ (5 << 4) // Normal / Low power mode (100 Hz) +#define CTRL_REG1_ODR_200HZ (6 << 4) // Normal / Low power mode (200 Hz) +#define CTRL_REG1_ODR_400HZ (7 << 4) // Normal / Low power mode (400 Hz) +#define CTRL_REG1_ODR_1_6KHZ (8 << 4) // Low power mode (1.6 KHz) +#define CTRL_REG1_ODR_1_25KHZ (9 << 4) // normal working mode (1.25 kHz) / Low power mode (5KHz) + +// CTRL_REG2 + +#define CTRL_REG2_HPIS1 (1 << 0) // Interrupt 1 AOIFunction high pass filter enable. (0: Filter disabled; 1: filter enable) +#define CTRL_REG2_HPIS2 (1 << 1) // Interrupt 2 AOIFunction high pass filter enable. (0: Filter disabled; 1: filter enable) +#define CTRL_REG2_HPCLICK (1 << 2) // CLICK Function high pass filter enable. (0: Filter disabled; 1: filter enable) +// Data filtering options. Defaults: 0. (0: skip internal filtering; 1: The data after internal filtering is output to the data register or +// FIFO) +#define CTRL_REG2_FDS (1 << 3) +#define CTRL_REG2_HPCF1 (1 << 4) // High pass cutoff frequency selection +#define CTRL_REG2_HPCF2 (1 << 5) +#define CTRL_REG2_HPM0 (1 << 6) // High pass mode selection, Default 00 +#define CTRL_REG2_HPM1 (1 << 7) + +#define CTRL_REG2_HPM_NORMAL_HPFILTER_AUTORESET (0 << 6) // Normal mode (read high-pass filter resets automatically) +#define CTRL_REG2_HPM_FILTER_REF (1 << 6) // Filter reference signal +#define CTRL_REG2_HPM_NORMAL (2 << 6) // Normal mode +#define CTRL_REG2_HPM_INTERRUPT_AUTORESET (3 << 6) // Interrupt event auto reset + +// CTRL_REG3 + +#define CTRL_REG3_I1_OVERRUN (1 << 1) // FIFO overflow interrupt at INT1 superior. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG3_I1_WTM (1 << 2) // FIFO watermark breaks at INT1 superior. Defaults:0 (0: prohibit; 1:Enable) +#define CTRL_REG3_I1_DRDY2 (1 << 3) // DRDY2 interrupted at INT1 superior. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG3_I1_DRDY1 (1 << 4) // DRDY1 interrupted at INT1 superior. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG3_I1_AOI2 (1 << 5) // Enable interrupt function 2 on interrupt pin 1. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG3_I1_AOI1 (1 << 6) // Enable interrupt function 1 on interrupt pin 1. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG3_I1_CLICK (1 << 7) // CLICK interrupted at INT1 superior. Defaults:0 (0: prohibit; 1: Enable) + +// CTRL_REG4 + +#define CTRL_REG4_SIM (1 << 0) // SPI Serial interface mode configuration. Defaults: 0 (0: 4line interface; 1: 3line interface) +#define CTRL_REG4_ST0 (1 << 1) // Self-test enabled. Defaults: 00. +#define CTRL_REG4_ST1 (1 << 2) +#define CTRL_REG4_HR (1 << 3) // High precision output mode selection. Defaults: (0: high precision prohibited; 1: high precision enable) +#define CTRL_REG4_FS0 (1 << 4) // Full range selection. Defaults: 00. +#define CTRL_REG4_FS1 (1 << 5) +// Big endian/little endian data selection. Defaults:0 (0: The low byte data is at the low address; 1: high byte data at low address) +#define CTRL_REG4_BLE (1 << 6) +// Block data update. Defaults: 0. (0: continuous update; 1: The output data register is not updated until MSB and LSB is read) +#define CTRL_REG4_BDU (1 << 7) + +#define CTRL_REG4_ST_NORMAL (0 << 1) +#define CTRL_REG4_ST_TEST0 (1 << 1) +#define CTRL_REG4_ST_TEST1 (2 << 1) + +#define CTRL_REG4_FS_2G (0 << 4) +#define CTRL_REG4_FS_4G (1 << 4) +#define CTRL_REG4_FS_8G (2 << 4) +#define CTRL_REG4_FS_16G (3 << 4) + +// CTRL_REG5 + +// 4D enable: in INT2 enable on pin 4D detection, while taking the interrupt2 in the configuration register 6D set 1. +#define CTRL_REG5_D4D_INT2 (1 << 0) +// Latch Interrupt2 The interrupt response specified on the configuration register. Interrupt by read 2 The configuration +// register can clear the corresponding interrupt latch signal. Defaults: 0 (0: Do not latch the interrupt signal; 1: Latch interrupt +// signal) +#define CTRL_REG5_LIR_INT2 (1 << 1) +// 4D enable: in INT1 enable on pin 4D detection, while taking the interrupt1 in the configuration register 6D set 1. +#define CTRL_REG5_D4D_INT1 (1 << 2) +// Latch Interrupt1 The interrupt response specified on the configuration register. Interrupt by read 1 The configuration +// register can clear the corresponding interrupt latch signal. Defaults: 0 (0: Do not latch the interrupt signal; 1: Latch interrupt +// signal) +#define CTRL_REG5_LIR_INT1 (1 << 3) +// FIFO Enable. Defaults: 0. (0: FIFO prohibit; 1: FIFO Enable) +#define CTRL_REG5_FIFO_EN (1 << 6) +// Override trim value. Defaults: 0. (0: normal mode; 1: Overload trim value) +#define CTRL_REG5_BOOT (1 << 7) + +// CTRL_REG6 + +#define CTRL_REG6_H_LACTIVE (1 << 1) // 0: High level trigger interrupt; 1: Low level trigger interrupt +#define CTRL_REG6_BOOT_I2 (1 << 4) // BOOT status is INT2 superior. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG6_I2_AOI2 (1 << 5) // Enable interrupt function 2 on interrupt pin 2. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG6_I2_AOI1 (1 << 6) // Enable interrupt function 1 on interrupt pin 2. Defaults: 0 (0: prohibit; 1: Enable) +#define CTRL_REG6_I2_CLICK (1 << 7) // CLICK interrupted at INT2 superior. Defaults: 0. (0: prohibit; 1: Enable) + +// Status register + +// STATUS_REG + +// X New data for the axis arrives. Defaults: 0 (0: X The new data of the axis has not been converted; 1: X Axis new data conversion +// completed) +#define STATUS_REG_XDA (1 << 0) +// Y New data for the axis arrives. Defaults: 0 (0: Y The new data of the axis has not been converted; 1: Y Axis new data conversion +// completed) +#define STATUS_REG_YDA (1 << 1) +// Z New data for the axis arrives. Defaults: 0 (0: Z The new data of the axis has not been converted; 1: Z Axis new data conversion +// completed) +#define STATUS_REG_ZDA (1 << 2) +// X, Y and Z The new data of the three axes are all converted. Defaults: 0 (0: The data of at least one of the three axes has +// not been converted; 1: The new data of the three axes are all converted) +#define STATUS_REG_ZYXDA (1 << 3) +// X The new data of the axis has overwritten the old data. Defaults: 0. (0: X The new data of the axis has not overwritten the +// old data; 1: X The new data of the axis overwrites the old data) +#define STATUS_REG_XOR (1 << 4) +// Y The new data of the axis has overwritten the old data. Defaults: 0. (0: Y The new data of the axis has not overwritten the +// old data; 1: Y The new data of the axis overwrites the old data) +#define STATUS_REG_YOR (1 << 5) +// Z The new data of the axis has overwritten the old data. Defaults: 0. (0: Z The new data of the axis has not overwritten the +// old data; 1: Z The new data of the axis overwrites the old data) +#define STATUS_REG_ZOR (1 << 6) +// X, Y and Z At least one of the new data on the three axes has overwritten the old data. Defaults: 0 .(0: The new data of none +// of the three axes overwrites the old data; 1: The new data of at least one of the three axes has overwritten the old data) +#define STATUS_REG_ZYXOR (1 << 7) + +// FIFO configuration + +// FIFO_CTRL_REG + +#define FIFO_CTRL_REG_BYPASS (0 << 6) // Bypass mode +#define FIFO_CTRL_REG_FIFO (1 << 6) // FIFO mode +#define FIFO_CTRL_REG_STREAM (2 << 6) // Stream mode +#define FIFO_CTRL_REG_STREAM_TO_FIFO (3 << 6) // Stream to FIFO mode + +// FIFO_SRC_REG + +#define FIFO_SRC_REG_FSS_MASK 0x1F + +#define FIFO_SRC_REG_FSS0 (1 << 0) // Contains the current number of unread samples stored in the FIFO buffer +#define FIFO_SRC_REG_FSS1 (1 << 1) +#define FIFO_SRC_REG_FSS2 (1 << 2) +#define FIFO_SRC_REG_FSS3 (1 << 3) +#define FIFO_SRC_REG_FSS4 (1 << 4) +// Set high when all FIFO samples have been read and the FIFO is empty +#define FIFO_SRC_REG_EMPTY (1 << 5) +// Set high when the FIFO buffer is full, which means that the FIFO buffer contains 32 unread samples +#define FIFO_SRC_REG_OVRN_FIFO (1 << 6) +#define FIFO_SRC_REG_WTM (1 << 7) // Set high when FIFO content exceeds watermark level + +// Interrupt configuration + +// INT1_CFG + +// X Axis low event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT1_CFG_XLIE_XDOWNE (1 << 0) +// X Axis high event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT1_CFG_XHIE_XUPE (1 << 1) +// Y Axis low event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT1_CFG_YLIE_YDOWNE (1 << 2) +// Y Axis high event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT1_CFG_YHIE_YUPE (1 << 3) +// Z Axis low event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT1_CFG_ZLIE_XDOWNE (1 << 4) +// Z Axis high event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT1_CFG_ZHIE_ZUPE (1 << 5) +// 6 The direction detection function is enabled. Defaults: 0. Refer to "Interrupt Mode" +#define INT1_CFG_6D (1 << 6) +// and/or interrupt events. Defaults: 0. Refer to "Interrupt Mode" +#define INT1_CFG_AOI (1 << 7) + +#define INT1_CFG_6D_AOI_OR_INT_EVENT (0 << 6) // or interrupt event +#define INT1_CFG_6D_AOI_6D_MOTION (1 << 6) // 6 direction motion recognition +#define INT1_CFG_6D_AOI_AND_INT_EVENT (2 << 6) // and interrupt event +#define INT1_CFG_6D_AOI_6D_POSITION (3 << 6) // 6 direction position detection + +// INT1_SOURCE + +#define INT1_SOURCE_XL (1 << 0) // X axis low. Defaults: 0. (0: no interruption, 1: X Axis low event has been generated) +#define INT1_SOURCE_XH (1 << 1) // X axis high. Defaults: 0. (0: no interruption, 1: X Axis high event has been generated) +#define INT1_SOURCE_YL (1 << 2) // Y axis low. Defaults: 0. (0: no interruption, 1: Y Axis low event has been generated) +#define INT1_SOURCE_YH (1 << 3) // Y axis high. Defaults: 0. (0: no interruption, 1: Y Axis high event has been generated) +#define INT1_SOURCE_ZL (1 << 4) // Z axis low. Defaults: 0. (0: no interruption, 1: Z Axis low event has been generated) +#define INT1_SOURCE_ZH (1 << 5) // Z axis high. Defaults: 0. (0: no interruption, 1: Z Axis high event has been generated) +// Interrupt activation. Defaults: 0. (0: Interrupt is not generated; 1: one or more interrupts have been generated) +#define INT1_SOURCE_IA (1 << 6) + +// INT1_THS + +#define INT1_THS_TH0 (1 << 0) // Interrupt 1 threshold. Defaults: 000 0000. Units: 16mg @ FS=2g, 32mg @ FS=4g, 64mg @ FS=8g, 128mg @ FS=16g +#define INT1_THS_TH1 (1 << 1) +#define INT1_THS_TH2 (1 << 2) +#define INT1_THS_TH3 (1 << 3) +#define INT1_THS_TH4 (1 << 4) +#define INT1_THS_TH5 (1 << 5) +#define INT1_THS_TH6 (1 << 6) + +// INT2_DURATION + +// Duration count value. Defaults: 000 0000. set recognized interrupt The minimum duration of the event. The maximum time and +// time step of the duration register is ODR for the clock. +#define INT1_DURATION_D0 (1 << 0) +#define INT1_DURATION_D1 (1 << 1) +#define INT1_DURATION_D2 (1 << 2) +#define INT1_DURATION_D3 (1 << 3) +#define INT1_DURATION_D4 (1 << 4) +#define INT1_DURATION_D5 (1 << 5) +#define INT1_DURATION_D6 (1 << 6) + +// INT2_CFG +// X Axis low event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT2_CFG_XLIE_XDOWNE (1 << 0) +// X Axis high event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT2_CFG_XHIE_XUPE (1 << 1) +// Y Axis low event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT2_CFG_YLIE_YDOWNE (1 << 2) +// Y Axis high event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT2_CFG_YHIE_YUPE (1 << 3) +// Z Axis low event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT2_CFG_ZLIE_XDOWNE (1 << 4) +// Z Axis high event interrupt or Z Axis Orientation Detection Interrupt Enable. Defaults: 0 (0: disable interrupt; 1: enable interrupt) +#define INT2_CFG_ZHIE_ZUPE (1 << 5) +// 6 The direction detection function is enabled. Defaults: 0. Refer to "Interrupt Mode" +#define INT2_CFG_6D (1 << 6) +// and/or interrupt events. Defaults: 0. Refer to "Interrupt Mode" +#define INT2_CFG_AOI (1 << 7) + +#define INT2_CFG_6D_AOI_OR_INT_EVENT (0 << 6) // or interrupt event +#define INT2_CFG_6D_AOI_6D_MOTION (1 << 6) // 6 direction motion recognition +#define INT2_CFG_6D_AOI_AND_INT_EVENT (2 << 6) // and interrupt event +#define INT2_CFG_6D_AOI_6D_POSITION (3 << 6) // 6 direction position detection + +// INT2_SOURCE + +#define INT2_SOURCE_XL (1 << 0) // X axis low. Defaults: 0. (0: no interruption, 1: X Axis low event has been generated) +#define INT2_SOURCE_XH (1 << 1) // X axis high. Defaults: 0. (0: no interruption, 1: X Axis high event has been generated) +#define INT2_SOURCE_YL (1 << 2) // Y axis low. Defaults: 0. (0: no interruption, 1: Y Axis low event has been generated) +#define INT2_SOURCE_YH (1 << 3) // Y axis high. Defaults: 0. (0: no interruption, 1: Y Axis high event has been generated) +#define INT2_SOURCE_ZL (1 << 4) // Z axis low. Defaults: 0. (0: no interruption, 1: Z Axis low event has been generated) +#define INT2_SOURCE_ZH (1 << 5) // Z axis high. Defaults: 0. (0: no interruption, 1: Z Axis high event has been generated) +// Interrupt activation. Defaults: 0. (0: Interrupt is not generated; 1: one or more interrupts have been generated) +#define INT2_SOURCE_IA (1 << 6) + +// INT2_THS + +#define INT2_THS_TH0 (1 << 0) // Interrupt 1 threshold. Defaults: 000 0000. Units: 16mg @ FS=2g, 32mg @ FS=4g, 64mg @ FS=8g, 128mg @ FS=16g +#define INT2_THS_TH1 (1 << 1) +#define INT2_THS_TH2 (1 << 2) +#define INT2_THS_TH3 (1 << 3) +#define INT2_THS_TH4 (1 << 4) +#define INT2_THS_TH5 (1 << 5) +#define INT2_THS_TH6 (1 << 6) + +// INT2_DURATION + +// Duration count value. Defaults: 000 0000. set recognized interrupt The minimum duration of the event. The maximum time and +// time step of the duration register is ODR for the clock. +#define INT2_DURATION_D0 (1 << 0) +#define INT2_DURATION_D1 (1 << 1) +#define INT2_DURATION_D2 (1 << 2) +#define INT2_DURATION_D3 (1 << 3) +#define INT2_DURATION_D4 (1 << 4) +#define INT2_DURATION_D5 (1 << 5) +#define INT2_DURATION_D6 (1 << 6) + +// Click configuration + +// CLICK_CFG + +// Enable interrupt single tap on X axis. Default value: 0. (0: disable interrupt request; 1: enable interrupt request on +// measured accel. value higher than preset threshold) +#define CLICK_CFG_XS (1 << 0) +// Enable interrupt double tap on X axis. Default value: 0. (0: disable interrupt request; 1: enable interrupt request on +// measured accel. value higher than preset threshold) +#define CLICK_CFG_XD (1 << 1) +// Enable interrupt single tap on Y axis. Default value: 0. (0: disable interrupt request; 1: enable interrupt request on +// measured accel. value higher than preset threshold) +#define CLICK_CFG_YS (1 << 2) +// Enable interrupt double tap on Y axis. Default value: 0. (0: disable interrupt request; 1: enable interrupt request on +// measured accel. value higher than preset threshold) +#define CLICK_CFG_YD (1 << 3) +// Enable interrupt single tap on Z axis. Default value: 0. (0: disable interrupt request; 1: enable interrupt request on +// measured accel. value higher than preset threshold) +#define CLICK_CFG_ZS (1 << 4) +// Enable interrupt double tap on Z axis. Default value: 0. (0: disable interrupt request; 1: enable interrupt request on +// measured accel. value higher than preset threshold) +#define CLICK_CFG_ZD (1 << 5) + +// CLICK_SRC + +#define CLICK_SRC_X (1 << 0) // X Click-Click detection. Default value: 0. (0: no interrupt, 1: X High event has occurred) +#define CLICK_SRC_Y (1 << 1) // Y Click-Click detection. Default value: 0. (0: no interrupt, 1: Y High event has occurred) +#define CLICK_SRC_Z (1 << 2) // Z Click-Click detection. Default value: 0. (0: no interrupt, 1: Z High event has occurred) +#define CLICK_SRC_SIGN (1 << 3) // Click-Click Sign. 0: positive detection, 1: negative detection +// Single Click-Click enable. Default value: 0. (0:Single Click-Click detection disable, 1: single Click-Click detection enable) +#define CLICK_SRC_SCLICK (1 << 4) +// Single Click-Click enable. Default value: 0. (0:Single Click-Click detection disable, 1: single Click-Click detection enable) +#define CLICK_SRC_DCLICK (1 << 5) +// Interrupt active. Default value: 0. (0: no interrupt has been generated; 1: one or more interrupts have been generated) +#define CLICK_SRC_IA (1 << 6) + +// CLICK_THS + +#define CLICK_THS_TH0 (1 << 0) // Click-Click threshold. Default value: 000 0000 +#define CLICK_THS_TH1 (1 << 1) +#define CLICK_THS_TH2 (1 << 2) +#define CLICK_THS_TH3 (1 << 3) +#define CLICK_THS_TH4 (1 << 4) +#define CLICK_THS_TH5 (1 << 5) +#define CLICK_THS_TH6 (1 << 6) +// If the LIR_Click bit is not set, the interrupt is kept high for the duration of the latency window. If the LIR_Click bit is +// set, the interrupt is kept high until CLICK_SRC (39h) is read +#define CLICK_THS_LIR_CLICK (1 << 7) + +// TIME_LIMIT + +#define CLICK_TIME_LIMIT_TLI0 (1 << 0) // Click-Click Time Limit. Default value: 000 0000 +#define CLICK_TIME_LIMIT_TLI1 (1 << 1) +#define CLICK_TIME_LIMIT_TLI2 (1 << 2) +#define CLICK_TIME_LIMIT_TLI3 (1 << 3) +#define CLICK_TIME_LIMIT_TLI4 (1 << 4) +#define CLICK_TIME_LIMIT_TLI5 (1 << 5) +#define CLICK_TIME_LIMIT_TLI6 (1 << 6) + +// TIME_LATENCY + +#define CLICK_TIME_LATENCY_TLA0 (1 << 0) // Click-Click Time Latency. Default value: 000 0000 +#define CLICK_TIME_LATENCY_TLA1 (1 << 1) +#define CLICK_TIME_LATENCY_TLA2 (1 << 2) +#define CLICK_TIME_LATENCY_TLA3 (1 << 3) +#define CLICK_TIME_LATENCY_TLA4 (1 << 4) +#define CLICK_TIME_LATENCY_TLA5 (1 << 5) +#define CLICK_TIME_LATENCY_TLA6 (1 << 6) +#define CLICK_TIME_LATENCY_TLA7 (1 << 7) + +// TIME_WINDOW + +#define CLICK_TIME_WINDOW_TW0 (1 << 0) // Click-Click Time Window +#define CLICK_TIME_WINDOW_TW1 (1 << 1) +#define CLICK_TIME_WINDOW_TW2 (1 << 2) +#define CLICK_TIME_WINDOW_TW3 (1 << 3) +#define CLICK_TIME_WINDOW_TW4 (1 << 4) +#define CLICK_TIME_WINDOW_TW5 (1 << 5) +#define CLICK_TIME_WINDOW_TW6 (1 << 6) +#define CLICK_TIME_WINDOW_TW7 (1 << 7) + +// Active configuration + +// ACT_THS + +// Sleep to wake, return to Sleep activation threshold in Low power mode (1LSb = 16mg @FS=2g, 1LSb = 32 mg @FS=4g, 1LSb = 62 mg @FS=8g, 1LSb +// = 186 mg @FS=16g) +#define ACT_THS_ACTH0 (1 << 0) +#define ACT_THS_ACTH1 (1 << 1) +#define ACT_THS_ACTH2 (1 << 2) +#define ACT_THS_ACTH3 (1 << 3) +#define ACT_THS_ACTH4 (1 << 4) +#define ACT_THS_ACTH5 (1 << 5) +#define ACT_THS_ACTH6 (1 << 6) + +// ACT_DUR + +#define ACT_DUR_ACTD0 (1 << 0) // Sleep to Wake, Return to Sleep duration (1LSb = (8*1[LSb]+1)/ODR) +#define ACT_DUR_ACTD1 (1 << 1) +#define ACT_DUR_ACTD2 (1 << 2) +#define ACT_DUR_ACTD3 (1 << 3) +#define ACT_DUR_ACTD4 (1 << 4) +#define ACT_DUR_ACTD5 (1 << 5) +#define ACT_DUR_ACTD6 (1 << 6) +#define ACT_DUR_ACTD7 (1 << 7) From 52b5b7236dc3128591ad39921b2b65d83309b47d Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Wed, 11 May 2022 00:28:52 +0200 Subject: [PATCH 08/12] CMake: Add acceleration sensor configuration The DRIVER_ACC configuration variable can be used to select the acceleration sensor driver to be used. --- src/CMakeLists.txt | 5 +++++ src/main.cpp | 8 +++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index a58f9b61cd..86a8c8d14f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -805,23 +805,28 @@ add_definitions(-DTARGET_DEVICE_NAME="${TARGET_DEVICE}") if(TARGET_DEVICE STREQUAL "PINETIME") add_definitions(-DDRIVER_PINMAP_PINETIME) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_ACC_BMA421) elseif(TARGET_DEVICE STREQUAL "MOY-TFK5") # P8a add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_ACC_BMA421) elseif(TARGET_DEVICE STREQUAL "MOY-TIN5") # P8a variant 2 add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL + add_definitions(-DDRIVER_ACC_SC7A20) elseif(TARGET_DEVICE STREQUAL "MOY-TON5") # P8b add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) + add_definitions(-DDRIVER_ACC_SC7A20) elseif(TARGET_DEVICE STREQUAL "MOY-UNK") # P8b mirrored add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) add_definitions(-DDRIVER_DISPLAY_MIRROR) + add_definitions(-DDRIVER_ACC_SC7A20) else() message(FATAL_ERROR "Invalid TARGET_DEVICE") endif() diff --git a/src/main.cpp b/src/main.cpp index fddec544ac..cc26f4b4fc 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -89,13 +89,11 @@ Pinetime::Drivers::Cst816S touchPanel {twiMaster, touchPanelTwiAddress}; Pinetime::Components::LittleVgl lvgl {lcd, touchPanel}; #if (defined DRIVER_ACC_SC7A20) -#include - static constexpr uint8_t motionSensorTwiAddress = 0x18; + #include +static constexpr uint8_t motionSensorTwiAddress = 0x18; Pinetime::Drivers::SC7A20 motionSensor {twiMaster, motionSensorTwiAddress}; #else -// Assume DRIVER_ACC_BMA421, -// this is needed for the LVGL simulator, -// which does not set any target hardware configuration variables +// Assume PineTime (DRIVER_ACC_BMA421) #include static constexpr uint8_t motionSensorTwiAddress = 0x18; Pinetime::Drivers::Bma421 motionSensor {twiMaster, motionSensorTwiAddress}; From 7a67517eb630a62532425af063764558d3d62f3c Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Wed, 11 May 2022 00:27:59 +0200 Subject: [PATCH 09/12] Motion: Expose acceleration FIFO via BLE The motion BLE service now broadcasts the entire FIFO buffer, in order to expose a higher frequency measurement. A high enough MTU has to be negotiated to fit all max. 192 bytes. The format is backwards-compatible. --- src/components/ble/MotionService.cpp | 18 ++++++++++-------- src/components/ble/MotionService.h | 2 +- src/components/motion/MotionController.cpp | 4 ++-- src/components/motion/MotionController.h | 2 +- src/systemtask/SystemTask.cpp | 8 ++------ 5 files changed, 16 insertions(+), 18 deletions(-) diff --git a/src/components/ble/MotionService.cpp b/src/components/ble/MotionService.cpp index 121ad3b08a..8750f96672 100644 --- a/src/components/ble/MotionService.cpp +++ b/src/components/ble/MotionService.cpp @@ -90,20 +90,22 @@ void MotionService::OnNewStepCountValue(uint32_t stepCount) { ble_gattc_notify_custom(connectionHandle, stepCountHandle, om); } -void MotionService::OnNewMotionValues(int16_t x, int16_t y, int16_t z) { + +void MotionService::OnNewMotionValues(int16_t* samples, uint16_t samples_length) { if (!motionValuesNoficationEnabled) return; - int16_t buffer[3] = {motionController.X(), motionController.Y(), motionController.Z()}; - auto* om = ble_hs_mbuf_from_flat(buffer, 3 * sizeof(int16_t)); + if (samples_length > 0 && samples != nullptr) { + auto* om = ble_hs_mbuf_from_flat(samples, samples_length * 3 * sizeof(int16_t)); - uint16_t connectionHandle = system.nimble().connHandle(); + uint16_t connectionHandle = system.nimble().connHandle(); - if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { - return; - } + if (connectionHandle == 0 || connectionHandle == BLE_HS_CONN_HANDLE_NONE) { + return; + } - ble_gattc_notify_custom(connectionHandle, motionValuesHandle, om); + ble_gattc_notify_custom(connectionHandle, motionValuesHandle, om); + } } void MotionService::SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle) { diff --git a/src/components/ble/MotionService.h b/src/components/ble/MotionService.h index 1b4ac0a37e..172ed270fc 100644 --- a/src/components/ble/MotionService.h +++ b/src/components/ble/MotionService.h @@ -18,7 +18,7 @@ namespace Pinetime { void Init(); int OnStepCountRequested(uint16_t connectionHandle, uint16_t attributeHandle, ble_gatt_access_ctxt* context); void OnNewStepCountValue(uint32_t stepCount); - void OnNewMotionValues(int16_t x, int16_t y, int16_t z); + void OnNewMotionValues(int16_t* samples, uint16_t samples_length); void SubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); void UnsubscribeNotification(uint16_t connectionHandle, uint16_t attributeHandle); diff --git a/src/components/motion/MotionController.cpp b/src/components/motion/MotionController.cpp index 19b239c206..518ad08c55 100644 --- a/src/components/motion/MotionController.cpp +++ b/src/components/motion/MotionController.cpp @@ -2,13 +2,13 @@ #include "os/os_cputime.h" using namespace Pinetime::Controllers; -void MotionController::Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps) { +void MotionController::Update(uint32_t nbSteps, int16_t x, int16_t y, int16_t z, int16_t* samples, uint16_t samples_length) { if (this->nbSteps != nbSteps && service != nullptr) { service->OnNewStepCountValue(nbSteps); } if (service != nullptr && (this->x != x || this->y != y || this->z != z)) { - service->OnNewMotionValues(x, y, z); + service->OnNewMotionValues(samples, samples_length); } this->x = x; diff --git a/src/components/motion/MotionController.h b/src/components/motion/MotionController.h index 4ddc1af8bc..da9dd16050 100644 --- a/src/components/motion/MotionController.h +++ b/src/components/motion/MotionController.h @@ -8,7 +8,7 @@ namespace Pinetime { namespace Controllers { class MotionController { public: - void Update(int16_t x, int16_t y, int16_t z, uint32_t nbSteps); + void Update(uint32_t nbSteps, int16_t x, int16_t y, int16_t z, int16_t* samples, uint16_t samples_length); int16_t X() const { return x; diff --git a/src/systemtask/SystemTask.cpp b/src/systemtask/SystemTask.cpp index d86b6320b2..76e3d2f24e 100644 --- a/src/systemtask/SystemTask.cpp +++ b/src/systemtask/SystemTask.cpp @@ -471,11 +471,6 @@ void SystemTask::UpdateMotion() { return; } - if (state == SystemTaskState::Sleeping && !(settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) || - settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::Shake))) { - return; - } - if (stepCounterMustBeReset) { motionSensor.ResetStepCounter(); stepCounterMustBeReset = false; @@ -484,7 +479,8 @@ void SystemTask::UpdateMotion() { auto motionValues = motionSensor.Process(); motionController.IsSensorOk(motionSensor.IsInitialized()); - motionController.Update(motionValues.x, motionValues.y, motionValues.z, motionValues.steps); + motionController + .Update(motionValues.steps, motionValues.x, motionValues.y, motionValues.z, motionValues.samples, motionValues.samples_length); if (settingsController.GetNotificationStatus() != Controllers::Settings::Notification::Sleep) { if ((settingsController.isWakeUpModeOn(Pinetime::Controllers::Settings::WakeUpMode::RaiseWrist) && From 3e0841dd5d9b3fe08f85f1d468fcd968fd3281c0 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Sun, 29 Jan 2023 15:41:09 +0100 Subject: [PATCH 10/12] CMake: Remove hyphens in target names This removes the "ISO C99 requires whitespace after the macro name" warning --- CMakeLists.txt | 2 +- doc/buildAndProgram.md | 2 +- src/CMakeLists.txt | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index adb1754b28..77e5e875a4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ if(BUILD_RESOURCES) endif() set(TARGET_DEVICE "PINETIME" CACHE STRING "Target device") -set_property(CACHE TARGET_DEVICE PROPERTY STRINGS PINETIME MOY-TFK5 MOY-TIN5 MOY-TON5 MOY-UNK) +set_property(CACHE TARGET_DEVICE PROPERTY STRINGS PINETIME MOY_TFK5 MOY_TIN5 MOY_TON5 MOY_UNK) set(PROJECT_GIT_COMMIT_HASH "") diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md index 78bea1b458..7bec0d48ad 100644 --- a/doc/buildAndProgram.md +++ b/doc/buildAndProgram.md @@ -43,7 +43,7 @@ CMake configures the project according to variables you specify the command line **CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug` **BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1` **BUILD_RESOURCES (\*\*)**| Generate external resource while building (needs [lv_font_conv](https://github.com/lvgl/lv_font_conv) and [lv_img_conv](https://github.com/lvgl/lv_img_conv). |`-DBUILD_RESOURCES=1` -**TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY-TFK5, MOY-TIN5, MOY-TON5, MOY-UNK`|`-DTARGET_DEVICE=PINETIME` (Default) +**TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY_TFK5, MOY_TIN5, MOY_TON5, MOY_UNK`|`-DTARGET_DEVICE=PINETIME` (Default) #### (\*) Note about **CMAKE_BUILD_TYPE** By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/InfiniTimeOrg/InfiniTime/releases) new versions of InfiniTime. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e59c0d814b..73b1debf09 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -798,18 +798,18 @@ add_definitions(-DTARGET_DEVICE_NAME="${TARGET_DEVICE}") if(TARGET_DEVICE STREQUAL "PINETIME") add_definitions(-DDRIVER_PINMAP_PINETIME) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL -elseif(TARGET_DEVICE STREQUAL "MOY-TFK5") # P8a +elseif(TARGET_DEVICE STREQUAL "MOY_TFK5") # P8a add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL -elseif(TARGET_DEVICE STREQUAL "MOY-TIN5") # P8a variant 2 +elseif(TARGET_DEVICE STREQUAL "MOY_TIN5") # P8a variant 2 add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=1) # XTAL -elseif(TARGET_DEVICE STREQUAL "MOY-TON5") # P8b +elseif(TARGET_DEVICE STREQUAL "MOY_TON5") # P8b add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) -elseif(TARGET_DEVICE STREQUAL "MOY-UNK") # P8b mirrored +elseif(TARGET_DEVICE STREQUAL "MOY_UNK") # P8b mirrored add_definitions(-DDRIVER_PINMAP_P8) add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) From 0df84db1d1f4b95464d8823cdf1328bcbd0b517e Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Sun, 29 Jan 2023 15:44:32 +0100 Subject: [PATCH 11/12] Touch: Fix tap detection for P8b variant --- src/touchhandler/TouchHandler.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/touchhandler/TouchHandler.cpp b/src/touchhandler/TouchHandler.cpp index 8fef817d7d..16ce246c41 100644 --- a/src/touchhandler/TouchHandler.cpp +++ b/src/touchhandler/TouchHandler.cpp @@ -78,6 +78,12 @@ bool TouchHandler::GetNewTouchInfo() { #elif defined(DRIVER_TOUCH_GESTURE) if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { gesture = ConvertGesture(info.gesture); + // A new variant configuration behaves in a way such that it generates a gesture event at the start of a physical gesture, + // but does not set the info.touching flag at all. Since gestures are handled separately, special behaviour is only needed + // for the tap event. For the original P8b, which always sets info.touching = true, this operation is idempotent. + if (gesture == TouchEvents::Tap) { + info.touching = true; + } } #elif defined(DRIVER_TOUCH_DYNAMIC) if (info.gesture != Pinetime::Drivers::Cst816S::Gestures::None) { From a0b7b20e4822128e13a2c1265ace2c72b04a5cd5 Mon Sep 17 00:00:00 2001 From: Christoph Honal Date: Sun, 29 Jan 2023 17:15:30 +0100 Subject: [PATCH 12/12] Add MOY_UNK2 --- CMakeLists.txt | 2 +- doc/buildAndProgram.md | 2 +- src/CMakeLists.txt | 7 +++++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 77e5e875a4..f254b1fa75 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ if(BUILD_RESOURCES) endif() set(TARGET_DEVICE "PINETIME" CACHE STRING "Target device") -set_property(CACHE TARGET_DEVICE PROPERTY STRINGS PINETIME MOY_TFK5 MOY_TIN5 MOY_TON5 MOY_UNK) +set_property(CACHE TARGET_DEVICE PROPERTY STRINGS PINETIME MOY_TFK5 MOY_TIN5 MOY_TON5 MOY_UNK MOY_UNK2) set(PROJECT_GIT_COMMIT_HASH "") diff --git a/doc/buildAndProgram.md b/doc/buildAndProgram.md index 7bec0d48ad..29f7a91275 100644 --- a/doc/buildAndProgram.md +++ b/doc/buildAndProgram.md @@ -43,7 +43,7 @@ CMake configures the project according to variables you specify the command line **CMAKE_BUILD_TYPE (\*)**| Build type (Release or Debug). Release is applied by default if this variable is not specified.|`-DCMAKE_BUILD_TYPE=Debug` **BUILD_DFU (\*\*)**|Build DFU files while building (needs [adafruit-nrfutil](https://github.com/adafruit/Adafruit_nRF52_nrfutil)).|`-DBUILD_DFU=1` **BUILD_RESOURCES (\*\*)**| Generate external resource while building (needs [lv_font_conv](https://github.com/lvgl/lv_font_conv) and [lv_img_conv](https://github.com/lvgl/lv_img_conv). |`-DBUILD_RESOURCES=1` -**TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY_TFK5, MOY_TIN5, MOY_TON5, MOY_UNK`|`-DTARGET_DEVICE=PINETIME` (Default) +**TARGET_DEVICE**|Target device, used for hardware configuration. Allowed: `PINETIME, MOY_TFK5, MOY_TIN5, MOY_TON5, MOY_UNK, MOY_UNK2`|`-DTARGET_DEVICE=PINETIME` (Default) #### (\*) Note about **CMAKE_BUILD_TYPE** By default, this variable is set to *Release*. It compiles the code with size and speed optimizations. We use this value for all the binaries we publish when we [release](https://github.com/InfiniTimeOrg/InfiniTime/releases) new versions of InfiniTime. diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 01fef7810b..0e8763e0f4 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -833,6 +833,13 @@ elseif(TARGET_DEVICE STREQUAL "MOY_UNK") # P8b mirrored add_definitions(-DDRIVER_DISPLAY_MIRROR) add_definitions(-DDRIVER_ACC_SC7A20) add_definitions(-DDRIVER_TOUCH_REPORT) +elseif(TARGET_DEVICE STREQUAL "MOY_UNK2") # P8b variant + add_definitions(-DDRIVER_PINMAP_P8) + add_definitions(-DCLOCK_CONFIG_LF_SRC=0) # RC + add_definitions(-DMYNEWT_VAL_BLE_LL_SCA=500) + add_definitions(-DCLOCK_CONFIG_LF_CAL_ENABLED=1) + add_definitions(-DDRIVER_ACC_SC7A20) + add_definitions(-DDRIVER_TOUCH_GESTURE) else() message(FATAL_ERROR "Invalid TARGET_DEVICE") endif()