diff --git a/vignettes/articles/bme280MeasurementFlow.png b/vignettes/articles/bme280MeasurementFlow.png deleted file mode 100644 index e6d5b29..0000000 Binary files a/vignettes/articles/bme280MeasurementFlow.png and /dev/null differ diff --git a/vignettes/articles/i2cbme280.Rmd b/vignettes/articles/i2cbme280.Rmd deleted file mode 100644 index 51b6fe6..0000000 --- a/vignettes/articles/i2cbme280.Rmd +++ /dev/null @@ -1,466 +0,0 @@ ---- -title: "Use I2C for BME280" ---- - -```{r, include = FALSE} -knitr::opts_chunk$set( - collapse = TRUE, - comment = "#>" -) -``` - -This article shows an example of using `rpi_i2c…` to communicate with a BME280 sensor chip. - -# BME280 - -The BME280 [(Datasheet)](https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bme280-ds002.pdf) by Bosch is a versatile integrated environmental sensor designed for precision measurement of ambient temperature, relative humidity, and atmospheric pressure. This compact and low-power sensor is equipped with advanced MEMS (Micro-Electro-Mechanical Systems) technology, providing accurate and reliable data for various applications, including weather forecasting, indoor climate control, and IoT devices. Its I2C and SPI communication interfaces make it easy to interface with microcontrollers and microprocessors, while its small form factor and energy efficiency make it an ideal choice for a wide range of projects, from weather stations to wearable tech, where monitoring and controlling environmental conditions are paramount. - -# Wiring the BME280 - -## illustration to come - -# Setup Raspberry Pi for the BME280 - -Please refer to the [article](rpi_i2c.Rmd) on using i2c with R on the Raspberry Pi. You'll need to enable I2C (using Raspberry Pi Configuration) and find the address for the BME280 (using `i2c-tools -y 1`) - -To confirm the chip is connected and available, use `rpi_i2c_get(chip_address = BME280_location, data_address= 0xD0)`. Depending on the implementation you have purchased, the BME280 may also appear at chip address 0x76, in which case you would use `rpi_i2c_get(chip_address = 0x76, data_address= 0xD0).` This command should return the BME Chip ID, `0x60` - -# Preliminary: Data Calibration - -The temperature, humidity, and pressure data from the BME280 needs to be calibrated with other values provided by the BME280. This calibration algorithm is complex and obfuscates the process of using `rpi_i2c…` to read i2c interfaces. In an attempt to separate calibration from reading data, I've chosen to use the original c++ algorithm provided by Bosch Sensortec (shown in the BME280 datasheet) and use `Rcpp` to make it available to the R environment. - -Calibration requires values obtained from the BME280. These values can be identified as `dig_T1…`, `dig_H1…`, or `dig_P1…`followed by `_reg` (the register location in hex) or `_value` (the value at that register). I have placed the retrieval of these values close to the related function calls, but these values are stored on the BME280 as non-volatile RAM. They never change, so if you are looping data acquisition, your performance will improve if you move i2c calls to these calibration values outside of the loop. - -# Read the BME280 - -The BME280 datasheet provides this flowchart for reading the sensors. - -![BME280 measurement flow from data sheet](bme280MeasurementFlow.png) - -Here is the complete code to read temperature, pressure, and humidity from the bme280 with i2c. It leans heavily on the source found at [github.com/boschsensortec](https://github.com/boschsensortec/BME280_driver/blob/master/bme280.c). - -```{r, eval=FALSE} - -library(rpigpior) -library(Rcpp) - -BME280_location <- 0x77 #possibly change to 0x76 - -# locations of BME280 registers as identified in datasheet -BME280_id <- 0xD0 # 0x60 for BME280 -BME280_reset <- 0xE0 -BME280_ctrl_hum <- 0xF2 -BME280_status <- 0xF3 -BME280_ctrl_meas <- 0xF4 -BME280_config <- 0xF5 -BME280_press <- 0xF7 # through 0xF9. _msb, _lsb, _xlsb -BME280_temp <- 0xFA # through 0xFC. _msb, _lsb, _xlsb -BME280_hum <- 0xFD # through 0xFE. _msb, _lsb, _xlsb - -# these addresses contain values used in the calibration functions -dig_T1_reg <- 0x88 # these are all 2-byte / 1 word values -dig_T2_reg <- 0x8A -dig_T3_reg <- 0x8C -dig_P1_reg <- 0x8E -dig_P2_reg <- 0x90 -dig_P3_reg <- 0x92 -dig_P4_reg <- 0x94 -dig_P5_reg <- 0x96 -dig_P6_reg <- 0x98 -dig_P7_reg <- 0x9A -dig_P8_reg <- 0x9C -dig_P9_reg <- 0x9E -dig_H1_reg <- 0xA1 # this is one byte -dig_H2_reg <- 0xE1 # this is two bytes -dig_H3_reg <- 0xE3 # this is one byte -dig_H4_reg <- 0xE4 # Erg. This is 11 bits. 1.5 bytes. 0xE4/0xE5[3:0] -dig_H5_reg <- 0xE5 # 0xE5[7:4]/0xE6 -dig_H6_reg <- 0xE7 # one byte - -# start measurement cycle ------------------ -# set configuration values -config_value <- strtoi("01000100", base = 2) # t_sb = 125 ms/IIR_filter = on/2 /spi3w_en = off - -rpi_i2c_set( - chip_address = BME280_location, - data_address = BME280_config, - value = config_value, - data_size = "b" -) - -# set humidity data acquisition options -ctrl_hum_value <- 0x01 # humidity oversampling set to 1 - -rpi_i2c_set( - chip_address = BME280_location, - data_address = BME280_ctrl_hum, - value = ctrl_hum_value, - data_size = "b" -) - -# set pressure & temperature data acquisition options -ctrl_meas_value <- strtoi("00100101", base = 2) # osrs_t/osrs_p/mode - -rpi_i2c_set( - chip_address = BME280_location, - data_address = BME280_ctrl_meas, - value = ctrl_meas_value, - data_size = "b" - ) - -# read raw temperature --------------------- - -# Use Rcpp to compile the temperature measurement calibration -# Returns temp in DegC, resolution is 0.01 DegC. -# Output value of "5123" equals 51.23 DegC -# cppFunction('Rcpp::IntegerVector BME280_compensate_T_int32(Rcpp::IntegerVector adc_T, Rcpp::IntegerVector dig_T1, Rcpp::IntegerVector dig_T2, Rcpp::IntegerVector dig_T3) -# { -#long signed int var1, var2, T; -# Environment env = Environment::global_env(); -# long signed int t_fine; - -#var1 = ((((adc_T>>3) - (dig_T1<<1))) * (dig_T2)) >> 11; -#var2 = (((((adc_T>>4) - (dig_T1)) * ((adc_T>>4) - dig_T1)) >> 12) *dig_T3) >> 14; -#t_fine = var1 + var2; -#env["t_fine"] = t_fine; -#T = (t_fine * 5 + 128) >> 8; -#return T; -#}') - -# read the temperature -MsbLsb <- bitwShiftL(rpi_i2c_get(BME280_location, BME280_temp, "w"),4) -xlsb <- rpi_i2c_get(BME280_location, BME280_temp + 2, "b") -raw_temperature <- bitwOr(MsbLsb, xlsb) -# call the temperature compensation function just compiled -dig_T1_value <- rpi_i2c_get(BME280_location, dig_T1_reg, "w") -dig_T2_value <- rpi_i2c_get(BME280_location, dig_T2_reg, "w") -dig_T3_value <- rpi_i2c_get(BME280_location, dig_T3_reg, "w") - -# perform the calculation -------------------------- - -t_var1 <- bitShiftR((bitShiftR(raw_temperature, 3) - bitShiftL(dig_T1_value, 1)) * dig_T2_value, 11) - -t_var2 <- bitShiftR(bitShiftR((bitShiftR(adc_T, 4) - dig_T1_value) * (bitShiftR(adc_T, 4) - dig_T1_value), 12) * dig_T3_value, 14) - -t_fine <- t_var1 + t_var2; -temperature_celsius <- bitwShiftR((t_fine * 5 + 128),8) - -# temperature_celsius <- BME280_compensate_T_int32(raw_temperature, dig_T1_value,dig_T2_value,dig_T3_value) - -print(paste("temperature (c):", (temperature_celsius/100))) - -# read raw pressure ---------------------- - -# Use Rcpp to compile the pressure measurement calibration -# Returns pressure in Pa as unsigned 32 bit int in Q24.8 format -# (24 integer bits and 8 fractional bits) -# Output of "24674867" represents 24674867/256 = 96386.2 Pa -cppFunction('long unsigned int BME280_compensate_P_int32(long signed int adc_P, int dig_P1, int dig_P2, int dig_P3, int dig_P4, int dig_P5, int dig_P6, int dig_P7, int dig_P8, int dig_P9) -{ -long long unsigned int var1, var2, p; - Environment env = Environment::global_env(); - long signed int t_fine = env["t_fine"]; - -var1 = ((long long unsigned int)t_fine) - 128000; -var2 = var1 * var1 * (long long unsigned int)dig_P6; -var2 = var2 + (var1*((long long unsigned int)dig_P5)<<17); -var2 = var2 + (((long long unsigned int)dig_P4)<<35); -var1 = ((var1 * var1 * (long long unsigned int)dig_P3)>>8) + ((var1 * (long long unsigned int)dig_P2)<<12); -var1 = (((((long long unsigned int)1)<<47)+var1)) + ((long long unsigned int)dig_P1)>>33; -if(var1 == 0) -{ -return 0; // avoid exception caused by division by zero -} -p = 1048576-adc_P; -p = (((p<<31)-var2)*3125)/var1; -var1 = (((long long unsigned int)dig_P9) * (p>>13) * (p>>13)) >> 25; -var2 = (((long long unsigned int)dig_P8) * p) >> 19; -p = ((p +var1 + var2) >> 8) + (((long long unsigned int)dig_P7)<<4); -return (long signed int)p; -}') - -raw_pressure <- bitwShiftL(rpi_i2c_get(BME280_location, BME280_press, "w"),4) + bitwShiftR(rpi_i2c_get(BME280_location, BME280_press + 2, "b"),4) - -pressure <- BME280_compensate_P_int32(raw_pressure, - rpi_i2c_get(BME280_location, dig_P1_reg, "w"), - rpi_i2c_get(BME280_location, dig_P2_reg, "w"), - rpi_i2c_get(BME280_location, dig_P3_reg, "w"), - rpi_i2c_get(BME280_location, dig_P4_reg, "w"), - rpi_i2c_get(BME280_location, dig_P5_reg, "w"), - rpi_i2c_get(BME280_location, dig_P6_reg, "w"), - rpi_i2c_get(BME280_location, dig_P7_reg, "w"), - rpi_i2c_get(BME280_location, dig_P8_reg, "w"), - rpi_i2c_get(BME280_location, dig_P9_reg, "w") -) - -print(paste("pressure (Pa):", (pressure/256))) - -# read raw humidity ---------------------- - -# Use Rcpp to compile the humidity measurement calibration -# returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits) -# output value of "47445" represents 4755/1024 = 46.333 %RH -cppFunction('long unsigned int BME280_compensate_H_int32(long signed int adc_H, int dig_H1, int dig_H2, int dig_H3, int dig_H4, int dig_H5, int dig_H6) { - long signed int v_xl_u32r; - Environment env = Environment::global_env(); - long signed int t_fine = env["t_fine"]; - - v_xl_u32r = (t_fine - ((long signed int)76800)); - v_xl_u32r = (((((adc_H << 14) - - (((long signed int)dig_H4) << 20) - - (((long signed int)dig_H5) - * v_xl_u32r)) - + ((long signed int)16384)) >> 15) - * (((((((v_xl_u32r - * ((long signed int)dig_H6)) >> 10) - * (((v_xl_u32r - * ((long signed int)dig_H3)) >> 11) - + ((long signed int)32768))) >> 10) - + ((long signed int)2097152)) - * ((long signed int)dig_H2) + 8192) >> 14)); - v_xl_u32r = (v_xl_u32r - (((((v_xl_u32r >> 15) - * v_xl_u32r >> 15)) >> 7 - * ((long signed int)dig_H1)) >> 4)); - v_xl_u32r = (v_xl_u32r < 0 ?0 : v_xl_u32r); - v_xl_u32r = (v_xl_u32r > 419430400 ? 419430400 : v_xl_u32r); - return (long unsigned int) (v_xl_u32r>>12);}') - -raw_humidity <- rpi_i2c_get(BME280_location, BME280_hum, "w") - -# 11 bits. 1.5 bytes. 0xE4/0xE5[3:0] -dig_H4_value <- bitwShiftL(rpi_i2c_get(BME280_location, dig_H4_reg, "b"),4) + bitwAnd(rpi_i2c_get(BME280_location, dig_H4_reg + 1, "b"), 0x0F) - -dig_H5_value <- bitwShiftL(bitwAnd(rpi_i2c_get(BME280_location, dig_H5_reg, "b"),0xF0),4) + rpi_i2c_get(BME280_location, dig_H5_reg + 1, "b") - -humidity <- BME280_compensate_H_int32(raw_humidity, - rpi_i2c_get(BME280_location, dig_H1_reg, "b"), - rpi_i2c_get(BME280_location, dig_H2_reg, "w"), - rpi_i2c_get(BME280_location, dig_H3_reg, "b"), - dig_H4_value, - dig_H5_value, - rpi_i2c_get(BME280_location, dig_H6_reg, "b")) - -print(paste("humidity (%RH):", (humidity/1024))) - -``` - -# Optimized - -Here is the same code, optimized to repeat every one second - -```{r, eval= FALSE} - -library(rpigpior) -library(Rcpp) - -BME280_location <- 0x77 #possibly change to 0x76 - -# locations of BME280 registers as identified in datasheet -BME280_id <- 0xD0 # 0x60 for BME280 -BME280_reset <- 0xE0 -BME280_ctrl_hum <- 0xF2 -BME280_status <- 0xF3 -BME280_ctrl_meas <- 0xF4 -BME280_config <- 0xF5 -BME280_press <- 0xF7 # through 0xF9. _msb, _lsb, _xlsb -BME280_temp <- 0xFA # through 0xFC. _msb, _lsb, _xlsb -BME280_hum <- 0xFD # through 0xFE. _msb, _lsb, _xlsb - -# these addresses contain values used in the calibration functions -dig_T1_reg <- 0x88 # these are all 2-byte / 1 word values -dig_T1_value <- rpi_i2c_get(BME280_location, dig_T1_reg, "w") - -dig_T2_reg <- 0x8A -dig_T2_value <- rpi_i2c_get(BME280_location, dig_T2_reg, "w") - -dig_T3_reg <- 0x8C -dig_T3_value <- rpi_i2c_get(BME280_location, dig_T3_reg, "w") - -dig_P1_reg <- 0x8E -dig_P1_value <- rpi_i2c_get(BME280_location, dig_P1_reg, "w") - -dig_P2_reg <- 0x90 -dig_P2_value <- rpi_i2c_get(BME280_location, dig_P2_reg, "w") - -dig_P3_reg <- 0x92 -dig_P3_value <- rpi_i2c_get(BME280_location, dig_P3_reg, "w") - -dig_P4_reg <- 0x94 -dig_P4_value <- rpi_i2c_get(BME280_location, dig_P4_reg, "w") - -dig_P5_reg <- 0x96 -dig_P5_value <- rpi_i2c_get(BME280_location, dig_P5_reg, "w") - -dig_P6_reg <- 0x98 -dig_P6_value <- rpi_i2c_get(BME280_location, dig_P6_reg, "w") - -dig_P7_reg <- 0x9A -dig_P7_value <- rpi_i2c_get(BME280_location, dig_P7_reg, "w") - -dig_P8_reg <- 0x9C -dig_P8_value <- rpi_i2c_get(BME280_location, dig_P8_reg, "w") - -dig_P9_reg <- 0x9E -dig_P9_value <- rpi_i2c_get(BME280_location, dig_P9_reg, "w") - -dig_H1_reg <- 0xA1 # this is one byte -dig_H1_value <- rpi_i2c_get(BME280_location, dig_H1_reg, "b") - -dig_H2_reg <- 0xE1 # this is two bytes -dig_H2_value <- rpi_i2c_get(BME280_location, dig_H2_reg, "w") - -dig_H3_reg <- 0xE3 # this is one byte -dig_H3_value <- rpi_i2c_get(BME280_location, dig_H3_reg, "b") - -dig_H4_reg <- 0xE4 # Erg. This is 11 bits. 1.5 bytes. 0xE4/0xE5[3:0] -dig_H4_value <- bitwShiftL(rpi_i2c_get(BME280_location, dig_H4_reg, "b"),4) + bitwAnd(rpi_i2c_get(BME280_location, dig_H4_reg + 1, "b"), 0x0F) - -dig_H5_reg <- 0xE5 # 0xE5[7:4]/0xE6 -dig_H5_value <- bitwShiftL(bitwAnd(rpi_i2c_get(BME280_location, dig_H5_reg, "b"),0xF0),4) + rpi_i2c_get(BME280_location, dig_H5_reg + 1, "b") - -dig_H6_reg <- 0xE7 # one byte -dig_H6_value <- rpi_i2c_get(BME280_location, dig_H6_reg, "b") - -# set configuration values -config_value <- strtoi("01000100", base = 2) # t_sb = 125 ms/IIR_filter = on/2 /spi3w_en = off - -rpi_i2c_set( - chip_address = BME280_location, - data_address = BME280_config, - value = config_value, - data_size = "b" -) - -# set humidity data acquisition options -ctrl_hum_value <- 0x01 # humidity oversampling set to 1 - -rpi_i2c_set( - chip_address = BME280_location, - data_address = BME280_ctrl_hum, - value = ctrl_hum_value, - data_size = "b" -) - -# set pressure & temperature data acquisition options -ctrl_meas_value <- strtoi("00100101", base = 2) # osrs_t/osrs_p/mode - -# Use Rcpp to compile the temperature measurement calibration -# Returns temp in DegC, resolution is 0.01 DegC. -# Output value of "5123" equals 51.23 DegC -cppFunction('int BME280_compensate_T_int32(long signed int adc_T, int dig_T1, int dig_T2, int dig_T3) -{ -long signed int var1, var2, T; - Environment env = Environment::global_env(); - long signed int t_fine; - -var1 = ((((adc_T>>3) - ((long signed int)dig_T1<<1))) * ((long signed int)dig_T2)) >> 11; -var2 = (((((adc_T>>4) - ((long signed int)dig_T1)) * ((adc_T>>4) - ((long signed int)dig_T1))) >> 12) *((long signed int)dig_T3)) >> 14; -t_fine = var1 + var2; -env["t_fine"] = t_fine; -T = (t_fine * 5 + 128) >> 8; -return T; -}') - -# Use Rcpp to compile the pressure measurement calibration -# Returns pressure in Pa as unsigned 32 bit int in Q24.8 format -# (24 integer bits and 8 fractional bits) -# Output of "24674867" represents 24674867/256 = 96386.2 Pa -cppFunction('long unsigned int BME280_compensate_P_int32(long signed int adc_P, int dig_P1, int dig_P2, int dig_P3, int dig_P4, int dig_P5, int dig_P6, int dig_P7, int dig_P8, int dig_P9) -{ -long long unsigned int var1, var2, p; - Environment env = Environment::global_env(); - long signed int t_fine = env["t_fine"]; - -var1 = ((long long unsigned int)t_fine) - 128000; -var2 = var1 * var1 * (long long unsigned int)dig_P6; -var2 = var2 + (var1*((long long unsigned int)dig_P5)<<17); -var2 = var2 + (((long long unsigned int)dig_P4)<<35); -var1 = ((var1 * var1 * (long long unsigned int)dig_P3)>>8) + ((var1 * (long long unsigned int)dig_P2)<<12); -var1 = (((((long long unsigned int)1)<<47)+var1)) + ((long long unsigned int)dig_P1)>>33; -if(var1 == 0) -{ -return 0; // avoid exception caused by division by zero -} -p = 1048576-adc_P; -p = (((p<<31)-var2)*3125)/var1; -var1 = (((long long unsigned int)dig_P9) * (p>>13) * (p>>13)) >> 25; -var2 = (((long long unsigned int)dig_P8) * p) >> 19; -p = ((p +var1 + var2) >> 8) + (((long long unsigned int)dig_P7)<<4); -return (long signed int)p; -}') - -# Use Rcpp to compile the humidity measurement calibration -# returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits) -# output value of "47445" represents 4755/1024 = 46.333 %RH -cppFunction('long unsigned int BME280_compensate_H_int32(long signed int adc_H, int dig_H1, int dig_H2, int dig_H3, int dig_H4, int dig_H5, int dig_H6) { - long signed int v_xl_u32r; - Environment env = Environment::global_env(); - long signed int t_fine = env["t_fine"]; - - v_xl_u32r = (t_fine - ((long signed int)76800)); - v_xl_u32r = (((((adc_H << 14) - - (((long signed int)dig_H4) << 20) - - (((long signed int)dig_H5) - * v_xl_u32r)) - + ((long signed int)16384)) >> 15) - * (((((((v_xl_u32r - * ((long signed int)dig_H6)) >> 10) - * (((v_xl_u32r - * ((long signed int)dig_H3)) >> 11) - + ((long signed int)32768))) >> 10) - + ((long signed int)2097152)) - * ((long signed int)dig_H2) + 8192) >> 14)); - v_xl_u32r = (v_xl_u32r - (((((v_xl_u32r >> 15) - * v_xl_u32r >> 15)) >> 7 - * ((long signed int)dig_H1)) >> 4)); - v_xl_u32r = (v_xl_u32r < 0 ?0 : v_xl_u32r); - v_xl_u32r = (v_xl_u32r > 419430400 ? 419430400 : v_xl_u32r); - return (long unsigned int) (v_xl_u32r>>12);}') - - -# start measurement cycle ------------------ - -while (TRUE) { -rpi_i2c_set( - chip_address = BME280_location, - data_address = BME280_ctrl_meas, - value = ctrl_meas_value, - data_size = "b" -) - -# read raw temperature --------------------- - -raw_temperature <- bitwShiftL(rpi_i2c_get(BME280_location, BME280_temp, "w"),4) + bitwShiftR(rpi_i2c_get(BME280_location, BME280_temp + 2, "b"),4) -# call the temperature compensation function just compiled -temperature_celsius <- BME280_compensate_T_int32(raw_temperature, dig_T1_value,dig_T2_value,dig_T3_value) - - -# read raw pressure ---------------------- -raw_pressure <- bitwShiftL(rpi_i2c_get(BME280_location, BME280_press, "w"),4) + bitwShiftR(rpi_i2c_get(BME280_location, BME280_press + 2, "b"),4) - -pressure <- BME280_compensate_P_int32(raw_pressure, - dig_P1_value, dig_P2_value, dig_P3_value, - dig_P4_value, dig_P5_value, dig_P6_value, - dig_P7_value, dig_P8_value, dig_P9_value) - - -# read raw humidity ---------------------- - -raw_humidity <- rpi_i2c_get(BME280_location, BME280_hum, "w") - -humidity <- BME280_compensate_H_int32(raw_humidity, - dig_H1_value, - dig_H2_value, - dig_H3_value, - dig_H4_value, - dig_H5_value, - dig_H6_value) - -print(paste("temperature (c):", (temperature_celsius/100), "pressure (Pa):", (pressure/256), -"humidity (%RH):", (humidity/1024))) - -Sys.sleep(1) -} - - -```