本帖最后由 andeyqi 于 2019-6-21 13:07 编辑
依据上一篇对rt-thread I2C软件框架的分析,应用层调用I2C框架的接口就可以通过系统注册的总线设备,完成对应外设的控制。本次试验的芯片型号为ROHM 的i2c 三轴加速度传感器(KX224=1053)系列。
应用层只需使用 struct rt_i2c_bus_device *rt_i2c_bus_device_find(const char *bus_name) 函数找到对应的总线设备,并通过返回的 rt_i2c_bus_device 句柄操作外设,通过rt_size_t rt_i2c_transfer(struct rt_i2c_bus_device *bus, struct rt_i2c_msg msgs[],rt_uint32_t num)控制总线完成数据的发送接收,用户层不必关系IIC总线的相关操作,从而减少开发周期,用户只需关系芯片先关的操作即可。
===========================以下进入本次的主题==========================
虽然datasheet中寄存器的描述有很多,不过根据官方的使用说明文档,要想获得三轴加速度的信息,只需设定几个参数即可,设定加速度传感器的测量范围,及输出频率,和工作模式后就能够从芯片的X,Y,Z通道读取出三轴加速度信息。
本次试验使用的BSP为官方已经适配支持\rt-thread\bsp\stm32\stm32l476-st-nucleo 开发板,进入该目录后env工具执行menuconfig配置界面开启I2C1并设置SCL和SDA线的引脚ID后I2C驱动框架相关的代码就会加入工程中进行编译。
- #include <rtthread.h>
- #include <rtdevice.h>
- #include <board.h>
- #include "kx224.h"
- static rt_err_t write_reg(struct rt_i2c_bus_device *bus,rt_uint8_t reg,rt_uint8_t data)
- {
- struct rt_i2c_msg msgs;
- rt_uint8_t buff[2];
- rt_size_t size = 0;
-
- buff[0] = reg;
- buff[1] = data;
- msgs.addr = KX224_DEVICE_ADDRESS_1E;
- msgs.flags = RT_I2C_WR;
- msgs.buf = buff;
- msgs.len = 2;
- if( rt_i2c_transfer(bus, &msgs, 1))
- {
- return RT_EOK;
- }
- else
- {
- return -RT_ERROR;
- }
- }
- static rt_err_t write_cmd(struct rt_i2c_bus_device *bus,rt_uint8_t reg)
- {
- struct rt_i2c_msg msgs;
- rt_uint8_t buff[2];
- rt_size_t size = 0;
-
- buff[0] = reg;
- msgs.addr = KX224_DEVICE_ADDRESS_1E;
- msgs.flags = RT_I2C_WR;
- msgs.buf = buff;
- msgs.len = 1;
- if(rt_i2c_transfer(bus, &msgs, 1))
- {
- return RT_EOK;
- }
- else
- {
- return -RT_ERROR;
- }
- }
- static rt_err_t red_reg(struct rt_i2c_bus_device *bus,rt_uint8_t len,rt_uint8_t * buf)
- {
- struct rt_i2c_msg msgs;
- rt_size_t size = 0;
-
- msgs.addr = KX224_DEVICE_ADDRESS_1E;
- msgs.flags = RT_I2C_RD;
- msgs.buf = buf;
- msgs.len = len;
- if(rt_i2c_transfer(bus, &msgs, 1))
- {
- return RT_EOK;
- }
- else
- {
- return -RT_ERROR;
- }
- }
- static rt_uint32_t _g_sens;
- struct rt_i2c_bus_device* bus = NULL;
- void kx224_init(void)
- {
- rt_uint8_t deviceid = 0,reg = 0,gsel = 0;
-
- bus = rt_i2c_bus_device_find("i2c1");
- if(!bus)
- {
- rt_kprintf("can't find i2c device\n");
- return;
- }
- write_cmd(bus,KX224_WHO_AM_I);
- red_reg(bus,1,&deviceid);
- if(deviceid != KX224_WAI_VAL)
- {
- rt_kprintf("can't find device\n");
- return;
- }
- write_reg(bus,KX224_CNTL1,KX224_CNTL1_VAL);
- write_reg(bus,KX224_ODCNTL,KX224_ODCNTL_VAL);
- write_cmd(bus,KX224_CNTL1);
- red_reg(bus,1,®);
- gsel = reg & KX224_CNTL1_GSELMASK;
- rt_kprintf("reg is 0x%02x gsel is 0x%02x\n",reg,gsel);
- reg |= KX224_CNTL1_PC1;
- write_reg(bus,KX224_CNTL1, reg);
- switch(gsel) {
- case KX224_CNTL1_GSEL_8G :
- // (Equivalent counts) / (Range) = (32768 / 8)
- _g_sens = 4096;
- break;
- case KX224_CNTL1_GSEL_16G :
- // (Equivalent counts) / (Range) = (32768 / 16)
- _g_sens = 2048;
- break;
- case KX224_CNTL1_GSEL_32G :
- // (Equivalent counts) / (Range) = (32768 / 32)
- _g_sens = 1024;
- break;
- default:
- break;
- }
- rt_kprintf("_g_sens is <%d>\n",_g_sens);
- }
- void kx224_get_rawval(unsigned char *data)
- {
- write_cmd(bus,KX224_XOUT_L);
- red_reg(bus,6,data);
- }
- void kx224_get_val(float *data)
- {
- rt_uint8_t val[6] = {0};
- rt_int16_t acc[3] = {0};
-
- kx224_get_rawval(val);
- acc[0] = ((signed short)val[1] << 8) | (val[0]);
- acc[1] = ((signed short)val[3] << 8) | (val[2]);
- acc[2] = ((signed short)val[5] << 8) | (val[4]);
- // Convert LSB to g
- data[0] = (float)acc[0]/_g_sens;
- data[1] = (float)acc[1]/_g_sens;
- data[2] = (float)acc[2]/_g_sens;
- }
复制代码- #ifndef __KX224__
- #define __KX224__
- #define KX224_DEVICE_ADDRESS_1E (0x1E) // 7bit Addrss
- #define KX224_DEVICE_ADDRESS_1F (0x1F) // 7bit Address
- #define KX224_WAI_VAL (0x2B)
- #define KX224_XOUT_L (0x06)
- #define KX224_WHO_AM_I (0x0F)
- #define KX224_CNTL1 (0x18)
- #define KX224_ODCNTL (0x1B)
- #define KX224_CNTL1_TPE (1 << 0)
- #define KX224_CNTL1_WUFE (1 << 1)
- #define KX224_CNTL1_TDTE (1 << 2)
- #define KX224_CNTL1_GSELMASK (0x18)
- #define KX224_CNTL1_GSEL_8G (0x00)
- #define KX224_CNTL1_GSEL_16G (0x08)
- #define KX224_CNTL1_GSEL_32G (0x10)
- #define KX224_CNTL1_DRDYE (1 << 5)
- #define KX224_CNTL1_RES (1 << 6)
- #define KX224_CNTL1_PC1 (1 << 7)
- #define KX224_ODCNTL_OSA_50HZ (2)
- #define KX224_ODCNTL_LPRO (1 << 6)
- #define KX224_IIR_BYPASS (1 << 7)
- #define KX224_CNTL1_VAL (KX224_CNTL1_RES | KX224_CNTL1_GSEL_8G)
- #define KX224_ODCNTL_VAL (KX224_ODCNTL_OSA_50HZ)
- extern void kx224_get_val(float *data);
- extern void kx224_init(void);
- #endif /* end of KX224 */
复制代码
以上代码的设定相关代码主要如下,之后就可以读取数据了:- write_reg(bus,KX224_CNTL1,KX224_CNTL1_VAL);
- write_reg(bus,KX224_ODCNTL,KX224_ODCNTL_VAL);
- write_cmd(bus,KX224_CNTL1);
- red_reg(bus,1,®);
- gsel = reg & KX224_CNTL1_GSELMASK;
- rt_kprintf("reg is 0x%02x gsel is 0x%02x\n",reg,gsel);
- reg |= KX224_CNTL1_PC1;
- write_reg(bus,KX224_CNTL1, reg);
复制代码 读取数据的相关如下,设定完成后就可以从KX224_XOUT_L开始的寄存器来读取数据了,连续读取6个数据就会读出三轴加速度的值:
- void kx224_get_rawval(unsigned char *data)
- {
- write_cmd(bus,KX224_XOUT_L);
- red_reg(bus,6,data);
- }
复制代码
调试过程主要遇到两个问题:①设定的地址设定的读地址和对应的写地址,后开总是从机没有响应NACK,跟了下代码发现驱动框架中会根据设备的7bit或者10bit地址自动计算读读写时对应的地址,地址设定为七地址即可。
②因为板子上的IO口模拟的IIC 总线没有上拉电阻,造成每次都是NACK,IO设定为内部上拉即可。
以上只是相对简单的方式,模块还支持中断的方式,有时间再进一步研究,存粹个人理解有什么不对的欢迎拍砖指正。
|
???这个怎么讲,为啥屠版了呢