1.简介:
介绍一下开发环境及关键字:
MCU: S32K314
MCAL: EB配置,使用NXP提供的MCAL ,V2.0.3, AS4.4.0
IAM20381:加速计 X,Y,Z 轴 ±2g,4g,8g,16g 16-LGA(3x3)
I2C : 主机模式,与IAM20381连接,Port配置为开漏
2.port配置:
3.I2C配置:
I2C的数据传输方式先使用中断来传输,后续再更新为DMA,配置如下:
需要开启I2C的接收发送中断回调和错误回调,以便应用确认当前的传输状态
下面的I2C超时DEM的接口我们先不考虑,如果需要记录DTC可以打开;
选择好参考时钟,速率会自动帮你换算;
这里我们选择48M 64分频,得到125k的速率;
这个速率后期需要再根据MCU的时钟树来分频得到我们想要的大小,这里先不微调;
其他的参数可以根据对应调试芯片的参数来动态调整;
下面的高速模式,从机模式,10bit地址,先不配置后续更新;
4.中断配置:
如果使用autosar配置工具,请使能I2C中断:
中断标号:
S32K3XXRM.pdf \ S32K3xx_interrupt_map.XLSX
或者在Platform 使能I2C中断:
5.iam20381
IAM-20381是一款三轴运动跟踪加速计
资料在官网,有提供官网例程,这里我们将官方提供的驱动移植到我们的设备上;
手册:ds-000216-iam-20381-typ-v1.0.pdf (tdk.com.cn)
例程:Software Downloads | InvenSense Developers (tdk.com) 找到如下卡片:
点击上述框内开始下载工程压缩包:eMD-SmartMotion-IAM20381-1.0.0-MP
下载完毕解压缩,工程目录如下:
Streamlined_eMD_IAM20381_Software_Guide.pdf : 软件手册,主要是对基于EVB的开发的说明和对3个例程的功能解释;
驱动路径如下: EMD-Core\sources\Invn\Devices\Drivers\IAM20381
6.实现:
主要实现4个接口函数:
延时函数:
extern void inv_iam20381_sleep_us(int us);
extern void inv_iam20381_sleep_ms(int ms);
I2C写数据和读数据函数:
通过 SetupInvDevice注册
int SetupInvDevice(int (*read_reg)(void * context, uint8_t reg, uint8_t * buf, uint32_t len),
int (*write_reg)(void * context, uint8_t reg, const uint8_t * buf, uint32_t len),
inv_bool_t isSPI)
延时函数利用autosar的WaitEvent,GetEvent,ClearEvent实现
通过WaitEvent的等待时间来控制延迟的时间,
通过配置创建一个Extended类型 的task,创建两个事件,1.闹钟形式1ms触发一次处理数据,2触发事件等待初始化20381,
TASK(AppTask_Sensor)
{
EventMaskType ev;
for(;;)
{
(void)WaitEvent(RTE_EV_CYCLIC_APPTASK_SENSOR_1MS);
(void)GetEvent(APPTASK_SENSOR, &ev);
(void)ClearEvent(ev & (RTE_EV_CYCLIC_APPTASK_SENSOR_1MS));
if ((ev & RTE_EV_CYCLIC_APPTASK_SENSOR_SENSOR_EVENT_HDL) != (EventMaskType)0)
{
Sensor_Event_Hdl();
}
if ((ev & RTE_EV_CYCLIC_APPTASK_SENSOR_1MS) != (EventMaskType)0)
{
Sensor_Cyc_Hdl();
}
}
}
延时函数实现:
/* Sleep implementation for IAM20381 */
void inv_iam20381_sleep_ms(int ms) {
Std_ReturnType ret = 0 ;
int timeout = ms;
do {
ret = sensor_wait_event();
timeout--;
}while(sensor_get_event() != 0 && timeout != 0);
}
I2C接口实现:
static int idd_io_hal_read_reg(void * context, uint8_t reg, uint8_t * rbuffer, uint32_t rlen)
{
(void)context;
Std_ReturnType ret = 1;
volatile uint32_t timeout = 10; /* 10 * 1 ms*/
volatile I2c_StatusType status;
pRequestSend.DataBuffer[0] = reg;
pRequestSend.BufferSize = 1;
ret = I2c_AsyncTransmit(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1, &pRequestSend);
do {
ret = sensor_wait_event();
timeout--;
}while(sensor_get_event() != 0 && timeout != 0);
if ((status = I2c_GetStatus(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1)) == I2C_CH_SEND) {
return 1 ; /* 失败,I2C 异常 */
}
if (timeout) {
ret = 0;
pRequestRecv.BufferSize = rlen;
ret = I2c_AsyncTransmit(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1, &pRequestRecv);
}else {
return 1; /* 失败 */
}
timeout = 10; /* 重置超时cnt */
do {
ret = sensor_wait_event();
timeout--;
}while(sensor_get_event() != 0 && timeout != 0);
if ((status = I2c_GetStatus(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1)) == I2C_CH_RECEIVE) {
return 1 ; /* 失败,I2C 异常 */
}
if (timeout) {
ret = 0;
memcpy(rbuffer, pRequestRecv.DataBuffer,rlen); /* 读取数据 */
}else {
return 1; /* 失败 */
}
return ret;
}
static int idd_io_hal_write_reg(void * context, uint8_t reg, const uint8_t * wbuffer, uint32_t wlen)
{
(void)context;
Std_ReturnType ret = 1;
volatile uint32_t timeout = 10;
volatile I2c_StatusType status;
pRequestSend.DataBuffer[0] = reg;
pRequestSend.BufferSize = 1;
ret = I2c_AsyncTransmit(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1, &pRequestSend);
do {
ret = sensor_wait_event();
timeout--;
}while(sensor_get_event() != 0 && timeout != 0);
if ((status = I2c_GetStatus(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1)) == I2C_CH_SEND) {
return 1 ; /* 失败,I2C 异常 */
}
if (timeout) {
pRequestSend.BufferSize = wlen;
memcpy(pRequestSend.DataBuffer, wbuffer,wlen);
ret = I2c_AsyncTransmit(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1, &pRequestSend);
}
timeout = 10;
do {
ret = sensor_wait_event();
timeout--;
}while(sensor_get_event() != 0 && timeout != 0);
if ((status = I2c_GetStatus(I2cConf_I2cChannel_I2cChannel_MCU_SENSOR_I2C1)) == I2C_CH_SEND) {
return 1 ; /* 失败,I2C 异常 */
}
if (timeout) {
ret = 0;
}
return ret;
}
void I2C_MODULE_CALLBACK(uint8 Event, uint8 Channel)
{
/* todo check pin low timeout */
sensor_set_event();
}
I2C死锁问题:
I2C死锁一般发生在系统初始化、mcu软复位,硬件线路电平不稳定等情况下,从机设备将SDA拉低,而SCL保持为高,总线一直被占用,主机只能被动等待,无法对从及设备做控制,这时需要解锁;
1. 在初始化I2C之前,将SDA SCL初始化为IO,拉低拉高10次,解除锁定;
2.当产生I2C_MASTER_EVENT_PIN_LOW_TIMEOUT事件时,我们需要将i2c重新解锁;
我们需要配置如下参数:
设置为12个周期 :
10bit地址 + 1bit R/W + 1bit ACK
当产生I2C_MASTER_EVENT_PIN_LOW_TIMEOUT事件时,可以认为发生了死锁,我们需要在
I2C_CALLBACK 中去检查事件,当发生事件,则SetEvent在task AppTask_Sensor中处理;
初始化函数实现:
void iam20381_app_init(void)
{
int ret = 0;
SetupInvDevice(idd_io_hal_read_reg, idd_io_hal_write_reg);
/* Configure Device */
dev_config.enable_accel = (uint8_t)ENABLE_ACCEL;
dev_config.acc_fsr_g = FSR_ACC_G;
dev_config.odr_us = ODR_US;
ret = ConfigureInvDevice(&dev_config);
if (ret == 0) {
/* clear ringbuffer */
}
iam20381_valid = IAM20381_APP_E_OK;
}
例程选择的23081的i2c pin配置为推挽输出,这里我们需要修改一下pin设置为开漏输出根据20381手册:
新增寄存器设置pin函数:
int inv_iam20381_wr_int_pin_cfg(struct inv_iam20381 * s, uint8_t new_value)
{
uint8_t value;
int status;
status = inv_iam20381_read_reg(s, MPUREG_INT_PIN_CFG, 1, &value);
if(status)
return status;
value |= new_value;
status = inv_iam20381_write_reg(s, MPUREG_INT_PIN_CFG, 1, &value);
return status;
}
在inv_iam20381_init中最后一步添加:
int inv_iam20381_init(struct inv_iam20381 * s)
{
int status = 0;
/* Reset device */
status |= inv_iam20381_device_reset(s);
/* Wake up device */
status |= inv_iam20381_wr_pwr_mgmt_1_sleep(s, IAM20381_PWR_MGMT_1_SLEEP_awake);
/* Setup CLKSEL */
status |= inv_iam20381_wr_pwr_mgmt_1_clksel(s, CLK_SEL);
/* Disable Accel */
status |= inv_iam20381_wr_pwr_mgmt_2_accel_stby(s, (uint8_t)IAM20381_PWR_MGMT_2_XA_disable | (uint8_t)IAM20381_PWR_MGMT_2_YA_disable | (uint8_t)IAM20381_PWR_MGMT_2_ZA_disable);
/* Set default full scale range */
status |= inv_iam20381_wr_accel_config_accel_fs_sel(s, IAM20381_ACCEL_CONFIG_FS_SEL_4g);
/* Set default bandwidth */
status |= inv_iam20381_wr_accel_config2_a_dlpf_cfg(s, IAM20381_ACCEL_CONFIG2_A_DLPF_CFG_420);
status |= inv_iam20381_wr_config_dlpf_cfg(s, IAM20381_CONFIG_DLPF_CFG_176);
/* Set default averaging filter */
status |= inv_iam20381_wr_accel_config2_dec2_cfg(s, IAM20381_ACCEL_CONFIG2_DEC2_CFG_4x);
/* Initial sampling rate to 100Hz*/
status |= inv_iam20381_wr_smplrt_div(s, SAMPLE_RATE_DIVIDER);
/* make sure FIFO is disabled */
status |= inv_iam20381_wr_user_ctrl_fifo_en(s, IAM20381_USER_CTRL_FIFO_EN_disable);
status |= inv_iam20381_wr_fifo_en_accel_fifo_en(s, IAM20381_FIFO_EN_ACCEL_FIFO_EN_disable);
status |= inv_iam20381_wr_fifo_en_temp_fifo_en(s, IAM20381_FIFO_EN_TEMP_FIFO_EN_disable);
/* Configure FIFO:
- FIFO snapshot mode i.e drop the data when the FIFO overflows
*/
status |= inv_iam20381_wr_config_fifo_mode(s, IAM20381_CONFIG_FIFO_MODE_SNAPSHOT);
/* Enable Data Ready Interrupt */
status |= inv_iam20381_wr_int_enable_data_rdy_int_en(s, IAM20381_INT_ENABLE_DATA_RDY_INT_EN_enable);
/* open drain */
inv_iam20381_wr_int_pin_cfg(s,0xe0);
return status;
}