/* * test_fifo_dma.c * * Created on: Jul 1, 2020 * Author: avi */ //***************************************************************************** // // ektm4c129_i2c_master_udma_fifo.c - I2C Master with UDMA and FIFO Data Transfer // // Copyright (c) 2013-2015 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.1.1.71 of the EK-TM4C1294XL Firmware Package. // //***************************************************************************** #include #include #include "inc/hw_types.h" #include "inc/hw_i2c.h" #include "inc/hw_ints.h" #include "inc/hw_memmap.h" #include "inc/hw_udma.h" #include "driverlib/gpio.h" #include "driverlib/i2c.h" #include "driverlib/interrupt.h" #include "driverlib/pin_map.h" #include "driverlib/sysctl.h" #include "driverlib/uart.h" #include "driverlib/udma.h" #include "utils/random.h" #include "utils/uartstdio.h" //***************************************************************************** // //! \addtogroup example_list //!

ektm4c129_i2c_master_udma_fifo (ektm4c129_i2c_master_udma_fifo)

//! //! A Simple I2C Master Code for Performing Data Transfer with UDMA and //! I2CFIFODATA register // //***************************************************************************** //***************************************************************************** // // Define for I2C Module // //***************************************************************************** uint8_t SLAVE_ADDRESS_EXT; #define NUM_OF_I2CBYTES 255 //***************************************************************************** // // Enumerated Data Types for Master State Machine // //***************************************************************************** enum I2C_MASTER_STATE { I2C_OP_IDLE = 0, I2C_OP_TXADDR, I2C_OP_FIFO, I2C_OP_TXDATA, I2C_OP_RXDATA, I2C_OP_STOP, I2C_ERR_STATE }; //***************************************************************************** // // Global variable for Delay Count // //***************************************************************************** volatile uint16_t g_ui16SlaveWordAddress; uint8_t g_ui8MasterTxData[NUM_OF_I2CBYTES]; uint8_t g_ui8MasterRxData[NUM_OF_I2CBYTES]; volatile uint8_t g_ui8MasterCurrState; volatile uint8_t g_ui8MasterPrevState; volatile bool g_bI2CDirection; volatile bool g_bI2CRepeatedStart; volatile uint8_t g_ui8MasterBytes = NUM_OF_I2CBYTES; volatile uint8_t g_ui8MasterBytesLength = NUM_OF_I2CBYTES; uint32_t ui32TxArbSize, ui32RxArbSize; //***************************************************************************** // // The control table used by the uDMA controller. This table must be aligned // to a 1024 byte boundary. // //***************************************************************************** #if defined(ewarm) #pragma data_alignment=1024 uint8_t pui8ControlTable[1024]; #elif defined(ccs) #pragma DATA_ALIGN(pui8ControlTable, 1024) uint8_t pui8ControlTable[1024]; #else uint8_t pui8ControlTable[1024] __attribute__ ((aligned(1024))); #endif //***************************************************************************** // // Interrupt Handler for I2C Master Interface // //***************************************************************************** void I2C3IntHandler(void) { uint32_t ui32I2CMasterInterruptStatus; // // Toggle PL4 High to Indicate Entry to ISR // ///GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_4, GPIO_PIN_4); // // Get the masked interrupt status and clear the flags // ui32I2CMasterInterruptStatus = I2CMasterIntStatusEx(I2C3_BASE, true); I2CMasterIntClearEx(I2C3_BASE, ui32I2CMasterInterruptStatus); // // 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; // // Write the upper bits of the page to the Slave // I2CMasterSlaveAddrSet(I2C3_BASE, SLAVE_ADDRESS_EXT, false); I2CMasterDataPut(I2C3_BASE, (g_ui16SlaveWordAddress >> 8)); I2CMasterControl(I2C3_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 // I2CMasterDataPut(I2C3_BASE, (g_ui16SlaveWordAddress >> 0)); I2CMasterControl(I2C3_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; I2CMasterControl(I2C3_BASE, I2C_MASTER_CMD_FIFO_BURST_SEND_FINISH); } else { g_ui8MasterCurrState = I2C_OP_RXDATA; I2CMasterSlaveAddrSet(I2C3_BASE, SLAVE_ADDRESS_EXT, true); I2CMasterControl(I2C3_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 // ///GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_4, 0x0); } //***************************************************************************** // // This function sets up UDMA Channel Control Structures for TX // //***************************************************************************** void ConfigureuDMATX(uint8_t ui8Length, uint32_t ui32ArbSize) { // // Put the attributes in a known state for the uDMA channel. // These should already be disabled by default. // uDMAChannelAttributeDisable(UDMA_CH19_I2C3TX, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)); // // Configure the control parameters for the I2C2 TX channel. The channel // will be used to transfer between memory buffer and I2CFIFODATA register // 8 bits at a time. Therefore the data size is 8 bits, and the address // increment is 8 bits for source. The destination increment is none. // The arbitration size will be set based on the TX FIFO Threshold, which // causes the uDMA controller to rearbitrate after N items are transferred. // This keeps this channel from hogging the uDMA controller once the transfer // is started and allows other channels cycles if they are higher priority. // uDMAChannelControlSet(UDMA_CH19_I2C3TX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | ui32ArbSize); // // Set up the transfer parameters for the hardware channel. This will // configure the transfer buffers and the transfer size. Basic mode // is used in this example // uDMAChannelTransferSet(UDMA_CH19_I2C3TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8MasterTxData, (void *)(I2C3_BASE + I2C_O_FIFODATA), ui8Length); // // The channel must be enabled. For hardware based transfers, a request // must be issued by the peripheral. After this, the uDMA memory transfer begins. // uDMAChannelEnable(UDMA_CH19_I2C3TX); } //***************************************************************************** // // This function sets up UDMA Channel Control Structures for RX // //***************************************************************************** void ConfigureuDMARX(uint8_t ui8Length, uint32_t ui32ArbSize) { // // Put the attributes in a known state for the uDMA software channel. // These should already be disabled by default. // uDMAChannelAttributeDisable(UDMA_CH18_I2C3RX, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)); // // Configure the control parameters for the I2C2 RX channel. The channel // will be used to transfer between I2CFIFODATA register and memory buffers, // 8 bits at a time. Therefore the data size is 8 bits, and the address // increment is 8 bits for destination. The source increment is none. // The arbitration size will be set based on the RX FIFO Threshold, which // causes the uDMA controller to rearbitrate after N items are transferred. // This keeps this channel from hogging the uDMA controller once the transfer // is started and allows other channels cycles if they are higher priority. // uDMAChannelControlSet(UDMA_CH18_I2C3RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | ui32ArbSize); // // Set up the transfer parameters for the hardware channel. This will // configure the transfer buffers and the transfer size. Basic mode // is used in this example // uDMAChannelTransferSet(UDMA_CH18_I2C3RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(I2C3_BASE + I2C_O_FIFODATA), g_ui8MasterRxData, ui8Length); // // The channel must be enabled. For hardware based transfers, a request // must be issued by the peripheral. After this, the uDMA memory transfer begins. // uDMAChannelEnable(UDMA_CH18_I2C3RX); } //***************************************************************************** // // This function sets up UART0 to be used for a console to display information // as the example is running. // //***************************************************************************** /* void InitConsole(void) { // // Enable GPIO port A which is used for UART0 pins. // TODO: change this to whichever GPIO port you are using. // SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // // Configure the pin muxing for UART0 functions on port A0 and A1. // This step is not necessary if your part does not support pin muxing. // TODO: change this to select the port/pin you are using. // GPIOPinConfigure(GPIO_PA0_U0RX); GPIOPinConfigure(GPIO_PA1_U0TX); // // Enable UART0 so that we can configure the clock. // SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); // // Use the internal 16MHz oscillator as the UART clock source. // UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC); // // Select the alternate (UART) function for these pins. // TODO: change this to select the port/pin you are using. // GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // // Initialize the UART for console I/O. // UARTStdioConfig(0, 115200, 16000000); } */ //***************************************************************************** // // Main Program to Configure and Use the I2C Master // //***************************************************************************** int InitI2C3_udma_fifo(void) { uint32_t ui32SysClock; uint8_t /*ui8Count, */ui8MasterBytesLength; // // // Set up the serial console to use for displaying messages. This is // just for this example program and is not needed for EPI operation. // ///InitConsole(); // // Display the setup on the console. // ///UARTprintf("\033[2J\033[H"); ///UARTprintf("\r\nExample Code for I2C Master with"); ///UARTprintf("\nUDMA and FIFO Data Transfer\n\n"); // // Stop the Clock, Reset and Enable UDMA Module // in Master Function // SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA); SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA); SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); // // Wait for the Peripheral to be ready for programming // while(!SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)); // // Enable the uDMA controller. // uDMAEnable(); // // Point at the control table to use for channel control structures. // uDMAControlBaseSet(pui8ControlTable); // // Assign the UDMA Channel for I2C2 RX and TX DMA Request // uDMAChannelAssign(UDMA_CH18_I2C3RX); uDMAChannelAssign(UDMA_CH19_I2C3TX); // // Enable GPIO for Configuring the I2C Interface Pins // SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOR); // // Wait for the Peripheral to be ready for programming // while(!SysCtlPeripheralReady(SYSCTL_PERIPH_GPIOR)); // // Configure Pins for I2C2 Master Interface // GPIOPinConfigure(GPIO_PR4_I2C3SCL); GPIOPinConfigure(GPIO_PR5_I2C3SDA); GPIOPinTypeI2C(GPIO_PORTR_BASE, GPIO_PIN_5); GPIOPinTypeI2CSCL(GPIO_PORTR_BASE, GPIO_PIN_4); // // Configure GPIO Pin PL4 for Interrupt Time Processing // ///GPIOPinTypeGPIOOutput(GPIO_PORTL_BASE, GPIO_PIN_4); ///GPIOPinWrite(GPIO_PORTL_BASE, GPIO_PIN_4, 0x0); // // Setup System Clock for 120MHz // ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_XTAL_25MHZ | SYSCTL_CFG_VCO_480), 120000000); // // Stop the Clock, Reset and Enable I2C Module // in Master Function // SysCtlPeripheralDisable(SYSCTL_PERIPH_I2C3); SysCtlPeripheralReset(SYSCTL_PERIPH_I2C3); SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C3); // // Wait for the Peripheral to be ready for programming // while(!SysCtlPeripheralReady(SYSCTL_PERIPH_I2C3)); // // Initialize and Configure the Master Module // I2CMasterInitExpClk(I2C3_BASE, ui32SysClock, true); // // Assign the Transmit and Receive FIFO to the Master // Transmit threshold of 2 means that when there are less // than or equal to 2 bytes in the TX FIFO then generate // an interrupt // Receive threshold of 6 means that when there are more // than or qual to 6 bytes in the RX FIFO then generate // an interrupt // I2CTxFIFOConfigSet(I2C3_BASE, I2C_FIFO_CFG_TX_MASTER_DMA | I2C_FIFO_CFG_TX_TRIG_2); I2CRxFIFOConfigSet(I2C3_BASE, I2C_FIFO_CFG_RX_MASTER_DMA | I2C_FIFO_CFG_RX_TRIG_3); // // Transmit uDMA Arbitrartion size is calculated as the // smaller mod 2 which can write to the TXFIFO without // overrun // TX TRIGGER ARB // I2C_FIFO_CFG_TX_NO_TRIG UDMA_ARB_8 // I2C_FIFO_CFG_TX_TRIG_1 UDMA_ARB_4 // I2C_FIFO_CFG_TX_TRIG_2 UDMA_ARB_4 // I2C_FIFO_CFG_TX_TRIG_3 UDMA_ARB_4 // I2C_FIFO_CFG_TX_TRIG_4 UDMA_ARB_4 // I2C_FIFO_CFG_TX_TRIG_5 UDMA_ARB_2 // I2C_FIFO_CFG_TX_TRIG_6 UDMA_ARB_2 // I2C_FIFO_CFG_TX_TRIG_7 UDMA_ARB_1 // ui32TxArbSize = UDMA_ARB_4; // // Receive uDMA Arbitrartion size is calculated as the // Trigger Level to read back data from RXFIFO without // an underrun // RX TRIGGER ARB // I2C_FIFO_CFG_RX_NO_TRIG INVALID // I2C_FIFO_CFG_RX_TRIG_1 UDMA_ARB_1 // I2C_FIFO_CFG_RX_TRIG_2 UDMA_ARB_2 // I2C_FIFO_CFG_RX_TRIG_3 UDMA_ARB_2 // I2C_FIFO_CFG_RX_TRIG_4 UDMA_ARB_4 // I2C_FIFO_CFG_RX_TRIG_5 UDMA_ARB_4 // I2C_FIFO_CFG_RX_TRIG_6 UDMA_ARB_4 // I2C_FIFO_CFG_RX_TRIG_7 UDMA_ARB_4 // ui32RxArbSize = UDMA_ARB_2; // // Flush any existing data in the FIFO // I2CTxFIFOFlush(I2C3_BASE); I2CRxFIFOFlush(I2C3_BASE); // // Enable Interrupts for Arbitration Lost, Stop, NAK, // Clock Low Timeout and Data. // I2CMasterIntEnableEx(I2C3_BASE, (I2C_MASTER_INT_ARB_LOST | I2C_MASTER_INT_STOP | I2C_MASTER_INT_NACK | I2C_MASTER_INT_TIMEOUT | I2C_MASTER_INT_DATA)); // // Enable the Interrupt in the NVIC from I2C Master // IntEnable(INT_I2C3); // // Enable the Glitch Filter. Writting a value 0 will // disable the glitch filter // I2C_MASTER_GLITCH_FILTER_DISABLED // I2C_MASTER_GLITCH_FILTER_1 // I2C_MASTER_GLITCH_FILTER_2 : Ideal Value when in HS Mode // for 120MHz clock // I2C_MASTER_GLITCH_FILTER_4 // I2C_MASTER_GLITCH_FILTER_8 : Ideal Value when in Std, // Fast, Fast+ for 120MHz clock // I2C_MASTER_GLITCH_FILTER_16 // I2C_MASTER_GLITCH_FILTER_32 // I2CMasterGlitchFilterConfigSet(I2C3_BASE, I2C_MASTER_GLITCH_FILTER_8); // // Initialize and Configure the Master Module State Machine // g_ui8MasterCurrState = I2C_OP_IDLE; return 0; } uint32_t I2C_Write_udmaFifo(uint32_t base, uint8_t addr, uint8_t *data, uint32_t len) { uint8_t ui8Count; //uint32_t ui32TxArbSize; SLAVE_ADDRESS_EXT = addr; uint8_t ui8MasterBytesLength; // // Check if the Bus is Busy or not // while(I2CMasterBusBusy(base)); // // Randomly Initialize the Transmit buffer and // set the receive buffer to 0xFF // for(ui8Count=0 ; ui8Count < len ; ui8Count++) { g_ui8MasterTxData[ui8Count] = data[ui8Count]; // // Change the Random Value for the next // iteration.. // ///RandomAddEntropy(RandomSeed()); // // Init the receive buffers with the value // 0xFF // ////g_ui8MasterRxData[ui8Count] = 0xFF; } // // When sending data to slave make sure // RX DMA DONE interrupt bit is masked and // TX DMA DONE interrupt bit is unmasked // I2CMasterIntEnableEx(base, I2C_MASTER_INT_TX_DMA_DONE); I2CMasterIntDisableEx(base, I2C_MASTER_INT_RX_DMA_DONE); // // Set the I2CMBLEN register and also initialize // the internal flag // ui8MasterBytesLength = 32; I2CMasterBurstLengthSet(base, ui8MasterBytesLength); // // Configure the uDMA Control Channel Structure for TX // ConfigureuDMATX(ui8MasterBytesLength, ui32TxArbSize); // // Set Transmit Flag and set the Page Address in // external slave to 0x0000 // g_bI2CDirection = false; g_ui16SlaveWordAddress = 0x0; g_ui8MasterBytes = 0; // // Print Message before sending data // ///UARTprintf("Transmit %d bytes to external Slave...\n\n",ui8MasterBytesLength); // // Trigger the Transfer using Software Interrupt // g_ui8MasterCurrState = I2C_OP_IDLE; IntTrigger(INT_I2C3); while(g_ui8MasterCurrState != I2C_OP_STOP); return 0; } uint32_t I2C_Read_udmaFifo(uint32_t base, uint8_t addr, uint8_t *data, uint32_t len) { uint8_t ui8Count; bool bError; //uint32_t ui32RxArbSize; uint8_t ui8MasterBytesLength; SLAVE_ADDRESS_EXT = addr; // // When receiving data from slave make sure // TX DMA DONE interrupt bit is masked and // RX DMA DONE interrupt bit is unmasked // I2CMasterIntEnableEx(base, I2C_MASTER_INT_RX_DMA_DONE); I2CMasterIntDisableEx(base, I2C_MASTER_INT_TX_DMA_DONE); // // Set the I2CMBLEN register and also initialize // the internal flag // ui8MasterBytesLength = 32; I2CMasterBurstLengthSet(base, ui8MasterBytesLength); // // Configure the uDMA Control Channel Structure for RX // ConfigureuDMARX(ui8MasterBytesLength,ui32RxArbSize); // // Set receive Flag and set the Page Address in // external slave to 0x0000 // g_bI2CDirection = true; g_bI2CRepeatedStart = true; g_ui16SlaveWordAddress = 0x0; g_ui8MasterBytes = 0; // // Print Message before receiving data // ///UARTprintf("Receiving %d bytes from external Slave...\n\n",ui8MasterBytesLength); // // Trigger the Transfer using Software Interrupt // g_ui8MasterCurrState = I2C_OP_IDLE; IntTrigger(INT_I2C3); while(g_ui8MasterCurrState != I2C_OP_STOP); // // Perform Data Integrity Check... // bError = false; for(ui8Count = 0 ; ui8Count < len ; ui8Count++) { data[ui8Count] = g_ui8MasterRxData[ui8Count]; } return 0; }