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.

Compiler/TM4C1294NCPDT: 10 sets I2C (FIFO + DMA )

Part Number: TM4C1294NCPDT

Tool/software: TI C/C++ Compiler

Hi Pals,

I set 10 I2C peripherals  (I2C0~9) to read / write data, and met hard fault again.


If I disable or change to be FIFO on I2C3 & I2C4 &I2C7, the function is no problem.


Please kindly to review my code and provide your advise, thanks.

int main(void)
{
// uint16_t inVersion;
 //uint32_t uiLoopTest=0;
 volatile uint32_t ui32Boot = 0;
 uint8_t nPntCnt=25,nPntCnt2=26,nMaxPntCnt=0;
 uint8_t nPalmCnt=30,nPalmCnt2=31,nMaxPalmCnt=0;
 uint8_t i;
 
  g_ShotProtect=1;
  
 #ifdef TI_Board
 g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ |
                                         SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                                         SYSCTL_CFG_VCO_480), 120000000);
 #else
 g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_12MHZ|
                                         SYSCTL_OSC_MAIN | SYSCTL_USE_PLL |
                                         SYSCTL_CFG_VCO_480), 120000000);
 #endif
 //gpio port function init
 PortFunctionInit();
 #ifdef TI_Board
 ConfigureDBGUART(3,115200); //can't use port 0, uart0 conflict with I2C9 
 #else
 ConfigureDBGUART(2,115200); //can't use port 0, uart0 conflict with I2C9 
 #endif

  UARTprintf("Configure___________OK!!!\n");

 PowerOnEnable();

 I2C_InitialAll(I2C_EN);
 I2C_DMAInitialAll(I2C_DMA_EN);
        //#define SLAVE_0_EN  0x0001
        //#define SLAVE_1_EN  0x0002
        //#define SLAVE_2_EN  0x0004
        //#define SLAVE_3_EN  0x0008
        //#define SLAVE_4_EN  0x0010
        //#define SLAVE_5_EN  0x0020
        //#define SLAVE_6_EN  0x0040
        //#define SLAVE_7_EN  0x0080
        //#define SLAVE_8_EN  0x0100
        //#define SLAVE_9_EN  0x0200

        //#define I2C_EN (0x3FF)  //-->Function is ok if defined 0x367
        //#define I2C_DMA_EN (0x3FF)  //-->Function is ok if defined 0x367

 I2CMaster_Speed(I2C_SPEED_400K);
 vfDelay_ms(1);
 
 Flash_Test(); 
 while(1){ };
}

void I2C_InitialAll(uint16_t u16MaskCH)
{
 uint8_t i;
 for (i=0; i<10; i++)
 {
  if(u16MaskCH & ( 1 << i ))
  {
   SysCtlPeripheralDisable(I2C_PERIPH[i]);
   SysCtlPeripheralReset(I2C_PERIPH[i]);
   SysCtlPeripheralEnable(I2C_PERIPH[i]);
   while(!SysCtlPeripheralReady(I2C_PERIPH[i]));

   GPIOPinTypeI2C(I2C_PIN_BASE[i], I2C_SDA_PIN[i]);
   GPIOPinTypeI2CSCL(I2C_PIN_BASE[i], I2C_SCL_PIN[i]);
   GPIOPinConfigure(I2C_SDA[i]);
   GPIOPinConfigure(I2C_SCL[i]);
   HWREG(I2C_PIN_BASE[i] + GPIO_O_PUR) = (I2C_SDA_PIN[i]|I2C_SCL_PIN[i]);

   I2CRxFIFOConfigSet(I2C_BASE[i], (I2C_FIFO_CFG_RX_MASTER_DMA | I2C_FIFO_CFG_RX_TRIG_8));
   I2CTxFIFOConfigSet(I2C_BASE[i], (I2C_FIFO_CFG_TX_MASTER_DMA));
   I2CRxFIFOFlush(I2C_BASE[i]);
   I2CTxFIFOFlush(I2C_BASE[i]);

   I2CMInit(&g_sI2CMInst[i], I2C_BASE[i], I2C_INT[i], 0xff, 0xff, g_ui32SysClock, 1); 
   I2CIntRegister(I2C_BASE[i], pISRHandler[i]);
  }
 }
 #if 0
 if(SLAVE_3_EN & u16MaskCH)
 {
  I2CRxFIFOConfigSet(I2C_BASE[3], I2C_FIFO_CFG_RX_MASTER);
  I2CTxFIFOConfigSet(I2C_BASE[3], I2C_FIFO_CFG_TX_MASTER);
 }
 if(SLAVE_4_EN & u16MaskCH)
 {
  I2CRxFIFOConfigSet(I2C_BASE[4], I2C_FIFO_CFG_RX_MASTER);
  I2CTxFIFOConfigSet(I2C_BASE[4], I2C_FIFO_CFG_TX_MASTER);
 }
 if(SLAVE_5_EN & u16MaskCH)
 {
  I2CRxFIFOConfigSet(I2C_BASE[5], I2C_FIFO_CFG_RX_MASTER);
  I2CTxFIFOConfigSet(I2C_BASE[5], I2C_FIFO_CFG_TX_MASTER);
 }
 if(SLAVE_7_EN & u16MaskCH)
 {
  I2CRxFIFOConfigSet(I2C_BASE[7], I2C_FIFO_CFG_RX_MASTER);
  I2CTxFIFOConfigSet(I2C_BASE[7], I2C_FIFO_CFG_TX_MASTER);
 }
 #else
 if(SLAVE_5_EN & u16MaskCH)
 {
  I2CRxFIFOConfigSet(I2C_BASE[5], I2C_FIFO_CFG_RX_MASTER);
  I2CTxFIFOConfigSet(I2C_BASE[5], I2C_FIFO_CFG_TX_MASTER);
 }
 #endif
}

void I2C_DMAInitialAll(uint16_t u16MaskCH)
{
 uint8_t i;
 SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
 SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
 IntEnable(INT_UDMAERR);
 uDMAEnable();
 uDMAControlBaseSet(pui8ControlTable);
 IntEnable(INT_UDMA);
 for (i=0; i<10; i++)
 {
  #if 0
  if(u16MaskCH & ( 1 << i ) && (i != 3)&&(i!=4)&&(i!=5)&&(i!=7))//if(u16MaskCH & ( 1 << i ) && (i != 5))
  #else
  if(u16MaskCH & ( 1 << i ) && (i != 5))
  #endif
  {
   uDMAChannelAssign(DMA_I2CTX[i]);
   uDMAChannelAttributeDisable(DMA_I2CTX[i],
     UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
   uDMAChannelControlSet(DMA_I2CTX[i] | UDMA_PRI_SELECT,
     UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);

   uDMAChannelAssign(DMA_I2CRX[i]);
   uDMAChannelAttributeDisable(DMA_I2CRX[i],
     UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK));
   uDMAChannelControlSet(DMA_I2CRX[i] | UDMA_PRI_SELECT,
     UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);
   //uDMAIntRegister
  }
 }
}

void I2C_DMAWriteAll(uint16_t u16MaskCH, uint8_t (*pu8TxBuffer)[200], uint16_t u16Len)
{
 uint8_t u8CH;
 uint16_t u16Free=0, u16Cnt=0;
 
// DMA setting ========================================================================
 for(u8CH=0; u8CH<10; u8CH++)
 {
  #if 0
  if(u16MaskCH & ( 1 << u8CH ) && (u8CH != 3)&&(u8CH!=4)&&(u8CH!=5)&&(u8CH!=7))
  #else
  if((u16MaskCH & (1<<u8CH)) && (u8CH != 5))
  #endif 
  {
   I2CMasterSlaveAddrSet(I2C_BASE[u8CH], I2C_SLAVE_ADDR, false);
   uDMAChannelTransferSet(DMA_I2CTX[u8CH] | UDMA_PRI_SELECT, UDMA_MODE_BASIC,
            pu8TxBuffer[u8CH], ((void *)(I2C_BASE[u8CH] + I2C_O_FIFODATA)), u16Len);
   uDMAChannelEnable(DMA_I2CTX[u8CH]);
   I2CMasterBurstLengthSet(I2C_BASE[u8CH], u16Len);  
  }
 }

// DMA star ========================================================================
 for(u8CH=0; u8CH<10; u8CH++)
 {
  #if 0
  if(u16MaskCH & ( 1 << u8CH ) && ((u8CH != 3)&&(u8CH!=4)&&(u8CH!=5)&&(u8CH!=7)))//
  #else
  if((u16MaskCH & (1<<u8CH)) && (u8CH != 5))
  #endif
   I2CMasterControl(I2C_BASE[u8CH], I2C_MASTER_CMD_FIFO_SINGLE_SEND);
 }
SysCtlDelay(1000);
// I2C5 start ========================================================================
 #if 0
 if((SLAVE_3_EN & u16MaskCH)|(SLAVE_4_EN & u16MaskCH)|(SLAVE_5_EN & u16MaskCH)|(SLAVE_7_EN & u16MaskCH))//if(SLAVE_5_EN & u16MaskCH)
 {
//  I2C_Write(I2C_SLAVE_ADDR, pu8TxBuffer[5], u16Len);
//  //I2C0_FIFO_Write(pu8TxBuffer[5], u16Len);
//  while(I2CMasterBusy(I2C_BASE[5]));
  if(SLAVE_3_EN & u16MaskCH)
  {
   I2C_Write(3,I2C_SLAVE_ADDR, pu8TxBuffer[3], u16Len);
  }
  if(SLAVE_4_EN & u16MaskCH)
  {
   I2C_Write(4,I2C_SLAVE_ADDR, pu8TxBuffer[4], u16Len);
  }
  if(SLAVE_5_EN & u16MaskCH)
  {
   I2C_Write(5,I2C_SLAVE_ADDR, pu8TxBuffer[5], u16Len);
  }
  if(SLAVE_7_EN & u16MaskCH)
  {
   I2C_Write(7,I2C_SLAVE_ADDR, pu8TxBuffer[7], u16Len);
  }
  
  if(SLAVE_3_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[3]));
  }
  if(SLAVE_4_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[4]));
  }
  if(SLAVE_5_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[5]));
  }
  if(SLAVE_7_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[7]));
  }
 }
 #else
 if(SLAVE_5_EN & u16MaskCH)
 {
  I2C_Write(5,I2C_SLAVE_ADDR, pu8TxBuffer[5], u16Len);   <-- *******Get stuck here in debug mode********
  //I2C0_FIFO_Write(pu8TxBuffer[5], u16Len);
  while(I2CMasterBusy(I2C_BASE[5]));
 }
 #endif
 
// Wait for bus free ========================================================================
 while(u16Cnt<5000)
 {
  SysCtlDelay(1000);
  u16Cnt++;
  for(u8CH=0; u8CH<10; u8CH++)
  {
   if((u16MaskCH & (1<<u8CH)) && (I2CMasterBusy(I2C_BASE[u8CH]) == false))
    u16Free |= (1 << u8CH);
   
  }
  if(u16MaskCH == u16Free)
   break;
 }
 if(u16Cnt == 5000)
  UARTprintf("\nWrite ERROR!!!");
}

void I2C_DMAReadAll(uint16_t u16MaskCH, uint8_t (*pu8RxBuffer)[200], uint16_t u16Len)
{
 uint8_t u8CH;
 uint16_t u16Free=0, u16Cnt=0;
 
// DMA setting ========================================================================
 for(u8CH=0; u8CH<10; u8CH++)
 {
  if(u16MaskCH & (1<<u8CH) && (u8CH != 5))
  {
   I2CMasterSlaveAddrSet(I2C_BASE[u8CH], I2C_SLAVE_ADDR, true);
   I2CMasterBurstLengthSet(I2C_BASE[u8CH], u16Len);
   uDMAChannelTransferSet(DMA_I2CRX[u8CH] | UDMA_PRI_SELECT, UDMA_MODE_BASIC,
      ((void *)(I2C_BASE[u8CH] + I2C_O_FIFODATA)), pu8RxBuffer[u8CH], u16Len);
   uDMAChannelEnable(DMA_I2CRX[u8CH]);
  }
 }

// DMA star ========================================================================
 for(u8CH=0; u8CH<10; u8CH++)
 {
  #if 0
  if(u16MaskCH & ( 1 << u8CH ) && ((u8CH != 3)&&(u8CH!=4)&&(u8CH!=5)&&(u8CH!=7)))
  #else
  if(u16MaskCH & (1<<u8CH) && (u8CH != 5))
  #endif
  I2CMasterControl(I2C_BASE[u8CH], I2C_MASTER_CMD_FIFO_SINGLE_RECEIVE);
 }

// I2C5 start ========================================================================
// if(SLAVE_5_EN & u16MaskCH)
// {
//  I2C_Read(I2C_SLAVE_ADDR, pu8RxBuffer[5], u16Len);
//  while(I2CMasterBusy(I2C_BASE[5]));
// }
 #if 0
 if((SLAVE_3_EN & u16MaskCH)|(SLAVE_4_EN & u16MaskCH)|(SLAVE_5_EN & u16MaskCH)|(SLAVE_7_EN & u16MaskCH))//if(SLAVE_5_EN & u16MaskCH)
 {
//  I2C_Write(I2C_SLAVE_ADDR, pu8TxBuffer[5], u16Len);
//  //I2C0_FIFO_Write(pu8TxBuffer[5], u16Len);
//  while(I2CMasterBusy(I2C_BASE[5]));
  if(SLAVE_3_EN & u16MaskCH)
  {
   I2C_Read(3,I2C_SLAVE_ADDR, pu8RxBuffer[3], u16Len);
  }
  if(SLAVE_4_EN & u16MaskCH)
  {
   I2C_Read(4,I2C_SLAVE_ADDR, pu8RxBuffer[4], u16Len);
  }
  if(SLAVE_5_EN & u16MaskCH)
  {
   I2C_Read(5,I2C_SLAVE_ADDR, pu8RxBuffer[5], u16Len);
  }
   if(SLAVE_7_EN & u16MaskCH)
  {
   I2C_Read(7,I2C_SLAVE_ADDR, pu8RxBuffer[7], u16Len);
  }
  
  if(SLAVE_3_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[3]));
  }
  if(SLAVE_4_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[4]));
  }
  if(SLAVE_5_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[5]));
  }
  if(SLAVE_7_EN & u16MaskCH)
  {
   while(I2CMasterBusy(I2C_BASE[7]));
  }
 }
 #else
 if(SLAVE_5_EN & u16MaskCH)
 {
  I2C_Read(5,I2C_SLAVE_ADDR, pu8RxBuffer[5], u16Len);
  //I2C0_FIFO_Write(pu8TxBuffer[5], u16Len);
  while(I2CMasterBusy(I2C_BASE[5]));
 }
 #endif
  
// Wait for bus free ========================================================================
 while(u16Cnt<5000)
 {
  SysCtlDelay(1000);
  u16Cnt++;
  for(u8CH=0; u8CH<10; u8CH++)
  {
   if((u16MaskCH & (1<<u8CH)) && (I2CMasterBusy(I2C_BASE[u8CH]) == false))
    u16Free |= (1 << u8CH);
   
  }
  if(u16MaskCH == u16Free)
   break;
 }
 if(u16Cnt == 5000)
  UARTprintf("\nRead ERROR!!!");
}

void Flash_Test(void)
{
  uint8_t u8i;
    uint8_t data[5];

    // Enter the Serial Debug Mode
    data[0] = 0x53;
    data[1] = 0x45;
    data[2] = 0x52;
    data[3] = 0x44;
    data[4] = 0x42;
 for(u8i=0;u8i<10;u8i++)
 {
  if(I2C_EN&(1<<u8i))
  {
   memcpy(&(gau8TxBuf[u8i][0]),data,sizeof(data));
  }
 }
 I2C_DMAWriteAll(I2C_EN, gau8TxBuf, 5);
    delay_1ms();
}

  • Hi,
    Many times when a hard fault occurs, it has something to do with the stack. Sometime it has something to do with accessing a peripheral that is not yet enabled via the SysCtlPeripheralEnable(). Since you say if in DMA mode then you are not getting the hard fault, this means it is not likely the fault is due to the peripheral not yet enabled. What do you read from the Bus Fault Status register (BFAULTSTAT) in the CPU? Please try to increase the stack size and see if that makes any difference. I will also suggest that you first try to limit the number of I2C and gradually increase one by one.

    Here is an app note that shows how to debug a hard fault issue. www.ti.com/.../spma043.pdf
  • Charles Tsai said:
    I will also suggest that you first try to limit the number of I2C and gradually increase one by one.

    Or - to state this in two words,   "employ KISS."

    I (also) note a, "hard-coded" DELAY w/in the code - the "Cascade of I2C calls" may "so build" that a test for "I2C Peripheral Ready" (instead of a delay) - proves far more robust!

  • Hi,

    I am QZboy's colleague.

    QZboy said, only fail when do config both i2c6 and i2c7 using i2c+udma.

    How to add a delay during transfer data via udma?

    I think that is only hardware operation, is it right?

  • Hi Will,

    So i2c6 and i2c7 without uDMA will work? What about only one I2C6 with uDMA, will it work? The uDMA is based on the trigger coming from the I2C module. Once it is triggered it will just start based on its priority with respect to other channels. If there are no higher priority pending operations from other channels, it will just start.

    Again, I will suggest you start from the basic. Start with one I2C first. Then move on to one I2C with uDMA. If this works, you will then continue to add another I2C and later with the uDMA. If you can get one I2C with uDMA to work then you basically have the correct configuration for the I2C and uDMA modules. It will be much easier to debug the problem this way.
  • Greetings,

    We note 3 occurrences of:   "SysCtlDelay(1000); "   w/in your program.     You must determine if this value delay (always) proves proper - and/or - if a "Peripheral Ready" call proves superior.

    Both the vendor (via many words) and I (via 2,  "Use KISS") suggested that your program code be reduced to just those parts which (for now) result in Faults.

    It is usual that, "Obtaining proper code operation" proves "faster & easier" when tasks are, "Reduced in Number."     Only when each task has achieved great success - should another task be (then) "Added to the Mix."      Your current method appears to, "Continue to attempt to "DO EVERYTHING" - which I have found to, "ADD UNNECESSARY COMPLICATIONS" - and make your "FIX" both "Harder and Longer to achieve!"

    Again - I'd focus on your "failing functions ALONE" - I suspect you will (greatly) benefit by learning:

    • When those (presently) failing functions WORK (if they ever work)
    • What conditions - prevent  - those functions from working?    (usually this requires your adding other functions - carefully & systematically - one at a time.)    And that IS  "KISS."

    I must note that, "Even upon reading your thread's Subject/Title ... "TEN Sets i2C" - the "Rejection of KISS was most apparent" - and your "problems" were (almost) GUARANTEED!     Simplify!

  • Sorry for the confusing title.
    I want to use 10 sets I2C to read/write 10 devices in the same time, but found some problems. pls refer below info.

    1. Enable each I2C periph One-by-One
    --> I2C3 and I2C4 can't use DMA, but it works in INTERRUPTmode.
    2. I2C5 & I2C8 is the same uDMA channel (refer to the Datasheet)
    --> I set I2C5 to "INTERRUPT" mode, and set I2C8 to DMA mode; It seems work now.
    3. I2C6/I2C7 works in INTERRUPT and DMA mode INDIVIDUALLY, but can't set both to DMA mode.
    --> I guess that is the same uDMA channel, and need your confirm.
  • Hi Charles,
    Please kindly refer to my reply (Feb 12, 2018 2:55 PM ), thanks.
  • QZboy said:
    I want to use 10 sets I2C to read/write 10 devices in the same time

    This (likely) is a, "language issue" - you don't (really) expect to "Read/Write 10  "I2C devices" (simultaneously) - do you?      (such is what your writing suggests...And quite impossible!)

    Vendor agents are most talented at, "Digging thru the datasheet" - should you seek a more "General Problem Solving Method" - I'll try to assist.

  • We really need to use ten sets of i2c transfer at same time.
    Is anyone can guide us to implement it? or it is not possible to do it?
  • QZboy said:
    --> I2C3 and I2C4 can't use DMA, but it works in INTERRUPTmode.

    I2C3 and I2C4 use different DMA channels according to the datasheet. Did it work for you if you only use I2C3 with uDMA or I2C4 with uDMA but not both of them together?

    QZboy said:
    2. I2C5 & I2C8 is the same uDMA channel (refer to the Datasheet)
    --> I set I2C5 to "INTERRUPT" mode, and set I2C8 to DMA mode; It seems work now.

    You are correct that I2C5 and I2C8 share the same channels so you can use DMA on both of them at the same time. 

    QZboy said:
    3. I2C6/I2C7 works in INTERRUPT and DMA mode INDIVIDUALLY, but can't set both to DMA mode.
    --> I guess that is the same uDMA channel, and need your confirm.

    According to the datasheet, the I2C6 uses channel 26/27 while the I2C7 uses channel 28/29. 

  • Will Wu said:
    We really need to use ten sets of i2c transfer at same time.

    As noted previously - much depends upon your definition of,  "at same time."      (it is assumed that you intend,  "simultaneously.")

    While the use of the "MCU's  µDMA"  may (somewhat) automate the I2C transfer process - it is doubted that,  "All ten I2C channels" can,  "Operate w/out compromise" - at the standard I2C data rate.    (commentary by Vendor Agents would prove (greatly) helpful - and is much invited -  in this "Ten I2C channel, simultaneous operation's" regard!)

    At some point - it is expected - that the MCU must  "Deal w/the µDMA managed data" - and in that process - (any) simultaneous operation exceeds my  recognition/understanding...

  • Hi Will,
    I think you meant to have 10 I2Cs activated in your application. I believe that you know the CPU can only write or read to a I2C module one at a time. Even though the DMA module can support up to 32 channels, at any one time only one channel is activated for transfers while the rest are just pending waiting for their turns.
  • Hi Charles,

    Thank you for so well noting that, "One and ONLY One - I2C Peripheral Module - may "transact" at any given time!"     Poster has "Rejected or Over-Looked" that reality - my writings attempted to alert poster - hearing from you (the Vendor) ... (may) now bring about his "acceptance!"     Maybe...