This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TMS320F280039C: I2C SCL line is always low (0.043V)

Part Number: TMS320F280039C
Other Parts Discussed in Thread: SYSCONFIG, , C2000WARE

I am currently learning to write code for TMS320F280039C. I using sysconfig to setup the I2C registers. After loading the code, I checked the SCL line and its showing 0.043v. I wrote a program that would write some data to MCP4725. Just before data is transferred to the registers, I check whether the bus is busy or not by calling the function I2C_isBusBusy(). Every time when I try to transmit, the I2C_isBusBusy returns true.

I am using MCP4725 module  as a slave device and it has a 4.7k pull resistors on both SCL and SDA.

 

main.c

#include "board.h"
#include "device.h"
#include "driverlib.h"
#include "src/App/uart.h"
#include "src/Drivers/i2c.h"

#include <stdio.h>
//
// Main

__interrupt void INT_myI2C0_ISR(void);
__interrupt void INT_myI2C0_FIFO_ISR(void);
uint16_t trxBuff[3]   = {0x1, 0x2, 0x3};
char data[100] = "Hello world";
I2C_Data_s I2C_Params = {.Data = trxBuff, .Data_Length = 3, .Peripherial_Address = 0x60};
void main(void) {
    // Device Initialization
    Device_init();
    //
    // Initializes Peripheral Interrupt Expansion module (PIE) and clears PIE registers. Disables CPU interrupts.
    //
    Interrupt_initModule();
    //
    // Initializes the PIE vector table with pointers to the shell Interrupt
    // Service Routines (ISR).
    //
    Interrupt_initVectorTable();
    Board_init();
    //
    // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
    //
    EINT;
    ERTM;

    sprintf(data, "Programmed stated");


    while (1) {
        I2C_Transmit(myI2C0_BASE, &I2C_Params);
        while (I2C_Params.Status == PENDING)
            ;
        GPIO_togglePin(myGPIO0 );
        DEVICE_DELAY_US(250000);
        GPIO_togglePin(myGPIO0 );
        DEVICE_DELAY_US(250000);
    }
}
__interrupt void INT_myI2C0_ISR() {
    handleI2C_Interrupts(myI2C0_BASE,&I2C_Params);
    Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
};
__interrupt void INT_myI2C0_FIFO_ISR() {
    sprintf(data, "FIFO Interrupt");
    UART_TX(data);
};

i2c.c

#include "i2c.h"

#include "board.h"
#include "driverlib.h"

static uint8_t totalDataSend = 0;

void I2C_Initialize() {
}

I2C_Status_TypDef checkBusStatus(uint32_t base) {
    if (I2C_isBusBusy(base)) {
        return ERROR_BUS_BUSY;
    }

    if (I2C_getStopConditionStatus(base)) {
        return ERROR_STOP_NOT_READY;
    }

    return SUCCESS;
}

void I2C_Transmit(uint32_t base, I2C_Data_s *I2C_Params) {
    ASSERT(I2C_isBaseValid(base));
    I2C_Status_TypDef status;
    status = checkBusStatus(base);
    if (status != SUCCESS) {
        I2C_Params->Status = status;
    } else {
        I2C_disableModule(myI2C0_BASE);
        I2C_setConfig(base, (I2C_CONTROLLER_SEND_MODE));
        I2C_setTargetAddress(base, I2C_Params->Peripherial_Address);
        I2C_setDataCount(base, I2C_Params->Data_Length);
        I2C_enableModule(myI2C0_BASE);
        // for (int i = 0; i < I2C_Params->Data_Length; i++)
        // {
        //     I2C_putData(base, *(I2C_Params->Data + i));
        // }
        I2C_Params->Status = PENDING;
        I2C_sendStartCondition(base);
    }
}

void I2C_Recieve(uint32_t base, I2C_Data_s *I2C_Params) {
    ASSERT(I2C_isBaseValid(base));

    I2C_setConfig(base, (I2C_CONTROLLER_RECEIVE_MODE));
    I2C_setTargetAddress(base, I2C_Params->Peripherial_Address);
    I2C_setDataCount(base, I2C_Params->Data_Length);

    // for (int i = 0; i < I2C_Params->Data_Length; i++)
    // {
    //     I2C_putData(base, *(I2C_Params->Data + i));
    // }
    I2C_Params->Status = PENDING;
    I2C_sendStartCondition(base);
}

void handleI2C_Interrupts(uint32_t base, I2C_Data_s *I2C_Params) {
    I2C_InterruptSource intSource = I2C_getInterruptSource(base);

    if (I2C_getStatus(base) & I2C_STS_NO_ACK) {
        I2C_clearStatus(base, I2C_STS_NO_ACK);
        I2C_sendStopCondition(base);
    }

    switch (intSource) {
        case I2C_INTSRC_ARB_LOST:
            // Report Arbitration lost failure
            I2C_Params->Status = ERROR_ARBITRATION_LOST;
            break;

        case I2C_INTSRC_NO_ACK:
            // Clear NACK flag and generate STOP condition on a NACK condition
            I2C_clearStatus(base, I2C_STS_NO_ACK);
            I2C_sendStopCondition(base);
            I2C_Params->Status = ERROR_NACK_RECEIVED;
            break;

        case I2C_INTSRC_REG_ACCESS_RDY:
            I2C_clearStatus(base, I2C_STS_RX_DATA_RDY);
            break;

        case I2C_INTSRC_RX_DATA_RDY: {
            if (totalDataSend < I2C_Params->Data_Length)
                *(I2C_Params->Data + totalDataSend) = I2C_getData(base);
            else {
                I2C_sendNACK(base);
                I2C_sendStopCondition(base);
            }
            totalDataSend = totalDataSend + 1;
            break;
        }
        case I2C_INTSRC_TX_DATA_RDY:
            if (totalDataSend < I2C_Params->Data_Length) {
                I2C_putData(base, *(I2C_Params->Data + totalDataSend));
                I2C_sendStopCondition(base);
            } else {
                I2C_Params->Status = SUCCESS;
            }

            totalDataSend = totalDataSend + 1;

            break;

        case I2C_INTSRC_STOP_CONDITION:
            // I2C_disableInterrupt(base, (I2C_INT_TXFF | I2C_INT_RXFF));
            // I2C_Params->pTX_MsgBuffer = TX_MsgBuffer;
            // I2C_Params->pRX_MsgBuffer = RX_MsgBuffer;
            // I2C_disableFIFO(base);
            break;

        case I2C_INTSRC_ADDR_TARGET:

            break;
    }
}

  • Hi Abhijith,

    Are the SDA and SCL pulled high on reset? The issue may be that when the I2C comes out of reset, the busy bit may not correctly have the I2C bus state. This would be due to an incorrect start/stop condition. Please check out this thread and let me know if this is something you have already implemented.

    In addition, the I2C_isBusBusy(base) function indicates whether the bus is free or busy as you mentioned, but it doesn't wait till the I2C bus is free to start another I2C transaction.

    Regards,

    Aishwarya

  • Hi  Aishwarya,

    I added a 2ms delay just after I call I2C_disableModule inside I2C_Transmit. But the problem is that the program never enters data transmitting section since I2C_isBusBusy is returning true. After further debugging, when the PinMux_init() GPIO_init() is called in the board.c file,the SCL and SDA lines are held low. Even after I2C_init() is called both the line are not held low.

    Previously only SCL was held low but not both SCL and SDA are held low.

    main.c

    #include "board.h"
    #include "device.h"
    #include "driverlib.h"
    #include "src/App/uart.h"
    #include "src/Drivers/i2c.h"
    
    #include <stdio.h>
    //
    // Main
    
    __interrupt void INT_myI2C0_ISR(void);
    __interrupt void INT_myI2C0_FIFO_ISR(void);
    uint16_t trxBuff[3]   = {0x1, 0x2, 0x3};
    char data[100] = "Hello world";
    I2C_Data_s I2C_Params = {.Data = trxBuff, .Data_Length = 3, .Peripherial_Address = 0x60};
    void main(void) {
        // Device Initialization
        Device_init();
        //
        // Initializes Peripheral Interrupt Expansion module (PIE) and clears PIE registers. Disables CPU interrupts.
        //
        Interrupt_initModule();
        //
        // Initializes the PIE vector table with pointers to the shell Interrupt
        // Service Routines (ISR).
        //
        Interrupt_initVectorTable();
        Board_init();
        //
        // Enable Global Interrupt (INTM) and realtime interrupt (DBGM)
        //
        EINT;
        ERTM;
    
        sprintf(data, "Programmed stated");
        UART_TX(data);
    
        while (1) {
            I2C_Transmit(myI2C0_BASE, &I2C_Params);
            while (I2C_Params.Status == PENDING)
                ;
            GPIO_togglePin(myGPIO0 );
            DEVICE_DELAY_US(250000);
            GPIO_togglePin(myGPIO0 );
            DEVICE_DELAY_US(250000);
        }
    }
    __interrupt void INT_myI2C0_ISR() {
        handleI2C_Interrupts(myI2C0_BASE,&I2C_Params);
        Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP8);
    };
    __interrupt void INT_myI2C0_FIFO_ISR() {
        sprintf(data, "FIFO Interrupt");
        UART_TX(data);
    };
    

    i2c.c

    #include "i2c.h"
    
    #include "board.h"
    #include "driverlib.h"
    
    static uint8_t totalDataSend = 0;
    
    void I2C_Initialize() {
    }
    
    I2C_Status_TypDef checkBusStatus(uint32_t base) {
        if (I2C_isBusBusy(base)) {
            return ERROR_BUS_BUSY;
        }
    
        if (I2C_getStopConditionStatus(base)) {
            return ERROR_STOP_NOT_READY;
        }
    
        return SUCCESS;
    }
    
    void I2C_Transmit(uint32_t base, I2C_Data_s *I2C_Params) {
        ASSERT(I2C_isBaseValid(base));
        I2C_Status_TypDef status;
        status = checkBusStatus(base);
        if (status != SUCCESS) {
            I2C_Params->Status = status;
        } else {
            I2C_disableModule(myI2C0_BASE);
            DEVICE_DELAY_US(2000);
            I2C_setConfig(base, (I2C_CONTROLLER_SEND_MODE));
            I2C_setTargetAddress(base, I2C_Params->Peripherial_Address);
            I2C_setDataCount(base, I2C_Params->Data_Length);
            I2C_enableModule(myI2C0_BASE);
            // for (int i = 0; i < I2C_Params->Data_Length; i++)
            // {
            //     I2C_putData(base, *(I2C_Params->Data + i));
            // }
            I2C_Params->Status = PENDING;
            I2C_sendStartCondition(base);
        }
    }
    
    void I2C_Recieve(uint32_t base, I2C_Data_s *I2C_Params) {
        ASSERT(I2C_isBaseValid(base));
    
        I2C_setConfig(base, (I2C_CONTROLLER_RECEIVE_MODE));
        I2C_setTargetAddress(base, I2C_Params->Peripherial_Address);
        I2C_setDataCount(base, I2C_Params->Data_Length);
    
        // for (int i = 0; i < I2C_Params->Data_Length; i++)
        // {
        //     I2C_putData(base, *(I2C_Params->Data + i));
        // }
        I2C_Params->Status = PENDING;
        I2C_sendStartCondition(base);
    }
    
    void handleI2C_Interrupts(uint32_t base, I2C_Data_s *I2C_Params) {
        I2C_InterruptSource intSource = I2C_getInterruptSource(base);
    
        if (I2C_getStatus(base) & I2C_STS_NO_ACK) {
            I2C_clearStatus(base, I2C_STS_NO_ACK);
            I2C_sendStopCondition(base);
        }
    
        switch (intSource) {
            case I2C_INTSRC_ARB_LOST:
                // Report Arbitration lost failure
                I2C_Params->Status = ERROR_ARBITRATION_LOST;
                break;
    
            case I2C_INTSRC_NO_ACK:
                // Clear NACK flag and generate STOP condition on a NACK condition
                I2C_clearStatus(base, I2C_STS_NO_ACK);
                I2C_sendStopCondition(base);
                I2C_Params->Status = ERROR_NACK_RECEIVED;
                break;
    
            case I2C_INTSRC_REG_ACCESS_RDY:
                I2C_clearStatus(base, I2C_STS_RX_DATA_RDY);
                break;
    
            case I2C_INTSRC_RX_DATA_RDY: {
                if (totalDataSend < I2C_Params->Data_Length)
                    *(I2C_Params->Data + totalDataSend) = I2C_getData(base);
                else {
                    I2C_sendNACK(base);
                    I2C_sendStopCondition(base);
                }
                totalDataSend = totalDataSend + 1;
                break;
            }
            case I2C_INTSRC_TX_DATA_RDY:
                if (totalDataSend < I2C_Params->Data_Length) {
                    I2C_putData(base, *(I2C_Params->Data + totalDataSend));
                    I2C_sendStopCondition(base);
                } else {
                    I2C_Params->Status = SUCCESS;
                }
    
                totalDataSend = totalDataSend + 1;
    
                break;
    
            case I2C_INTSRC_STOP_CONDITION:
                // I2C_disableInterrupt(base, (I2C_INT_TXFF | I2C_INT_RXFF));
                // I2C_Params->pTX_MsgBuffer = TX_MsgBuffer;
                // I2C_Params->pRX_MsgBuffer = RX_MsgBuffer;
                // I2C_disableFIFO(base);
                break;
    
            case I2C_INTSRC_ADDR_TARGET:
    
                break;
        }
    }
    

  • I removed the bus status checking section to  let the I2C transmit data but I get ERROR_ARBITRATION_LOST interrupt everytime

  • How many controllers are there on the bus, specifically controller-transmitters? The I2CSTR.ARBL bit gets set when there are multiple controller-transmitters on the bus, so ensure that only the C2000 is in this mode and the other device is in target-receiver mode.

    I would also recommend trying to see what happens when you manually write a 0 to the I2CSTR.BB bit to simulate a reset. If doing this allows for an I2C transmission to occur, then we can confirm the issue is that the I2C module is not resetting and receiving start/stop conditions in between transmissions properly.

    In addition, I would move the while loop on line 40 to before the outer loop so that way your transmission only occurs after the bus is known to be free. If you haven't already, I would take a look at the C2000ware examples specifically examples #5 for the I2C setup.