| 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 |