RSL10的I2C操作与KX023加速度测量数据读取
本帖最后由 cruelfox 于 2021-7-2 20:48 编辑<p> RSL10的I2C接口访问,可以用SDK提供的API实现,当然也可以自己操作寄存器。</p>
<p> SDK pack 里面的 firmware/syslib 下面只提供了 include/rsl10_sys_i2c.h 头文件,定义了几个 inline 函数,可以看作是寄存器操作的快捷方式。并没有 rsl10_sys_i2c.c 文件,不足以进行完整的I2C读写流程。</p>
<p> firmware/drivers/i2c_driver 目录下有 I2C_RSLxx.c 文件,实现了好多函数如 I2C_MasterTransmit() 这类的,还有 IRQHandler, DMA_Handler 支持函数。但是我发现代码不全,比如 ARM_DRIVER_I2C 这个类型没有定义,在 I2C_RSLxx.h 头文件中也没有。后来找到在背带裤(BDK)里面的 Driver_I2C.h 才有这个定义。因为依赖关系太复杂,我就不想用了,还是自己写寄存器操作吧。</p>
<p> 看起来也不复杂,I2C寄存器组的访问C语言写法和用STM32是差不多的。I2C的APB时钟默认已经开启了,可以直接操作I2C的CTRLx寄存器来开启 I2C 功能。I/O口的配置只需要借助头文件定义的一条函数 Sys_I2C_DIOConfig() 便可指定 SCL, SDA 两个信号各用哪个引脚,甚为方便。</p>
<p> 那么是用 PIO 方式,还是 IRQ 方式、DMA 方式进行数据传输呢?虽然 I2C 属于低速设备,但是 RSL10 的运行频率不高,I2C 在这里被我用在 1MHz SCL 频率(线短,挂的设备少),每9个SCL时钟就中断一次,CPU空闲出来的周期也很有限。DMA方式好一些,但读 I2C 的时候程序也没有其它任务可以做,还是等着,短时间利用 WFI 省电也很有限。我就直接用 PIO 方式遍了,就是循环测试寄存器状态位。</p>
<p> 大部分 I2C 设备都是通过 写一个寄存器地址,再连续读或者写一连串数据的方式访问的。KX023 就属于这种,于是我实现两个函数分别用于 KX023 的访问。</p>
<pre>
<code class="language-cpp">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;
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;
}</code></pre>
<pre>
<code class="language-cpp">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=I2C->DATA;
}
return i;
}</code></pre>
<p> 每次从Sleep模式唤醒后,都需要重新初始化I2C接口硬件。</p>
<pre>
<code class="language-cpp">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;
}</code></pre>
<p> </p>
<p> 在试验阶段,读取 KX023 的加速度数据可以用 RTT 打印出来,从 Segger RTT Viewer 软件中保存成日志文件。RTT比用UART速度快,而且不需要额外的连线。</p>
<p></p>
<p> 加速度计在一块PCB上(从手环电路板裁下来的),用橡皮泥粘在门上,采集门板的加速度。<i></i></p>
<p> 然后把数据整理一下,用GNU Octave (语法跟商业软件Matlab相似)读取,画图。</p>
<p></p>
<p><i><i> </i></i></p>
<p></p>
<p> 这是一些对门的“动作”的数据记录。</p>
<p>厉害,废物利用</p>
<p>很详细,谢谢分享~</p>
<p>GNU Octave 这个是什么软件啊??matlab的替换软件吗?</p>
okhxyyo 发表于 2021-7-1 17:08
GNU Octave 这个是什么软件啊??matlab的替换软件吗?
<p>不是替换软件。Matlab很庞大,Octave是个开源软件,功能没那么多,能支持一部分matlab的语法。</p>
cruelfox 发表于 2021-7-2 20:52
不是替换软件。Matlab很庞大,Octave是个开源软件,功能没那么多,能支持一部分matlab的语法。
<p>哦哦哦。这样呀,原来如此。什么时候能出来一个或一套的软件可以替代matlab呀</p>
<p>华健兄也是个“折腾人”哈哈,Octave,握手</p>
页:
[1]