Line data Source code
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 2 : if (!m_i2c.init(scl, sda)) { 39 0 : return false; 40 : } 41 : 42 : // Read ident register 43 2 : auto whoAmI = m_i2c.readRegister(addr, REG_WhoAmI); 44 : 45 2 : switch (whoAmI) 46 : { 47 0 : case expectedWhoAmILps22: 48 0 : m_type = Type::Lps22; 49 0 : break; 50 0 : case expectedWhoAmILps25: 51 0 : m_type = Type::Lps25; 52 0 : break; 53 2 : default: 54 : // chip not detected 55 2 : return false; 56 : } 57 : 58 0 : 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 0 : if (m_type == Type::Lps25) { 64 : // Set to active mode 65 : // this bit must be 0 on LPS22 66 0 : cr1 |= LPS_CR1_PD; 67 : } 68 : 69 : // Set the control registers 70 0 : m_i2c.writeRegister(addr, regCr1(), cr1); 71 : 72 0 : m_hasInit = true; 73 0 : return true; 74 : } 75 : 76 0 : expected<float> Lps25::readPressureKpa() { 77 0 : if (!m_hasInit) { 78 0 : return unexpected; 79 : } 80 : 81 0 : 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 0 : constexpr uint8_t readAddr = REG_Status | 0x80; 85 0 : m_i2c.writeRead(addr, &readAddr, 1, buffer, 4); 86 : 87 : // First check the status reg to check if there are data available 88 0 : bool hasPressure = buffer[0] & LPS_SR_P_DA; 89 : 90 0 : if (!hasPressure) { 91 0 : return unexpected; 92 : } 93 : 94 : // Glue the 3 bytes back in to a 24 bit integer 95 0 : uint32_t counts = buffer[3] << 16 | buffer[2] << 8 | buffer[1]; 96 : 97 : // 4096 counts per hectopascal 98 : // = 40960 counts per kilopascal 99 0 : constexpr float ratio = 1 / 40960.0f; 100 : 101 0 : 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 0 : if (kilopascal > 120 || kilopascal < 50) { 110 0 : return unexpected; 111 : } 112 : 113 0 : return kilopascal; 114 : } 115 : 116 0 : uint8_t Lps25::regCr1() const { 117 0 : switch (m_type) 118 : { 119 0 : case Type::Lps22: 120 0 : return REG_Cr1_Lps22; 121 0 : case Type::Lps25: 122 : default: 123 0 : return REG_Cr1_Lps25; 124 : } 125 : }