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 Setup Question for the TM4C1294NCPDT

Other Parts Discussed in Thread: TM4C1294NCPDT

When setting the I2C Bus 0 in loop back mode and using the DMA to transfer and receive data out messages across the I2C bus I never seeing the DMA shifting data into the FIFO.

To start the program I am initializing the DMA by:

ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
ROM_IntEnable(INT_UDMAERR);
ROM_uDMAEnable();
ROM_uDMAControlBaseSet(pui8ControlTable);
ROM_IntEnable(INT_UDMA);

ROM_uDMAChannelAssign(UDMA_CH1_I2C0TX);
ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_USBEP1TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); //ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_USBEP1TX, UDMA_ATTR_USEBURST); ROM_uDMAChannelControlSet(UDMA_CHANNEL_I2S0TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4); ROM_uDMAChannelAssign(UDMA_CH0_I2C0RX); ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_USBEP1RX, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)); ROM_uDMAChannelControlSet(UDMA_CHANNEL_USBEP1RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); ROM_uDMAChannelControlSet(UDMA_CHANNEL_USBEP1RX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);

I then initialize the GPIO port for I2C and loop back mode by:

SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_I2C0);
SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
GPIOPinConfigure(GPIO_PB2_I2C0SCL);
GPIOPinConfigure(GPIO_PB3_I2C0SDA);
GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
IntEnable(INT_I2C0);
HWREG(I2C0_BASE + I2C_O_MCR) |= 0x01;
I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
I2CSlaveEnable(I2C0_BASE);
I2CSlaveInit(I2C0_BASE, ADDRESS);
I2CRxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_RX_SLAVE_DMA | I2C_FIFO_CFG_RX_TRIG_8));
I2CMasterSlaveAddrSet(I2C0_BASE, ADDRESS, false);
I2CMasterIntEnable(I2C0_BASE);
I2CMasterTimeoutSet(I2C0_BASE, 0x7D);  // 20 ms Timeout
I2CTxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_TX_MASTER_DMA | I2C_FIFO_CFG_TX_TRIG_1));
IntMasterEnable();

Then I setup and enable the RX DMA for Ping Pong Mode:

ROM_uDMAChannelTransferSet(UDMA_CHANNEL_USBEP1RX | UDMA_PRI_SELECT,
			   UDMA_MODE_PINGPONG,
			   ((void *)(I2C0_BASE + I2C_O_FIFODATA)), g_ui8RxBuf,
			   1023);
ROM_uDMAChannelTransferSet(UDMA_CHANNEL_USBEP1RX | UDMA_ALT_SELECT,
			   UDMA_MODE_PINGPONG,
			   ((void *)(I2C0_BASE + I2C_O_FIFODATA)), g_ui8RxBufB,
			   1023);
ROM_uDMAChannelEnable(UDMA_CHANNEL_USBEP1RX);

I then add data to my transmit buffer used for DMA and setup and run the I2C in Bust Transmit mode:

ROM_uDMAChannelTransferSet(UDMA_CHANNEL_USBEP1TX | UDMA_PRI_SELECT,
			   UDMA_MODE_BASIC,
			   g_ui8TxBuf, ((void *)(I2C0_BASE + I2C_O_FIFODATA)),
			   (dataToSend - 1));
ROM_uDMAChannelEnable(UDMA_CHANNEL_USBEP1TX);
I2CMasterBurstLengthSet(I2C0_BASE, dataToSend);
I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_START);

After starting the Data being transmitted the Timeout is always reached with nothing in either one of the RX buffers.  Is something missing in the setup before data transfers start?

  • Christopher Tisdale said:
    ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_USBEP1TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); //ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_USBEP1TX, UDMA_ATTR_USEBURST); ROM_uDMAChannelControlSet(UDMA_CHANNEL_I2S0TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);

    Do check your uDMA channel names throughout the code. Use the UDMA_CHn_xxxx macros you can find in udma.h, with the proper I2C suffix - just to remain sane.

    Also, I suggest skipping the loopback mode and using a real I2C slave - that way you can use a logic analyzer to snoop on the signal. It really helps to be able to actually see what the hardware is really doing, instead of trying to guessmulate the operation in your head not knowing whether it's your logic, your code or the hardware that's at fault.

  • So after removing the loop back operation and connecting an external Loop Back (Loop I2C0 to I2C7). All data but the last one is sent to the slave. Once the I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH); a perpetual interrupt loop is entered.



    Here is the updated Code:

    Initializing the DMA:

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    ROM_IntEnable(INT_UDMAERR);
    ROM_uDMAEnable();
    ROM_uDMAControlBaseSet(pui8ControlTable);
    ROM_IntEnable(INT_UDMA);
    ROM_uDMAChannelAssign(UDMA_CH1_I2C0TX);
    ROM_uDMAChannelAttributeDisable(UDMA_CH1_I2C0TX,
    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    //ROM_uDMAChannelAttributeEnable(UDMA_CH1_I2C0TX, UDMA_ATTR_USEBURST);
    ROM_uDMAChannelControlSet(UDMA_CH1_I2C0TX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_8 |
    UDMA_DST_INC_NONE |
    UDMA_ARB_4);


    ROM_uDMAChannelAssign(UDMA_CH0_I2C0RX);
    ROM_uDMAChannelAttributeDisable(UDMA_CH0_I2C0RX,
    UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
    (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK));
    ROM_uDMAChannelControlSet(UDMA_CH0_I2C0RX | UDMA_PRI_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);
    ROM_uDMAChannelControlSet(UDMA_CH0_I2C0RX | UDMA_ALT_SELECT,
    UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);


    Initializing the I2C Ports:

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_I2C0);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);

    SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C7);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_I2C7);
    SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);

    GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    GPIOPinConfigure(GPIO_PD0_I2C7SCL);
    GPIOPinConfigure(GPIO_PD1_I2C7SDA);

    GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);

    IntEnable(INT_I2C0);
    I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
    I2CRxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_RX_MASTER_DMA | I2C_FIFO_CFG_RX_TRIG_8));
    I2CMasterSlaveAddrSet(I2C0_BASE, ADDRESS, false);
    I2CMasterIntEnable(I2C0_BASE);
    I2CTxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_TX_MASTER_DMA));
    I2CMasterIntEnableEx(I2C0_BASE, I2C_MASTER_INT_TX_DMA_DONE | I2C_MASTER_INT_RX_DMA_DONE | I2C_MASTER_INT_DATA | I2C_MASTER_INT_TX_FIFO_REQ | I2C_MASTER_INT_RX_FIFO_REQ);
    I2CRxFIFOFlush(I2C0_BASE);
    I2CTxFIFOFlush(I2C0_BASE);

    IntEnable(INT_I2C7);
    I2CSlaveEnable(I2C7_BASE);
    I2CSlaveInit(I2C7_BASE, ADDRESS);
    I2CSlaveIntEnableEx(I2C7_BASE, I2C_SLAVE_INT_DATA);

    IntMasterEnable();


    Setting up the Receive DMA:

    ROM_uDMAChannelTransferSet(UDMA_CH0_I2C0RX | UDMA_PRI_SELECT,
    UDMA_MODE_PINGPONG,
    ((void *)(I2C0_BASE + I2C_O_FIFODATA)), g_ui8RxBuf,
    64);
    ROM_uDMAChannelTransferSet(UDMA_CH0_I2C0RX | UDMA_ALT_SELECT,
    UDMA_MODE_PINGPONG,
    ((void *)(I2C0_BASE + I2C_O_FIFODATA)), g_ui8RxBufB,
    64);

    ROM_uDMAChannelEnable(UDMA_CH0_I2C0RX);


    Sending Data:

    ROM_uDMAChannelTransferSet(UDMA_CH1_I2C0TX | UDMA_PRI_SELECT,
    UDMA_MODE_BASIC,
    g_ui8TxBuf, ((void *)(I2C0_BASE + I2C_O_FIFODATA)),
    (dataToSend - 1));
    ROM_uDMAChannelEnable(UDMA_CH1_I2C0TX);

    I2CMasterBurstLengthSet(I2C0_BASE, dataToSend);
    I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_START);


    After the transmit DMA is disabled and the I2C Bus is no longer busy the I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH); is called. When this happens it is expected that all data bytes sent are stored in the RX buffer of the I2C 7 buffer but instead only 1 - dataToSend is received and the processor is in a perpetual interrupt loop for I2C0 and the I2CBus is always busy with the busy value set to SDA line.
  • The issue with shifting data out the I2C port has been resolved.  The issue was that the ROM_uDMAChannelTransferSet takes the data size and not 1 less as ROM_uDMAChannelTransferSet will decrements the value before storing it into the register.  Another change was made to change I2C_MASTER_CMD_FIFO_BURST_SEND_START to I2C_MASTER_CMD_FIFO_SINGLE_SEND.  

    Here is the updated code:

    Initializing the DMA:

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    ROM_IntEnable(INT_UDMAERR);
    ROM_uDMAEnable();
    ROM_uDMAControlBaseSet(pui8ControlTable);
    ROM_IntEnable(INT_UDMA);
    
    ROM_uDMAChannelAssign(UDMA_CH1_I2C0TX);
    ROM_uDMAChannelAttributeDisable(UDMA_CH1_I2C0TX,
    								UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK);
    ROM_uDMAChannelControlSet(UDMA_CH1_I2C0TX | UDMA_PRI_SELECT,
    						  UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4);
    
    ROM_uDMAChannelAssign(UDMA_CH0_I2C0RX);
    ROM_uDMAChannelAttributeDisable(UDMA_CH0_I2C0RX,
    								UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT |
    								(UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK));
    ROM_uDMAChannelControlSet(UDMA_CH0_I2C0RX | UDMA_PRI_SELECT,
    						  UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);
    ROM_uDMAChannelControlSet(UDMA_CH0_I2C0RX | UDMA_ALT_SELECT,
    							  UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4);

    Initializing the I2C Ports:

    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C0);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_I2C0);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
    
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C7);
    ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_I2C7);
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
    
    ROM_GPIOPinConfigure(GPIO_PB2_I2C0SCL);
    ROM_GPIOPinConfigure(GPIO_PB3_I2C0SDA);
    
    ROM_GPIOPinConfigure(GPIO_PD0_I2C7SCL);
    ROM_GPIOPinConfigure(GPIO_PD1_I2C7SDA);
    
    ROM_GPIOPinTypeI2CSCL(GPIO_PORTB_BASE, GPIO_PIN_2);
    ROM_GPIOPinTypeI2C(GPIO_PORTB_BASE, GPIO_PIN_3);
    
    ROM_GPIOPinTypeI2CSCL(GPIO_PORTD_BASE, GPIO_PIN_0);
    ROM_GPIOPinTypeI2C(GPIO_PORTD_BASE, GPIO_PIN_1);
    
    ROM_IntEnable(INT_I2C0);
    ROM_I2CMasterInitExpClk(I2C0_BASE, SysCtlClockGet(), false);
    ROM_I2CMasterSlaveAddrSet(I2C0_BASE, ADDRESS, false);
    ROM_I2CMasterIntEnable(I2C0_BASE);
    ROM_I2CRxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_RX_MASTER_DMA | I2C_FIFO_CFG_RX_TRIG_8));
    ROM_I2CTxFIFOConfigSet(I2C0_BASE, (I2C_FIFO_CFG_TX_MASTER_DMA));
    ROM_I2CMasterIntEnableEx(I2C0_BASE, I2C_MASTER_INT_TX_DMA_DONE | I2C_MASTER_INT_RX_DMA_DONE | I2C_MASTER_INT_TX_FIFO_REQ | I2C_MASTER_INT_RX_FIFO_REQ);
    ROM_I2CRxFIFOFlush(I2C0_BASE);
    ROM_I2CTxFIFOFlush(I2C0_BASE);
    
    ROM_IntEnable(INT_I2C7);
    I2CSlaveEnable(I2C7_BASE);
    I2CSlaveInit(I2C7_BASE, ADDRESS);
    I2CSlaveAddressSet(I2C7_BASE, 1, GENERAL_CALL_ADDR);
    I2CSlaveIntEnableEx(I2C7_BASE, I2C_SLAVE_INT_DATA);
    
    ROM_IntMasterEnable();

    Setting up the Receive DMA:

    ROM_uDMAChannelTransferSet(UDMA_CH0_I2C0RX | UDMA_PRI_SELECT,
    						   UDMA_MODE_PINGPONG,
    						   ((void *)(I2C0_BASE + I2C_O_FIFODATA)), g_ui8RxBuf,
    						   sizeof(g_ui8RxBuf));
    ROM_uDMAChannelTransferSet(UDMA_CH0_I2C0RX | UDMA_ALT_SELECT,
    						   UDMA_MODE_PINGPONG,
    						   ((void *)(I2C0_BASE + I2C_O_FIFODATA)), g_ui8RxBufB,
    						   sizeof(g_ui8RxBufB));
    
    ROM_uDMAChannelEnable(UDMA_CH0_I2C0RX);

    Sending Data:

    ROM_uDMAChannelTransferSet(UDMA_CH1_I2C0TX | UDMA_PRI_SELECT,
    						   UDMA_MODE_BASIC,
    						   buffer, ((void *)(I2C0_BASE + I2C_O_FIFODATA)),
    						   dataSize);
    ROM_uDMAChannelEnable(UDMA_CH1_I2C0TX);
    
    ROM_I2CMasterBurstLengthSet(I2C0_BASE, dataSize);
    ROM_I2CMasterControl(I2C0_BASE, I2C_MASTER_CMD_FIFO_SINGLE_SEND);

  • Hi,

    Good that you figured out the problem. However I went through the code to understand how it works. I have one question.
    I understand that you are sending data using I2C FIFO while using Basic Mode.
    On the receiver part you are using ping pong mode. Isnt it necessary to have same mode on both side?
    For transmit purpose you are using only PRIMARY Control Structure and on receiver side you are using both PRIMARY and ALTERNATE control structure. why is so?

    Thanks
  • The Mode does not need to be the same for the RX and TX of the I2C. The Transmit side was chosen to be BASIC mode because it is know in this application that the data being transmitted out will be less than 1024 (The max amount the DMA can do at once) so the PRIMARY is only needed. The Receive side was chosen to be PING PONG mode which requires both the PRIMARY and ALTERNATE structures to be setup so data can be received when it exceeds 1024 transfers. The PING PONG mode will automatically switch to the ALTERNATE once the PRIMARY transfer amount has been achieved (There is very detailed information on PING PONG mode in the TM4C1294NCPDT datasheet).
  • Hi Christopher,

    Thanks a lot for explanation. I have once again read the datasheet and now its more clear with your explanation.