I2C operation of RSL10 and reading of acceleration measurement data of KX023
[Copy link]
This post was last edited by cruelfox on 2021-7-2 20:48
The I2C interface access of RSL10 can be realized by using the API provided by SDK, of course, you can also operate the registers yourself.
The firmware/syslib in the SDK pack only provides the include/rsl10_sys_i2c.h header file, which defines several inline functions, which can be regarded as shortcuts for register operations. There is no rsl10_sys_i2c.c file, which is not enough to perform a complete I2C read and write process.
There is a I2C_RSLxx.c file in the firmware/drivers/i2c_driver directory, which implements many functions such as I2C_MasterTransmit(), as well as IRQHandler and DMA_Handler support functions. But I found that the code is incomplete, for example, the ARM_DRIVER_I2C type is not defined, and it is not in the I2C_RSLxx.h header file. Later, I found that the definition is only found in Driver_I2C.h in the BDK. Because the dependency is too complicated, I don't want to use it anymore, so I'd better write the register operation myself.
It doesn't look complicated. The C language access to the I2C register group is similar to that of STM32. The APB clock of I2C is enabled by default, and the CTRLx register of I2C can be directly operated to enable the I2C function. The configuration of the I/O port only requires the use of a function Sys_I2C_DIOConfig() defined in the header file to specify which pins are used for the SCL and SDA signals, which is very convenient.
So should I use PIO, IRQ or DMA for data transmission? Although I2C is a low-speed device, the operating frequency of RSL10 is not high. I2C is used here at 1MHz SCL frequency (short line, few devices connected), and it is interrupted once every 9 SCL clocks, and the CPU idle cycle is also very limited. DMA is better, but when reading I2C, the program has no other tasks to do, so it still waits, and the power saving of using WFI for a short time is also limited. I just used PIO mode, which is to test the register status bit in a loop.
Most I2C devices are accessed by writing a register address and then continuously reading or writing a series of data. KX023 is one of these devices, so I implemented two functions for accessing 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;
}
Each time after waking up from Sleep mode, the I2C interface hardware needs to be reinitialized.
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;
}
During the test phase, the acceleration data read from the KX023 can be printed out using RTT and saved as a log file from the Segger RTT Viewer software. RTT is faster than using UART and does not require additional wiring.
The accelerometer is on a PCB (cut from the wristband circuit board), which is glued to the door with plasticine to collect the acceleration of the door panel.
Then organize the data, read it using GNU Octave (the syntax is similar to the commercial software Matlab), and draw the graph.
This is some data record of the "action" of the door.
|