diff --git a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c index 5c91098..337e324 100644 --- a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c +++ b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.c @@ -5,6 +5,10 @@ #include "wm_adc.h" #include "wm_timer.h" #include "wm_pwm.h" +#include "i2c.h" +#include "BMP280.h" +#include "FreeRTOS.h" // <---- Only needed for the pdMS_TO_TICKS macro, to be removed +#include "bma456w.h" #define INTERRUPT_POLICY (0) #define POLL_POLICY (1) @@ -21,6 +25,23 @@ static uint8_t _vibration_motor_timer_id = WM_TIMER_ID_INVALID; static battery_controller_status_e _battery_fsm = BATTERY_CONTROLLER_STATUS_DISCHARGING; static BatteryControllerStatusChangeCb_t _BatteryControllerStatusChangeCb = NULL; +/* BMA456 strcture */ +struct +{ + uint8_t dev_addr; + struct bma4_dev bma; + struct bma4_accel_config accel_conf; + struct bma456w_wrist_wear_wakeup_params setting; + struct bma4_int_pin_config pin_config; + bool wrist_wakeup_enable; + bool step_counter_enable; +} _bma456 = +{ + .dev_addr = BMA4_I2C_ADDR_SECONDARY, + .wrist_wakeup_enable = false, +}; + + static void vibration_motor_timer_irq_cb(void *p) { (void)p; @@ -29,7 +50,7 @@ static void vibration_motor_timer_irq_cb(void *p) tls_gpio_write(VIBRATION_MOTOR_ENABLE, 0); } -#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY +#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY && HARDWARE_PLATFORM == SMART_WATCH_PCB static uint8_t _battery_status_timer_id = WM_TIMER_ID_INVALID; static void battery_status_timer_irq_cb(void *p) @@ -58,7 +79,7 @@ static void battery_status_timer_irq_cb(void *p) if(_BatteryControllerStatusChangeCb) _BatteryControllerStatusChangeCb(old_battery_status, _battery_fsm); } } -#elif BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY +#elif BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY && HARDWARE_PLATFORM == SMART_WATCH_PCB static void battery_controller_irq_cb(void *p) { enum tls_io_name gpio_pin = (enum tls_io_name)p; @@ -122,7 +143,7 @@ static void watch_peripherals_io_init(void) tls_gpio_cfg(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); tls_gpio_cfg(BATTERY_CONTROLLER_CHARGING_STATUS, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); -#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY +#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == INTERRUPT_POLICY && HARDWARE_PLATFORM == SMART_WATCH_PCB tls_gpio_isr_register(BATTERY_CONTROLLER_CHARGED_STATUS, &(battery_controller_irq_cb), (int*) BATTERY_CONTROLLER_CHARGED_STATUS); tls_gpio_irq_enable(BATTERY_CONTROLLER_CHARGED_STATUS, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE); // Enabled when level is changing edge @@ -171,7 +192,7 @@ void watch_peripherals_init(int8_t adcOffset) if(WM_TIMER_ID_INVALID == _vibration_motor_timer_id) APP_LOG_ERROR("Failed to create vibration motor timer"); } -#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY +#if BATTERY_CONTROLLER_STATUS_DETECTION_POLICY == POLL_POLICY && HARDWARE_PLATFORM == SMART_WATCH_PCB if(WM_TIMER_ID_INVALID == _battery_status_timer_id) { struct tls_timer_cfg battery_status_timer_cfg = @@ -190,6 +211,9 @@ void watch_peripherals_init(int8_t adcOffset) tls_timer_start(_battery_status_timer_id); } #endif + + /* Let's init the I2C interface */ + i2c_init(I2C_SDA, I2C_SCL, I2C_CLOCK_SPEED); } void watch_peripherals_register_battery_controller_status_change_cb(BatteryControllerStatusChangeCb_t BatteryControllerStatusChangeCb) @@ -264,3 +288,309 @@ void watch_peripherals_set_orientation(LCDOrientation_e orientation) extern LCDConfig_t LCDConfig; lcd_orientation(&LCDConfig, orientation); } + +bool watch_peripherals_magnetometer_init(void) +{ + /* Init the magnetometer */ + if(!QMC5883L_init()) + { + APP_LOG_ERROR("Failed to init QMC5883L"); + return false; + } + else + APP_LOG_INFO("Inited QMC5883L"); + + /* Needed but UGLY */ + tls_os_time_delay(2); + + if(!QMC5883L_set_power_mode(QMC5883L_Mode_Control_Continuous)) + { + APP_LOG_ERROR("Failed to set QMC5883L mode"); + return false; + } + else + APP_LOG_INFO("QMC5883L Mode set"); + + /* Needed but UGLY */ + tls_os_time_delay(2); + + if(!QMC5883L_configure_1(ODR_10HZ, FS_2G, OSR_512)) + { + APP_LOG_ERROR("Failed to configure 1 QMC5883L"); + return false; + } + else + APP_LOG_INFO("QMC5883L configured"); + + return true; +} + +void watch_peripherals_magnetometer_calibration_data_set( + int16_t x_min, int16_t x_max, + int16_t y_min, int16_t y_max, + int16_t z_min, int16_t z_max, float temperature_offset +) +{ + QMC5883L_set_calibration_data(x_min, x_max, y_min, y_max, z_min, z_max, temperature_offset); +} + +uint16_t watch_peripherals_magnetometer_azimuth_read(bool *is_data_available) +{ + bool data_ready = QMC5883L_is_data_available(); + + if(is_data_available) *is_data_available = data_ready; + + if(!data_ready) return 0; + + QMC5883L_MData_calibrated_t MData = QMC5883L_get_MFields_calibrated(); + return QMC5883L_get_azimuth(MData); +} + +QMC5883L_MData_t watch_peripherals_magnetometer_raw_data_read(void) +{ + return QMC5883L_get_MFields_raw(); +} + +bool watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_e mode_control) +{ + return QMC5883L_set_power_mode(mode_control); +} + +bool watch_peripherals_pressure_sensor_init(void) +{ + /* Init the BMP280 */ + if(!BMP280_init()) + { + APP_LOG_ERROR("Failed to init BMP280"); + return false; + } + else + APP_LOG_INFO("Inited BMP280"); + + if(!BMP280_configure(BMP280_Forced, BMP280_Oversampling_x16, BMP280_Oversampling_x16, BMP280_Filter_x16, BMP280_Standby_4000MS)) + { + APP_LOG_ERROR("Failed to configure BMP280"); + return false; + } + else + APP_LOG_INFO("BMP280 configured"); + + return true; +} + +float watch_peripherals_pressure_sensor_get_pressure(float * const temperature) +{ + BMP280_trigger_measurement(); + + while(BMP280_is_measuring()); + + return BMP280_get_pressure(temperature); +} + +static BMA4_INTF_RET_TYPE _bma4_i2c_read(uint8_t reg_addr, uint8_t *read_data, uint32_t len, void *intf_ptr) +{ + uint8_t dev_address = *(uint8_t*)intf_ptr; + + return !i2c_read(dev_address, reg_addr, read_data, len); +} + +static BMA4_INTF_RET_TYPE _bma4_i2c_write(uint8_t reg_addr, const uint8_t *read_data, uint32_t len, void *intf_ptr) +{ + uint8_t dev_address = *(uint8_t*)intf_ptr; + + return !i2c_write(dev_address, reg_addr, read_data, len); +} + +// TODO: Rework the delay_us function to rather use a timer and have real µs resolution and not ms ... +static void _bma4_delay_us(uint32_t period, void *intf_ptr) +{ + (void) intf_ptr; + + if(period < 1000) + tls_os_time_delay(1); + else + tls_os_time_delay(pdMS_TO_TICKS(period / 1000)); +} + +bool watch_peripherals_accelerometer_init(void) +{ + /* Init the BMA456 */ + _bma456.bma.intf = BMA4_I2C_INTF; + _bma456.bma.intf_ptr = &_bma456.dev_addr; + _bma456.bma.bus_read = &(_bma4_i2c_read); + _bma456.bma.bus_write = &(_bma4_i2c_write); + _bma456.bma.variant = BMA45X_VARIANT; + _bma456.bma.delay_us = &(_bma4_delay_us); + _bma456.bma.read_write_len = 46; + _bma456.bma.perf_mode_status = BMA4_DISABLE; + + if(bma456w_init(&_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 init"); + else + { + APP_LOG_ERROR("Failed to init BMA456"); + return false; + } + + if(bma4_soft_reset(&_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 soft reset"); + else + { + APP_LOG_ERROR("Failed to soft reset BMA456"); + return false; + } + tls_os_time_delay(2); + + if(bma456w_write_config_file(&_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 config ok"); + else + { + APP_LOG_ERROR("BMA456 config failed"); + return false; + } + + _bma456.accel_conf.odr = BMA4_OUTPUT_DATA_RATE_100HZ; + _bma456.accel_conf.range = BMA4_ACCEL_RANGE_2G; + _bma456.accel_conf.bandwidth = BMA4_ACCEL_NORMAL_AVG4; + _bma456.accel_conf.perf_mode = BMA4_CIC_AVG_MODE; + + if(bma4_set_accel_config(&_bma456.accel_conf, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 accel conf ok"); + else + { + APP_LOG_ERROR("BMA456 accel conf failed"); + return false; + } + + if(bma4_set_accel_enable(1, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 accel en ok"); + else + { + APP_LOG_ERROR("BMA456 accel en failed"); + return false; + } + + return true; +} + +bool watch_peripherals_accelerometer_wrist_wakeup_enable(bool enable) +{ + if(_bma456.wrist_wakeup_enable == enable) return true; + + _bma456.wrist_wakeup_enable = enable; + + if(bma456w_feature_enable(BMA456W_WRIST_WEAR_WAKEUP, enable, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 feature enable ok"); + else + { + APP_LOG_ERROR("BMA456 feature enable failed"); + return false; + } + + if(bma456w_get_wrist_wear_wakeup_param_config(&_bma456.setting, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 get wrist param ok"); + else + { + APP_LOG_ERROR("BMA456 get wrist param failed"); + return false; + } + + APP_LOG_DEBUG("%d %d %d %d %d %d %d %d", + _bma456.setting.min_angle_focus, + _bma456.setting.min_angle_non_focus, + _bma456.setting.angle_landscape_right, + _bma456.setting.angle_landscape_left, + _bma456.setting.angle_portrait_up, + _bma456.setting.angle_portrait_down, + _bma456.setting.min_dur_moved, + _bma456.setting.min_dur_quite); + + if(bma4_get_int_pin_config(&_bma456.pin_config, BMA4_INTR1_MAP, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 get pin conf ok"); + else + { + APP_LOG_ERROR("BMA456 get pin conf failed"); + return false; + } + + if(bma456w_map_interrupt(BMA4_INTR1_MAP, BMA456W_WRIST_WEAR_WAKEUP_INT, enable, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 map int ok"); + else + { + APP_LOG_ERROR("BMA456 map int failed"); + return false; + } + + _bma456.pin_config.edge_ctrl = BMA4_EDGE_TRIGGER; + _bma456.pin_config.output_en = BMA4_OUTPUT_ENABLE; + _bma456.pin_config.lvl = BMA4_ACTIVE_LOW; + _bma456.pin_config.od = BMA4_PUSH_PULL; + _bma456.pin_config.input_en = BMA4_INPUT_DISABLE; + + if(bma4_set_int_pin_config(&_bma456.pin_config, BMA4_INTR1_MAP, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 set pin conf ok"); + else + { + APP_LOG_ERROR("BMA456 set pin conf failed"); + return false; + } + + return true; +} + +bool watch_peripherals_accelerometer_wrist_wakeup_interrupt(void) +{ + uint16_t bma456_int_status; + uint8_t rslt = bma456w_read_int_status(&bma456_int_status, &_bma456.bma); + if(rslt != BMA4_OK) + { + APP_LOG_ERROR("Failed to read int status"); + return false; + } + + if((BMA4_OK == rslt) && (bma456_int_status & BMA456W_WRIST_WEAR_WAKEUP_INT)) + return true; + + return false; +} + +bool watch_peripherals_accelerometer_step_counter_enable(bool enable) +{ + if(_bma456.step_counter_enable == enable) return true; + + _bma456.step_counter_enable = enable; + + if(bma456w_feature_enable(BMA456W_STEP_CNTR, BMA4_ENABLE, &_bma456.bma) == BMA4_OK) + APP_LOG_INFO("BMA456 step cnter feature enable ok"); + else + { + APP_LOG_ERROR("BMA456 step cnter feature enable failed"); + return false; + } + + return true; +} + +bool watch_peripherals_accelerometer_step_count_read(uint32_t *step_count) +{ + if(!step_count) return false; + + if(bma456w_step_counter_output(step_count, &_bma456.bma) != BMA4_OK) + { + APP_LOG_ERROR("Failed to read step counts"); + return false; + } + + return true; +} + +bool watch_peripherals_accelerometer_step_count_reset(void) +{ + if(bma456w_reset_step_counter(&_bma456.bma) != BMA4_OK) + { + APP_LOG_ERROR("Failed to reset step counts"); + return false; + } + + return true; +} diff --git a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h index 8dd9f03..1a3402c 100644 --- a/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h +++ b/src/W800_SDK_v1.00.10/app/app_drivers/watch_peripherals/watch_peripherals.h @@ -6,6 +6,7 @@ #define WATCH_PERIPHERALS_H #include "lcd.h" #include "wm_type_def.h" +#include "QMC5883L.h" typedef enum battery_unit { @@ -32,8 +33,8 @@ typedef void (*BatteryControllerStatusChangeCb_t)(battery_controller_status_e ol const char *battery_controller_status_2_str(battery_controller_status_e status); /** - * @brief Inits the watch peripherals driver. - * This must be called before using the API. + * @brief Inits the watch peripherals drivers and sets battery sensing ADC offset. + * This must be called before using the watch peripherals API. * * @param adcOffset an offset in mV to apply to the battery voltage reading. */ @@ -100,4 +101,34 @@ void watch_peripherals_set_brightness(uint8_t brightness); */ void watch_peripherals_set_orientation(LCDOrientation_e orientation); +bool watch_peripherals_magnetometer_init(void); + +void watch_peripherals_magnetometer_calibration_data_set( + int16_t x_min, int16_t x_max, + int16_t y_min, int16_t y_max, + int16_t z_min, int16_t z_max, float temperature_offset +); + +uint16_t watch_peripherals_magnetometer_azimuth_read(bool *is_data_available); + +QMC5883L_MData_t watch_peripherals_magnetometer_raw_data_read(void); + +bool watch_peripherals_magnetometer_power_mode_set(QMC5883L_Mode_Control_e mode_control); + +bool watch_peripherals_pressure_sensor_init(void); + +float watch_peripherals_pressure_sensor_get_pressure(float * const temperature); + +bool watch_peripherals_accelerometer_init(void); + +bool watch_peripherals_accelerometer_wrist_wakeup_enable(bool enable); + +bool watch_peripherals_accelerometer_wrist_wakeup_interrupt(void); + +bool watch_peripherals_accelerometer_step_counter_enable(bool enable); + +bool watch_peripherals_accelerometer_step_count_read(uint32_t *step_count); + +bool watch_peripherals_accelerometer_step_count_reset(void); + #endif //WATCH_PERIPHERALS_H \ No newline at end of file