2021-01-17 15:33:45 +00:00
|
|
|
/*
|
|
|
|
SPDX-License-Identifier: LGPL-3.0-or-later
|
|
|
|
Original work Copyright (C) 2020 Daniel Thompson
|
|
|
|
C++ port Copyright (C) 2021 Jean-François Milants
|
|
|
|
*/
|
|
|
|
|
2021-11-05 22:55:34 +00:00
|
|
|
#include "drivers/Hrs3300.h"
|
2021-01-10 16:57:26 +00:00
|
|
|
#include <algorithm>
|
|
|
|
#include <nrf_gpio.h>
|
|
|
|
|
|
|
|
#include <FreeRTOS.h>
|
|
|
|
#include <task.h>
|
|
|
|
#include <nrf_log.h>
|
|
|
|
|
|
|
|
using namespace Pinetime::Drivers;
|
2023-01-03 14:05:30 +00:00
|
|
|
|
2023-05-07 16:18:49 +00:00
|
|
|
namespace {
|
|
|
|
static constexpr uint8_t ledDriveCurrentValue = 0x2f;
|
|
|
|
}
|
|
|
|
|
2021-01-17 15:33:45 +00:00
|
|
|
/** Driver for the HRS3300 heart rate sensor.
|
|
|
|
* Original implementation from wasp-os : https://github.com/daniel-thompson/wasp-os/blob/master/wasp/drivers/hrs3300.py
|
2023-04-30 13:50:18 +00:00
|
|
|
*
|
|
|
|
* Experimentaly derived changes to improve signal/noise (see comments below) - Ceimour
|
2021-01-17 15:33:45 +00:00
|
|
|
*/
|
2021-04-18 17:28:14 +00:00
|
|
|
Hrs3300::Hrs3300(TwiMaster& twiMaster, uint8_t twiAddress) : twiMaster {twiMaster}, twiAddress {twiAddress} {
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Hrs3300::Init() {
|
|
|
|
nrf_gpio_cfg_input(30, NRF_GPIO_PIN_NOPULL);
|
|
|
|
|
|
|
|
Disable();
|
|
|
|
vTaskDelay(100);
|
|
|
|
|
2023-04-30 13:50:18 +00:00
|
|
|
// HRS disabled, 50ms wait time between ADC conversion period, current 12.5mA
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Enable), 0x50);
|
2021-01-10 16:57:26 +00:00
|
|
|
|
2023-04-30 13:50:18 +00:00
|
|
|
// Current 12.5mA and low nibble 0xF.
|
|
|
|
// Note: Setting low nibble to 0x8 per the datasheet results in
|
|
|
|
// modulated LED driver output. Setting to 0xF results in clean,
|
|
|
|
// steady output during the ADC conversion period.
|
2023-05-07 16:18:49 +00:00
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::PDriver), ledDriveCurrentValue);
|
2021-01-10 16:57:26 +00:00
|
|
|
|
2023-04-30 13:50:18 +00:00
|
|
|
// HRS and ALS both in 15-bit mode results in ~50ms LED drive period
|
|
|
|
// and presumably ~50ms ADC conversion period.
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Res), 0x77);
|
2021-01-10 16:57:26 +00:00
|
|
|
|
2023-04-30 13:50:18 +00:00
|
|
|
// Gain set to 1x
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Hgain), 0x00);
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Hrs3300::Enable() {
|
|
|
|
NRF_LOG_INFO("ENABLE");
|
|
|
|
auto value = ReadRegister(static_cast<uint8_t>(Registers::Enable));
|
|
|
|
value |= 0x80;
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Enable), value);
|
2023-05-07 16:18:49 +00:00
|
|
|
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::PDriver), ledDriveCurrentValue);
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Hrs3300::Disable() {
|
|
|
|
NRF_LOG_INFO("DISABLE");
|
|
|
|
auto value = ReadRegister(static_cast<uint8_t>(Registers::Enable));
|
|
|
|
value &= ~0x80;
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Enable), value);
|
2023-05-07 16:18:49 +00:00
|
|
|
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::PDriver), 0);
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
2021-12-13 10:47:52 +00:00
|
|
|
uint32_t Hrs3300::ReadHrs() {
|
2021-01-10 16:57:26 +00:00
|
|
|
auto m = ReadRegister(static_cast<uint8_t>(Registers::C0DataM));
|
|
|
|
auto h = ReadRegister(static_cast<uint8_t>(Registers::C0DataH));
|
|
|
|
auto l = ReadRegister(static_cast<uint8_t>(Registers::C0dataL));
|
2021-12-13 10:39:34 +00:00
|
|
|
return ((l & 0x30) << 12) | (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f);
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
2021-12-13 10:47:52 +00:00
|
|
|
uint32_t Hrs3300::ReadAls() {
|
2021-01-10 16:57:26 +00:00
|
|
|
auto m = ReadRegister(static_cast<uint8_t>(Registers::C1dataM));
|
|
|
|
auto h = ReadRegister(static_cast<uint8_t>(Registers::C1dataH));
|
|
|
|
auto l = ReadRegister(static_cast<uint8_t>(Registers::C1dataL));
|
2021-12-13 10:39:34 +00:00
|
|
|
return ((h & 0x3f) << 11) | (m << 3) | (l & 0x07);
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Hrs3300::SetGain(uint8_t gain) {
|
2021-02-12 17:36:56 +00:00
|
|
|
constexpr uint8_t maxGain = 64U;
|
2021-01-10 16:57:26 +00:00
|
|
|
gain = std::min(gain, maxGain);
|
|
|
|
uint8_t hgain = 0;
|
2021-04-18 17:28:14 +00:00
|
|
|
while ((1 << hgain) < gain) {
|
2021-02-12 17:36:56 +00:00
|
|
|
++hgain;
|
|
|
|
}
|
2021-01-10 16:57:26 +00:00
|
|
|
|
2021-02-12 17:36:56 +00:00
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Hgain), hgain << 2);
|
2021-01-10 16:57:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Hrs3300::SetDrive(uint8_t drive) {
|
|
|
|
auto en = ReadRegister(static_cast<uint8_t>(Registers::Enable));
|
|
|
|
auto pd = ReadRegister(static_cast<uint8_t>(Registers::PDriver));
|
|
|
|
|
|
|
|
en = (en & 0xf7) | ((drive & 2) << 2);
|
|
|
|
pd = (pd & 0xbf) | ((drive & 1) << 6);
|
|
|
|
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::Enable), en);
|
|
|
|
WriteRegister(static_cast<uint8_t>(Registers::PDriver), pd);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Hrs3300::WriteRegister(uint8_t reg, uint8_t data) {
|
|
|
|
auto ret = twiMaster.Write(twiAddress, reg, &data, 1);
|
2021-04-18 17:28:14 +00:00
|
|
|
if (ret != TwiMaster::ErrorCodes::NoError)
|
2021-01-10 16:57:26 +00:00
|
|
|
NRF_LOG_INFO("WRITE ERROR");
|
|
|
|
}
|
|
|
|
|
|
|
|
uint8_t Hrs3300::ReadRegister(uint8_t reg) {
|
|
|
|
uint8_t value;
|
|
|
|
auto ret = twiMaster.Read(twiAddress, reg, &value, 1);
|
2021-04-18 17:28:14 +00:00
|
|
|
if (ret != TwiMaster::ErrorCodes::NoError)
|
2021-01-10 16:57:26 +00:00
|
|
|
NRF_LOG_INFO("READ ERROR");
|
|
|
|
return value;
|
|
|
|
}
|