这次用 SPI。BBB 有两套 SPI 接口可用,两套都是默认 disable,需要用 overlay 方式启用,即:

echo BB-SPIDEV0 > /sys/devices/bone_capemgr.9/slots

我的 BBB 当前配置当前配置

/opt/source/Userspace-Arduino/overlay/BB-SPI0-01-00A0.dts

/dts-v1/;
/plugin/;

/ {
    compatible = "ti,beaglebone", "ti,beaglebone-black";

/* identification */
    part-number = "spi0pinmux";

fragment@0 {
        target = <&am33xx_pinmux>;
        __overlay__ {
            spi0_pins_s0: spi0_pins_s0 {
                pinctrl-single,pins = <
                  0x150 0x30  /* spi0_sclk, INPUT_PULLUP | MODE0 */
                  0x154 0x30  /* spi0_d0, INPUT_PULLUP | MODE0 */
                  0x158 0x10  /* spi0_d1, OUTPUT_PULLUP | MODE0 */
                  0x15c 0x10  /* spi0_cs0, OUTPUT_PULLUP | MODE0 */
                >;
            };
        };
    };

fragment@2 {
        target = <&spi0>;
        __overlay__ {
             #address-cells = <1>;
             #size-cells = <0>;

status = "okay";
             pinctrl-names = "default";
             pinctrl-0 = <&spi0_pins_s0>;

spidev@0 {
                 spi-max-frequency = <24000000>;
                 reg = <0>;
                 compatible = "linux,spidev";
            };
        };
    };
};

说明书第三十页,BMP280 支持 Mode 00 和 11,自动选的。可三线或四线连接。

dts 档内可见,当前就是 mode 0,可以直接连 BMP280了。

SPI 接线 – BMP280

原理图在上一篇博文,从图可以得知,BMP280 的片选是 CSB,NCS 是九轴 MPU9250 的片选引脚。

我那很烂的焊接,锡明显过多,烙铁温度过高,家里没洗板水,脏兮兮的。SPI0 的接线如下:

BBB GY-91 说明
P9_1 GND
P9_3 3V3 电源
P9_22 SCL 时钟
P9_17 CSB 片选
P9_18 SDA MOSI
P9_21 SA0 MISO

启用 SPI0 :

echo BB-SPIDEV0 > /sys/devices/bone_capemgr.9/slots

然后在 /dev 就会出现了:

spidev1.0 代表总线号 1 片选号 0。

SPI 读取 BMP280 的 ID Register 值

注意事项如上图,图片截取自 BMP280 Datasheet,BMP280 的 SPI Read 方式从 BBB 发出的一个 byte 是 Control byte,Control byte 的 bit 7 用来控制读写,地址是后面余下的 7 个 bits。上图Control byte 后面的 Data byte 是接收的,比如我四线情况,它在 MISO 出现的,上图这样表达比较难理解……。

看一下时序图,看这个我比较好理解一些:

通讯过程中片选 pull down。

毕竟主角是九轴,BMP280温度气压就快速试一次,试试而已。C 代码。

有好几段小插曲,我首先想用 Python,易写易改,找到了SPIDEV,可是无论如何都无法用双工连,最终由于时间关系,放弃了。PY-SPIDEV见以此链接:

https://pypi.python.org/pypi/spidev 。后来改用 C,各种百度FQ再 Google,多半是 Arduino 和用上 Adafruit 的类库,看到各种 Digital Write,最后也放弃了。最后直接用 linux/spi/spidev 自己参考一下别人就直接写。

#include <stdio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h> char buf[1];
char buf2[10]; struct spi_ioc_transfer xfer[2]; int spi_init(char filename[40]) {
int file;
__u8 mode = 0;
__u8 lsb = 0;
__u8 bits = 8;
__u32 speed = 10000000; if ((file = open(filename,O_RDWR)) < 0) {
printf("Failed to open the bus.");
exit(1);
} if (ioctl(file, SPI_IOC_WR_MODE, &mode)<0) {
perror("can't set spi mode");
return;
} if (ioctl(file, SPI_IOC_RD_MODE, &mode) < 0) {
perror("SPI rd_mode");
return;
}
if (ioctl(file, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
perror("SPI rd_lsb_fist");
return;
}
if (ioctl(file, SPI_IOC_WR_BITS_PER_WORD, &bits)<0) {
perror("can't set bits per word");
return;
}
if (ioctl(file, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
perror("SPI bits_per_word");
return;
}
if (ioctl(file, SPI_IOC_WR_MAX_SPEED_HZ, &speed)<0) {
perror("can't set max speed hz");
return;
}
if (ioctl(file, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
perror("SPI max_speed_hz");
return;
}
printf("%s: spi mode %d, %d bits %sper word, %d Hz max\n",filename, mode, bits, lsb ? "(lsb first) " : "", speed);
return file;
} char * spi_read(int addr,int nbytes,int file) {
int status; memset(buf, 0, sizeof buf);
memset(buf2, 0, sizeof buf2);
buf[0] = addr | 128;
xfer[0].tx_buf = (unsigned long)buf;
xfer[0].len = 1;
xfer[1].rx_buf = (unsigned long) buf2;
xfer[1].len = nbytes;
status = ioctl(file, SPI_IOC_MESSAGE(2), xfer);
if (status < 0) {
perror("SPI_IOC_MESSAGE");
return;
}
return buf2;
} int main(){
char * buffer;
int file=spi_init("/dev/spidev1.0");
buffer = spi_read(0xD0,1,file);
printf("0x%x\n",*buffer);
}

代码改自这里:http://linux-sunxi.org/SPIdev,原版是 SUNXI 的,我已修改并去掉些不合理地方。

首先配置, 默认 mode 0 ,8 bit per word 再把速度调到BMP280 的上限 10MHz,然后用 read 方法,两个 xfer 丢进去,一个是写 0xD0,代表我想读取 ID Register,一个是读取的 buf2,返回 buf2 到 main 再打印出来。read 里面的 bitwise OR 是为了确保 bit 7 是 1,以免我敲错地址错误地操作了写入。效果:

返回 0x58,ID 正确。

SPI 写入 BMP280 Register,读取当前温度

对 BMP280 的 ctrl_meas 写入值,连续测量,最高精度,只检测温度不管气压(地址和值见上一篇),然后读取气温原始数据和温度补偿,再转换为摄氏 printf 出来,代码:

#include <stdio.h>
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/spi/spidev.h> #define DIG_START 0x88
#define TEMP_START 0xFA
#define CTRL_MEAS 0xF4
#define TEMP_ONLY_NORMAL_MODE 0xE3 // 111 000 11 char buf[10];
char buf2[10]; struct spi_ioc_transfer xfer[2]; int spi_init(char filename[40]) {
int file;
__u8 lsb = 0;
__u8 mode = 0;
__u8 bits = 8;
__u32 speed = 10000000; if ((file = open(filename,O_RDWR)) < 0) {
printf("Failed to open the bus.");
exit(1);
} if (ioctl(file, SPI_IOC_WR_MODE, &mode)<0) {
perror("can't set spi mode");
return;
} if (ioctl(file, SPI_IOC_RD_MODE, &mode) < 0) {
perror("SPI rd_mode");
return;
}
if (ioctl(file, SPI_IOC_RD_LSB_FIRST, &lsb) < 0) {
perror("SPI rd_lsb_fist");
return;
}
if (ioctl(file, SPI_IOC_WR_BITS_PER_WORD, &bits)<0) {
perror("can't set bits per word");
return;
}
if (ioctl(file, SPI_IOC_RD_BITS_PER_WORD, &bits) < 0) {
perror("SPI bits_per_word");
return;
}
if (ioctl(file, SPI_IOC_WR_MAX_SPEED_HZ, &speed)<0) {
perror("can't set max speed hz");
return;
}
if (ioctl(file, SPI_IOC_RD_MAX_SPEED_HZ, &speed) < 0) {
perror("SPI max_speed_hz");
return;
}
return file;
} char * spi_read(int addr,int nbytes,int file) {
int status; memset(buf, 0, sizeof buf);
memset(buf2, 0, sizeof buf2);
buf[0] = addr | 128;
xfer[0].tx_buf = (unsigned long)buf;
xfer[0].len = 1;
xfer[1].rx_buf = (unsigned long) buf2;
xfer[1].len = nbytes;
status = ioctl(file, SPI_IOC_MESSAGE(2), xfer);
if (status < 0) {
perror("SPI_IOC_MESSAGE");
return;
}
return buf2;
} void spi_write(int addr, char value, int file) {
int status; memset(buf, 0, sizeof buf);
buf[0] = addr & 127;
buf[1] = value;
xfer[0].tx_buf = (unsigned long)buf;
xfer[0].len = 2;
status = ioctl(file, SPI_IOC_MESSAGE(1), xfer);
if (status < 0) {
perror("SPI_IOC_MESSAGE");
}
} float myFunc(uint32_t adc_T, unsigned short dig_T1, short dig_T2, short dig_T3){
uint32_t var1, var2;
float T;
var1 = (((double)adc_T)/16384.0-((double)dig_T1)/1024.0)*((double)dig_T2);
var2 = ((((double)adc_T)/131072.0-((double)dig_T1)/8192.0)*(((double)adc_T)/131072.0-((double)dig_T1)/8192.0))*((double)dig_T2);
T = (var1+var2)/5120.0;
return T;
} int main() {
int i;
char * id;
char * mode;
char dig_buff[6];
char tmp_buff[3]; int file=spi_init("/dev/spidev1.0");
id = spi_read(0xD0,1,file);
printf("ID: 0x%02x\n",*id);
spi_write(CTRL_MEAS,TEMP_ONLY_NORMAL_MODE,file);
mode = spi_read(CTRL_MEAS,1,file);
printf("Mode: 0x%02x\n", *mode); memcpy(dig_buff, spi_read(DIG_START, 6, file), 6);
memcpy(tmp_buff, spi_read(TEMP_START, 3, file), 3); printf("Dump:\n");
for (i=0; i<6; i++){
printf("%02x ",dig_buff[i]);
}
printf("\n");
for (i=0; i<3; i++){
printf("%02x ",tmp_buff[i]);
}
printf("\n");
int adc_T = ((tmp_buff[0]<<16)|(tmp_buff[1]<<8)|(tmp_buff[2]))>>4;
unsigned short dig_T1 = (dig_buff[1]<<8)|(dig_buff[0]);
short dig_T2 = (dig_buff[3]<<8)|(dig_buff[2]);
short dig_T3 = (dig_buff[5]<<8)|(dig_buff[4]);
printf("adc_T is : %d \n", adc_T);
printf("dig_T1 is : %d \n", dig_T1);
printf("dig_T2 is : %d \n", dig_T2);
printf("dig_T3 is : %d \n", dig_T3);
printf("Temperature is : %f \n", myFunc(adc_T, dig_T1, dig_T2, dig_T3));
return 0;
}

效果:

关于温度补偿和实际摄氏温度计算,请看上一篇 I2C 示范。spi_write 里面的 bitwise AND 是为了确保 bit 7 是零,写入模式。由于我全部用相同的 buf 和 buf2,实际应用 read 时候需要 copy 出来。我还没很好地理解 linux 的 spidev 库(比如读取时两个 xfer buffer 是否需要大小一致,片选结束拉低的时间点是取决于 xfer[0] 长度还是 xfer[0] 和 xfer[1] 两者较长的值,初始化后 SPI 参数能否修改,user space 能否改 mode 等等的问题),但以上代码勉强够用了,将来有空再慢慢研究。将来的项目里不是 embedded linux 的。

我纠结于尝试用 Python 做 SPI 双工浪费了很多时间,最终还是没结果做不出来。最后放弃那一层层的封装,直接用 C 的 spidev,顿时春天了,28°C。

下一篇,用 SPI 调用加速传感和倾斜角。

我在这群里,欢迎加入交流:
开发板玩家群 578649319
硬件创客 (10105555)

Beaglebone Black – 连接 GY-91 MPU9250+BMP280 九轴传感器(2)的更多相关文章

  1. Beaglebone Black – 连接 GY-91 MPU9250+BMP280 九轴传感器(1)

    本篇内容为,通过 I2C 配置 GY-91 MPU9250+BMP280 里面的 MPU9250 连接 AK8963 磁感应.两个办法,1)MPU9250 设置 Master Mode 通过 AUX ...

  2. [算法][三轴、六轴、九轴传感器算法分析] 1、分享一个三轴加速计matlab动态可视化脚本

    一.有啥用 这里用的是LIS3DH三轴加速计,输出为X.Y.Z轴的加速度,通过串口连接电脑,电脑里运行matlab脚本通过串口实时获取数据并做可视化显示. 这里虽然是针对LIS3DH的,其实稍作修改即 ...

  3. SLAM+语音机器人DIY系列:(三)感知与大脑——2.带自校准九轴数据融合IMU惯性传感器

    摘要 在我的想象中机器人首先应该能自由的走来走去,然后应该能流利的与主人对话.朝着这个理想,我准备设计一个能自由行走,并且可以与人语音对话的机器人.实现的关键是让机器人能通过传感器感知周围环境,并通过 ...

  4. MPU9250九轴陀螺仪--连接MPU9250

    树莓派连接MPU9250九轴加速度传感器1,配线方法 树莓派侧 MPU9250侧 3.3V VCC (SDA)GPIO2 SDA (SCL)GPIO3 SCL GND GND 2,I2C有效在树莓派里 ...

  5. Google Cardboard的九轴融合算法——基于李群的扩展卡尔曼滤波

    Google Cardboard的九轴融合算法 --基于李群的扩展卡尔曼滤波 极品巧克力 前言 九轴融合算法是指通过融合IMU中的加速度计(三轴).陀螺仪(三轴).磁场计(三轴),来获取物体姿态的方法 ...

  6. GY91(MPU9250 + BMP280)惯性传感器开发指南

    目录 参考资料 I2C 设备ID 关键数据读取 MPU6500:读取加速度数据&换算单位 BMP280: 读取温度和气压信息 & 单位换算 推荐库 参考资料 参考资料说明: 用户手册时 ...

  7. MPU9250九轴陀螺仪--读接口数据

    1.使用i2c链接到树莓派的scl , sda 接口vcc给3v引脚,gnd接树莓派gnd就ok. 2.要操作mpu必须使用mpu的寄存器实现对参数的设定以及读取,取官方下载资料看了一下,在githu ...

  8. 【.NET 与树莓派】六轴飞控传感器(MPU 6050)

    所谓"飞控",其实是重力加速度计和陀螺仪的组合,因为多用于控制飞行器的平衡(无人机.遥控飞机).有同学会问,这货为什么会有六轴呢?咱们常见的不是X.Y.Z三轴吗?重力加速度有三轴, ...

  9. 六轴加速度传感器MPU6050官方DMP库到瑞萨RL78/G13的移植

    2015年的电赛已经结束了.赛前接到器件清单的时候,看到带防护圈的多旋翼飞行器赫然在列,又给了一个瑞萨RL78/G13的MCU,于是自然联想到13年的电赛,觉得多半是拿RL78/G13做四旋翼的主控, ...

随机推荐

  1. Session 知识点再整理(一)基本概念和原理

    Session 的概念 Session 和 Cookie 一样,也是针对 HTTP 的局限性而提出的一种保持客户端和服务器端会话连接状态的机制. Session 被称为会话,指用户在进入网站到浏览器关 ...

  2. 20145218&20145240 《信息安全系统设计基础》实验一 开发环境的熟悉

    20145218&20145240 <信息安全系统设计基础>实验一 开发环境的熟悉 课程:信息安全系统设计基础 班级:1452 姓名:(按贡献大小排名)刘士嘉 张晓涵 学号:(按贡 ...

  3. You and Your Research(Chinese)

    转自:http://lyxh-2003.iteye.com/blog/434014 这是大科学家Richard Hamming的著名讲演,于1986年在贝尔通讯研究中心给200多名Bellcore的科 ...

  4. ADB工具和手机抓包方法介绍

    Android抓包方法 工具包内容如下:(下载地址:http://download.csdn.net/download/yezhaohui2011/8368061) adb ——谷歌提供的安卓远程调试 ...

  5. maven项目导入,包名出现异常-多出一个java的前缀

    maven工程导入项目的时候,整个结构出现混乱,如下图所示,包名前面莫名其妙的出现了java的前缀: 原因是导入错误,重新导入即可.

  6. js获取url中参数

      /** * 获取地址栏参数值 * @param name 参数名 * @returns */ $(function () { var url = location.search; //获取url中 ...

  7. 【axc】关于duplicate symbols for architecture x86_64错误的第三种可能及其解决办法

    今天分析一下duplicate symbols for architecture x86_64错误  也是困扰我一段时间   不过很幸运 在半个小时内找到了解决方案 百度上对于duplicate sy ...

  8. vscode 编写python如何禁止 flake8 提示 line too long

    使用vscode编写python还是挺舒服的,但是如果给vscode安装了语法校验插件,例如flake8,会常常提示一些非常苛刻的语法问题,其中最让人不能忍受的就是line to long. 一行仅能 ...

  9. Web性能API——帮你分析Web前端性能

    前端性能统计必备api,有不知道的吗? 正文从这开始- 开发一个现代化的互联网网站是一项复杂的任务,需要各种职能的密切合作以应对用户日新月异的需求.其中,网页的性能直接决定了用户的体验,而随着新型客户 ...

  10. [Ubuntu][Linux]更改PATH路径

    1.什么是环境变量(PATH) 在Linux中,在执行命令时,系统会按照PATH的设置,去每个PATH定义的路径下搜索执行文件,先搜索到的文件先执行. 我们知道查阅文件属性的指令ls 完整文件名为:/ ...