MSPM0G3507: MCU作为从机,I2C SCL短接到GND 1秒后松开,SCL无法恢复高电平

Part Number: MSPM0G3507

如题,本来MCU作为从机,I2C可以正常被外部主机读写,但是无意中把SCL短时间内拉低(如1秒),然后松开,SCL居然无法恢复。

经排查是3507这边的问题(重启主机无效,重启从机恢复)。

开启所有中断标志位,无法响应,甚至TimeoutA设置也无法响应。

目前看不知道这个问题出现的原因,且3507作为从机自身也没有标志位可感知此异常:

  • 补充:看现象3507作为从机把SCL给拉住了(0电平)

  • SYSCONFIG_WEAK void SYSCFG_DL_I2C_init(void) {
    
        DL_I2C_setClockConfig(I2C_INST,
            (DL_I2C_ClockConfig *) &gI2CClockConfig);
        DL_I2C_disableAnalogGlitchFilter(I2C_INST);
    
        /* Configure Target Mode */
        DL_I2C_setTargetOwnAddress(I2C_INST, I2C_TARGET_OWN_ADDR);
        DL_I2C_setTargetTXFIFOThreshold(I2C_INST, DL_I2C_TX_FIFO_LEVEL_BYTES_1);
        DL_I2C_setTargetRXFIFOThreshold(I2C_INST, DL_I2C_RX_FIFO_LEVEL_BYTES_1);
        DL_I2C_enableTargetTXEmptyOnTXRequest(I2C_INST);
    
        DL_I2C_enableTargetClockStretching(I2C_INST);
        /* Configure Interrupts */
        DL_I2C_enableInterrupt(I2C_INST,
                               DL_I2C_INTERRUPT_TARGET_RXFIFO_TRIGGER |
                               DL_I2C_INTERRUPT_TARGET_START |
                               DL_I2C_INTERRUPT_TARGET_STOP);
    
    
        /* Enable module */
        DL_I2C_enableTarget(I2C_INST);
    
    
    }
    
    
    
    /*
     * Copyright (c) 2021, Texas Instruments Incorporated
     * All rights reserved.
     *
     * Redistribution and use in source and binary forms, with or without
     * modification, are permitted provided that the following conditions
     * are met:
     *
     * *  Redistributions of source code must retain the above copyright
     *    notice, this list of conditions and the following disclaimer.
     *
     * *  Redistributions in binary form must reproduce the above copyright
     *    notice, this list of conditions and the following disclaimer in the
     *    documentation and/or other materials provided with the distribution.
     *
     * *  Neither the name of Texas Instruments Incorporated nor the names of
     *    its contributors may be used to endorse or promote products derived
     *    from this software without specific prior written permission.
     *
     * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
     * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
     * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
     * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
     * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
     * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
     * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     */
    
    #include "ti_msp_dl_config.h"
    
    /* Maximum size of TX packet */
    #define I2C_TX_MAX_PACKET_SIZE (16)
    
    /* Maximum size of RX packet */
    #define I2C_RX_MAX_PACKET_SIZE (16)
    
    /* Data sent to Controller in response to Read transfer */
    uint8_t gTxPacket[I2C_TX_MAX_PACKET_SIZE] = {0x00};
    
    /* Counters for TX length and bytes sent */
    uint32_t gTxLen, gTxCount;
    uint32_t gTxFillNum;
    /* Data received from Controller during a Write transfer */
    uint8_t gRxPacket[I2C_RX_MAX_PACKET_SIZE];
    /* Counters for TX length and bytes sent */
    uint32_t gRxLen, gRxCount;
    
    int main(void)
    {
        SYSCFG_DL_init();
        /* Set LED to indicate start of transfer */
        DL_GPIO_setPins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
    
        /*
         * Fill FIFO with data.
         * Note that transactions are initiated by the Controller, so this example
         * only fills the buffer and the Target device will send this data when
         * requested by the Controller.
         * The TX FIFO is initialized to zero and then it will echo the data sent by
         * Controller.
         */
        gTxCount = 0;
        gTxLen   = I2C_TX_MAX_PACKET_SIZE;
        DL_I2C_setTimeoutACount(I2C_INST,2);
        DL_I2C_setTimeoutBCount(I2C_INST,2);
        DL_I2C_enableTimeoutA(I2C_INST);
        //DL_I2C_enableTimeoutB(I2C_INST);
        DL_I2C_disableTargetTXEmptyOnTXRequest(I2C_INST);
        DL_I2C_enableInterrupt(I2C_INST, DL_I2C_INTERRUPT_TARGET_RXFIFO_OVERFLOW|
                               DL_I2C_TARGET_INTERRUPT_OVERFLOW|
                               DL_I2C_INTERRUPT_TARGET_TXFIFO_UNDERFLOW|
                               DL_I2C_INTERRUPT_TARGET_TXFIFO_EMPTY |
                               DL_I2C_INTERRUPT_TIMEOUT_A |
                               DL_I2C_INTERRUPT_TIMEOUT_B|
                               DL_I2C_INTERRUPT_TARGET_PEC_RX_ERROR|
                               DL_I2C_INTERRUPT_TARGET_RX_DONE|
                               DL_I2C_INTERRUPT_TARGET_ARBITRATION_LOST|
                               DL_I2C_INTERRUPT_TARGET_GENERAL_CALL|
                               DL_I2C_INTERRUPT_TARGET_STOP|
                               DL_I2C_INTERRUPT_TARGET_RXFIFO_FULL|
                               DL_I2C_INTERRUPT_TARGET_TXFIFO_TRIGGER|
                               DL_I2C_INTERRUPT_TARGET_TX_DONE
                               );
    
        /* Initialize variables to receive data inside RX ISR */
        gRxCount = 0;
        gRxLen   = I2C_RX_MAX_PACKET_SIZE;
        DL_I2C_enableTargetACKOverride(I2C_INST);
        NVIC_EnableIRQ(I2C_INST_INT_IRQN);
    
        DL_SYSCTL_enableSleepOnExit();
    
        /* Go to STOP, the device will wake-up on address match */
        while (1) {
            __WFI();
        }
    }
    int aa;
    int f1= 0;
    int f2= 0;
    int tmt_flag= 0;
    int rvflag= 0;
    void I2C_INST_IRQHandler(void)
    {
        static bool dataRx = false;
    
        aa = DL_I2C_getPendingInterrupt(I2C_INST);
        switch (aa) {
            case DL_I2C_IIDX_TARGET_START:
                /* Initialize RX or TX after Start condition is received */
                gTxCount = 0;
                gRxCount = 0;
                dataRx   = false;
                rvflag= 0;
                /* Flush TX FIFO to refill it */
                DL_I2C_flushTargetTXFIFO(I2C_INST);
                break;
            case DL_I2C_IIDX_TARGET_RXFIFO_TRIGGER:
                /* Store received data in buffer */
                dataRx = true;
                while (DL_I2C_isTargetRXFIFOEmpty(I2C_INST) != true) {
                    if (gRxCount < gRxLen) {
                        gRxPacket[gRxCount++] = DL_I2C_receiveTargetData(I2C_INST);
                    } else {
                        /* Prevent overflow and just ignore data */
                        DL_I2C_receiveTargetData(I2C_INST);
                    }
                    if(gRxCount >= 2)
                    {
                        DL_I2C_enableTargetACKOverride(I2C_INST);
                        DL_I2C_setTargetACKOverrideValue(I2C_INST,DL_I2C_TARGET_RESPONSE_OVERRIDE_VALUE_NACK);
                        f1 = 1;
                    }
                    else
                    {
                        DL_I2C_enableTargetACKOverride(I2C_INST);
                        DL_I2C_setTargetACKOverrideValue(I2C_INST,DL_I2C_TARGET_RESPONSE_OVERRIDE_VALUE_ACK);
                        f2 = 1;
                    }
                }
                break;
            case DL_I2C_IIDX_TARGET_TXFIFO_TRIGGER:
                /* Fill TX FIFO if there are more bytes to send */
                if (gTxCount < gTxLen) {
                    gTxFillNum = DL_I2C_fillTargetTXFIFO(
                        I2C_INST, &gTxPacket[gTxCount], 1);
                    gTxCount += gTxFillNum;
                } else {
                    /*
                     * Fill FIFO with 0x00 if more data is requested than
                     * expected gTxLen
                     */
                    while (DL_I2C_transmitTargetDataCheck(I2C_INST, 0x88) != false)
                        ;
                }
                break;
            case DL_I2C_IIDX_TARGET_STOP:
                /* If data was received, echo to TX buffer */
                if (dataRx == true) {
                    for (uint16_t i = 0;
                         (i < gRxCount) && (i < I2C_TX_MAX_PACKET_SIZE); i++) {
                        gTxPacket[i] = gRxPacket[i];
                        DL_I2C_flushTargetTXFIFO(I2C_INST);
                    }
                    dataRx = false;
                }
                /* Toggle LED to indicate successful RX or TX */
                DL_GPIO_togglePins(GPIO_LEDS_PORT, GPIO_LEDS_USER_LED_1_PIN);
                break;
    
            case DL_I2C_IIDX_TARGET_TXFIFO_EMPTY:
                /* Fill TX FIFO if there are more bytes to send */
                if (gTxCount < 8) {
                    gTxFillNum = DL_I2C_fillTargetTXFIFO(
                        I2C_INST, &gTxPacket[gTxCount], 1);
                    gTxCount += gTxFillNum;
                } else {
                    /*
                     * Fill FIFO with 0x00 if more data is requested than
                     * expected gTxLen
                     */
                    while (DL_I2C_transmitTargetDataCheck(I2C_INST, 0x99) != false)
                    ;
                }
                break;
            case DL_I2C_IIDX_TARGET_RX_DONE:
                rvflag++;
                break;
                /* Not used for this example */
            case DL_I2C_IIDX_TARGET_RXFIFO_FULL:
                /* Not used for this example */
            case DL_I2C_IIDX_TARGET_GENERAL_CALL:
                /* Not used for this example */
            case DL_I2C_IIDX_TARGET_EVENT1_DMA_DONE:
                /* Not used for this example */
            case DL_I2C_IIDX_TARGET_EVENT2_DMA_DONE:
                /* Not used for this example */
                break;
            case DL_I2C_IIDX_TARGET_PEC_RX_ERROR:
                aa = 100;
                break;
            case DL_I2C_IIDX_TARGET_ARBITRATION_LOST:
            case DL_I2C_IIDX_TIMEOUT_A:
            case DL_I2C_IIDX_TIMEOUT_B:
            case DL_I2C_IIDX_TARGET_TXFIFO_UNDERFLOW:
            case DL_I2C_IIDX_TARGET_RXFIFO_OVERFLOW:
            case DL_I2C_IIDX_INTERRUPT_OVERFLOW:
    
                tmt_flag = 1;
                break;
            default:
                break;
        }
    }
    

  • 急急急!! 

    这是有什么处理办法?还是说是这个芯片的硬伤(无法解决?)。

  • 有没有TI工程师可以解答一下。我感觉这有点像是芯片bug。

  • 求解答!!!

  • 哪位能帮忙看下这个问题?