GadgetSeed  0.9.6
bme280.c
[詳解]
1 /** @file
2  @brief BME280 温湿度・気圧センサ
3 
4  @date 2018.01.22
5  @authoer Takashi SHUDO
6 */
7 
8 #include "device.h"
9 #include "str.h"
10 #include "device/i2c_ioctl.h"
11 #include "device/envsnsr_ioctl.h"
12 
13 //#define DEBUGKBITS 0x01
14 #include "dkprintf.h"
15 
16 
17 static struct st_device *i2c_dev;
18 static char dev_name[MAX_DEVNAMELRN];
19 
20 typedef int BME280_S32_t;
21 typedef unsigned int BME280_U32_t;
22 
23 static unsigned short dig_T1; // Reg 0x88, 0x89
24 static signed short dig_T2; // Reg 0x8A, 0x8B
25 static signed short dig_T3; // Reg 0x8C, 0x8D
26 static unsigned short dig_P1; // Reg 0x8E, 0x8F
27 static signed short dig_P2; // Reg 0x90, 0x91
28 static signed short dig_P3; // Reg 0x92, 0x93
29 static signed short dig_P4; // Reg 0x94, 0x95
30 static signed short dig_P5; // Reg 0x96, 0x97
31 static signed short dig_P6; // Reg 0x98, 0x99
32 static signed short dig_P7; // Reg 0x9A, 0x9B
33 static signed short dig_P8; // Reg 0x9C, 0x9D
34 static signed short dig_P9; // Reg 0x9E, 0x9F
35 static unsigned char dig_H1; // Reg 0xA1
36 static signed short dig_H2; // Reg 0xE1, 0xE2
37 static unsigned char dig_H3; // Reg 0xE3
38 static signed short dig_H4; // Reg 0xE5, 0xE5[3:0]
39 static signed short dig_H5; // Reg 0xE5[7:4], 0xE6
40 static signed char dig_H6; // Reg 0xE7
41 
42 // Returns temperature in DegC, resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
43 // t_fine carries fine temperature as global value
44 BME280_S32_t t_fine;
45 BME280_S32_t BME280_compensate_T_int32(BME280_S32_t adc_T)
46 {
47  BME280_S32_t var1, var2, T;
48  var1 = ((((adc_T>>3) - ((BME280_S32_t)dig_T1<<1))) * ((BME280_S32_t)dig_T2)) >> 11;
49  var2 = (((((adc_T>>4) - ((BME280_S32_t)dig_T1)) * ((adc_T>>4) - ((BME280_S32_t)dig_T1))) >> 12) *
50  ((BME280_S32_t)dig_T3)) >> 14;
51  t_fine = var1 + var2;
52  T = (t_fine * 5 + 128) >> 8;
53  return T;
54 }
55 
56 // Returns pressure in Pa as unsigned 32 bit integer. Output value of “96386” equals 96386 Pa = 963.86 hPa
57 BME280_U32_t BME280_compensate_P_int32(BME280_S32_t adc_P)
58 {
59  BME280_S32_t var1, var2;
60  BME280_U32_t p;
61  var1 = (((BME280_S32_t)t_fine)>>1) - (BME280_S32_t)64000;
62  var2 = (((var1>>2) * (var1>>2)) >> 11 ) * ((BME280_S32_t)dig_P6);
63  var2 = var2 + ((var1*((BME280_S32_t)dig_P5))<<1);
64  var2 = (var2>>2)+(((BME280_S32_t)dig_P4)<<16);
65  var1 = (((dig_P3 * (((var1>>2) * (var1>>2)) >> 13 )) >> 3) + ((((BME280_S32_t)dig_P2) * var1)>>1))>>18;
66  var1 =((((32768+var1))*((BME280_S32_t)dig_P1))>>15);
67  if (var1 == 0)
68  {
69  return 0; // avoid exception caused by division by zero
70  }
71  p = (((BME280_U32_t)(((BME280_S32_t)1048576)-adc_P)-(var2>>12)))*3125;
72  if (p < 0x80000000)
73  {
74  p = (p << 1) / ((BME280_U32_t)var1);
75  }
76  else
77  {
78  p = (p / (BME280_U32_t)var1) * 2;
79  }
80  var1 = (((BME280_S32_t)dig_P9) * ((BME280_S32_t)(((p>>3) * (p>>3))>>13)))>>12;
81  var2 = (((BME280_S32_t)(p>>2)) * ((BME280_S32_t)dig_P8))>>13;
82  p = (BME280_U32_t)((BME280_S32_t)p + ((var1 + var2 + dig_P7) >> 4));
83  return p;
84 }
85 
86 // Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
87 // Output value of “47445” represents 47445/1024 = 46.333 %RH
88 BME280_U32_t bme280_compensate_H_int32(BME280_S32_t adc_H)
89 {
90  BME280_S32_t v_x1_u32r;
91  v_x1_u32r = (t_fine - ((BME280_S32_t)76800));
92  v_x1_u32r = (((((adc_H << 14) - (((BME280_S32_t)dig_H4) << 20) - (((BME280_S32_t)dig_H5) * v_x1_u32r)) +
93  ((BME280_S32_t)16384)) >> 15) * (((((((v_x1_u32r * ((BME280_S32_t)dig_H6)) >> 10) * (((v_x1_u32r *
94  ((BME280_S32_t)dig_H3)) >> 11) + ((BME280_S32_t)32768))) >> 10) + ((BME280_S32_t)2097152)) *
95  ((BME280_S32_t)dig_H2) + 8192) >> 14));
96  v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((BME280_S32_t)dig_H1)) >> 4));
97  v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
98  v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
99  return (BME280_U32_t)(v_x1_u32r>>12);
100 }
101 
102 #define DEV_ADDR 0x76
103 
104 static void init_bme280(void)
105 {
106  unsigned char osrs_t = 1; // Temperature oversampling x 1
107  unsigned char osrs_p = 1; // Pressure oversampling x 1
108  unsigned char osrs_h = 1; // Humidity oversampling x 1
109  unsigned char mode = 3; // Normal mode
110  unsigned char t_sb = 5; // Tstandby 1000ms
111  unsigned char filter = 0; // Filter off
112  unsigned char spi3w_en = 0; // 3-wire SPI Disable
113 
114  unsigned char ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
115  unsigned char config_reg = (t_sb << 5) | (filter << 2) | spi3w_en;
116  unsigned char ctrl_hum_reg = osrs_h;
117 
118  lock_device(i2c_dev, 0);
119  ioctl_device(i2c_dev, IOCMD_I2C_SLAVE_ADDR7, DEV_ADDR, 0);
121  seek_device(i2c_dev, 0xf2, SEEK_SET);
122  putc_device(i2c_dev, ctrl_hum_reg);
123  seek_device(i2c_dev, 0xf4, SEEK_SET);
124  putc_device(i2c_dev, ctrl_meas_reg);
125  seek_device(i2c_dev, 0xf5, SEEK_SET);
126  putc_device(i2c_dev, config_reg);
127  unlock_device(i2c_dev);
128 }
129 
130 static void calib_bme280(void)
131 {
132  unsigned char reg[32];
133 
134  lock_device(i2c_dev, 0);
135  ioctl_device(i2c_dev, IOCMD_I2C_SLAVE_ADDR7, DEV_ADDR, 0);
137 
138  seek_device(i2c_dev, 0x88, SEEK_SET);
139  read_device(i2c_dev, reg, 24);
140 
141  seek_device(i2c_dev, 0xA1, SEEK_SET);
142  read_device(i2c_dev, &reg[24], 1);
143 
144  seek_device(i2c_dev, 0xE1, SEEK_SET);
145  read_device(i2c_dev, &reg[25], 7);
146 
147  unlock_device(i2c_dev);
148 
149  KXDUMP(0x01, reg, 32);
150 
151  dig_T1 = (((unsigned short)reg[1])<<8) + reg[0];
152  DKPRINTF(0x01, "T1 : %d\n", dig_T1);
153  dig_T2 = (((signed short)reg[3])<<8) + reg[2];
154  DKPRINTF(0x01, "T2 : %d\n", dig_T2);
155  dig_T3 = (((signed short)reg[5])<<8) + reg[4];
156  DKPRINTF(0x01, "T3 : %d\n", dig_T3);
157 
158  dig_P1 = (((unsigned short)reg[7])<<8) + reg[6];
159  dig_P2 = ((signed short)reg[9]<<8) + reg[8];
160  dig_P3 = (((signed short)reg[11])<<8) + reg[10];
161  dig_P4 = (((signed short)reg[13])<<8) + reg[12];
162  dig_P5 = (((signed short)reg[15])<<8) + reg[14];
163  dig_P6 = (((signed short)reg[17])<<8) + reg[16];
164  dig_P7 = (((signed short)reg[19])<<8) + reg[18];
165  dig_P8 = (((signed short)reg[21])<<8) + reg[20];
166  dig_P9 = (((signed short)reg[23])<<8) + reg[22];
167  dig_H1 = reg[24];
168  dig_H2 = (((signed short)reg[26])<<8) + reg[25];
169  dig_H3 = reg[27];
170  dig_H4 = (((signed short)reg[28])<<4) + (0x0F & reg[29]);
171  dig_H5 = (((signed short)reg[30])<<4) + ((reg[29]>>4) & 0x0F);
172  dig_H6 = reg[31];
173 }
174 
175 static int bme280_register(struct st_device *dev, char *param)
176 {
177  strncopy((uchar *)dev_name, (uchar *)param, MAX_DEVNAMELRN);
178 
179  i2c_dev = open_device(dev_name);
180  if(i2c_dev == 0) {
181  SYSERR_PRINT("Cannot open device \"%s\"\n", dev_name);
182  return -1;
183  }
184 
185  init_bme280();
186  calib_bme280();
187 
188  close_device(i2c_dev);
189 
190  return 0;
191 }
192 
193 unsigned int hum_raw;
194 unsigned int temp_raw;
195 unsigned int pres_raw;
196 
197 static void get_raw_data(void)
198 {
199  unsigned char reg[8];
200 
201  lock_device(i2c_dev, 0);
202 
203  ioctl_device(i2c_dev, IOCMD_I2C_SLAVE_ADDR7, DEV_ADDR, 0);
205 
206  seek_device(i2c_dev, 0xf7, SEEK_SET);
207  read_device(i2c_dev, reg, 8);
208 
209  unlock_device(i2c_dev);
210 
211  pres_raw = (((unsigned int)reg[0]) << 12) | (((unsigned int)reg[1]) << 4) | (((unsigned int)reg[2]) >> 4);
212  temp_raw = (((unsigned int)reg[3]) << 12) | (((unsigned int)reg[4]) << 4) | (((unsigned int)reg[5]) >> 4);
213  hum_raw = (((unsigned int)reg[6]) << 8) | reg[7];
214 
215  DKFPRINTF(0x01, "PRES_RAW : %d(%x)\n", pres_raw, pres_raw);
216  DKFPRINTF(0x01, "TEMP_RAW : %d(%x)\n", temp_raw, temp_raw);
217  DKFPRINTF(0x01, "HUM_RAW : %d(%x)\n", hum_raw, hum_raw);
218 }
219 
220 static int bme280_ioctl(struct st_device *dev, unsigned int com, unsigned int arg, void *param)
221 {
222  switch(com) {
224  {
225  get_raw_data();
226  int rtn = BME280_compensate_T_int32(temp_raw);
227  DKPRINTF(0x01, "ENVSNSR_GET_TEMP %d\n", rtn);
228  return rtn;
229  }
230 
232  {
233  get_raw_data();
234  unsigned int rtn = bme280_compensate_H_int32(hum_raw);
235  DKPRINTF(0x01, "ENVSNSR_GET_HUM %d\n", rtn);
236  return rtn;
237  }
238 
240  {
241  get_raw_data();
242  unsigned int rtn = BME280_compensate_P_int32(pres_raw);
243  DKPRINTF(0x01, "ENVSNSR_GET_PRESS %d\n", rtn);
244  return rtn;
245  }
246 
248  {
249  get_raw_data();
250  int *thp = param;
251  thp[0] = BME280_compensate_T_int32(temp_raw);
252  thp[1] = bme280_compensate_H_int32(hum_raw);
253  thp[2] = BME280_compensate_P_int32(pres_raw);
254  DKPRINTF(0x01, "ENVSNSR_GET_THP T:%d H:%d P:%d\n", thp[0], thp[1], thp[2]);
255  return 0;
256  }
257 
258  default:
259  SYSERR_PRINT("Unknown ioctl(%08X)\n", com);
260  return -1;
261  }
262 
263  return 0;
264 }
265 
266 const struct st_device bme280_device = {
268  .explan = "BME280 Temp. sensor",
269  .register_dev = bme280_register,
270  .ioctl = bme280_ioctl,
271 };
unsigned char uchar
GadgetSeedの文字(列)は unsigned char 型となる
Definition: str.h:13
#define IOCMD_I2C_MEMADDRSIZE
Memory Address Size 8bit or 16bit etc
Definition: i2c_ioctl.h:36
#define IOCMD_ENVSNSR_GET_HUM
湿度を取得する(%)
Definition: envsnsr_ioctl.h:18
struct st_device * open_device(char *name)
デバイスをオープンする
Definition: device.c:262
文字列処理
int read_device(struct st_device *dev, void *buf, unsigned int count)
デバイスよりデータを読み出す
Definition: device.c:378
int seek_device(struct st_device *dev, int offset, int whence)
デバイスのアクセスポイントを設定する
Definition: device.c:545
#define DEF_DEV_NAME_ENVSNSR
標準環境センサデバイス名
Definition: envsnsr_ioctl.h:15
#define I2C_MEM_ADDR_SIZE_8BIT
I2Cスレーブデバイスメモリアドレスサイズは8ビット
Definition: i2c_ioctl.h:26
int unlock_device(struct st_device *dev)
デバイスをアンロックする
Definition: device.c:343
#define IOCMD_ENVSNSR_GET_THP
TEMP & HUM & PRES
Definition: envsnsr_ioctl.h:20
int putc_device(struct st_device *dev, unsigned char data)
デバイスにデータを1バイト書き込む
Definition: device.c:502
#define IOCMD_I2C_SLAVE_ADDR7
Set Save 7bit Address
Definition: i2c_ioctl.h:33
環境センサ(温度、湿度、気圧等)ドライバ ioctl 用マクロ定義
#define SEEK_SET
設定
Definition: device.h:21
#define IOCMD_ENVSNSR_GET_PRESS
気圧を取得する(hPa)
Definition: envsnsr_ioctl.h:19
uchar * strncopy(uchar *dest, const uchar *src, unsigned int n)
文字列コピー
Definition: str.c:632
#define IOCMD_ENVSNSR_GET_TEMP
温度を取得する(℃)
Definition: envsnsr_ioctl.h:17
int close_device(struct st_device *dev)
デバイスをクローズする
Definition: device.c:291
デバイスドライバAPI
デバイスドライバ構造体
Definition: device.h:25
I2Cドライバ ioctl 用マクロ定義
カーネル、ドライバ(非タスク)デバッグ用マクロ
int ioctl_device(struct st_device *dev, unsigned int com, unsigned int arg, void *param)
デバイスを制御する
Definition: device.c:525
char name[MAX_DEVNAMELRN]
デバイス名文字列
Definition: device.h:26
int lock_device(struct st_device *dev, unsigned int timeout)
デバイスをロックする
Definition: device.c:310