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.

CCS/TM4C1294NCPDT: I2C with FIFO and uDMA example

Part Number: TM4C1294NCPDT

Tool/software: Code Composer Studio

Hello,

I need to implement an I2C communication using FIFO and uDMA.
Analyzing the document SPMA073, I found the example 'ektm4c129_i2c_master_udma_fifo', but it seems strange interrupts 'I2C_MASTER_INT_RX_DMA_DONE' and 'I2C_MASTER_INT_TX_DMA_DONE' are not used.
Is that correct?
Is there an example where they are used?
Which way would be more efficient?

Thanks,

Simion.

  • I don't think there is any advantage to using the DMA_DONE interrupts in this example because you are getting an I2C interrupt when the master transaction has completed. You could get the I2C_MASTER_INT_TX_DMA_DONE earlier, but there would still be data in the I2C FIFO to transmit. You would not want to change the state to I2C_OP_STOP at that time because you might still get an error or NAK as the last bytes are transmit. In short, I see no benefit of using the DMA_DONE interrupts in this example.

  • OK, it makes sense ... 

    I have some more doubts ... 

    My case is a little different, in the example a 16-bit word is sent referring to the I2C slave's registration address, but I need a word of just 8 bits, as requested by the datasheet of my I2C slave.

    To do this, I commented and changed some lines in the I2C1IntHandler function.

    void I2C1IntHandler(void)
    {
        uint32_t ui32I2CMasterInterruptStatus;
    
        //
        // Toggle PL4 High to Indicate Entry to ISR
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, GPIO_PIN_4);
    
        //
        // Get the masked interrupt status and clear the flags
        //
        ui32I2CMasterInterruptStatus = ROM_I2CMasterIntStatusEx(I2C1_BASE, true);
        ROM_I2CMasterIntClearEx(I2C1_BASE, ui32I2CMasterInterruptStatus);
    
        LOG[CONT] = ui32I2CMasterInterruptStatus;
        CONT++;
    
        //
        // Execute the State Machine
        //
        switch (g_ui8MasterCurrState) {
        case I2C_OP_IDLE:
            //
            // Move from IDLE to Transmit Address State
            //
            g_ui8MasterPrevState = g_ui8MasterCurrState;
    //        g_ui8MasterCurrState = I2C_OP_TXADDR;
            g_ui8MasterCurrState = I2C_OP_FIFO;
    
            //
            // Write the upper bits of the page to the Slave
            //
            ROM_I2CMasterSlaveAddrSet(I2C1_BASE, SLAVE_ADDRESS_EXT, false);
    //        I2CMasterDataPut(I2C2_BASE, (g_ui16SlaveWordAddress >> 8));
    //        I2CMasterControl(I2C2_BASE, I2C_MASTER_CMD_BURST_SEND_START);
            ROM_I2CMasterDataPut(I2C1_BASE, (g_ui16SlaveWordAddress >> 0));
            ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START);
            break;
    
        case I2C_OP_TXADDR:
            //
            // Assign the current state to the previous state
            //
            g_ui8MasterPrevState = g_ui8MasterCurrState;
    
            //
            // If Address has been NAK'ed then go to stop state
            // else go the FIFO Priming State
            //
            if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            else
            {
                g_ui8MasterCurrState = I2C_OP_FIFO;
            }
    
            //
            // Write the lower bits of the page to the Slave if
            // Address has been ACK-ed
            //
    //        ROM_I2CMasterDataPut(I2C1_BASE, (g_ui16SlaveWordAddress >> 0));
    //        ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_CONT);
            break;
    
        case I2C_OP_FIFO:
            //
            // If Last Data has been NAK'ed then go to stop state
            //
            if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            //
            // Based on the direction move to the appropriate state
            // of Transmit or Receive. Also send the BURST command
            // for FIFO Operations.
            //
            else if(!g_bI2CDirection)
            {
                g_ui8MasterCurrState = I2C_OP_TXDATA;
                ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH);
            }
            else
            {
                g_ui8MasterCurrState = I2C_OP_RXDATA;
                ROM_I2CMasterSlaveAddrSet(I2C1_BASE, SLAVE_ADDRESS_EXT, true);
                ROM_I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE);
            }
            break;
    
        case I2C_OP_TXDATA:
            //
            // Move the current state to the previous state
            // Else continue with the transmission till last byte
            //
            g_ui8MasterPrevState = g_ui8MasterCurrState;
    
            //
            // If Address or Data has been NAK'ed then go to stop state
            // If a Stop condition is seen due to number of bytes getting
            // done then move to STOP state
            //
            if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            else if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_STOP)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            else if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_TX_DMA_DONE)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            else
            {
                g_ui8MasterCurrState = I2C_ERR_STATE;
            }
            break;
    
        case I2C_OP_RXDATA:
            //
            // Move the current state to the previous state
            // Else continue with the transmission till last byte
            //
            g_ui8MasterPrevState = g_ui8MasterCurrState;
    
            //
            // If Address has been NAK'ed then go to stop state
            // If a Stop condition is seen due to number of bytes getting
            // done then move to STOP state and read the last data byte
            //
            if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_NACK)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            else if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_STOP)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            else if(ui32I2CMasterInterruptStatus & I2C_MASTER_INT_RX_DMA_DONE)
            {
                g_ui8MasterCurrState = I2C_OP_STOP;
            }
            break;
    
        case I2C_OP_STOP:
            //
            // Move the current state to the previous state
            // Else continue with the transmission till last byte
            //
            g_ui8MasterPrevState = g_ui8MasterCurrState;
            break;
    
        case I2C_ERR_STATE:
            g_ui8MasterCurrState = I2C_ERR_STATE;
            break;
    
        default:
            g_ui8MasterCurrState = I2C_ERR_STATE;
            break;
        }
    
        //
        // Toggle PL4 Low to Indicate Exit from ISR
        //
        ROM_GPIOPinWrite(GPIO_PORTE_BASE, GPIO_PIN_4, 0x0);
    }

    The SDA and SCL lines behaved perfectly when sending, but I got 4 interruptions, two of which were very close.

    The green line shows each I2C interrupt.

    the LOG variable stores the values ​​of ui32I2CMasterInterruptStatus at each interruption, I got the following results:
    LOG [0] = 0x00;
    LOG [1] = I2C_MASTER_INT_DATA;
    LOG [2] = I2C_MASTER_INT_TX_DMA_DONE;
    LOG [3] = I2C_MASTER_INT_STOP | I2C_MASTER_INT_DATA;

    Are these two almost simultaneous interruptions expected? Is there a better way to do this?

    Thanks,

    Simion

  • I see your point. Since the DMA_DONE interrupt moves the state from I2C_OP_TXDATA to I2C_OP_STOP, the final interrupt only copies the I2C_OP_STOP state to the previous state variable. You can try without enabling I2C_MASTER_INT_TX_DMA_DONE and see if it works, but with one less interrupt.

  • Works perfectly, but I preferred to leave it as is.

    Thanks,
    Simion