Post Go back to editing

ADSP21569 TWI operation failure with system clock of 400Mhz

Category: Software
Product Number: ADSP 21569
Software Version: CCES 2.9.4

We are adsp21569 SHARC processor for Communicating with AT24C256C EEPROM on TWI,  using baremetal programming.

If System Clock is configured as 125 MHz  both read and write operations are working as expected.

If  System Clock is configured as 400 MHz. we are receiving timeout error, On checking the master status register we are seeing the master read buffer error.

Provide the guidance on how to resolve the issue.

Code is available below for your reference

/*! ***********************************************************************************************************
 * \fn    dp_scm_init_i2c
 * \brief Perform the I2C Initialization
 * This function is used to Initialize the I2C.
 ****************************************************************************************************************/
int dp_scm_init_i2c(void)
{
    int iRetVal = DP_SUCCESS;
    //    unsigned short usClkDiv = 13;
    //    unsigned short usPreScalVal = 12;
    //    unsigned short usFrequency = 400;

    /* PORTx_MUX registers */
    *pREG_PORTB_MUX = TWI1_SCL_PORTB_MUX | TWI1_SDA_PORTB_MUX;

    /* PORTx_FER registers */
    *pREG_PORTB_FER = TWI1_SCL_PORTB_FER | TWI1_SDA_PORTB_FER;

    // Set the TWI controller
    *pREG_TWI1_CTL = BITM_TWI_CTL_EN |
            ((DP_SCM_I2C_PRE_SCALE << BITP_TWI_CTL_PRESCALE) & BITM_TWI_CTL_PRESCALE) | 0;

    // Setting clock duty cycle
    //*pREG_TWI1_CLKDIV = (DP_SCM_I2C_CLKDIV << BITP_TWI_CLKDIV_CLKHI) | DP_SCM_I2C_CLKDIV;
    *pREG_TWI1_CLKDIV = (13 << BITP_TWI_CLKDIV_CLKHI) | 13;

    *pREG_TWI1_MSTRCTL = BITM_TWI_MSTRCTL_FAST | 0;

    // Set the device address
    *pREG_TWI1_MSTRADDR = EEPROM_ID;

    *pREG_TWI1_FIFOCTL = BITM_TWI_FIFOCTL_RXFLUSH|BITM_TWI_FIFOCTL_TXFLUSH;
    *pREG_TWI1_FIFOCTL = 0;

    // Clear status bits
    *pREG_TWI1_MSTRSTAT = (ENUM_TWI_MSTRSTAT_BUFWRERR_YES |
                           ENUM_TWI_MSTRSTAT_BUFRDERR_YES |
                           ENUM_TWI_MSTRSTAT_DNAK_YES |
                           ENUM_TWI_MSTRSTAT_ANAK_YES |
                           ENUM_TWI_MSTRSTAT_LOSTARB_YES | 0);

    // Clearing all pending interrupt flags
    *pREG_TWI1_ISTAT = 0xFFFF;

    return iRetVal;
}

/*! ***********************************************************************************************************
 * \fn    dp_scm_i2c_write
 * \brief To write I2C
 * This function is used to write data through I2C.
 ****************************************************************************************************************/
int dp_scm_i2c_write(unsigned char *in_pucData, unsigned short in_usDataLength)
{
    int iRetVal = DP_SUCCESS;
    unsigned long  ulTimeOut = 0;
    unsigned short usLooper = 0;
    volatile unsigned long  ulIntStatus = 0;
    /*Pointer Validation*/
    if(in_pucData == NULL)
    {
        iRetVal = DP_SCM_INVALID_POINTER;
    }
    else
    {
        // Flush FIFO in case a previous transfer encountered an error

        *pREG_TWI1_FIFOCTL = BITM_TWI_FIFOCTL_RXFLUSH|BITM_TWI_FIFOCTL_TXFLUSH;
        *pREG_TWI1_FIFOCTL = 0;

        // Set up the transfer
        *pREG_TWI1_MSTRCTL = (in_usDataLength << 6) |  /* set count to a 2 but we'll never let it finish*/
                BITM_TWI_MSTRCTL_EN |   /* enable*/
                0;

        for (usLooper = 0; usLooper < in_usDataLength; usLooper++)
        {
            // Load value into TX register
            *pREG_TWI1_TXDATA8 = in_pucData[usLooper];

            // Wait for transfer to complete
            ulTimeOut = DP_SCM_I2C_TX_TIMEOUT;

            while(ulTimeOut)
            {
                ulTimeOut--;

                ulIntStatus = *pREG_TWI1_ISTAT;
                if((ulIntStatus & BITM_TWI_ISTAT_TXSERV) == BITM_TWI_ISTAT_TXSERV)
                {
                    break;
                }
            }

            if(ulTimeOut != 0)
            {
                *pREG_TWI1_ISTAT |= BITM_TWI_ISTAT_TXSERV;                                                                // Clear tx status latch
            }
            else
            {
                iRetVal = DP_SCM_I2C_TX_TIMEOUT_ERROR;
                break;
            }
        }

        *pREG_TWI1_ISTAT |= BITM_TWI_ISTAT_MCOMP;
    }

    return iRetVal;
}

/*! ***********************************************************************************************************
 * \fn    dp_scm_i2c_write_and_read
 * \brief To read I2C
 * This function is used to read data through I2C.
 ****************************************************************************************************************/
int dp_scm_i2c_write_and_read(unsigned char *in_pucAddress, unsigned char *out_pucData)
{
    int iRetVal = DP_SUCCESS;
    unsigned long  ulTimeOut = 0;
    volatile unsigned long ulISTAT = 0;
    unsigned short usLooper = 0;

    /*Pointer Validation*/
    if((in_pucAddress == NULL) || (out_pucData == NULL))
    {
        iRetVal = DP_SCM_INVALID_POINTER;
    }
    else
    {
        // Flush FIFO in case a previous transfer encountered an error
        *pREG_TWI1_FIFOCTL = BITM_TWI_FIFOCTL_RXFLUSH|BITM_TWI_FIFOCTL_TXFLUSH;
        *pREG_TWI1_FIFOCTL = 0;


        *pREG_TWI1_TXDATA8 = in_pucAddress[0];

        // Set up the transfer
        *pREG_TWI1_MSTRCTL = (2 << 6) |  /* set count to a 2 but we'll never let it finish*/
                BITM_TWI_MSTRCTL_EN |   /* enable*/
                0;

        ulTimeOut = DP_SCM_I2C_TX_TIMEOUT;

        while(ulTimeOut--)
        {
            //            dp_scm_delay_ms(5);

            ulISTAT = *pREG_TWI1_ISTAT;
            if((ulISTAT & BITM_TWI_ISTAT_TXSERV) == BITM_TWI_ISTAT_TXSERV)
            {
                break;
            }

        }

        if(ulTimeOut != 0)
        {
            *pREG_TWI1_ISTAT |= BITM_TWI_ISTAT_TXSERV;                                                                // Clear tx status latch
        }
        else
        {
            iRetVal = DP_SCM_I2C_TX_TIMEOUT_ERROR;
        }

        if(DP_SUCCESS == iRetVal)
        {

            *pREG_TWI1_MSTRCTL  |=  BITM_TWI_MSTRCTL_RSTART;

            *pREG_TWI1_TXDATA8 = in_pucAddress[1];

            ulTimeOut = DP_SCM_I2C_TX_TIMEOUT;

            while(ulTimeOut--)
            {

                ulISTAT = *pREG_TWI1_ISTAT;
                if((ulISTAT & BITM_TWI_ISTAT_MCOMP) == BITM_TWI_ISTAT_MCOMP)
                {
                    break;
                }

            }

            if(ulTimeOut != 0)
            {                                                                // Clear tx status latch
                iRetVal = DP_SUCCESS;
            }
            else
            {
                iRetVal = DP_SCM_I2C_TX_TIMEOUT_ERROR;
            }

            *pREG_TWI1_ISTAT |= BITM_TWI_ISTAT_MCOMP;
        }

        /*Read Data*/
        if(DP_SUCCESS == iRetVal)
        {
            // Enable master transmitter
            *pREG_TWI1_MSTRCTL  =    BITM_TWI_MSTRCTL_DIR | // receive mode
                    (1 << 6) | // set count to a 1
                    BITM_TWI_MSTRCTL_EN | // enable
                    0;

            ulTimeOut = DP_SCM_I2C_RX_TIMEOUT;

            while(ulTimeOut--)
            {
                //                dp_scm_delay_ms(5);

                ulISTAT = *pREG_TWI1_ISTAT;
                if((ulISTAT & BITM_TWI_ISTAT_MCOMP) == BITM_TWI_ISTAT_MCOMP)
                {
                    break;
                }
            }

            if(ulTimeOut != 0)
            {
                *pREG_TWI1_ISTAT |= BITM_TWI_ISTAT_MCOMP;

                *out_pucData = *pREG_TWI1_RXDATA8;                                                            // Clear tx status latch
            }
            else
            {
                iRetVal = DP_SCM_I2C_RX_TIMEOUT_ERROR;
            }
        }
    }

    return iRetVal;
}