My trial of BME280 library, tested with Adafruit BME280 module

Dependents:   test_BME280

Files at this revision

API Documentation at this revision

Comitter:
Rhyme
Date:
Tue May 09 06:32:36 2017 +0000
Child:
1:7b525853bad0
Commit message:
spi read/write started working

Changed in this revision

BME280.cpp Show annotated file Show diff for this revision Revisions of this file
BME280.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BME280.cpp	Tue May 09 06:32:36 2017 +0000
@@ -0,0 +1,403 @@
+#include "mbed.h"
+#include "BME280.h"
+
+/* internal registers */
+#define REG_HUM_LSB    0xFE
+#define REG_HUM_MSB    0xFD
+#define REG_TEMP_XLSB  0xFC
+#define REG_TEMP_LSB   0xFB
+#define REG_TEMP_MSB   0xFA
+#define REG_PRESS_XLSB 0xF9
+#define REG_PRESS_LSB  0xF8
+#define REG_PRESS_MSB  0xF7
+#define REG_CONFIG     0xF5
+#define REG_CTRL_MEAS  0xF4
+#define REG_STATUS     0xF3
+#define REG_CTRL_HUM   0xF2
+#define REG_RESET      0xE0
+#define REG_ID         0xD0
+
+#define REG_CALIB00   0x88
+#define REG_CALIB25   0xA1
+#define REG_CALIB26   0xE1
+#define REG_CALIB41   0xF0
+
+/** Trimming parameters */
+/* temperature */
+#define REG_T1_LSB 0x88
+#define REG_T1_MSB 0x89
+#define REG_T2_LSB 0x8A
+#define REG_T2_MSB 0x8B
+#define REG_T3_LSB 0x8C
+#define REG_T3_MSB 0x8D
+/* pressure */
+#define REG_P1_LSB 0x8E
+#define REG_P1_MSB 0x8F
+#define REG_P2_LSB 0x90
+#define REG_P2_MSB 0x91
+#define REG_P3_LSB 0x92
+#define REG_P3_MSB 0x93
+#define REG_P4_LSB 0x94
+#define REG_P4_MSB 0x95
+#define REG_P5_LSB 0x96
+#define REG_P5_MSB 0x97
+#define REG_P6_LSB 0x98
+#define REG_P6_MSB 0x99
+#define REG_P7_LSB 0x9A
+#define REG_P7_MSB 0x9B
+#define REG_P8_LSB 0x9C
+#define REG_P8_MSB 0x9D
+#define REG_P9_LSB 0x9E
+#define REG_P9_MSB 0x9F
+/* humidity */
+#define REG_H1     0xA1
+#define REG_H2_LSB 0xE1
+#define REG_H2_MSB 0xE2
+#define REG_H3     0xE3
+
+
+/*
+ * Register description
+ * 0xD0 "id"
+ *  chip identification number chip_id[7:0], which is 0x60
+ *
+ * 0xE0 "reset"
+ *  Software reset register, writing 0xB6 causes complete power-on-reset.
+ *
+ * 0xF2 "ctrl_hum"
+ *  Specifies the humidity data acquision options.
+ *  Note: Changes to this register only become effective after a write
+ *  operaion to "ctrl_meas".
+ * bit[2:0] osrs_h[2:0] Controls oversampling of humidity data.
+ *  000: Skipped (output set to 0x8000)
+ *  001: oversampling x1
+ *  010: oversampling x2
+ *  011: oversampling x4
+ *  100: oversampling x8
+ *  101, others, oversampling x16
+ *
+ * 0xF3 "status"
+ * bit[3] measuring[0] Automatically set to '1' during conversion 
+ *        and back to '0' when done
+ * bit[0] im_update[0] Automatically set to '1' during NVM data copy 
+ *        and back to '0' when done
+ *
+ * 0xF4 "ctrl_meas" 
+ *  Specifies the pressure and temperature data acquision options.
+ *  Note: This register needs to be written after canging "ctrl_hum" to take effect.
+ * bit[7:5] osrs_t[2:0] Controls oversampling of temperature data
+ *  bit value is similar to osrs_h (except 000 output set to 0x80000)
+ * bit[4:2] osrs_p[2:0] Controls oversampling of pressure data
+ *  bit value is similar to osrs_h (except 000 output set to 0x80000)
+ * bit[1:0] mode[1:0] Controls the sensor mode.
+ *  00: Sleep mode
+ *  01: Forced mode
+ *  10: Forced mode
+ *  11: Normal mode
+ *
+ * 0xF5 "config" 
+ *  Specifies the rate, filter and interface options.
+ *  Writes to "config" in normal mode may be ignored.
+ *  In sleep mode writes are not ignored.
+ * bit[7:5] t_sb[2:0] Controls inactive duration t_standby in normal mode.
+ * 000:    0.5 [ms]
+ * 001:   62.5 [ms]
+ * 010:  125   [ms]
+ * 011:  250   [ms]
+ * 100:  500   [ms]
+ * 101: 1000   [ms]
+ * 110:   10   [ms]
+ * 111:   20   [ms]
+ * bit[4:2] filter[2:0] Controls the time constant of the IIR filter.
+ * 000: Filter off
+ * 001:  2
+ * 010:  4
+ * 011:  8
+ * 100, others: 16
+ *
+ * 0xF7 .. 0xF9 "press" (_msb, _lsb, _xlsb)
+ * 0xF7 bit[7:0] press_msb[7:0]   MSB part up[19:12]
+ * 0xF8 bit[7:0] press_lsb[7:0]   LSB part  up[11:4]
+ * 0xF9 bit[7:4] press_xlsb[3:0] XLSB part   up[3:0]
+ *
+ * 0xFA .. 0xFC "temp" (_msb, _lsb, _xlsb)
+ * 0xFA bit[7:0] temp_msb[7:0]   MSB part ut[19:12]
+ * 0xFB bit[7:0] temp_lsb[7:0]   LSB part  ut[11:4]
+ * 0xFC bit[7:4] temp_xlsp[3:0] XLSB part   ut[3:0]
+ *
+ * 0xFD .. 0xFE "hum" (_msb, _lsb)
+ * 0xFD bit[7:0] hum_msb[7:0]    MSB part uh[15:8]
+ * 0xFE bit[7:0] hum_lsb[7:0]    LSB part  uh[7:0]
+ */
+
+void BME280::init(void)
+{
+    uint8_t data[18] ;
+    
+    data[0] = REG_CTRL_HUM ;
+    data[1] = 0x03 ; /* Humidity oversampling x4 */
+    writeRegs(data, 2) ;
+    
+    data[0] = REG_CTRL_MEAS ;
+    data[1] = (0x3 << 5) /* temp oversample x4 */
+            | (0x3 << 3) /* pres oversample x4 */
+            | (0x00)      /* Sleep Mode */
+            ;
+    writeRegs(data, 2) ;
+readRegs(REG_CTRL_MEAS, data, 1) ;
+printf("ctrl_meas: 0x%02X\n", data[0]) ;
+    
+    data[0] = REG_CONFIG ;
+    data[1] = (0x4 << 5) /* standby 500ms */
+            | (0x0 << 2) /* filter off */
+            | (0x0)      /* spi 4wire mode */   
+            ;
+    writeRegs(data, 2) ;
+    
+    /* read dig_T regs */
+    readRegs(REG_T1_LSB, data, 6) ;
+    dig_T1 = (data[1] << 8) | data[0] ;
+    dig_T2 = (data[3] << 8) | data[2] ;
+    dig_T3 = (data[5] << 8) | data[4] ;
+// printf("dig_T1:0x%04X, dig_T2:0x%04X, dig_T3:0x%04X\n",dig_T1, dig_T2, dig_T3) ;
+    
+    /* read dig_P regs */
+    readRegs(REG_P1_LSB, data, 18) ;
+    dig_P1 = (data[ 1] << 8) | data[ 0] ;
+    dig_P2 = (data[ 3] << 8) | data[ 2] ;
+    dig_P3 = (data[ 5] << 8) | data[ 4] ;
+    dig_P4 = (data[ 7] << 8) | data[ 6] ;
+    dig_P5 = (data[ 9] << 8) | data[ 8] ;
+    dig_P6 = (data[11] << 8) | data[10] ;
+    dig_P7 = (data[13] << 8) | data[12] ;
+    dig_P8 = (data[15] << 8) | data[14] ;
+    dig_P9 = (data[17] << 8) | data[16] ;
+// printf("dig_P1:0x%04X, dig_P2:0x%04X, dig_P3:0x%04X\n",dig_P1, dig_P2, dig_P3) ;
+// printf("dig_P4:0x%04X, dig_P5:0x%04X, dig_P6:0x%04X\n",dig_P4, dig_P5, dig_P6) ;
+// printf("dig_P7:0x%04X, dig_P8:0x%04X, dig_P9:0x%04X\n",dig_P7, dig_P8, dig_P9) ;
+    
+    /* read dig_H regs */
+    readRegs(REG_H1, data, 1) ;
+    dig_H1 = data[0] ;
+    readRegs(REG_H2_LSB, data, 3) ;
+    dig_H2 = (data[1] << 8) | data[0] ;
+    dig_H3 = data[2] ;
+// printf("dig_H1:0x%04X, dig_H2:0x%04X, dig_H3:0x%04X\n",dig_H1, dig_H2, dig_H3) ;    
+}
+
+BME280::BME280(PinName sda, PinName scl, int addr) 
+{
+    m_i2c = new I2C(sda, scl) ;
+    m_addr = (addr << 1) ;
+    m_spi = 0 ;
+    m_cs = 0 ;
+    init() ;
+}
+
+BME280::BME280(PinName sck, PinName miso, PinName mosi, PinName cs) 
+{
+    m_cs = new DigitalOut(cs, 1) ;
+    m_spi = new SPI(mosi, miso, sck) ;
+    m_spi->format(8, 3) ;
+#if 0
+#if defined (TARGET_KL25Z)
+    *((uint8_t *)0x40076000) |= 0x01 ; /* lsb first  */
+#endif
+#endif
+    m_i2c = 0 ;
+    m_addr = 0 ;
+    init() ;
+}
+
+BME280::~BME280() 
+{
+    if (m_spi) { 
+        delete m_spi ;
+        delete m_cs ; 
+    }
+    if (m_i2c) { 
+        delete m_i2c ; 
+        m_addr = 0 ;
+    }
+}
+
+void BME280::i2c_readRegs(int addr, uint8_t * data, int len) {
+    char t[1] = {addr} ;
+    m_i2c->write(m_addr, t, 1, true) ;
+    m_i2c->read(m_addr, (char*)data, len) ;
+}
+
+void BME280::i2c_writeRegs(uint8_t * data, int len) {
+   m_i2c->write(m_addr, (char *)data, len) ;
+}
+
+void BME280::spi_readRegs(int addr, uint8_t * data, int len) {
+    *m_cs = 0 ;
+    m_spi->write(addr | 0x80) ;
+    for (int i = 0 ; i < len ; i++ ) {    
+ //     m_spi->write((addr+i)|0x80) ;  // spacify address to read
+      data[i] = m_spi->write((addr+i)|0x80) ; 
+    } 
+    m_spi->write(0x00) ; // to terminate read mode
+    *m_cs = 1 ;
+}
+
+void BME280::spi_writeRegs(uint8_t * data, int len) {
+   *m_cs = 0 ;
+   for (int i = 0 ; i < len-1 ; i++ ) {
+// printf("writing 0x%02X := 0x%02X\n", (data[0]+i)^0x80, data[i+1]) ;
+      m_spi->write((data[0]+i)^0x80) ; /* register address */
+      m_spi->write(data[i+1]) ; /* data to write */
+
+   }
+   *m_cs = 1 ;
+}
+
+void BME280::readRegs(int addr, uint8_t *data, int len) 
+{
+    if (m_spi) {
+        spi_readRegs(addr, data, len) ;
+    } else if (m_i2c) {
+        i2c_readRegs(addr, data, len) ;
+    }
+}
+
+void BME280::writeRegs(uint8_t *data, int len) 
+{
+    if (m_spi) {
+        spi_writeRegs(data, len) ;
+    } else if (m_i2c) {
+        i2c_writeRegs(data, len) ;
+    }
+}
+
+void BME280::reset(void)
+{
+    uint8_t data[2] ;
+    data[0] = REG_RESET ;
+    data[1] = 0xB6 ;
+    writeRegs(data, 2) ;
+}
+
+void BME280::trigger(void)
+{
+    uint8_t data[2] ;
+    readRegs(REG_CTRL_MEAS, &data[1], 1) ;
+    
+    data[0] = REG_CTRL_MEAS ;
+    data[1] = (data[1] & 0xFC) /* keep oversampling */
+            | (0x2)      /* Forced Mode */
+            ;
+//    data[1] = 0x38 | 0x02 ;
+    writeRegs(data, 2) ;
+}
+
+uint8_t BME280::busy(void)
+{
+    uint8_t data[1] ;
+    readRegs(REG_STATUS, data, 1) ;
+    return( data[0] & 0x9 ) ;
+}
+
+uint8_t BME280::getID(void)
+{
+    uint8_t data[1] ;
+    readRegs(REG_ID, data, 1) ;
+    return(data[0]) ;
+}
+
+void BME280::readData(uint8_t data[]) 
+{
+    readRegs(REG_PRESS_MSB, data, 8) ;
+printf("Data Read: ") ;    
+for(int i = 0 ; i < 8 ; i++ ) {
+    printf("%02X ", data[i]) ;
+}
+printf("\n") ;
+}
+
+float BME280::getTemperature(uint8_t data[]) 
+{
+    uint32_t temp_raw;
+    float tempf;
+//    uint8_t data[3];
+ 
+//    readRegs(REG_TEMP_MSB, data, 3) ;
+ 
+    temp_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
+ 
+    int32_t temp;
+ 
+    temp =
+        (((((temp_raw >> 3) - (dig_T1 << 1))) * dig_T2) >> 11) +
+        ((((((temp_raw >> 4) - dig_T1) * ((temp_raw >> 4) - dig_T1)) >> 12) * dig_T3) >> 14);
+ 
+    t_fine = temp;
+    temp = (temp * 5 + 128) >> 8;
+    tempf = (float)temp;
+ 
+    return (tempf/100.0f);
+    
+}
+
+float BME280::getHumidity(uint8_t data[]) 
+{
+    uint32_t hum_raw;
+    float humf;
+//    uint8_t data[2];
+ 
+//    readRegs(REG_HUM_MSB, data, 2) ;
+ 
+    hum_raw = (data[0] << 8) | data[1];
+ 
+    int32_t v_x1;
+ 
+    v_x1 = t_fine - 76800;
+    v_x1 =  (((((hum_raw << 14) -(((int32_t)dig_H4) << 20) - (((int32_t)dig_H5) * v_x1)) +
+               ((int32_t)16384)) >> 15) * (((((((v_x1 * (int32_t)dig_H6) >> 10) *
+                                            (((v_x1 * ((int32_t)dig_H3)) >> 11) + 32768)) >> 10) + 2097152) *
+                                            (int32_t)dig_H2 + 8192) >> 14));
+    v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * (int32_t)dig_H1) >> 4));
+    v_x1 = (v_x1 < 0 ? 0 : v_x1);
+    v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
+ 
+    humf = (float)(v_x1 >> 12);
+ 
+    return (humf/1024.0f);
+}
+
+float BME280::getPressure(uint8_t data[]) 
+{
+    uint32_t press_raw;
+    float pressf;
+//    uint8_t data[3];
+ 
+//    readRegs(REG_PRESS_MSB, data, 3) ;
+ 
+    press_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
+ 
+    int32_t var1, var2;
+    uint32_t press;
+ 
+    var1 = (t_fine >> 1) - 64000;
+    var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * dig_P6;
+    var2 = var2 + ((var1 * dig_P5) << 1);
+    var2 = (var2 >> 2) + (dig_P4 << 16);
+    var1 = (((dig_P3 * (((var1 >> 2)*(var1 >> 2)) >> 13)) >> 3) + ((dig_P2 * var1) >> 1)) >> 18;
+    var1 = ((32768 + var1) * dig_P1) >> 15;
+    if (var1 == 0) {
+        return 0;
+    }
+    press = (((1048576 - press_raw) - (var2 >> 12))) * 3125;
+    if(press < 0x80000000) {
+        press = (press << 1) / var1;
+    } else {
+        press = (press / var1) * 2;
+    }
+    var1 = ((int32_t)dig_P9 * ((int32_t)(((press >> 3) * (press >> 3)) >> 13))) >> 12;
+    var2 = (((int32_t)(press >> 2)) * (int32_t)dig_P8) >> 13;
+    press = (press + ((var1 + var2 + dig_P7) >> 4));
+ 
+    pressf = (float)press;
+    return (pressf/100.0f);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BME280.h	Tue May 09 06:32:36 2017 +0000
@@ -0,0 +1,77 @@
+#ifndef _BME280_H_
+#define _BME280_H_
+#include "mbed.h"
+
+#define BME280_U32_t uint32_t
+#define BME280_S32_t int32_t
+#define BME280_S64_t int64_t
+
+/**
+ * BME280 Environmental sensor
+ *
+ * Note: Interface selection is done by the value of CSB (chip select)
+ * if CSB is pulled-up, I2C interface is active.
+ * if CSB is pulled-down, SPI interface is active.
+ * After CSB has been pulled down once (regardless of whether any clock cycle occurred)
+ * the I2C interface is disabled until the next power-on-reset.
+ */
+
+class BME280
+{
+public:
+ /**
+  * BME280 I2C Interface
+  *
+  * @param sda SDA pin
+  * @param scl SCL pin
+  * @param addr address of the I2C peripheral
+  */
+BME280(PinName sda, PinName scl, int addr) ;
+
+ /**
+  * BME280 SPI Interface
+  *
+  * @param sck  SPI SCKL pin
+  * @param miso SPI Master In Slave Out pin
+  * @param mosi SPI Master Out Slave In pin
+  * @param cs   SPI Chip Select pin
+  */
+BME280(PinName sck, PinName miso, PinName mosi, PinName cs) ;
+
+~BME280() ;
+
+void reset(void) ; 
+void init(void) ;
+void trigger(void) ; /* forced mode */
+uint8_t  busy(void) ;
+
+uint8_t getID(void) ;
+
+void readData(uint8_t data[]) ;
+  
+float getTemperature(uint8_t data[]) ;
+float getHumidity(uint8_t data[]) ;
+float getPressure(uint8_t data[]) ;
+
+private:
+  SPI *m_spi ;
+  I2C *m_i2c ;
+  DigitalOut *m_cs ;
+  int m_addr ;
+  BME280_S32_t t_fine ;
+  
+  uint16_t dig_T1, dig_T2, dig_T3 ;
+  uint16_t dig_P1, dig_P2, dig_P3 ; 
+  uint16_t dig_P4, dig_P5, dig_P6 ; 
+  uint16_t dig_P7, dig_P8, dig_P9 ;
+  uint16_t dig_H1, dig_H2, dig_H3 ;
+  uint16_t dig_H4, dig_H5, dig_H6 ;
+
+  void i2c_readRegs(int addr, uint8_t *data, int len) ;
+  void i2c_writeRegs(uint8_t *data, int len) ;
+  void spi_readRegs(int addr, uint8_t *data, int len) ;
+  void spi_writeRegs(uint8_t *data, int len) ;
+  void readRegs(int addr, uint8_t *data, int len) ;
+  void writeRegs(uint8_t *data, int len) ;
+} ;
+#endif /* _BME280_H_ */
\ No newline at end of file