RSL10的I2C操作与KX023加速度测量数据读取
[复制链接]
本帖最后由 cruelfox 于 2021-7-2 20:48 编辑
RSL10的I2C接口访问,可以用SDK提供的API实现,当然也可以自己操作寄存器。
SDK pack 里面的 firmware/syslib 下面只提供了 include/rsl10_sys_i2c.h 头文件,定义了几个 inline 函数,可以看作是寄存器操作的快捷方式。并没有 rsl10_sys_i2c.c 文件,不足以进行完整的I2C读写流程。
firmware/drivers/i2c_driver 目录下有 I2C_RSLxx.c 文件,实现了好多函数如 I2C_MasterTransmit() 这类的,还有 IRQHandler, DMA_Handler 支持函数。但是我发现代码不全,比如 ARM_DRIVER_I2C 这个类型没有定义,在 I2C_RSLxx.h 头文件中也没有。后来找到在背带裤(BDK)里面的 Driver_I2C.h 才有这个定义。因为依赖关系太复杂,我就不想用了,还是自己写寄存器操作吧。
看起来也不复杂,I2C寄存器组的访问C语言写法和用STM32是差不多的。I2C的APB时钟默认已经开启了,可以直接操作I2C的CTRLx寄存器来开启 I2C 功能。I/O口的配置只需要借助头文件定义的一条函数 Sys_I2C_DIOConfig() 便可指定 SCL, SDA 两个信号各用哪个引脚,甚为方便。
那么是用 PIO 方式,还是 IRQ 方式、DMA 方式进行数据传输呢?虽然 I2C 属于低速设备,但是 RSL10 的运行频率不高,I2C 在这里被我用在 1MHz SCL 频率(线短,挂的设备少),每9个SCL时钟就中断一次,CPU空闲出来的周期也很有限。DMA方式好一些,但读 I2C 的时候程序也没有其它任务可以做,还是等着,短时间利用 WFI 省电也很有限。我就直接用 PIO 方式遍了,就是循环测试寄存器状态位。
大部分 I2C 设备都是通过 写一个寄存器地址,再连续读或者写一连串数据的方式访问的。KX023 就属于这种,于是我实现两个函数分别用于 KX023 的访问。
int acc_write(uint8_t addr, const uint8_t *data, uint8_t len)
{
int i;
uint16_t s;
I2C->ADDR_START = I2C_SlaveAddr<<I2C_ADDR_START_ADDRESS_Pos|I2C_START_WRITE;
while(I2C->STATUS & I2C_BUFFER_FULL)
{ // Address buffered
}
// may write data here
I2C->DATA = addr; // first reg address
while( (s=I2C->STATUS) & I2C_BUFFER_FULL)
{
if(s & I2C_HAS_NACK) // cannot continue
return i;
}
for(i=0;i<len;i++)
{
// buffer available
I2C->DATA = data[i];
while( (s=I2C->STATUS) & I2C_BUFFER_FULL)
{
if(s & I2C_HAS_NACK) // cannot continue
return i;
}
if(i==len-1)
I2C->CTRL1 = I2C_LAST_DATA;
}
while(!(I2C->STATUS & I2C_BUS_FREE))
{
}
return i;
}
int acc_read(uint8_t addr, uint8_t *data, uint8_t len)
{
int i;
uint16_t s;
I2C->ADDR_START = I2C_SlaveAddr<<I2C_ADDR_START_ADDRESS_Pos|I2C_START_WRITE;
while(I2C->STATUS & I2C_BUFFER_FULL)
{ // Address buffered
}
// may write data here
I2C->DATA = addr; // first reg address
while( (s=I2C->STATUS) & I2C_BUFFER_FULL)
{
if(s & I2C_HAS_NACK) // cannot continue
return 0;
}
// repeated START, READ
I2C->ADDR_START = I2C_SlaveAddr<<I2C_ADDR_START_ADDRESS_Pos|I2C_START_READ;
while(I2C->STATUS & I2C_BUFFER_FULL)
{ // address buffered
}
for(i=0;i<len;i++)
{
if(i==len-1)
I2C->CTRL1 = I2C_LAST_DATA;
while(!((s=I2C->STATUS) & I2C_BUFFER_FULL))
{
if(s & I2C_HAS_NACK) // error
return i;
}
data[i]=I2C->DATA;
}
return i;
}
每次从Sleep模式唤醒后,都需要重新初始化I2C接口硬件。
void i2c_initialize(void)
{
Sys_I2C_DIOConfig(DIO_STRONG_PULL_UP, 1, 9); // SCL on DIO7, SDA on DIO8
I2C->CTRL0 = 1<<I2C_CTRL0_SPEED_Pos
|I2C_AUTO_ACK_ENABLE
|I2C_SAMPLE_CLK_ENABLE;
}
在试验阶段,读取 KX023 的加速度数据可以用 RTT 打印出来,从 Segger RTT Viewer 软件中保存成日志文件。RTT比用UART速度快,而且不需要额外的连线。
加速度计在一块PCB上(从手环电路板裁下来的),用橡皮泥粘在门上,采集门板的加速度。
然后把数据整理一下,用GNU Octave (语法跟商业软件Matlab相似)读取,画图。
这是一些对门的“动作”的数据记录。
|