ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

rk3568学习记录 spi-----bmp280(学习资料:瑞芯微-正点原子)

rk3568学习记录 spi-----bmp280(学习资料:瑞芯微-正点原子)

1. 图形化配置界面中打开spi

对应内核配置文件

1 CONFIG_SPI=y 2 CONFIG_SPI_DEBUG=y 3 CONFIG_SPI_MASTER=y 4 CONFIG_SPI_MEM=y 5 CONFIG_SPI_BITBANG=y 6 CONFIG_SPI_ROCKCHIP=y 7 CONFIG_SPI_SPIDEV=y 8 CONFIG_SPI_LOOPBACK_TEST=m 9 CONFIG_SPI_SLAVE=y 10 CONFIG_SPI_SLAVE_TIME=y 11 CONFIG_SPI_SLAVE_SYSTEM_CONTROL=y

编译内核

rk35568_linux_sdk/下 ./build.sh kernel

3. 设备树添加spi节点

kernel/arch/arm64/boot/dts/rockchip/rk3568-atk-evb1-ddr4-v10.dtsi

&spi1 { status = "okay"; pinctrl-names = "default","high_speed"; pinctrl-0 = <&spi1m1_pins>; pinctrl-1 = <&spi1m1_pins_hs>; cs-gpios = <&gpio3 RK_PA1 GPIO_ACTIVE_LOW>; // 片选用法与上面同理:硬件CS与GPIO CS二选一 spidev@0 { compatible = "linux,spidev"; /* 有的主线更严格,可用 "rohm,dh2228fv" 旧兼容ID蹭上 */ reg = <0>; spi-max-frequency = <10000000>; status = "okay"; }; };

我只用过“linux,spidev”

编译、下载boot

4. 在/dev中可以看到spidev1.0(“linux,spidev”-驱动匹配了字符设备-用户接口)

dmesg | grep spi*有日志内容(内核内核驱动初始化完成)

5.spi

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/spi/spidev.h> #include <stdint.h> #include <string.h> #include <math.h> // BMP280寄存器地址 #define BMP280_REG_CHIP_ID 0xD0 #define BMP280_REG_RESET 0xE0 #define BMP280_REG_STATUS 0xF3 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_PRESS_MSB 0xF7 #define BMP280_REG_PRESS_LSB 0xF8 #define BMP280_REG_PRESS_XLSB 0xF9 #define BMP280_REG_TEMP_MSB 0xFA #define BMP280_REG_TEMP_LSB 0xFB #define BMP280_REG_TEMP_XLSB 0xFC #define BMP280_REG_CALIB_DATA 0x88 // SPI读写标志 #define SPI_READ_FLAG 0x80 #define SPI_WRITE_FLAG 0x00 // 校准参数结构体 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; int32_t t_fine; }; int spi_init(const char* device, uint32_t speed, uint8_t mode) { int fd = open(device, O_RDWR); if (fd < 0) { perror("无法打开SPI设备"); return -1; } // 设置SPI模式 if (ioctl(fd, SPI_IOC_WR_MODE, &mode) < 0) { perror("无法设置SPI模式"); close(fd); return -1; } // 设置SPI位宽(8位) uint8_t bits = 8; if (ioctl(fd, SPI_IOC_WR_BITS_PER_WORD, &bits) < 0) { perror("无法设置SPI位宽"); close(fd); return -1; } // 设置SPI速度 if (ioctl(fd, SPI_IOC_WR_MAX_SPEED_HZ, &speed) < 0) { perror("无法设置SPI速度"); close(fd); return -1; } return fd; } // SPI单字节写函数 int spi_write_byte(int fd, uint8_t reg, uint8_t value) { uint8_t tx_buf[2] = {reg & 0x7F, value}; // 写操作,清除最高位 uint8_t rx_buf[2] = {0}; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx_buf, .rx_buf = (unsigned long)rx_buf, .len = 2, .delay_usecs = 0, .speed_hz = 1000000, .bits_per_word = 8, }; if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) < 0) { perror("SPI写操作失败"); return -1; } return 0; } // SPI单字节读函数 int spi_read_byte(int fd, uint8_t reg, uint8_t *value) { uint8_t tx_buf[2] = {reg | SPI_READ_FLAG, 0x00}; // 读操作,设置最高位 uint8_t rx_buf[2] = {0}; struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx_buf, .rx_buf = (unsigned long)rx_buf, .len = 2, .delay_usecs = 0, .speed_hz = 1000000, .bits_per_word = 8, }; if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) < 0) { perror("SPI读操作失败"); return -1; } *value = rx_buf[1]; return 0; } // SPI多字节突发读取(重要:保证数据一致性) int spi_read_burst(int fd, uint8_t start_reg, uint8_t *buffer, int length) { uint8_t tx_buf[length + 1]; uint8_t rx_buf[length + 1]; // 设置起始寄存器(读模式) tx_buf[0] = start_reg | SPI_READ_FLAG; memset(&tx_buf[1], 0x00, length); // 填充空数据以产生时钟 struct spi_ioc_transfer tr = { .tx_buf = (unsigned long)tx_buf, .rx_buf = (unsigned long)rx_buf, .len = length + 1, .delay_usecs = 0, .speed_hz = 1000000, .bits_per_word = 8, }; if (ioctl(fd, SPI_IOC_MESSAGE(1), &tr) < 0) { perror("SPI突发读取失败"); return -1; } // 复制接收到的数据(跳过第一个字节) memcpy(buffer, &rx_buf[1], length); return 0; } int bmp280_spi_init(int fd, struct bmp280_calib_param *calib) { uint8_t chip_id; // 读取芯片ID确认连接 if (spi_read_byte(fd, BMP280_REG_CHIP_ID, &chip_id) < 0) { return -1; } if (chip_id != 0x58) { fprintf(stderr, "BMP280未找到,芯片ID: 0x%02X\n", chip_id); return -1; } printf("BMP280检测成功,芯片ID: 0x%02X\n", chip_id); // 读取校准参数(突发读取) uint8_t calib_data[24]; if (spi_read_burst(fd, BMP280_REG_CALIB_DATA, calib_data, 24) < 0) { return -1; } // 解析校准参数(小端格式) calib->dig_T1 = (calib_data[1] << 8) | calib_data[0]; calib->dig_T2 = (calib_data[3] << 8) | calib_data[2]; calib->dig_T3 = (calib_data[5] << 8) | calib_data[4]; calib->dig_P1 = (calib_data[7] << 8) | calib_data[6]; calib->dig_P2 = (calib_data[9] << 8) | calib_data[8]; calib->dig_P3 = (calib_data[11] << 8) | calib_data[10]; calib->dig_P4 = (calib_data[13] << 8) | calib_data[12]; calib->dig_P5 = (calib_data[15] << 8) | calib_data[14]; calib->dig_P6 = (calib_data[17] << 8) | calib_data[16]; calib->dig_P7 = (calib_data[19] << 8) | calib_data[18]; calib->dig_P8 = (calib_data[21] << 8) | calib_data[20]; calib->dig_P9 = (calib_data[23] << 8) | calib_data[22]; // 软件复位 if (spi_write_byte(fd, BMP280_REG_RESET, 0xB6) < 0) { return -1; } usleep(10000); // 等待复位完成 // 配置传感器(根据文档第4.3.4和4.3.5节) // 设置测量控制:温度4倍过采样,压力4倍过采样,正常模式 if (spi_write_byte(fd, BMP280_REG_CTRL_MEAS, 0xB7) < 0) { // osrs_t=2, osrs_p=2, mode=3 return -1; } // 设置配置:standby时间500ms,滤波器系数16 if (spi_write_byte(fd, BMP280_REG_CONFIG, 0x94) < 0) { // t_sb=101, filter=100, spi3w_en=0 return -1; } calib->t_fine = 0; return 0; } // 温度补偿函数(文档第3.11.3节) int32_t bmp280_compensate_temperature(struct bmp280_calib_param *calib, int32_t adc_T) { int32_t var1, var2, T; var1 = ((((adc_T >> 3) - ((int32_t)calib->dig_T1 << 1))) * ((int32_t)calib->dig_T2)) >> 11; var2 = (((((adc_T >> 4) - ((int32_t)calib->dig_T1)) * ((adc_T >> 4) - ((int32_t)calib->dig_T1))) >> 12) * ((int32_t)calib->dig_T3)) >> 14; calib->t_fine = var1 + var2; T = (calib->t_fine * 5 + 128) >> 8; return T; } // 压力补偿函数(文档第3.11.3节) uint32_t bmp280_compensate_pressure(struct bmp280_calib_param *calib, int32_t adc_P) { int64_t var1, var2, p; var1 = ((int64_t)calib->t_fine) - 128000; var2 = var1 * var1 * (int64_t)calib->dig_P6; var2 = var2 + ((var1 * (int64_t)calib->dig_P5) << 17); var2 = var2 + (((int64_t)calib->dig_P4) << 35); var1 = ((var1 * var1 * (int64_t)calib->dig_P3) >> 8) + ((var1 * (int64_t)calib->dig_P2) << 12); var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)calib->dig_P1) >> 33; if (var1 == 0) { return 0; } p = 1048576 - adc_P; p = (((p << 31) - var2) * 3125) / var1; var1 = (((int64_t)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25; var2 = (((int64_t)calib->dig_P8) * p) >> 19; p = ((p + var1 + var2) >> 8) + (((int64_t)calib->dig_P7) << 4); return (uint32_t)p; } int read_bmp280_pressure_spi(int fd, struct bmp280_calib_param *calib, double *pressure_hPa, double *temperature_c) { uint8_t data[6]; // 使用突发读取获取压力和温度数据(文档第3.9节) if (spi_read_burst(fd, BMP280_REG_PRESS_MSB, data, 6) < 0) { return -1; } // 检查数据是否就绪 uint8_t status; if (spi_read_byte(fd, BMP280_REG_STATUS, &status) < 0) { return -1; } if (status & 0x08) { // 测量进行中 printf("测量进行中,等待完成...\n"); int timeout = 100; while ((status & 0x08) && timeout > 0) { usleep(1000); spi_read_byte(fd, BMP280_REG_STATUS, &status); timeout--; } if (timeout <= 0) { fprintf(stderr, "测量超时\n"); return -1; } // 重新读取数据 if (spi_read_burst(fd, BMP280_REG_PRESS_MSB, data, 6) < 0) { return -1; } } // 组合20位原始数据 int32_t adc_P = ((data[0] << 12) | (data[1] << 4) | (data[2] >> 4)); int32_t adc_T = ((data[3] << 12) | (data[4] << 4) | (data[5] >> 4)); // 补偿计算 int32_t temp_comp = bmp280_compensate_temperature(calib, adc_T); uint32_t press_comp = bmp280_compensate_pressure(calib, adc_P); // 转换为常用单位 *temperature_c = temp_comp / 100.0; *pressure_hPa = press_comp / 256.0 / 100.0; return 0; } int main() { int fd; const char *spi_device = "/dev/spidev1.0"; // 根据实际SPI设备调整 struct bmp280_calib_param calib; // 初始化SPI(模式0,速度1MHz) fd = spi_init(spi_device, 100000, 0); if (fd < 0) { fprintf(stderr, "SPI初始化失败\n"); return 1; } // 初始化BMP280 if (bmp280_spi_init(fd, &calib) < 0) { fprintf(stderr, "BMP280 SPI初始化失败\n"); close(fd); return 1; } printf("BMP280 SPI初始化成功\n"); // 连续读取示例 for (int i = 0; i < 10; i++) { double pressure_hPa, temperature_c; if (read_bmp280_pressure_spi(fd, &calib, &pressure_hPa, &temperature_c) == 0) { printf("读数 %d: 温度 = %.2f°C, 压强 = %.2f hPa, 海拔 ≈ %.1f米\n", i + 1, temperature_c, pressure_hPa, (1 - pow(pressure_hPa / 1013.25, 0.190284)) * 44307.7); } else { fprintf(stderr, "读取失败\n"); } sleep(1); // 每秒读取一次 } close(fd); return 0; }

iic

#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <sys/ioctl.h> #include <linux/i2c-dev.h> #include <stdint.h> #include <math.h> // BMP280寄存器地址 #define BMP280_REG_CHIP_ID 0xD0 #define BMP280_REG_RESET 0xE0 #define BMP280_REG_STATUS 0xF3 #define BMP280_REG_CTRL_MEAS 0xF4 #define BMP280_REG_CONFIG 0xF5 #define BMP280_REG_PRESS_MSB 0xF7 #define BMP280_REG_PRESS_LSB 0xF8 #define BMP280_REG_PRESS_XLSB 0xF9 #define BMP280_REG_TEMP_MSB 0xFA #define BMP280_REG_TEMP_LSB 0xFB #define BMP280_REG_TEMP_XLSB 0xFC #define BMP280_REG_CALIB_DATA 0x88 // BMP280校准参数结构体 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; int32_t t_fine; }; // I2C写函数 int i2c_write_byte(int fd, uint8_t reg, uint8_t value) { uint8_t buf[2] = {reg, value}; if (write(fd, buf, 2) != 2) { perror("I2C write failed"); return -1; } return 0; } // I2C读函数 int i2c_read_bytes(int fd, uint8_t reg, uint8_t *buf, int len) { if (write(fd, &reg, 1) != 1) { perror("I2C register select failed"); return -1; } if (read(fd, buf, len) != len) { perror("I2C read failed"); return -1; } return 0; } int bmp280_init(int fd, struct bmp280_calib_param *calib) { uint8_t chip_id; // 读取芯片ID确认连接 if (i2c_read_bytes(fd, BMP280_REG_CHIP_ID, &chip_id, 1) < 0) { return -1; } if (chip_id != 0x58) { fprintf(stderr, "BMP280 not found, chip ID: 0x%02X\n", chip_id); return -1; } printf("BMP280 detected, chip ID: 0x%02X\n", chip_id); // 读取校准参数 uint8_t calib_data[24]; if (i2c_read_bytes(fd, BMP280_REG_CALIB_DATA, calib_data, 24) < 0) { return -1; } // 解析校准参数(小端格式) calib->dig_T1 = (calib_data[1] << 8) | calib_data[0]; calib->dig_T2 = (calib_data[3] << 8) | calib_data[2]; calib->dig_T3 = (calib_data[5] << 8) | calib_data[4]; calib->dig_P1 = (calib_data[7] << 8) | calib_data[6]; calib->dig_P2 = (calib_data[9] << 8) | calib_data[8]; calib->dig_P3 = (calib_data[11] << 8) | calib_data[10]; calib->dig_P4 = (calib_data[13] << 8) | calib_data[12]; calib->dig_P5 = (calib_data[15] << 8) | calib_data[14]; calib->dig_P6 = (calib_data[17] << 8) | calib_data[16]; calib->dig_P7 = (calib_data[19] << 8) | calib_data[18]; calib->dig_P8 = (calib_data[21] << 8) | calib_data[20]; calib->dig_P9 = (calib_data[23] << 8) | calib_data[22]; // 配置传感器(文档第4.3.4和4.3.5节) // 设置测量控制:温度4倍过采样,压力4倍过采样,强制模式 if (i2c_write_byte(fd, BMP280_REG_CTRL_MEAS, 0x93) < 0) { // osrs_t=2, osrs_p=2, mode=1 return -1; } // 设置配置:standby时间500ms,滤波器关闭 if (i2c_write_byte(fd, BMP280_REG_CONFIG, 0x00) < 0) { // t_sb=000, filter=000, spi3w_en=0 return -1; } calib->t_fine = 0; return 0; } int32_t bmp280_compensate_temperature(struct bmp280_calib_param *calib, int32_t adc_T) { int32_t var1, var2, T; var1 = ((((adc_T >> 3) - ((int32_t)calib->dig_T1 << 1))) * ((int32_t)calib->dig_T2)) >> 11; var2 = (((((adc_T >> 4) - ((int32_t)calib->dig_T1)) * ((adc_T >> 4) - ((int32_t)calib->dig_T1))) >> 12) * ((int32_t)calib->dig_T3)) >> 14; calib->t_fine = var1 + var2; T = (calib->t_fine * 5 + 128) >> 8; return T; // 返回温度值,单位0.01°C } uint32_t bmp280_compensate_pressure(struct bmp280_calib_param *calib, int32_t adc_P) { int64_t var1, var2, p; var1 = ((int64_t)calib->t_fine) - 128000; var2 = var1 * var1 * (int64_t)calib->dig_P6; var2 = var2 + ((var1 * (int64_t)calib->dig_P5) << 17); var2 = var2 + (((int64_t)calib->dig_P4) << 35); var1 = ((var1 * var1 * (int64_t)calib->dig_P3) >> 8) + ((var1 * (int64_t)calib->dig_P2) << 12); var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)calib->dig_P1) >> 33; if (var1 == 0) { return 0; // 避免除零错误 } p = 1048576 - adc_P; p = (((p << 31) - var2) * 3125) / var1; var1 = (((int64_t)calib->dig_P9) * (p >> 13) * (p >> 13)) >> 25; var2 = (((int64_t)calib->dig_P8) * p) >> 19; p = ((p + var1 + var2) >> 8) + (((int64_t)calib->dig_P7) << 4); return (uint32_t)p; // 返回压力值,单位Pa/256 } int read_bmp280_pressure(int fd, struct bmp280_calib_param *calib, double *pressure_hPa, double *temperature_c) { uint8_t data[6]; // 触发单次测量(强制模式) if (i2c_write_byte(fd, BMP280_REG_CTRL_MEAS, 0x93) < 0) { return -1; } // 等待测量完成(检查状态寄存器) uint8_t status; int timeout = 100; // 最大等待100ms do { usleep(1000); // 等待1ms if (i2c_read_bytes(fd, BMP280_REG_STATUS, &status, 1) < 0) { return -1; } timeout--; } while ((status & 0x08) && timeout > 0); // 检查measuring位(文档第4.3.3节) if (timeout <= 0) { fprintf(stderr, "Measurement timeout\n"); return -1; } // 读取压力和温度数据(文档第3.9节,突发读取) if (i2c_read_bytes(fd, BMP280_REG_PRESS_MSB, data, 6) < 0) { return -1; } // 组合20位原始数据 int32_t adc_P = ((data[0] << 12) | (data[1] << 4) | (data[2] >> 4)); int32_t adc_T = ((data[3] << 12) | (data[4] << 4) | (data[5] >> 4)); // 补偿计算 int32_t temp_comp = bmp280_compensate_temperature(calib, adc_T); uint32_t press_comp = bmp280_compensate_pressure(calib, adc_P); // 转换为常用单位 *temperature_c = temp_comp / 100.0; // 转换为°C *pressure_hPa = press_comp / 256.0 / 100.0; // 转换为hPa return 0; } int main() { int fd; const char *i2c_device = "/dev/i2c-4"; // 根据实际I2C总线调整 const int bmp280_addr = 0x76; // 或0x77,取决于SDO引脚 // 打开I2C设备 if ((fd = open(i2c_device, O_RDWR)) < 0) { perror("Failed to open I2C device"); return 1; } // 设置I2C从设备地址 if (ioctl(fd, I2C_SLAVE, bmp280_addr) < 0) { perror("Failed to set I2C address"); close(fd); return 1; } struct bmp280_calib_param calib; // 初始化BMP280 if (bmp280_init(fd, &calib) < 0) { fprintf(stderr, "BMP280 initialization failed\n"); close(fd); return 1; } printf("BMP280 initialized successfully\n"); // 读取压强和温度值 double pressure_hPa, temperature_c; if (read_bmp280_pressure(fd, &calib, &pressure_hPa, &temperature_c) == 0) { printf("Temperature: %.2f °C\n", temperature_c); printf("Pressure: %.2f hPa\n", pressure_hPa); printf("Pressure: %.2f mmHg\n", pressure_hPa * 0.750062); } else { fprintf(stderr, "Failed to read pressure\n"); } close(fd); return 0; }
内核源码 + .config → 编译 → Image dts源码 + dtc工具 → 编译 → dtb 打包 → boot.img
返回列表