S32K314+MCAL I2C主机模式配置控制IAM20381

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;
}

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值