文章目錄
前言
一、寄存器頭文件定義
二、設備樹文件中添加節點
?三、驅動文件編寫
四、編寫驅動測試文件并編譯測試
總結
前言
本文驅動開發仿照正點原子的iic驅動實現,同時附上bmp280的數據手冊,可訪問下面的鏈接:
BMP280_Bosch(博世)_BMP280中文資料_PDF手冊_價格-立創商城下載數據手冊。
一、寄存器頭文件定義
? ? ? ? 在查看數據手冊時,可發現bmp280器件對各個寄存器,如數據,校準,采樣,濾波等等寄存器進行定義,如下代碼所示:
#ifndef BMP280_H
#define BMP280_H#define BMP280_ADDR 0x76 /* BMP280器件地址*//* BMP280寄存器 */
#define BMP280_ID_REG 0xD0 /* 芯片ID寄存器,值是0x58 */
#define BMP280_RESET_REG 0xE0 /* 復位寄存器 */
#define BMP280_STATUS_REG 0xF3 /* 狀態寄存器 */
#define BMP280_CTRL_MEAS_REG 0xF4 /* 測量控制寄存器 */
#define BMP280_CONFIG_REG 0xF5 /* 配置寄存器 *//* 數據寄存器 */
#define BMP280_PRESSURE_MSB 0xF7 /* 壓力數據高字節 */
#define BMP280_PRESSURE_LSB 0xF8 /* 壓力數據中字節 */
#define BMP280_PRESSURE_XLSB 0xF9 /* 壓力數據低字節 */
#define BMP280_TEMP_MSB 0xFA /* 溫度數據高字節 */
#define BMP280_TEMP_LSB 0xFB /* 溫度數據中字節 */
#define BMP280_TEMP_XLSB 0xFC /* 溫度數據低字節 *//* 校準參數寄存器 - 存儲補償計算需要的出廠校準數據 */
#define BMP280_DIG_T1_LSB_REG 0x88
#define BMP280_DIG_T1_MSB_REG 0x89
#define BMP280_DIG_T2_LSB_REG 0x8A
#define BMP280_DIG_T2_MSB_REG 0x8B
#define BMP280_DIG_T3_LSB_REG 0x8C
#define BMP280_DIG_T3_MSB_REG 0x8D
#define BMP280_DIG_P1_LSB_REG 0x8E
#define BMP280_DIG_P1_MSB_REG 0x8F
#define BMP280_DIG_P2_LSB_REG 0x90
#define BMP280_DIG_P2_MSB_REG 0x91
#define BMP280_DIG_P3_LSB_REG 0x92
#define BMP280_DIG_P3_MSB_REG 0x93
#define BMP280_DIG_P4_LSB_REG 0x94
#define BMP280_DIG_P4_MSB_REG 0x95
#define BMP280_DIG_P5_LSB_REG 0x96
#define BMP280_DIG_P5_MSB_REG 0x97
#define BMP280_DIG_P6_LSB_REG 0x98
#define BMP280_DIG_P6_MSB_REG 0x99
#define BMP280_DIG_P7_LSB_REG 0x9A
#define BMP280_DIG_P7_MSB_REG 0x9B
#define BMP280_DIG_P8_LSB_REG 0x9C
#define BMP280_DIG_P8_MSB_REG 0x9D
#define BMP280_DIG_P9_LSB_REG 0x9E
#define BMP280_DIG_P9_MSB_REG 0x9F/* 復位值 */
#define BMP280_RESET_VALUE 0xB6/* 工作模式 */
#define BMP280_SLEEP_MODE 0x00
#define BMP280_FORCED_MODE 0x01
#define BMP280_NORMAL_MODE 0x03/* 過采樣設置 */
#define BMP280_OSRS_T_SKIP 0x00 /* 溫度測量跳過 */
#define BMP280_OSRS_T_X1 0x20 /* 溫度測量1倍過采樣 */
#define BMP280_OSRS_T_X2 0x40
#define BMP280_OSRS_T_X4 0x60
#define BMP280_OSRS_T_X8 0x80
#define BMP280_OSRS_T_X16 0xA0#define BMP280_OSRS_P_SKIP 0x00 /* 壓力測量跳過 */
#define BMP280_OSRS_P_X1 0x04 /* 壓力測量1倍過采樣 */
#define BMP280_OSRS_P_X2 0x08
#define BMP280_OSRS_P_X4 0x0C
#define BMP280_OSRS_P_X8 0x10
#define BMP280_OSRS_P_X16 0x14/* 濾波器設置 */
#define BMP280_FILTER_OFF 0x00
#define BMP280_FILTER_COEF_2 0x04
#define BMP280_FILTER_COEF_4 0x08
#define BMP280_FILTER_COEF_8 0x0C
#define BMP280_FILTER_COEF_16 0x10/* 待機時間設置 */
#define BMP280_STANDBY_0_5_MS 0x00
#define BMP280_STANDBY_62_5_MS 0x20
#define BMP280_STANDBY_125_MS 0x40
#define BMP280_STANDBY_250_MS 0x60
#define BMP280_STANDBY_500_MS 0x80
#define BMP280_STANDBY_1000_MS 0xA0
#define BMP280_STANDBY_2000_MS 0xC0
#define BMP280_STANDBY_4000_MS 0xE0/* 結構體定義 */
struct bmp280_calib_param {uint16_t dig_T1;int16_t dig_T2;int16_t dig_T3;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;
};#endif
二、設備樹文件中添加節點
? 在設備樹文件中的i2c1節點中添加子節點,如下:,其中bmp280的器件地址即reg定義為0x76,使用的引腳定義是SCL使用:MX6UL_PAD_UART4_TX_DATA__I2C1_SCL? SDA使用:MX6UL_PAD_UART4_RX_DATA__I2C1_SDA及完成設備樹的節點定義,加載到內核:
?查看節點:
?三、驅動文件編寫
(1)首先就是字符設備的結構體定義:添加了溫度和氣壓數據。
struct bmp280_dev {dev_t devid; // 設備號struct cdev cdev; // 字符設備結構體struct class *class; // 類struct device *device; // 設備struct device_node *nd; // 設備樹節點int major; // 主設備號void *private_data; // I2C客戶端指針int temperature; // 溫度值(單位:0.01℃)int pressure; // 氣壓值(單位:Pa)struct bmp280_calib_param calib_param; // 校準參數int32_t t_fine; // 溫度補償中間值
};
?(2)接著完成對讀寄存器函數的編寫:,使用i2c_msg來加載數據,發送的數據是bmp280的器件地址以及加載要寫入的數據,并調用i2c_transfer來完成數據發送
?(3)寫寄存器:發送的數據位器件地址0x76+寄存器地址+數據
?(4)讀取寄存器的校準參數:從0x88開始兩個字節的讀,
(5)計算實際的溫度和氣壓值,參考數據手冊給出的計算公式和實現例程代碼,有興趣的話可以仔細看看手冊:
?仿照實現的計算函數:
?
static int32_t bmp280_compensate_temperature(struct bmp280_dev *dev, int32_t adc_T)
{int32_t var1, var2, temperature;var1 = ((((adc_T >> 3) - ((int32_t)dev->calib_param.dig_T1 << 1))) * ((int32_t)dev->calib_param.dig_T2)) >> 11;var2 = (((((adc_T >> 4) - ((int32_t)dev->calib_param.dig_T1)) * ((adc_T >> 4) - ((int32_t)dev->calib_param.dig_T1))) >> 12) * ((int32_t)dev->calib_param.dig_T3)) >> 14;dev->t_fine = var1 + var2;temperature = (dev->t_fine * 5 + 128) >> 8;return temperature;
}/** @description : 計算實際氣壓值,避免使用64位除法* @param - dev : bmp280設備* @param - adc_P: 原始氣壓ADC值* @return : 實際氣壓值(Pa)*/
static uint32_t bmp280_compensate_pressure(struct bmp280_dev *dev, int32_t adc_P)
{int32_t var1, var2;uint32_t p;var1 = (((int32_t)dev->t_fine) >> 1) - (int32_t)64000;var2 = (((var1 >> 2) * (var1 >> 2)) >> 11) * ((int32_t)dev->calib_param.dig_P6);var2 = var2 + ((var1 * ((int32_t)dev->calib_param.dig_P5)) << 1);var2 = (var2 >> 2) + (((int32_t)dev->calib_param.dig_P4) << 16);var1 = (((dev->calib_param.dig_P3 * (((var1 >> 2) * (var1 >> 2)) >> 13)) >> 3) + ((((int32_t)dev->calib_param.dig_P2) * var1) >> 1)) >> 18;var1 = ((((32768 + var1)) * ((int32_t)dev->calib_param.dig_P1)) >> 15);if (var1 == 0)return 0; // 避免除零錯誤p = (((uint32_t)(((int32_t)1048576) - adc_P) - (var2 >> 12))) * 3125;if (p < 0x80000000)p = (p << 1) / ((uint32_t)var1);elsep = (p / (uint32_t)var1) * 2;var1 = (((int32_t)dev->calib_param.dig_P9) * ((int32_t)(((p >> 3) * (p >> 3)) >> 13))) >> 12;var2 = (((int32_t)(p >> 2)) * ((int32_t)dev->calib_param.dig_P8)) >> 13;p = (uint32_t)((int32_t)p + ((var1 + var2 + dev->calib_param.dig_P7) >> 4));return p;
}
(6) 實現讀取數據函數定義:從數據寄存器0xf7讀到0xfc
(7)剩下就是完成對bmp280初始化定義,設備文件的操作函數定義,如下所示即為,設備初始化代碼:,主要完成對設備的喚醒,校準以及采樣配置:
static int bmp280_init_sensor(struct bmp280_dev *dev)
{uint8_t chip_id;/* 1. 讀取芯片ID,確認設備存在 */chip_id = bmp280_read_reg(dev, BMP280_ID_REG);printk("BMP280 Chip ID: 0x%02X\n", chip_id);if (chip_id != 0x58) {//0x76地址存儲的是0x58printk("BMP280 Chip ID not matching, expected 0x58, got 0x%02X\n", chip_id);return -ENODEV;}/* 2. 軟復位 */bmp280_write_reg(dev, BMP280_RESET_REG, BMP280_RESET_VALUE);mdelay(10); // 等待復位完成/* 3. 讀取校準參數 */bmp280_read_calibration_data(dev);/* 4. 配置傳感器 * - 設置過采樣: 溫度16x,壓力16x* - 設置工作模式: 正常模式*/bmp280_write_reg(dev, BMP280_CONFIG_REG, BMP280_FILTER_COEF_16 | BMP280_STANDBY_500_MS);bmp280_write_reg(dev, BMP280_CTRL_MEAS_REG, BMP280_OSRS_T_X16 | BMP280_OSRS_P_X16 | BMP280_NORMAL_MODE);mdelay(100); // 等待配置生效return 0;
}
?如上即為主要關鍵驅動代碼的定義。
四、編寫驅動測試文件并編譯測試
類似正點原子的驅動測試文件:
打開設備并讀取到數據時,間隔2s打印一次數據
?編譯加載驅動文件和驅動測試文件:
測試結果:
?
能夠正確獲取數據并進行打印,完成驅動!!!
總結
通過對IIC驅動的學習測試以及完成對具體iic設備的驅動來獲取數據,對嵌入式linux的驅動了解更加深刻了。