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.

I2C DMA usage problem

Other Parts Discussed in Thread: CC3200, TMP006

HI,all

I am using the I2C peripheral with DMA.

It seems that the system cannot work well.

Hardware: CC3200 LP rev 4.1

Software: SDK 1.1.0,FreeRTOS ,PMF (Power management framework)

I2C Pin: PIN_05, PIN_17.

I have tried to communicate with the on board  sensor TMP006 and BMA22.

I can read/write the TMP006 register.

However, I have to do a "dummy read "first.

I can not read/write with BMA22 register.

Here is my code

Init the peripheral 

void i2c_master_init_os()
{
  osi_LockObjCreate(&lock_i2cTrans);
  osi_SyncObjCreate(&signal_i2cDone);
  osi_SyncObjCreate(&signal_i2cReadDone);
}

void i2c_master_init()
{
    //
    // Configure I2C Master
    //
    MAP_I2CMasterInitExpClk(I2CA0_BASE,80000000,true);
    MAP_I2CIntRegister(I2CA0_BASE,I2CIntHandler);
    MAP_I2CMasterIntClearEx(I2CA0_BASE,0xFFFF);
    MAP_I2CMasterIntEnableEx(I2CA0_BASE,I2C_MASTER_INT_STOP|I2C_MASTER_INT_RX_DMA_DONE);
    
    MAP_I2CRxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_RX_MASTER_DMA|
                              I2C_FIFO_CFG_RX_TRIG_1);
    
    MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER_DMA|
                              I2C_FIFO_CFG_TX_TRIG_1);
    
    /*MAP_uDMAChannelAssign(UDMA_CH25_I2CA0_RX);
    MAP_uDMAChannelAssign(UDMA_CH26_I2CA0_TX);*/
    
    UDMAChannelSelect(UDMA_CH25_I2CA0_RX,NULL);
    UDMAChannelSelect(UDMA_CH26_I2CA0_TX,NULL);    
    
}

The read/write api.The problem is here: The RX FIFO is always not empty after "I2C_MASTER_INT_RX_DMA_DONE"

int I2C_Transfer( unsigned char ucDevAddr, unsigned char *ucWriteBuffer,
unsigned char *ucReadBuffer, unsigned long ulWriteSize,
unsigned long ulReadSize)
{
u8 rdData;
if(ulReadSize==0 && ulWriteSize==0)
return -1;

if(ulWriteSize>256 || ulReadSize>256)
return -1;

osi_LockObjLock(&lock_i2cTrans,OSI_WAIT_FOREVER);

/*UART_PRINT("Err:%x\r\n",MAP_I2CFIFOStatus (I2CA0_BASE));

while(MAP_I2CFIFODataGetNonBlocking (I2CA0_BASE,&rdData)>0)
{
UART_PRINT("%02x ",rdData);
}

UART_PRINT("\r\nErr:%x\r\n",MAP_I2CFIFOStatus (I2CA0_BASE));*/

if(ulWriteSize!=0)
{
osi_SyncObjClear(&signal_i2cDone);
//i2c dma tx
UDMASetupTransfer(UDMA_CH26_I2CA0_TX,
UDMA_MODE_BASIC,
ulWriteSize,
UDMA_SIZE_8,
UDMA_ARB_1,
ucWriteBuffer,
UDMA_SRC_INC_8,
(u8 *)0x40020F00,
UDMA_DST_INC_NONE);

MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,false);
MAP_I2CMasterBurstLengthSet(I2CA0_BASE,ulWriteSize);
MAP_I2CMasterIntClear(I2CA0_BASE);

UDMAStartTransfer(UDMA_CH26_I2CA0_TX);

MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_FIFO_BURST_SEND_START|
I2C_MASTER_CMD_FIFO_BURST_SEND_ERROR_STOP);

osi_SyncObjWait(&signal_i2cDone,OSI_WAIT_FOREVER);
Message("Send done!\r\n");
}

UART_PRINT("Err:%x\r\n",MAP_I2CFIFOStatus (I2CA0_BASE));

if(ulReadSize!=0)
{
osi_SyncObjClear(&signal_i2cReadDone);
osi_SyncObjClear(&signal_i2cDone);
memset(ucReadBuffer,0,ulReadSize);
readDone=0;
//i2c dma rx
UDMASetupTransfer(UDMA_CH25_I2CA0_RX,
UDMA_MODE_BASIC,
ulReadSize,
UDMA_SIZE_8,
UDMA_ARB_1,
(u8 *)0x40020F00,
UDMA_SRC_INC_NONE,
ucReadBuffer,
UDMA_DST_INC_8);

MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,true);
MAP_I2CMasterBurstLengthSet(I2CA0_BASE,ulReadSize);
MAP_I2CMasterIntClear(I2CA0_BASE);

MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START|
I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);

UDMAStartTransfer(UDMA_CH25_I2CA0_RX);

osi_SyncObjWait(&signal_i2cDone,OSI_WAIT_FOREVER);
Message("Receive done 0!\r\n");
osi_SyncObjWait(&signal_i2cReadDone,OSI_WAIT_FOREVER);
Message("Receive done 1!\r\n");
//UART_PRINT("Err:%x\r\n",MAP_I2CMasterErr (I2CA0_BASE));
}

/*if(ulReadSize!=0)
{
MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,true);
MAP_I2CMasterBurstLengthSet(I2CA0_BASE,ulReadSize);
MAP_I2CMasterIntClear(I2CA0_BASE);

MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_FIFO_BURST_RECEIVE_START|
I2C_MASTER_CMD_FIFO_BURST_RECEIVE_ERROR_STOP);

while(ulReadSize!=0)
{
*ucReadBuffer=(u8)MAP_I2CFIFODataGet(I2CA0_BASE);
ucReadBuffer++;
ulReadSize--;
}
}*/


UART_PRINT("Err:%x\r\n",MAP_I2CFIFOStatus (I2CA0_BASE));

while(MAP_I2CFIFODataGetNonBlocking (I2CA0_BASE,&rdData)>0)
{
UART_PRINT("%02x ",rdData);
}

UART_PRINT("\r\nErr:%x\r\n",MAP_I2CFIFOStatus (I2CA0_BASE));

osi_LockObjUnlock(&lock_i2cTrans);

return 0;

}

the interrupt handler

static void I2CIntHandler()
{
  unsigned long ulStatus   = MAP_I2CMasterIntStatusEx(I2CA0_BASE,false);
  MAP_I2CMasterIntClearEx(I2CA0_BASE,ulStatus);

  if( ulStatus & I2C_MASTER_INT_STOP )
  {
    osi_SyncObjSignal(&signal_i2cDone);
  }
  
  if(ulStatus & I2C_MASTER_INT_RX_DMA_DONE)
  {
    osi_SyncObjSignal(&signal_i2cReadDone);
    readDone=1;
  }
}

Regards,

  • In the static void I2CIntHandler(),
    I use the osi_SyncObjSignalFromISR first,but the system crashed at
    "void vAssertCalled( const char *pcFile, unsigned long ulLine )"
  • Kaifeng,

    You said you are using PMF - Is your application based on 'idle_profile' sample example then?
    Please note that the idle_profile application will configure M4 in LPDS mode If there are no active tasks running.

    Can you please retest by turning off M4’s PM using API ‘cc_app_putoff_pm’ and share the results? Fucntion ‘cc_app_resume_pm’ can be used to resume PM?

    -/Praneet
  • Hi, Praneet.

    I have used the API ‘cc_app_putoff_pm' and 'cc_app_resume_pm'.
    But the problem is still there.

    But I have found the "FIFO not empty" issue .It is due to the software problem.

    Now I can read/write with the on board TM006 well.
    But I can not read from the BMA222. Every time I do the read process,the SDA pin never returns to HIGH (idle state) when the process done.
    So the next time I do the read or write process, the I2C mater module can not work anymore (SDA HIGH makes bus busy).
    Then I have to reset the system(power off and on,pressing the on board reset key helps nothing) to make the system work again.

    I have tried to figure this issue for days.I almost want to give it up.

    Regards,
  • Kaifeng,

    Few Qs:
    - Are you saying that the communication b/w the master and slave start and locked-up after sometime, or it never started?
    - Can you please share the scope capture of the I2C lines?
    - Which device pins are you using for I2C?
    - To which header pins on the LaunchPad (J22 and J23) have you connected the slave? And, is the jumper on J6 and J7 placed towards 'FLASH' or 'BP'?

    -/Praneet
  • Hi,Praneet

    According to your questions:
    1, Communication with BMA222E was locked after the read process,any read from BMA222E (1 byte or more).
    2, Sorry for the scope is not unavailable currently. :)
    3, I2C Pin: PIN_05, PIN_17. And I have fix the bus contention problem when not using PIN_01 and PIN_02 as I2C pins.
    link is here: processors.wiki.ti.com/.../CC32xx_Summary_of_Known_Issues
    4,I have removed the default shorted header (J22 and J23),and connect the PIN_05 and PIN_17 to the slave devices.
    5, I have tested my code in debug mode and flash downloaded mode. They all have the same phenomenon.

    Regards,

  • Hi,Praneet

    According to your questions:
    1, Communication with BMA222E was locked after the read process,any read from BMA222E (1 byte or more).
    2, Sorry for the scope is not unavailable currently. :)
    3, I2C Pin: PIN_05, PIN_17. And I have fix the bus contention problem when not using PIN_01 and PIN_02 as I2C pins.
    link is here: processors.wiki.ti.com/.../CC32xx_Summary_of_Known_Issues
    4,I have removed the default shorted header (J22 and J23),and connect the PIN_05 and PIN_17 to the slave devices.
    5, I have tested my code in debug mode and flash downloaded mode. They all have the same phenomenon.

    Regards,
  • Hi,Praneet

    According to your questions:
    1, Communication with BMA222E was locked after the read process,any read from BMA222E (1 byte or more).
    2, Sorry for the scope is not unavailable currently. :)
    3, I2C Pin: PIN_05, PIN_17. And I have fix the bus contention problem when not using PIN_01 and PIN_02 as I2C pins.
    link is here: processors.wiki.ti.com/.../CC32xx_Summary_of_Known_Issues
    4,I have removed the default shorted header (J22 and J23),and connect the PIN_05 and PIN_17 to the slave devices.
    5, I have tested my code in debug mode and flash downloaded mode. They all have the same phenomenon.

    Regards
  • Hi, Praneet.

    I have given up using I2C with DMA.

    Now  I am using the I2C just with  interrupt,and it works fine.

    Here is my code.I hope this can help  someone who wants  to use the  I2C .

    static OsiLockObj_t lock_i2cTrans;
    
    #if defined(USE_I2C_DMA_FIFO) && (USE_I2C_DMA_FIFO==1)
    
    static OsiSyncObj_t signal_i2cReadDone;
    static OsiSyncObj_t signal_i2cWriteDone;
    
    static u8* g_writeBuff;
    static u8 g_writeSize;
    static u8* g_readBuff;
    static u8 g_readSize;
    static u8 g_state;
    //*****************************************************************************
    // Int handler for I2C
    //*****************************************************************************
    static void I2CIntHandler()
    {
      unsigned long ulStatus   = MAP_I2CMasterIntStatusEx(I2CA0_BASE,false);
    
      MAP_I2CMasterIntClearEx(I2CA0_BASE,ulStatus);
      
      if(ulStatus & (I2C_MASTER_INT_TIMEOUT|I2C_MASTER_INT_DATA))
      {
        
        if(MAP_I2CMasterErr(I2CA0_BASE) != I2C_MASTER_ERR_NONE)
        {
          if(g_state<0x80)
          {
            MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_SEND_ERROR_STOP);
            g_state=0x02;
            osi_SyncObjSignalFromISR(&signal_i2cWriteDone);
          }
          else
          {
            MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_RECEIVE_ERROR_STOP);
            g_state=0x82;
            osi_SyncObjSignalFromISR(&signal_i2cReadDone);
          }
          
        }
        
        if(g_state == 0)
        {
            if(g_writeSize!=0)
            {
              //MAP_I2CMasterTimeoutSet(I2CA0_BASE,0x7D);
              MAP_I2CMasterDataPut (I2CA0_BASE,*g_writeBuff);
              MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_SEND_CONT);
              g_writeSize--;
              g_writeBuff++;
            }
            else
            {
              g_state=0x01;//write done
              osi_SyncObjSignalFromISR(&signal_i2cWriteDone);
              MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_SEND_STOP);
            }
        }
        else if(g_state==0x80)//read state..
        {
          *g_readBuff=MAP_I2CMasterDataGet(I2CA0_BASE);
           g_readBuff++;
           g_readSize--;
           
           if(g_readSize!=0)
           {
             MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_RECEIVE_CONT);
           }
           else
           {
             osi_SyncObjSignalFromISR(&signal_i2cReadDone);
             MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_RECEIVE_FINISH);
             g_state=0x81;
           }
        }
        
      }
    }
    
    //*****************************************************************************
    // I2C DMA Transfer API
    //*****************************************************************************
    
    void i2c_master_init_os()
    {
      osi_LockObjCreate(&lock_i2cTrans);
      osi_SyncObjCreate(&signal_i2cReadDone);
      osi_SyncObjCreate(&signal_i2cWriteDone);
    }
    
    void i2c_master_init()
    {
        //
        // Configure I2C Master
        //
        MAP_I2CMasterInitExpClk(I2CA0_BASE,80000000,true);
        //MAP_I2CIntRegister(I2CA0_BASE,I2CIntHandler);
        
        osi_InterruptRegister(INT_I2CA0,I2CIntHandler,INT_PRIORITY_LVL_2);
        
        MAP_I2CMasterIntClearEx(I2CA0_BASE,0xFFFF);
        MAP_I2CMasterIntEnableEx(I2CA0_BASE,I2C_MASTER_INT_DATA|I2C_MASTER_INT_TIMEOUT);
        
        /*MAP_I2CRxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_RX_MASTER_DMA|
                                  I2C_FIFO_CFG_RX_TRIG_1);
        
        MAP_I2CTxFIFOConfigSet(I2CA0_BASE,I2C_FIFO_CFG_TX_MASTER_DMA|
                                  I2C_FIFO_CFG_TX_TRIG_1);
        
        UDMAChannelSelect(UDMA_CH25_I2CA0_RX,NULL);
        UDMAChannelSelect(UDMA_CH26_I2CA0_TX,NULL);  */  
        
        MAP_I2CMasterEnable(I2CA0_BASE);
    }
    
    int I2C_Transfer( unsigned char ucDevAddr, unsigned char *ucWriteBuffer,
                      unsigned char *ucReadBuffer, unsigned long ulWriteSize,
                      unsigned long ulReadSize)
    {
      int res;
      if(ulReadSize==0 && ulWriteSize==0)
        return -1;
      
      if(ulWriteSize>256 || ulReadSize>256)
        return -1;
      
      osi_LockObjLock(&lock_i2cTrans,OSI_WAIT_FOREVER);
    
      //Message("\r\nDebug.......start\r\n");
    
      res=0;
      if(ulWriteSize!=0)
      {
        osi_SyncObjClear(&signal_i2cWriteDone);
        g_writeBuff=ucWriteBuffer+1;
        g_writeSize=ulWriteSize-1;
        g_state=0;
        MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,false);
        MAP_I2CMasterTimeoutSet(I2CA0_BASE,0x7D);
        MAP_I2CMasterDataPut (I2CA0_BASE,ucWriteBuffer[0]);
        MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_SEND_START);
        osi_SyncObjWait(&signal_i2cWriteDone,OSI_WAIT_FOREVER);
        //UART_PRINT("Write done %d!\r\n",g_state);
        if(g_state!=1)
          res=-1;
      }
      
      if(ulReadSize!=0 && res==0)
      {
        osi_SyncObjClear(&signal_i2cReadDone);
        g_readBuff=ucReadBuffer;
        g_readSize=ulReadSize;
        g_state=0x80;
        MAP_I2CMasterSlaveAddrSet(I2CA0_BASE,ucDevAddr,true);
        MAP_I2CMasterTimeoutSet(I2CA0_BASE,0x7D);
        MAP_I2CMasterControl(I2CA0_BASE,I2C_MASTER_CMD_BURST_RECEIVE_START);
        osi_SyncObjWait(&signal_i2cReadDone,OSI_WAIT_FOREVER);
        //UART_PRINT("Read done %d!\r\n",g_state);
        if(g_state!=0x81)
          res=-2;
      }
    
      osi_LockObjUnlock(&lock_i2cTrans);
      
      return res;
    }

    usage example :

    (Get on board TMP006's  temperature)

    int tmp006_get_temp(u8 devAddr,float *rdTemp)
    {
      u8 rdBuff[2];
      u8 wtBuff[1];
      u16 temp;
      
      wtBuff[0]=0x01;
    
      if(I2C_Transfer(devAddr,wtBuff,rdBuff,1,2)==0)
      {
        temp=GET_U16_VALUE(rdBuff);
        temp>>=2;
        *rdTemp=temp;
        (*rdTemp)*=0.03125f;
        return 0;
      }
      return -1;
    }
    

    Regards,