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.

TM4C129ENCPDT: TM4C129ENCPDT

Part Number: TM4C129ENCPDT

Tool/software:

Hello,

I've been reading up on using the EPI peripheral and notice that there are use cases that do and do not use uDMA. I would like to know what the recommended approach is from TI. For background, my design utilizes TI RTOS. There is a tcp task, which receives commands through a POE interface, the EPI provides an interface from the MCU to a Lattice FPGA. The FPGA controls the state of some high-power relays, and there are interlocks for safety and other control signals.

Presently, I plan to use the EPI by creating a bunch a struct pointers for the "peripherals" within the FPGA, and then pointing these to addresses within the EPI's memory space. For example, here's a breakdown of a temperature sensor that the FPGA periodically polls through a SPI-like interface:

// Classes/Structures

/*Temperature Sensor Peripheral data structures */

/* Register Definitions */
typedef struct
{
//lsb
uint8_t enable : 1; ///< when set, the peripheral is enabled
uint8_t softRst : 1; ///< when set, the peripheral is held in reset
uint8_t modeSelection : 3; ///< per datasheet, selects the operational mode
uint8_t tempDataFormat : 3; ///< per datasheet, selects the temperature data format
//msb
}TempCntrlReg0Type;
typedef union
{
TempCntrlReg0Type bits;
uint8_t byte;
}TempCntrlReg0UseType;

typedef struct
{
//lsb
uint8_t faultQueue : 2; ///< per datasheet, holds fault related data/settings
uint8_t ctPinPolarity : 1; ///< per datasheet, sets the polarity of the CT pin
uint8_t intPinPolarity : 1; ///< per datasheet, sets the polarity of the INT pin
uint8_t intCtMode : 1; ///< per datasheet, sets the mode
uint8_t shutDown : 1; ///< per datasheet, sets the sensor into shutdown mode
uint8_t unused : 1; ///< unused bit
uint8_t resolution : 1; ///< per datasheet, sets the resolution
//msb
}TempCntrlReg1Type;
typedef union
{
TempCntrlReg1Type bits;
uint8_t byte;
}TempCntrlReg1UseType;

typedef struct
{
//lsb
uint8_t unused : 4; ///< unused bits
uint8_t tLow : 1; ///< per datasheet, enables the low temp. threshold
uint8_t tHigh : 1; ///< per datasheet, enables the high temp. threshold
uint8_t tCrt : 1; ///< per datasheet, enables the critical temp. threshold
uint8_t nRdy : 1; ////< per datasheet, the nRdy state
//msb
}TempStatusRegType;
typedef union
{
TempStatusRegType bits;
uint8_t byte;
}TempStatusRegUseType;

typedef struct
{
//lsb
uint16_t tempValue0 : 8; ///< lsb byte of two-byte value
uint16_t tempValue1 : 8; ///< msb byte of two-byte value
//msb
}TempValueRegType;
typedef union
{
TempValueRegType bytes;
uint16_t full;
}TempValueRegUseType;

typedef struct
{
//lsb
uint16_t tempCritValue0 : 8; ///< lsb byte of two-byte value
uint16_t tempCritValue1 : 8; ///< msb byte of two-byte value
//msb
}TempCritValueRegType;
typedef union
{
TempCritValueRegType bytes;
uint16_t full;
}TempCritValueRegUseType;

typedef struct
{
//lsb
uint8_t tHyst : 4;
uint8_t unused : 4;
}TempHysteresisRegType;
typedef union
{
TempHysteresisRegType bits;
uint8_t byte;
}TempHysteresisRegUseType;

typedef struct
{
//lsb
uint16_t tempHighValue0 : 8; ///< lsb byte of two-byte value
uint16_t tempHighValue1 : 8; ///< msb byte of two-byte value
//msb
}TempHighValueRegType;
typedef union
{
TempHighValueRegType bytes;
uint16_t full;
}TempHighValueRegUseType;

typedef struct
{
//lsb
uint16_t tempLowValue0 : 8; ///< lsb byte of two-byte value
uint16_t tempLowValue1 : 8; ///< msb byte of two-byte value
//msb
}TempLowValueRegType;
typedef union
{
TempLowValueRegType bytes;
uint16_t full;
}TempLowValueRegUseType;

/* Temp Sensor Peripheral Register Defintion */

typedef struct
{
//lsb
TempCntrlReg0UseType tempCntrlReg0;
TempCntrlReg1UseType tempCntrlReg1;
TempStatusRegUseType tempStatusReg;
TempValueRegUseType tempValueReg;
TempCritValueRegUseType tempCritValueReg;
TempHysteresisRegUseType tempHysterValueReg;
TempHighValueRegUseType tempHighValueReg;
TempLowValueRegUseType tempLowValueReg;
//msb
}TempSensorType;

Now, my plan is instantiate a pointer of this type and set it equal to the EPI base address + an offset specific for this peripheral.

TempSensorType* tempSense = EPI_BASE + TEMP_SENSE_ADDR (<- this is pseduo code meant to convey a concept and not an implementation). 

When this is done, all I need to do is write or read from elements within this structure and resulting writes or reads will occur on the EPI. For example, if I wanted to enable this peripheral within the FPGA, my code would look like this:

tempSense->tempCntrlReg0.bits.enable = 1;

Equally true, if I wanted to read the value of the entire 8-bit register where the enable bit resides, it would like this this:

uint8_t cntrReg0Val = 0;

cntrlReg0Val = tempSense->tempCntrlReg0.byte;

There's going to be between 10 - 15 of these peripherals within the FPGA, and each of these will have structures (and structure pointers) used to write and read to specific address locations within the FPGA. 

My question is would using uDMA be beneficial? I am concerned that these transactions my take too much time and other tasks, like the tcp task, could become less responsive. 

And, if I do use uDMA would I have to use the EPI FIFO, or could memory-to-memory transfers be sufficient so that writing/reading to/from an element of a structure would result in a corresponding write/read to/from the EPI?

Thank you!

  • My question is would using uDMA be beneficial? I am concerned that these transactions my take too much time and other tasks, like the tcp task, could become less responsive. 

    Hi Noah,

      I think it depends on several factors if using uDMA is beneficial. Transactions to peripherals are normally singles instead of bursts. For example, writing to configure a control register or reading a peripheral data register. How often do you need to write to a register and read registers in order to process the data. Since these are normally done in a non-burst fashion and peripherals in your FPGA are not continuous, I don't feel there is much benefit using uDMA but you would need to try it out yourself. Let's say you have a peripheral A and a peripheral B in the FPGA that you want to read from. You may need to create two different RTOS tasks to read these peripherals. Each task may be configured at different interval to initiate a read and may have to pend until the data is read. I don't know how this will impact the rest of tasks. Unlike reading a peripheral register in side the MCU which is fast, reading a register from FPGA will be much slower. The time to pend a task will be longer and you would want to take this into account. 

    And, if I do use uDMA would I have to use the EPI FIFO, or could memory-to-memory transfers be sufficient so that writing/reading to/from an element of a structure would result in a corresponding write/read to/from the EPI?

     Yes, you can use a software initiated memory to memory transfer between internal memories and external memories.