|
【NXP Rapid IoT评测】触摸按键没有反应——I2C死锁解除方法
[复制链接]
NXP Rapid IoT 上用I2C1上挂了很多外设,
I2C1: Sensors + Touch: FXOS8700, FXAS21002, MPL3115, ENS210, TSL25711, CCS811 (behind I2C switch), SX9500
I2C2: after I2C switch (...NTAG_I2C_EN): NT3H2211, A1006, A71
而且在开发过程中不何避免的复位重启Rapid IoT,造成了I2C时序混乱,同时又由于电池供电,而且I2C上所有设置并不是都全可以进行掉电或者硬件复件。
体现的现象 触摸按键没有反应,传感器没有数据,信号现象 SCL为高,SDA一直为低
死锁产生的原因分析如下:
在正常情况下,I2C总线协议能够保证总线正常的读写操作。但是,当I2C主设备异常复位时(看门狗动作,板上电源异常导致复位芯片动作,手动按钮复位等等)有可能导致I2C总线死锁产生。下面详细说明一下总线死锁产生的原因。
在I2C主设备进行读写操作的过程中.主设备在开始信号后控制SCL产生8个时钟脉冲,然后拉低SCL信号为低电平,在这个时候,从设备输出应答信号,将SDA信号拉为低电平。如果这个时候主设备异常复位,SCL就会被释放为高电平。此时,如果从设备没有复位,就会继续I2C的应答,将SDA一直拉为低电平,直到SCL变为低电平,才会结束应答信号。而对于I2C主设备来说.复位后检测SCL和SDA信号,如果发现SDA信号为低电平,则会认为I2C总线被占用,会一直等待SCL和SDA信号变为高电平。这样,I2C主设备等待从设备释放SDA信号,而同时I2C从设备又在等待主设备将SCL信号拉低以释放应答信号,两者相互等待,I2C总线进人一种死锁状态。同样,当I2C进行读操作,I2C从设备应答后输出数据,如果在这个时刻I2C主设备异常复位而此时I2C从设备输出的数据位正好为0,也会导致I2C总线进入死锁状态。
解锁方法如下:
(1) 尽量选用带复位输人的I2C从器件。
(2) 将所有的从I2C设备的电源连接在一起,通过MOS管连接到主电源,而MOS管的导通关断由I2C主设备来实现。
(3) 在I2C从设备设计看门狗的功能。
(4) 在I2C主设备中增加I2C总线恢复程序。每次I2C主设备复位后,如果检测到SDA数据线被拉低,则控制I2C中的SCL时钟线产生9个时钟脉冲(针对8位数据的情况),这样I2C从设备就可以完成被挂起的读操作,从死锁状态中恢复过来。
(5) 在I2C总线上增加一个额外的总线恢复设备。
(6) 在I2C上串人一个具有死锁恢复的I2C缓冲器,如Linear公司的LTC4307。
硬件也设置好,而且并非每一个设备都满足上面的条件,只能选择方法(4),具体体现的代码如下:
- static void i2c_release_bus_delay(void)
- {
- #if 0
- #define I2C1_RELEASE_BUS_COUNT 200U
- uint32_t i = 0;
- for (i = 0; i < I2C1_RELEASE_BUS_COUNT; i++)
- {
- __NOP();
- }
- #else
- App_WaitUsec(100);
- #endif
- }
- void BOARD_I2C1_ConfigurePins(void)
- {
- /* Port C Clock Gate Control: Clock enabled */
- CLOCK_EnableClock(kCLOCK_PortC);
- const port_pin_config_t portc10_pinC7_config = {/* Internal pull-up resistor is enabled */
- kPORT_PullUp,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain is enabled */
- kPORT_OpenDrainEnable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Pin is configured as I2C1_SCL */
- kPORT_MuxAlt2,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORTC10 (pin C7) is configured as I2C1_SCL */
- PORT_SetPinConfig(PORTC, 10U, &portc10_pinC7_config);
- const port_pin_config_t portc11_pinB7_config = {/* Internal pull-up resistor is enabled */
- kPORT_PullUp,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain is enabled */
- kPORT_OpenDrainEnable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Pin is configured as I2C1_SDA */
- kPORT_MuxAlt2,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORTC11 (pin B7) is configured as I2C1_SDA */
- PORT_SetPinConfig(PORTC, 11U, &portc11_pinB7_config);
- }
- void I2C1_ReleaseBus(void)
- {
- uint8_t i = 0;
- gpio_pin_config_t pin_config;
- port_pin_config_t i2c_pin_config = {0};
- /* Config pin mux as gpio */
- i2c_pin_config.pullSelect = kPORT_PullUp;
- i2c_pin_config.mux = kPORT_MuxAsGpio;
- pin_config.pinDirection = kGPIO_DigitalOutput;
- pin_config.outputLogic = 1U;
- CLOCK_EnableClock(kCLOCK_PortC);
- PORT_SetPinConfig(BOARD_INITPINS_I2C1_SCL_PORT, BOARD_INITPINS_I2C1_SCL_PIN, &i2c_pin_config);
- PORT_SetPinConfig(BOARD_INITPINS_I2C1_SDA_PORT, BOARD_INITPINS_I2C1_SDA_PIN, &i2c_pin_config);
- GPIO_PinInit(BOARD_INITPINS_I2C1_SCL_PORT, BOARD_INITPINS_I2C1_SCL_PIN, &pin_config);
- GPIO_PinInit(BOARD_INITPINS_I2C1_SDA_PORT, BOARD_INITPINS_I2C1_SDA_PIN, &pin_config);
- /* Drive SDA low first to simulate a start */
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SDA_PORT, BOARD_INITPINS_I2C1_SDA_PIN, 0U);
- i2c_release_bus_delay();
- /* Send 9 pulses on SCL and keep SDA high */
- for (i = 0; i < 9; i++)
- {
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SCL_PORT, BOARD_INITPINS_I2C1_SCL_PIN, 0U);
- i2c_release_bus_delay();
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SDA_PORT, BOARD_INITPINS_I2C1_SDA_PIN, 1U);
- i2c_release_bus_delay();
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SCL_PORT, BOARD_INITPINS_I2C1_SCL_PIN, 1U);
- i2c_release_bus_delay();
- i2c_release_bus_delay();
- }
- /* Send stop */
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SCL_PORT, BOARD_INITPINS_I2C1_SCL_PIN, 0U);
- i2c_release_bus_delay();
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SDA_PORT, BOARD_INITPINS_I2C1_SDA_PIN, 0U);
- i2c_release_bus_delay();
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SCL_PORT, BOARD_INITPINS_I2C1_SCL_PIN, 1U);
- i2c_release_bus_delay();
- GPIO_PinWrite(BOARD_INITPINS_I2C1_SDA_PORT, BOARD_INITPINS_I2C1_SDA_PIN, 1U);
- i2c_release_bus_delay();
- BOARD_I2C1_ConfigurePins();
- }
复制代码
初始上时钟后,就可以调用上述代码。
完整代码,
board.rar
(6.03 KB, 下载次数: 7)
替换 工程文件\RapidIot_Base\board\board.c
此内容由EEWORLD论坛网友dvd1478原创,如需转载或用于商业用途需征得作者同意并注明出处
|
|