diff --git a/CmakeLists.txt b/CmakeLists.txt index d2c83be..7dcb1ad 100644 --- a/CmakeLists.txt +++ b/CmakeLists.txt @@ -19,12 +19,12 @@ pico_sdk_init() # the executable -add_executable( node1 node1.c ) +add_executable( node1 node1.c bme280.c ) pico_set_program_version(node1 "0.1") pico_set_program_name(node1 "node_one") # pull in common dependencies -target_link_libraries( node1 pico_stdlib ) +target_link_libraries( node1 pico_stdlib hardware_i2c) # create map/bin/hex file etc. pico_add_extra_outputs( node1 ) diff --git a/bme280.c b/bme280.c new file mode 100644 index 0000000..b14d986 --- /dev/null +++ b/bme280.c @@ -0,0 +1,145 @@ +#include "bme280.h" +#include "hardware/i2c.h" +#include "pico/binary_info.h" +#include "pico/stdlib.h" +#include +#include +/* + Lib for Bosh BME280 Env Sensor. To be used in weather station context. + Sources: + - pico example for bmp280 a simpler sensor then bme280 that does not + include humidity + https://github.com/raspberrypi/pico-examples/blob/master/i2c/bmp280_i2c/bmp280_i2c.c + - bme280 datasheet + https://cdn.shopify.com/s/files/1/0174/1800/files/bst-bme280-ds002.pdf?v=1662743150 + - bmp280 datasheet + https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf + - pimoroni eshop + https://shop.pimoroni.com/products/bme280-breakout?variant=29420960677971 + - pimoroni pico sdk + https://github.com/boschsensortec/BME280_SensorAPI/tree/c47f06eb44fc96970f0abfcc941ec16425b2a9e6 +*/ + +// Define the custom pins for I2C +#define I2C_SDA_PIN 14 // Replace with your custom SDA pin +#define I2C_SCL_PIN 15 // Replace with your custom SCL pin + +// Define the I2C instance to use (i2c0 or i2c1) +#define I2C_PORT i2c1 + +// device has default bus address of 0x76 +#define ADDR _u(0x76) + +// hardware registers +#define REG_CONFIG _u(0xF5) +#define REG_CTRL_MEAS _u(0xF4) +// #define REG_RESET _u(0xE0) + +// #define REG_TEMP_XLSB _u(0xFC) +// #define REG_TEMP_LSB _u(0xFB) +// #define REG_TEMP_MSB _u(0xFA) + +// #define REG_PRESSURE_XLSB _u(0xF9) +// #define REG_PRESSURE_LSB _u(0xF8) +// #define REG_PRESSURE_MSB _u(0xF7) + +// calibration registers +#define REG_DIG_T1_LSB _u(0x88) +// #define REG_DIG_T1_MSB _u(0x89) +// #define REG_DIG_T2_LSB _u(0x8A) +// #define REG_DIG_T2_MSB _u(0x8B) +// #define REG_DIG_T3_LSB _u(0x8C) +// #define REG_DIG_T3_MSB _u(0x8D) +// #define REG_DIG_P1_LSB _u(0x8E) +// #define REG_DIG_P1_MSB _u(0x8F) +// #define REG_DIG_P2_LSB _u(0x90) +// #define REG_DIG_P2_MSB _u(0x91) +// #define REG_DIG_P3_LSB _u(0x92) +// #define REG_DIG_P3_MSB _u(0x93) +// #define REG_DIG_P4_LSB _u(0x94) +// #define REG_DIG_P4_MSB _u(0x95) +// #define REG_DIG_P5_LSB _u(0x96) +// #define REG_DIG_P5_MSB _u(0x97) +// #define REG_DIG_P6_LSB _u(0x98) +// #define REG_DIG_P6_MSB _u(0x99) +// #define REG_DIG_P7_LSB _u(0x9A) +// #define REG_DIG_P7_MSB _u(0x9B) +// #define REG_DIG_P8_LSB _u(0x9C) +// #define REG_DIG_P8_MSB _u(0x9D) +// #define REG_DIG_P9_LSB _u(0x9E) +// #define REG_DIG_P9_MSB _u(0x9F) + +// number of calibration registers to be read +// 17 * 2 = 34 +#define NUM_COMPENSATION_PARAMS 34 + +static void bmp280_get_compensation_params(i2c_inst_t *i2c, bme280_compensation_params *params) { + // raw temp and pressure values need to be calibrated according to + // parameters generated during the manufacturing of the sensor + // there are 3 temperature params, and 9 pressure params, each with a LSB + // and MSB register, so we read from 24 registers + + uint8_t buf[NUM_COMPENSATION_PARAMS] = {0}; + uint8_t reg = REG_DIG_T1_LSB; + i2c_write_blocking(i2c, ADDR, ®, 1, + true); // true to keep master control of bus + // read in one go as register addresses auto-increment + i2c_read_blocking(i2c, ADDR, buf, NUM_COMPENSATION_PARAMS, + false); // false, we're done reading + + // store these in a struct for later use + params->dig_t1 = (uint16_t)(buf[1] << 8) | buf[0]; + params->dig_t2 = (int16_t)(buf[3] << 8) | buf[2]; + params->dig_t3 = (int16_t)(buf[5] << 8) | buf[4]; + + params->dig_p1 = (uint16_t)(buf[7] << 8) | buf[6]; + params->dig_p2 = (int16_t)(buf[9] << 8) | buf[8]; + params->dig_p3 = (int16_t)(buf[11] << 8) | buf[10]; + params->dig_p4 = (int16_t)(buf[13] << 8) | buf[12]; + params->dig_p5 = (int16_t)(buf[15] << 8) | buf[14]; + params->dig_p6 = (int16_t)(buf[17] << 8) | buf[16]; + params->dig_p7 = (int16_t)(buf[19] << 8) | buf[18]; + params->dig_p8 = (int16_t)(buf[21] << 8) | buf[20]; + params->dig_p9 = (int16_t)(buf[23] << 8) | buf[22]; + + params->dig_h1 = (int16_t)(buf[25] << 8) | buf[24]; + params->dig_h2 = (int16_t)(buf[27] << 8) | buf[26]; + params->dig_h3 = (int16_t)(buf[29] << 8) | buf[28]; + params->dig_h4 = (int16_t)(buf[31] << 8) | buf[30]; + params->dig_h5 = (int16_t)(buf[33] << 8) | buf[32]; +} + +void bme280_init(bme280_config *config, i2c_inst_t *i2c, uint8_t sda_pin, + uint8_t scl_pin) { + i2c_init(i2c, 100 * 1000); + gpio_set_function(sda_pin, GPIO_FUNC_I2C); + gpio_set_function(scl_pin, GPIO_FUNC_I2C); + gpio_pull_up(sda_pin); + gpio_pull_up(scl_pin); + // use the "handheld device dynamic" optimal setting (see datasheet) + // bi_decl(bi_2pins_with_func(sda_pin, scl_pin, GPIO_FUNC_I2C)); + // bi_decl(bi_program_description("BMP280 I2C LIB")); + + uint8_t buf[2]; + + // 500ms sampling time, x16 filter + const uint8_t reg_config_val = ((0x04 << 5) | (0x05 << 2)) & 0xFC; + + // send register number followed by its corresponding value + buf[0] = REG_CONFIG; + buf[1] = reg_config_val; + i2c_write_blocking(i2c, ADDR, buf, 2, false); + + // osrs_t x1, osrs_p x4, normal mode operation + const uint8_t reg_ctrl_meas_val = (0x01 << 5) | (0x03 << 2) | (0x03); + buf[0] = REG_CTRL_MEAS; + buf[1] = reg_ctrl_meas_val; + i2c_write_blocking(i2c, ADDR, buf, 2, false); + + bme280_compensation_params params; + bmp280_get_compensation_params(i2c, ¶ms); + + config->params = params; + config->i2c = i2c; + return; +} diff --git a/bme280.h b/bme280.h new file mode 100644 index 0000000..9ad84b6 --- /dev/null +++ b/bme280.h @@ -0,0 +1,36 @@ +#ifndef BME280_H +#define BME280_H +#include "hardware/i2c.h" +typedef struct { + // temperature params + uint16_t dig_t1; + int16_t dig_t2; + int16_t dig_t3; + + // pressure params + uint16_t dig_p1; + int16_t dig_p2; + int16_t dig_p3; + int16_t dig_p4; + int16_t dig_p5; + int16_t dig_p6; + int16_t dig_p7; + int16_t dig_p8; + int16_t dig_p9; + + // humidity params + uint16_t dig_h1; + int16_t dig_h2; + int16_t dig_h3; + int16_t dig_h4; + int16_t dig_h5; +} bme280_compensation_params; + +typedef struct { + i2c_inst_t *i2c; + bme280_compensation_params params; +} bme280_config; + +void bme280_init(bme280_config *config, i2c_inst_t *i2c, + uint8_t sda_pin, uint8_t scl_pin); +#endif /* BME280_H */ diff --git a/node1.c b/node1.c index 4783a2f..ed67a4c 100644 --- a/node1.c +++ b/node1.c @@ -1,10 +1,14 @@ #include +#include #include "pico/stdlib.h" -// #include "hardware/clocks.h" +#include "bme280.h" + int main() { stdio_init_all(); + bme280_config config; + bme280_init(&config, i2c1, 14, 15); while (true) { sleep_ms(1000); printf("One Second\n");