Line | Branch | Decision | Exec | Source |
---|---|---|---|---|
1 | /** | |||
2 | * @file lps25.cpp | |||
3 | * @brief Driver for the ST LPS25HB pressure sensor | |||
4 | * | |||
5 | * At the moment uses bit-banged I2C driver | |||
6 | * | |||
7 | * @date February 6, 2020 | |||
8 | * @author Matthew Kennedy, (c) 2020 | |||
9 | */ | |||
10 | ||||
11 | #include "pch.h" | |||
12 | ||||
13 | #include "lps25.h" | |||
14 | ||||
15 | static constexpr uint8_t addr = 0x5C; | |||
16 | static constexpr uint8_t expectedWhoAmILps22 = 0xB1; | |||
17 | static constexpr uint8_t expectedWhoAmILps25 = 0xBD; | |||
18 | ||||
19 | // Control register 1 | |||
20 | #define LPS_CR1_PD (1 << 7) | |||
21 | #define LPS_CR1_ODR_25hz (4 << 4) | |||
22 | #define LPS_CR1_BDU (1 << 2) | |||
23 | ||||
24 | // Status register flags | |||
25 | #define LPS_SR_P_DA (1 << 1) // Pressure data available | |||
26 | ||||
27 | #define REG_WhoAmI 0x0F | |||
28 | ||||
29 | // register address different on LPS22 vs LPS25 | |||
30 | #define REG_Cr1_Lps22 0x10 | |||
31 | #define REG_Cr1_Lps25 0x20 | |||
32 | #define REG_Status 0x27 | |||
33 | #define REG_PressureOutXl 0x28 | |||
34 | #define REG_PressureOutL 0x29 | |||
35 | #define REG_PressureOutH 0x2A | |||
36 | ||||
37 | 2 | bool Lps25::init(brain_pin_e scl, brain_pin_e sda) { | ||
38 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
1/2✗ Decision 'true' not taken.
✓ Decision 'false' taken 2 times.
|
2 | if (!m_i2c.init(scl, sda)) { |
39 | ✗ | return false; | ||
40 | } | |||
41 | ||||
42 | // Read ident register | |||
43 | 2 | auto whoAmI = m_i2c.readRegister(addr, REG_WhoAmI); | ||
44 | ||||
45 |
1/3✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
|
2 | switch (whoAmI) | |
46 | { | |||
47 | ✗ | case expectedWhoAmILps22: | ||
48 | ✗ | m_type = Type::Lps22; | ||
49 | ✗ | break; | ||
50 | ✗ | case expectedWhoAmILps25: | ||
51 | ✗ | m_type = Type::Lps25; | ||
52 | ✗ | break; | ||
53 |
1/1✓ Decision 'true' taken 2 times.
|
2 | default: | |
54 | // chip not detected | |||
55 | 2 | return false; | ||
56 | } | |||
57 | ||||
58 | ✗ | uint8_t cr1 = | ||
59 | LPS_CR1_ODR_25hz | // 25hz update rate | |||
60 | // TODO: should bdu be set? | |||
61 | LPS_CR1_BDU; // Output registers update only when read | |||
62 | ||||
63 | ✗ | if (m_type == Type::Lps25) { | ||
64 | // Set to active mode | |||
65 | // this bit must be 0 on LPS22 | |||
66 | ✗ | cr1 |= LPS_CR1_PD; | ||
67 | } | |||
68 | ||||
69 | // Set the control registers | |||
70 | ✗ | m_i2c.writeRegister(addr, regCr1(), cr1); | ||
71 | ||||
72 | ✗ | m_hasInit = true; | ||
73 | ✗ | return true; | ||
74 | } | |||
75 | ||||
76 | ✗ | expected<float> Lps25::readPressureKpa() { | ||
77 | ✗ | if (!m_hasInit) { | ||
78 | ✗ | return unexpected; | ||
79 | } | |||
80 | ||||
81 | ✗ | uint8_t buffer[4]; | ||
82 | // Sequential multi-byte reads need to set the high bit of the | |||
83 | // register address to enable multi-byte read | |||
84 | ✗ | constexpr uint8_t readAddr = REG_Status | 0x80; | ||
85 | ✗ | m_i2c.writeRead(addr, &readAddr, 1, buffer, 4); | ||
86 | ||||
87 | // First check the status reg to check if there are data available | |||
88 | ✗ | bool hasPressure = buffer[0] & LPS_SR_P_DA; | ||
89 | ||||
90 | ✗ | if (!hasPressure) { | ||
91 | ✗ | return unexpected; | ||
92 | } | |||
93 | ||||
94 | // Glue the 3 bytes back in to a 24 bit integer | |||
95 | ✗ | uint32_t counts = buffer[3] << 16 | buffer[2] << 8 | buffer[1]; | ||
96 | ||||
97 | // 4096 counts per hectopascal | |||
98 | // = 40960 counts per kilopascal | |||
99 | ✗ | constexpr float ratio = 1 / 40960.0f; | ||
100 | ||||
101 | ✗ | float kilopascal = counts * ratio; | ||
102 | ||||
103 | // Sensor limits are 26-126 kPa | |||
104 | // The highest ever barometric pressure measured was only 108.3 kPa | |||
105 | // The pressure at the highest altitude road (Khardung La, India/Tibet) is at 5600 meters, | |||
106 | // which should have a nominal barometric pressure of around 50 kPa | |||
107 | // Anything outside that range is not a place we expect your engine to run, so we assume | |||
108 | // some sensing problem (sealed ECU case and high temperature?) | |||
109 | ✗ | if (kilopascal > 120 || kilopascal < 50) { | ||
110 | ✗ | return unexpected; | ||
111 | } | |||
112 | ||||
113 | ✗ | return kilopascal; | ||
114 | } | |||
115 | ||||
116 | ✗ | uint8_t Lps25::regCr1() const { | ||
117 | ✗ | switch (m_type) | ||
118 | { | |||
119 | ✗ | case Type::Lps22: | ||
120 | ✗ | return REG_Cr1_Lps22; | ||
121 | ✗ | case Type::Lps25: | ||
122 | default: | |||
123 | ✗ | return REG_Cr1_Lps25; | ||
124 | } | |||
125 | } | |||
126 |