Skip to content

Commit ad3bf49

Browse files
authored
Atomic HRS reads (#1845)
- Combine the reading of all `HRS3300` registers into one I2C read so data is not partial - Downsizes both HRS and ALS to 16bit as the sensor does not generate larger than 16bit values in its current configuration - Increasing the resolution by 1 bit doubles the sensor acquisition time, since we are already at 10Hz we are never going to use a higher resolution - The PPG algorithm buffers for ALS/HRS are already 16bit anyway - Remove functions for setting gain / drive that are unused throughout the codebase - Calculate constants with constexpr
1 parent 7ca0418 commit ad3bf49

5 files changed

Lines changed: 40 additions & 40 deletions

File tree

src/components/heartrate/Ppg.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ Ppg::Ppg() {
142142
spectrum.fill(0.0f);
143143
}
144144

145-
int8_t Ppg::Preprocess(uint32_t hrs, uint32_t als) {
145+
int8_t Ppg::Preprocess(uint16_t hrs, uint16_t als) {
146146
if (dataIndex < dataLength) {
147147
dataHRS[dataIndex++] = hrs;
148148
}

src/components/heartrate/Ppg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ namespace Pinetime {
1414
class Ppg {
1515
public:
1616
Ppg();
17-
int8_t Preprocess(uint32_t hrs, uint32_t als);
17+
int8_t Preprocess(uint16_t hrs, uint16_t als);
1818
int HeartRate();
1919
void Reset(bool resetDaqBuffer);
2020
static constexpr int deltaTms = 100;

src/drivers/Hrs3300.cpp

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -67,40 +67,37 @@ void Hrs3300::Disable() {
6767
WriteRegister(static_cast<uint8_t>(Registers::PDriver), 0);
6868
}
6969

70-
uint32_t Hrs3300::ReadHrs() {
71-
auto m = ReadRegister(static_cast<uint8_t>(Registers::C0DataM));
72-
auto h = ReadRegister(static_cast<uint8_t>(Registers::C0DataH));
73-
auto l = ReadRegister(static_cast<uint8_t>(Registers::C0dataL));
74-
return ((l & 0x30) << 12) | (m << 8) | ((h & 0x0f) << 4) | (l & 0x0f);
75-
}
76-
77-
uint32_t Hrs3300::ReadAls() {
78-
auto m = ReadRegister(static_cast<uint8_t>(Registers::C1dataM));
79-
auto h = ReadRegister(static_cast<uint8_t>(Registers::C1dataH));
80-
auto l = ReadRegister(static_cast<uint8_t>(Registers::C1dataL));
81-
return ((h & 0x3f) << 11) | (m << 3) | (l & 0x07);
82-
}
83-
84-
void Hrs3300::SetGain(uint8_t gain) {
85-
constexpr uint8_t maxGain = 64U;
86-
gain = std::min(gain, maxGain);
87-
uint8_t hgain = 0;
88-
while ((1 << hgain) < gain) {
89-
++hgain;
70+
Hrs3300::PackedHrsAls Hrs3300::ReadHrsAls() {
71+
constexpr Registers dataRegisters[] =
72+
{Registers::C1dataM, Registers::C0DataM, Registers::C0DataH, Registers::C1dataH, Registers::C1dataL, Registers::C0dataL};
73+
// Calculate smallest register address
74+
constexpr uint8_t baseOffset = static_cast<uint8_t>(*std::min_element(std::begin(dataRegisters), std::end(dataRegisters)));
75+
// Calculate largest address to determine length of read needed
76+
// Add one to largest relative index to find the length
77+
constexpr uint8_t length = static_cast<uint8_t>(*std::max_element(std::begin(dataRegisters), std::end(dataRegisters))) - baseOffset + 1;
78+
79+
Hrs3300::PackedHrsAls res;
80+
uint8_t buf[length];
81+
auto ret = twiMaster.Read(twiAddress, baseOffset, buf, length);
82+
if (ret != TwiMaster::ErrorCodes::NoError) {
83+
NRF_LOG_INFO("READ ERROR");
9084
}
91-
92-
WriteRegister(static_cast<uint8_t>(Registers::Hgain), hgain << 2);
93-
}
94-
95-
void Hrs3300::SetDrive(uint8_t drive) {
96-
auto en = ReadRegister(static_cast<uint8_t>(Registers::Enable));
97-
auto pd = ReadRegister(static_cast<uint8_t>(Registers::PDriver));
98-
99-
en = (en & 0xf7) | ((drive & 2) << 2);
100-
pd = (pd & 0xbf) | ((drive & 1) << 6);
101-
102-
WriteRegister(static_cast<uint8_t>(Registers::Enable), en);
103-
WriteRegister(static_cast<uint8_t>(Registers::PDriver), pd);
85+
// hrs
86+
uint8_t m = static_cast<uint8_t>(Registers::C0DataM) - baseOffset;
87+
uint8_t h = static_cast<uint8_t>(Registers::C0DataH) - baseOffset;
88+
uint8_t l = static_cast<uint8_t>(Registers::C0dataL) - baseOffset;
89+
// There are two extra bits (17 and 18) but they are not read here
90+
// as resolutions >16bit aren't practically useful (too slow) and
91+
// all hrs values throughout InfiniTime are 16bit
92+
res.hrs = (buf[m] << 8) | ((buf[h] & 0x0f) << 4) | (buf[l] & 0x0f);
93+
94+
// als
95+
m = static_cast<uint8_t>(Registers::C1dataM) - baseOffset;
96+
h = static_cast<uint8_t>(Registers::C1dataH) - baseOffset;
97+
l = static_cast<uint8_t>(Registers::C1dataL) - baseOffset;
98+
res.als = ((buf[h] & 0x3f) << 11) | (buf[m] << 3) | (buf[l] & 0x07);
99+
100+
return res;
104101
}
105102

106103
void Hrs3300::WriteRegister(uint8_t reg, uint8_t data) {

src/drivers/Hrs3300.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ namespace Pinetime {
2121
Hgain = 0x17
2222
};
2323

24+
struct PackedHrsAls {
25+
uint16_t hrs;
26+
uint16_t als;
27+
};
28+
2429
Hrs3300(TwiMaster& twiMaster, uint8_t twiAddress);
2530
Hrs3300(const Hrs3300&) = delete;
2631
Hrs3300& operator=(const Hrs3300&) = delete;
@@ -30,10 +35,7 @@ namespace Pinetime {
3035
void Init();
3136
void Enable();
3237
void Disable();
33-
uint32_t ReadHrs();
34-
uint32_t ReadAls();
35-
void SetGain(uint8_t gain);
36-
void SetDrive(uint8_t drive);
38+
PackedHrsAls ReadHrsAls();
3739

3840
private:
3941
TwiMaster& twiMaster;

src/heartratetask/HeartRateTask.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ void HeartRateTask::Work() {
7070
}
7171

7272
if (measurementStarted) {
73-
int8_t ambient = ppg.Preprocess(heartRateSensor.ReadHrs(), heartRateSensor.ReadAls());
73+
auto sensorData = heartRateSensor.ReadHrsAls();
74+
int8_t ambient = ppg.Preprocess(sensorData.hrs, sensorData.als);
7475
int bpm = ppg.HeartRate();
7576

7677
// If ambient light detected or a reset requested (bpm < 0)

0 commit comments

Comments
 (0)