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.

TM4C129 EPI HB16 uDMA write not starting

Other Parts Discussed in Thread: TM4C129XNCZAD, TMS320C6472

Hi,

I'm having trouble getting the EPI uDMA write to function properly.

I have EPI write (no uDMA) working, EPI read (no uDMA) working and EPI uDMA read working.

From my tests it seems that the EPI uDMA is not even starting!

Please help.

Khaled.

//define the uDMA control table
#if defined(ewarm)
#pragma data_alignment=1024
unsigned char ucControlTable[1024];
#elif defined(ccs)
#pragma DATA_ALIGN(ucControlTable, 1024)
tDMAControlTable ucControlTable[1024];
#else
unsigned char ucControlTable[1024] __attribute__ ((aligned(1024)));
#endif

volatile uint16_t *g_pusEPIFPGA; // Pointer for EPI memory window.

uint32_t u32DataIn[100];
uint32_t u32DataOut[100];
uint32_t numSuccess;
uint32_t numFail;

/**********************************************************************
**********************************************************************/
int main(void) {

	uint16_t i;
	uint32_t status;
	uint16_t errorIndex;


	SystemInit();  					//system setup
	GPIO_Init();   					//setup GPIO
	uDMA_Init();   					//setup the uDMA
	EPI_Init(); 					//setup EPI HPI interface

	//test the access to the DSP/HPI interface
	numFail    = 0; 	numSuccess = 0;
	while(1) {
		//fill with dummy data
		for(i = 0; i < 100; i++) {
			u32DataIn[i]  = i;
			u32DataOut[i] = 0x0BAD0BAD;
		}

		EPI_HPI_write     ( u32DataIn, 100, (uint32_t *) HPI_MEM_DAC_TX_START);
		while((!EPIdone())) {		}	//wait until uDMA is done

		EPI_HPI_read      ((uint32_t *) HPI_MEM_DAC_TX_START, 100, u32DataOut);
		while((!EPIdone())) {		}	//wait until uDMA is done

		//compare
		for(i = 0, errorIndex = 0xFFFF; i < 100; i++) {
			if(u32DataIn[i] != u32DataOut[i]) numFail++;
			else                              numSuccess++;
		}//for all

//		status  = EPI_HPI_uDMA_write( u32DataIn, 100, (uint32_t *) HPI_MEM_DAC_TX_START);
//		while((!EPIdone())) {		}	//wait until uDMA is done

		status &= EPI_HPI_uDMA_read ((uint32_t *) HPI_MEM_DAC_TX_START, 100, u32DataOut);
//		SysCtlDelay(gSysCtlClock * 1e-3);
//		wait for uDMA interrupt
//		wait for uDMA to finish
		while((!EPIdone())) {		}	//wait until uDMA is done

		//compare
		for(i = 0, errorIndex = 0xFFFF; i < 100; i++) {
			if(u32DataIn[i] != u32DataOut[i]) numFail++;
			else                              numSuccess++;
		}//for all
	}//while(1)
}//main

/**********************************************************************
**********************************************************************/
void EPI_Init(void) {

	// Set pointer to EPI memory mapped window.
	g_pusEPIFPGA = (uint16_t *)0xC0000000;

	//reset the EPI interface
	EPIModeSet(			EPI0_BASE,
						EPI_MODE_DISABLE);

	// Set the EPI divider.
	EPIDividerSet(		EPI0_BASE,
						1);

	//enable the EPI interface, and use general purpose mode
	EPIModeSet(			EPI0_BASE,
						EPI_MODE_HB16);
    EPIConfigHB16Set(	EPI0_BASE,
//						EPI_HB16_USE_TXEMPTY          |		//Tx fifo empty enable
//						EPI_HB16_USE_RXFULL           |		//Rx fifo full enable
//						EPI_HB16_BURST_TRAFFIC        | 	//burst mode enabled
						EPI_HB16_IN_READY_EN          |  	//IRDY enabled
						EPI_HB16_IN_READY_EN_INVERTED |		//IRDY polarity inverted
						EPI_HB16_MODE_ADDEMUX         | 	//sets up data and address as separate
						EPI_HB16_CSCFG_ALE            |		//EPIS030 to operate as an address latch (ALE)
						EPI_HB16_ALE_HIGH             |		//sets the address latch active high
						EPI_HB16_WRWAIT_0             |		//sets write wait state to 2 EPI clocks.
						EPI_HB16_RDWAIT_0             , 	//sets read wait state to 2 EPI clocks.
						0xF0);								//FIFO mode	maximum number of clocks
	EPIConfigHB16TimingSet(EPI0_BASE,
						0			,						//specifies the chip select to configure[0-3]
						EPI_HB16_IN_READY_DELAY_1     |   	//sets the stall on input ready (EPIS032)
															//to start 1 EPI clock after signaled
						EPI_HB16_WRWAIT_MINUS_ENABLE  |		//enables a 1 EPI clock write wait state reduction
						EPI_HB16_RDWAIT_MINUS_ENABLE); 		//enables a 1 EPI clock read wait state reduction

	//setup the address mapping for low level driver
	EPIAddressMapSet(	EPI0_BASE,
						EPI_ADDR_PER_BASE_C   |
						EPI_ADDR_PER_SIZE_64KB);
	EPIFIFOConfig(		EPI0_BASE,
						EPI_FIFO_CONFIG_TX_1_4 |
						EPI_FIFO_CONFIG_RX_1_8);

	//configure the EPI Non blocking read
	EPINonBlockingReadConfigure(EPI0_BASE,
								0,
								EPI_NBCONFIG_SIZE_16,
								0);

	//-------------------------------------------------------------
	// Setup the EPI interrupt to service the NBRFIFO and the WFIFO
	// When the NBRFIFO is full, or the WFIFO is empty generate an
	// interrupt or trigger a uDMA transfer to service the buffer
	//-------------------------------------------------------------
	//clear the FIFO interrupt triggers
	EPIIntDisable(   EPI0_BASE, EPI_INT_RXREQ      |
								EPI_INT_TXREQ      |
								EPI_INT_ERR);
	EPIIntErrorClear(EPI0_BASE, EPI_INT_ERR_WTFULL |
								EPI_INT_ERR_RSTALL |
								EPI_INT_ERR_TIMEOUT);

	//setup the interrupt mask for the EPI.
	//Note: interrupt masking has no effect on uDMA, which
	//      operates off the raw source of the read/write
	//      interrupts
	//Note: we dont want to enable the EPI Rx and Tx interrupt,
	//      the EPI fifos will be serviced by the uDMA
    EPIIntEnable(	EPI0_BASE,
// 					EPI_INT_RXREQ       |
// 					EPI_INT_TXREQ       |
//					EPI_INT_DMA_TX_DONE |
//					EPI_INT_DMA_RX_DONE |
					EPI_INT_ERR);

	// Enable the EPI interrupt on the processor (NVIC).
	// Note: even if no EPI interrupt were enabled, the uDMA
	//       controller will generate an interrupt on the EPI
	//       interrupt signal when a uDMA transfer is complete.
	IntEnable(INT_EPI0);

	//-------------------------------------------------------------
	// Configure the uDMA for the EPI read and write
	//-------------------------------------------------------------
	// Put the attributes in a known state for the uDMA EPI channel.
	uDMAChannelAssign(UDMA_CH20_EPI0RX);
	uDMAChannelAssign(UDMA_CH21_EPI0TX);

	uDMAChannelAttributeDisable(UDMA_SEC_CHANNEL_EPI0RX, UDMA_ATTR_ALL);	//NBRFIFO
	uDMAChannelAttributeDisable(UDMA_SEC_CHANNEL_EPI0TX, UDMA_ATTR_ALL);	//WFIFO

	// Set the USEBURST attribute for the uDMA EPI RX/TX channel.
	// and allow the peripheral to generate software request for uDMA channel
	uDMAChannelSelectSecondary(	UDMA_DEF_TMR1A_SEC_EPI0RX |
								UDMA_DEF_TMR1B_SEC_EPI0TX);
	uDMAChannelAttributeEnable(	UDMA_SEC_CHANNEL_EPI0RX,	//NBRFIFO
								UDMA_ATTR_USEBURST       |	//single request is not supported
								UDMA_ATTR_HIGH_PRIORITY);	//needed for ADC transfers
	uDMAChannelAttributeEnable(	UDMA_SEC_CHANNEL_EPI0TX,	//WFIFO
								UDMA_ATTR_USEBURST);		//single request is not supported

	// Configure the control parameters for the EPI RX/TX.  The uDMA EPI RX/TX
	uDMAChannelControlSet(	UDMA_SEC_CHANNEL_EPI0RX,  //NBRFIFO
							UDMA_SIZE_16       |      //data size
							UDMA_SRC_INC_NONE  |      //no source address increment
							UDMA_DST_INC_16    |      //destination address increment
							UDMA_ARB_1);              //arbitration size
	uDMAChannelControlSet(	UDMA_SEC_CHANNEL_EPI0TX,  //WFIFO
							UDMA_SIZE_16       |      //data size
							UDMA_SRC_INC_16    |      //source address increment
							UDMA_DST_INC_NONE  |      //no destination address increment
							UDMA_ARB_1);              //arbitration size
	//-------------------------------------------------------------
	//setup the uDMA interrupts
	//we don't want the uDMA to generate an interrupt on conclusion
	//-------------------------------------------------------------
	IntDisable(INT_UDMA);
	IntDisable(INT_UDMAERR);
}
/**********************************************************************
**********************************************************************/
void EPI0_Handler(void) {

    uint32_t intStatus;
    intStatus = EPIIntStatus(EPI0_BASE, true);
	if(intStatus & EPI_INT_ERR) {
		if(EPIIntErrorStatus(EPI0_BASE)){
//			__breakpoint(0);
			EPIIntErrorClear(EPI0_BASE, intStatus);
		}
	}

	//if its the end of a Tx EPI/HPI uDMA transfer
	//	signal that the packet transfer is done
	if(uDMAChannelModeGet(UDMA_SEC_CHANNEL_EPI0TX) == UDMA_MODE_STOP) {
	}

	//if its the end of an Rx EPI/HPI uDMA transfer
	//	process the data
	if(uDMAChannelModeGet(UDMA_SEC_CHANNEL_EPI0RX) == UDMA_MODE_STOP) {
	}
}
#endif
/**********************************************************************
**********************************************************************/
void EPI_HPI_uDMA_write(uint32_t *src_p,
                            uint32_t  count,
                            uint32_t *dst_p) {

	// Set pointer to EPI memory mapped window.
	g_pusEPIFPGA = (uint16_t *)0xC0000000;

	//write the HPID with the data
//	EPIDMATxCount(			EPI0_BASE,
//							count * 2);
	uDMAChannelTransferSet(	UDMA_SEC_CHANNEL_EPI0TX,
							UDMA_MODE_BASIC,
							src_p,					//transfer payload
							(void *)g_pusEPIFPGA,	//to EPI WFIFO
							count * 2);				//convert from uint32 to uint16
	uDMAChannelEnable(		UDMA_SEC_CHANNEL_EPI0TX);
}
/**********************************************************************
**********************************************************************/
uint16_t EPI_HPI_uDMA_read(uint32_t *src_p,
                           uint32_t  count,
                           uint32_t *dst_p) {


    //read data from the HPID
    //configure the EPI interface to read into the NBRFIFO
    //configure the uDMA to service the NBRFIFO
    EPINonBlockingReadStart(EPI0_BASE,
							0,
							count * 2);
    uDMAChannelTransferSet(	UDMA_SEC_CHANNEL_EPI0RX,
							UDMA_MODE_BASIC,
							(void *)(EPI0_BASE + EPI_O_READFIFO0),//from EPI NBRFIFO
							dst_p,				//transfer payload
							count * 2);			//convert from uint32 to uint16
    uDMAChannelEnable(		UDMA_SEC_CHANNEL_EPI0RX);
}
/**********************************************************************
**********************************************************************/
void EPI_HPI_read(	uint32_t *src_p,
					uint32_t  count,
					uint32_t *dst_p) {

	uint32_t i;
	uint32_t word;				//HPI data

	// Set pointer to EPI memory mapped window.
	g_pusEPIFPGA = (uint16_t *)0xC0000000;

	//read the data
    for(i = 0; i < count; i++) {
		word  = ((uint32_t) *g_pusEPIFPGA);//read the HPID lower 16bits
		g_pusEPIFPGA++;
		word |= ((uint32_t) *g_pusEPIFPGA) << 16;
		g_pusEPIFPGA++;

		*dst_p = word;
		*dst_p++;
	}
}
/**********************************************************************
**********************************************************************/
void EPI_HPI_write( uint32_t *src_p,
                    uint32_t  count,
                    uint32_t *dst_p) {

    uint32_t i;
    uint32_t word;          //HPI data

	// Set pointer to EPI memory mapped window.
	g_pusEPIFPGA = (uint16_t *)0xC0000000;

	//write the data
	for(i = 0; i < count; i++) {
		word            = src_p[i];
		*g_pusEPIFPGA =  word & 0xFFFF;	//write the HPID lower 16bits
		 g_pusEPIFPGA++;
		*g_pusEPIFPGA = (word >> 16) & 0xFFFF;
		 g_pusEPIFPGA++;
	}
}
/**********************************************************************
**********************************************************************/
uint16_t EPIdone(void) {

	//check if there is a EPI RX uDMA transfer is in progress.
	if(UDMA_MODE_STOP != uDMAChannelModeGet(UDMA_SEC_CHANNEL_EPI0RX)) 	return FALSE;
	if(EPINonBlockingReadCount(EPI0_BASE, 0) != 0) 						return FALSE;

	//check if there is EPI TX uDMA transfer is in progress.
	if(UDMA_MODE_STOP != uDMAChannelModeGet(UDMA_SEC_CHANNEL_EPI0TX)) 	return FALSE;
	if(EPIWriteFIFOCountGet(EPI0_BASE) < 4) 							return FALSE;

	return TRUE;
}

/**********************************************************************
**********************************************************************/
void uDMA_Init(void) {
	uDMAControlBaseSet(ucControlTable);
	uDMAEnable();
    IntEnable(INT_UDMAERR);
}

/**********************************************************************
**********************************************************************/
void GPIO_Init(void) {

	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
	SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_EPI0);
	SysCtlPeripheralReset(SYSCTL_PERIPH_EPI0);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOA);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOB);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOC);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOD);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOE);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOE);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOF);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOG);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOH);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOJ);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOK);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOL);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOM);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPION);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPION);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOP);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOQ);

	//---------------------------------------------------------------
	//configure EPI pins
	//---------------------------------------------------------------
	GPIOPinConfigure(GPIO_PK5_EPI0S31); //EPI CLK
	GPIOPinConfigure(GPIO_PP3_EPI0S30); //EPI ALE/HAS
	GPIOPinConfigure(GPIO_PP2_EPI0S29); //EPI WR
	GPIOPinConfigure(GPIO_PB3_EPI0S28); //EPI RD
	GPIOPinConfigure(GPIO_PK4_EPI0S32); //EPI RDY
	GPIOPinConfigure(GPIO_PL0_EPI0S16); //EPI A0/HHWIL
	GPIOPinConfigure(GPIO_PH0_EPI0S0);  //EPI D0
	GPIOPinConfigure(GPIO_PH1_EPI0S1);  //EPI D1
	GPIOPinConfigure(GPIO_PH2_EPI0S2);  //EPI D2
	GPIOPinConfigure(GPIO_PH3_EPI0S3);  //EPI D3
	GPIOPinConfigure(GPIO_PC7_EPI0S4);  //EPI D4
	GPIOPinConfigure(GPIO_PC6_EPI0S5);  //EPI D5
	GPIOPinConfigure(GPIO_PC5_EPI0S6);  //EPI D6
	GPIOPinConfigure(GPIO_PC4_EPI0S7);  //EPI D7
	GPIOPinConfigure(GPIO_PA6_EPI0S8);  //EPI D8
	GPIOPinConfigure(GPIO_PA7_EPI0S9);  //EPI D9
	GPIOPinConfigure(GPIO_PG1_EPI0S10); //EPI D10
	GPIOPinConfigure(GPIO_PG0_EPI0S11); //EPI D11
	GPIOPinConfigure(GPIO_PM3_EPI0S12); //EPI D12
	GPIOPinConfigure(GPIO_PM2_EPI0S13); //EPI D13
	GPIOPinConfigure(GPIO_PM1_EPI0S14); //EPI D14
	GPIOPinConfigure(GPIO_PM0_EPI0S15); //EPI D15

	//---------------------------------------------------------------
	//for each function pin, select the type
	//---------------------------------------------------------------
	GPIOPinTypeEPI(GPIO_PORTH_BASE, GPIO_PIN_0 |	//EPI D0
									GPIO_PIN_1 |	//EPI D1
									GPIO_PIN_2 |	//EPI D2
									GPIO_PIN_3);	//EPI D3
	GPIOPinTypeEPI(GPIO_PORTC_BASE, GPIO_PIN_7 |	//EPI D4
									GPIO_PIN_6 |	//EPI D5
									GPIO_PIN_5 |	//EPI D6
									GPIO_PIN_4);	//EPI D7
	GPIOPinTypeEPI(GPIO_PORTA_BASE, GPIO_PIN_6 |	//EPI D8
									GPIO_PIN_7);	//EPI D9
	GPIOPinTypeEPI(GPIO_PORTG_BASE, GPIO_PIN_1 |	//EPI D10
									GPIO_PIN_0);	//EPI D11
	GPIOPinTypeEPI(GPIO_PORTM_BASE, GPIO_PIN_3 |	//EPI D12
									GPIO_PIN_2 |	//EPI D13
									GPIO_PIN_1 |	//EPI D14
									GPIO_PIN_0);	//EPI D15
	GPIOPinTypeEPI(GPIO_PORTB_BASE, GPIO_PIN_3);	//EPI RD
	GPIOPinTypeEPI(GPIO_PORTP_BASE, GPIO_PIN_2 |	//EPI WR
									GPIO_PIN_3);	//EPI ALE
	GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_4);	//EPI IRDY
	GPIOPinTypeEPI(GPIO_PORTK_BASE, GPIO_PIN_5);	//EPI CLOCK
	GPIOPinTypeEPI(GPIO_PORTL_BASE, GPIO_PIN_0);	//EPI A0/HHWIL
}

/**********************************************************************
**********************************************************************/
void SystemInit (void) {
	SysCtlMOSCConfigSet(SYSCTL_MOSC_HIGHFREQ);
	SysCtlDelay(5242880);

	gSysCtlClock = SysCtlClockFreqSet(
						SYSCTL_USE_PLL    |
						SYSCTL_OSC_MAIN   |
						SYSCTL_XTAL_25MHZ |
						SYSCTL_CFG_VCO_480,
						120000000);		//desired system frequency
}

  • Hi Saab,

    How do you trigger the DMA transfer, HW interrupts or SW? If you use SW trigger, you need to issue a transfer request by setting bit 30 of the DMA channel SW request register (DMASWREG).

    Regards,
    QJ
  • Hi,
    I will give it a try, but I think its something else since my EPI uDMA read works without setting this bit! unless...
    Khaled.
  • Hi QJ,
    Did the change and it worked :-)

    But what is the relation? I checked the documentation and DMASWREG /bit 30 should be set to initiate a memory-to-memory transfer and not a peripheral transfer:
    "This function could be used for performing a memory-to-memory transfer, or if for some reason a transfer needs to be initiated by software instead of the peripheral associated with that channel."

    So what it worked? and is it documented anywhere?
    Khaled.
  • Hi QJ,

    I was too hasty in my test: Its still not working.

    It should be something simple since the EPI uDMA read IS WORKING, and both EPI uDMA read and EPI uDMA write have very similar code.

    Khaled.

  • Hi All,
    I'm running out of options: I tried every single code combination that I can think of and I checked over a two dozen posts regarding the EPI interface and the uDMA interface. I need some help, and I need it soon.
    thanks.
    Khaled.
  • Hello Khaled,

    I checked the code. The issue is that the EPINonBlockingReadConfigure is not using the correct address. The address that must be used to read the data from the external device/memory should be in the same address map as configured using EPIAddressMapSet. As an example

    EPIAddressMapSet(EPI0_BASE, EPI_ADDR_RAM_SIZE_64KB | EPI_ADDR_PER_BASE_C);

    is used then then

    EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_16, 0xC0000000);

    Must be used instead of

    EPINonBlockingReadConfigure(EPI0_BASE, 0, EPI_NBCONFIG_SIZE_16, 0);

    Regards
    Amit
  • Hi Amit

    thanks for you reply, but the uDMA read is working just fine, its the uDMA write that I have trouble with.

    If I use non uDMA read or non uDMA write function, all is OK: I can write data and read it back.

    If I use the uDMA read all seems to be OK as well: I can use the non uDMA write followed by the uDMA read and its working.

    Khaled.

  • Hello Khaled

    In the code given the API call EPIDMATxCount is commented out. Also the Interrupt for DMA Done for TX is also commented. How would the CPU know that the DMA has completed transfer?

    Regards
    Amit
  • Hi Amit,

    I was testing with different configurations to see which one works. Tried both EPIDAMTxCount commented out and not commented and neither worked.

    As for the DMA Done, I did not get that far. I'm still trying to get the data across to the destination devise. One I have that part working, I can worry about uDMA done.

    Khaled.

  • Hello Khaled

    Since I do not have a similar setup, I would require the following information

    1. The EPI register dump for all EPI registers
    2. The uDMA register dump for all DMA registers
    3. The uDMA primary control table in SRAM for the values programmed in the channel control structures, when the write does not occur

    Regards
    Amit
  • Hi Amit

    Here are the 3 information captured just before calling uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0TX) that should write the data.

    I'm attaching the same information captured just before calling uDMAChannelEnable(UDMA_SEC_CHANNEL_EPI0RX) that should read the data.

  • Hello Khaled

    The data sheet specs the following
    "A μDMA request is asserted by the EPI WRFIFO when the TXCNT value of the EPIDMATXCNT register is greater than zero and the WTAV bit field of the EPIWFIFOCNT register is less than the programmed threshold trigger, WRFIFO, of the EPIFIFOLVL register"

    In the configuration above the WTAV is more than WRFIFO.

    I am trying to setup a TX transfer with SDRAM and uDMA to see if that indeed is the cause...

    Regards
    Amit
  • Ok, but what caused the WTAV register to have a larger value than WRFIFO? how much larger are we talking about? is a single word larger or multiples?
    thanks.
    Khaled.
  • Hello Khaled

    I tried a SDRAM data transfer using the DMA and Write Request from the EPI and it works as expected. Attached is the reference code. The code is for a DK-TM4C129X (TM4C129XNCZAD) coupled with a SDRAM Board

    //*****************************************************************************
    //
    // sdram.c - Example demonstrating how to configure the EPI bus in SDRAM
    //           mode.
    //
    // Copyright (c) 2014 Texas Instruments Incorporated.  All rights reserved.
    // Software License Agreement
    //
    //   Redistribution and use in source and binary forms, with or without
    //   modification, are permitted provided that the following conditions
    //   are met:
    //
    //   Redistributions of source code must retain the above copyright
    //   notice, this list of conditions and the following disclaimer.
    //
    //   Redistributions in binary form must reproduce the above copyright
    //   notice, this list of conditions and the following disclaimer in the
    //   documentation and/or other materials provided with the
    //   distribution.
    //
    //   Neither the name of Texas Instruments Incorporated nor the names of
    //   its contributors may be used to endorse or promote products derived
    //   from this software without specific prior written permission.
    //
    // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    //
    // This is part of revision 2.1.0.12573 of the Tiva Firmware Development Package.
    //
    //*****************************************************************************
    
    #include <stdbool.h>
    #include <stdint.h>
    #include "inc/hw_epi.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_gpio.h"
    #include "driverlib/epi.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "utils/uartstdio.h"
    
    //*****************************************************************************
    //
    //! \addtogroup epi_examples_list
    //! <h1>EPI SDRAM Mode (sdram)</h1>
    //!
    //! This example shows how to configure the TM4C129 EPI bus in SDRAM mode.  It
    //! assumes that a 64Mbit SDRAM is attached to EPI0.
    //!
    //! For the EPI SDRAM mode, the pinout is as follows:
    //!     Address11:0 - EPI0S11:0
    //!     Bank1:0     - EPI0S14:13
    //!     Data15:0    - EPI0S15:0
    //!     DQML        - EPI0S16
    //!     DQMH        - EPI0S17
    //!     /CAS        - EPI0S18
    //!     /RAS        - EPI0S19
    //!     /WE         - EPI0S28
    //!     /CS         - EPI0S29
    //!     SDCKE       - EPI0S30
    //!     SDCLK       - EPI0S31
    //!
    //! This example uses the following peripherals and I/O signals.  You must
    //! review these and change as needed for your own board:
    //! - EPI0 peripheral
    //! - GPIO Port A peripheral (for EPI0 pins)
    //! - GPIO Port B peripheral (for EPI0 pins)
    //! - GPIO Port C peripheral (for EPI0 pins)
    //! - GPIO Port G peripheral (for EPI0 pins)
    //! - GPIO Port H peripheral (for EPI0 pins)
    //! - GPIO Port K peripheral (for EPI0 pins)
    //! - GPIO Port L peripheral (for EPI0 pins)
    //! - GPIO Port M peripheral (for EPI0 pins)
    //! - GPIO Port P peripheral (for EPI0 pins)
    //! - EPI0S0  - PH0
    //! - EPI0S1  - PH1
    //! - EPI0S2  - PH2
    //! - EPI0S3  - PH3
    //! - EPI0S4  - PC7
    //! - EPI0S5  - PC6
    //! - EPI0S6  - PC5
    //! - EPI0S7  - PC4
    //! - EPI0S8  - PA6
    //! - EPI0S9  - PA7
    //! - EPI0S10 - PG1
    //! - EPI0S11 - PG0
    //! - EPI0S12 - PM3
    //! - EPI0S13 - PM2
    //! - EPI0S14 - PM1
    //! - EPI0S15 - PM0
    //! - EPI0S16 - PL0
    //! - EPI0S17 - PL1
    //! - EPI0S18 - PL2
    //! - EPI0S19 - PL3
    //! - EPI0S28 - PB3
    //! - EPI0S29 - PP2
    //! - EPI0S30 - PP3
    //! - EPI0S31 - PK5
    //!
    //! The following UART signals are configured only for displaying console
    //! messages for this example.  These are not required for operation of EPI0.
    //! - UART0 peripheral
    //! - GPIO Port A peripheral (for UART0 pins)
    //! - UART0RX - PA0
    //! - UART0TX - PA1
    //!
    //! This example uses the following interrupt handlers.  To use this example
    //! in your own application you must add these interrupt handlers to your
    //! vector table.
    //! - None.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // Use the following to specify the GPIO pins used by the SDRAM EPI bus.
    //
    //*****************************************************************************
    #define EPI_PORTA_PINS (GPIO_PIN_7 | GPIO_PIN_6)
    #define EPI_PORTB_PINS (GPIO_PIN_3)
    #define EPI_PORTC_PINS (GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4)
    #define EPI_PORTG_PINS (GPIO_PIN_1 | GPIO_PIN_0)
    #define EPI_PORTH_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
    #define EPI_PORTK_PINS (GPIO_PIN_5)
    #define EPI_PORTL_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
    #define EPI_PORTM_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0)
    #define EPI_PORTP_PINS (GPIO_PIN_3 | GPIO_PIN_2)
    
    //*****************************************************************************
    //
    // The starting and ending address for the 64MB SDRAM chip (32Meg x 16bits) on
    // the SDRAM daughter board.
    //
    //*****************************************************************************
    #define SDRAM_START_ADDRESS 0x00000000
    #define SDRAM_END_ADDRESS   0x01FFFFFF
    #define NO_OF_RAM_LOC		256
    
    //*****************************************************************************
    //
    // The Mapping address space for the EPI SDRAM.
    //
    //*****************************************************************************
    #define SDRAM_MAPPING_ADDRESS 0xA0000000
    
    //*****************************************************************************
    //
    // The Max Count value for the SysTick Timer.
    //
    //*****************************************************************************
    #define SYSTICK_MAX_COUNT	16777216
    
    //*****************************************************************************
    //
    // A pointer to the EPI memory aperture.  Note that g_pui16EPISdram is declared
    // as volatile so the compiler should not optimize reads out of the image.
    //
    //*****************************************************************************
    static volatile uint16_t *g_pui16EPISdram;
    
    volatile uint32_t g_ui32InternalRamArray[NO_OF_RAM_LOC];
    
    //*****************************************************************************
    //
    // The DMA control structure table.
    //
    //*****************************************************************************
    #ifdef ewarm
    #pragma data_alignment=1024
    tDMAControlTable psDMAControlTable[64];
    #elif defined(ccs)
    #pragma DATA_ALIGN(psDMAControlTable, 1024)
    tDMAControlTable psDMAControlTable[64];
    #else
    tDMAControlTable psDMAControlTable[64] __attribute__ ((aligned(1024)));
    #endif
    //*****************************************************************************
    //
    // A table used to determine the EPI clock frequency band in use.
    //
    //*****************************************************************************
    typedef struct
    {
        uint32_t ui32SysClock;
        uint32_t ui32FreqFlag;
    }
    tSDRAMFreqMapping;
    
    static tSDRAMFreqMapping g_psSDRAMFreq[] =
    {
        //
        // SysClock >= 100MHz, EPI clock >= 50Mhz (divided by 2)
        //
        {100000000, EPI_SDRAM_CORE_FREQ_50_100},
    
        //
        // SysClock >= 60MHz, EPI clock >= 30MHz (divided by 2)
        //
        {60000000, EPI_SDRAM_CORE_FREQ_50_100},
    
        //
        // SysClock >= 50MHz, EPI clock >= 50MHz (no divider)
        //
        {50000000, EPI_SDRAM_CORE_FREQ_50_100},
    
        //
        // SysClock >= 30MHz, EPI clock >= 30MHz (no divider)
        //
        {50000000, EPI_SDRAM_CORE_FREQ_30_50},
    
        //
        // SysClock >= 15MHz, EPI clock >= 15MHz (no divider)
        //
        {15000000, EPI_SDRAM_CORE_FREQ_15_30},
    
        //
        // SysClock < 15Mhz, EPI clock < 15Mhz (no divider)
        //
        {0, EPI_SDRAM_CORE_FREQ_0_15}
     };
    
    #define NUM_SDRAM_FREQ (sizeof(g_psSDRAMFreq) / sizeof(tSDRAMFreqMapping))
    
    //*****************************************************************************
    //
    // 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);
    }
    
    //*****************************************************************************
    //
    // Configure EPI0 in SDRAM mode.  The EPI memory space is setup using an a
    // simple C array.  This example shows how to read and write to an SDRAM card
    // using the EPI bus in SDRAM mode.
    //
    //*****************************************************************************
    int
    main(void)
    {
        uint32_t ui32Val, ui32Freq, ui32SysClock;
        uint32_t ui32Index;
    
        //
        // Set the clocking to run at 120MHz from the PLL.
        // TODO: Update this call to set the system clock frequency your
        // application requires.
        //
        ui32SysClock = SysCtlClockFreqSet((SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_XTAL_25MHZ |
                                          SYSCTL_CFG_VCO_480), 120000000);
    
        //
        // 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("EPI SDRAM Mode ->\n");
        UARTprintf("  Type: SDRAM\n");
        UARTprintf("  Starting Address: 0x%08x\n", SDRAM_MAPPING_ADDRESS);
        UARTprintf("  End Address: 0x%08x\n",
                   (SDRAM_MAPPING_ADDRESS + SDRAM_END_ADDRESS));
        UARTprintf("  Data: 16-bit\n");
        UARTprintf("  Size: 64MB (32Meg x 16bits)\n\n");
    
        //
        // The EPI0 peripheral must be enabled for use.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_EPI0);
    
        //
        // For this example EPI0 is used with multiple pins on PortA, B, C, G, H,
        // K, L, M and N.  The actual port and pins used may be different on your
        // part, consult the data sheet for more information.
        // TODO: Update based upon the EPI pin assignment on your target part.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOH);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP);
    
        //
        // This step configures the internal pin muxes to set the EPI pins for use
        // with EPI.  Please refer to the datasheet for more information about pin
        // muxing.  Note that EPI0S27:20 are not used for the EPI SDRAM
        // implementation.
        //
        GPIOPinConfigure(GPIO_PH0_EPI0S0);
        GPIOPinConfigure(GPIO_PH1_EPI0S1);
        GPIOPinConfigure(GPIO_PH2_EPI0S2);
        GPIOPinConfigure(GPIO_PH3_EPI0S3);
        GPIOPinConfigure(GPIO_PC7_EPI0S4);
        GPIOPinConfigure(GPIO_PC6_EPI0S5);
        GPIOPinConfigure(GPIO_PC5_EPI0S6);
        GPIOPinConfigure(GPIO_PC4_EPI0S7);
        GPIOPinConfigure(GPIO_PA6_EPI0S8);
        GPIOPinConfigure(GPIO_PA7_EPI0S9);
        GPIOPinConfigure(GPIO_PG1_EPI0S10);
        GPIOPinConfigure(GPIO_PG0_EPI0S11);
        GPIOPinConfigure(GPIO_PM3_EPI0S12);
        GPIOPinConfigure(GPIO_PM2_EPI0S13);
        GPIOPinConfigure(GPIO_PM1_EPI0S14);
        GPIOPinConfigure(GPIO_PM0_EPI0S15);
        GPIOPinConfigure(GPIO_PL0_EPI0S16);
        GPIOPinConfigure(GPIO_PL1_EPI0S17);
        GPIOPinConfigure(GPIO_PL2_EPI0S18);
        GPIOPinConfigure(GPIO_PL3_EPI0S19);
        GPIOPinConfigure(GPIO_PB3_EPI0S28);
        GPIOPinConfigure(GPIO_PP2_EPI0S29);
        GPIOPinConfigure(GPIO_PP3_EPI0S30);
        GPIOPinConfigure(GPIO_PK5_EPI0S31);
    
        //
        // Configure the GPIO pins for EPI mode.  All the EPI pins require 8mA
        // drive strength in push-pull operation.  This step also gives control of
        // pins to the EPI module.
        //
        GPIOPinTypeEPI(GPIO_PORTA_BASE, EPI_PORTA_PINS);
        GPIOPinTypeEPI(GPIO_PORTB_BASE, EPI_PORTB_PINS);
        GPIOPinTypeEPI(GPIO_PORTC_BASE, EPI_PORTC_PINS);
        GPIOPinTypeEPI(GPIO_PORTG_BASE, EPI_PORTG_PINS);
        GPIOPinTypeEPI(GPIO_PORTH_BASE, EPI_PORTH_PINS);
        GPIOPinTypeEPI(GPIO_PORTK_BASE, EPI_PORTK_PINS);
        GPIOPinTypeEPI(GPIO_PORTL_BASE, EPI_PORTL_PINS);
        GPIOPinTypeEPI(GPIO_PORTM_BASE, EPI_PORTM_PINS);
        GPIOPinTypeEPI(GPIO_PORTP_BASE, EPI_PORTP_PINS);
    
        //
        // Is our current system clock faster than we can drive the SDRAM clock?
        //
        if(ui32SysClock > 60000000)
        {
            //
            // Yes. Set the EPI clock to half the system clock.
            //
            EPIDividerSet(EPI0_BASE, 1);
        }
        else
        {
            //
            // With a system clock of 60MHz or lower, we can drive the SDRAM at
            // the same rate so set the divider to 0.
            //
            EPIDividerSet(EPI0_BASE, 0);
        }
    
        //
        // Sets the usage mode of the EPI module.  For this example we will use
        // the SDRAM mode to talk to the external 64MB SDRAM daughter card.
        //
        EPIModeSet(EPI0_BASE, EPI_MODE_SDRAM);
    
        //
        // Keep the compiler happy by setting a default value for the frequency
        // flag.
        //
        ui32Freq = g_psSDRAMFreq[NUM_SDRAM_FREQ - 1].ui32FreqFlag;
    
        //
        // Examine the system clock frequency to determine how to set the SDRAM
        // controller's frequency flag.
        //
        for(ui32Val = 0; ui32Val < NUM_SDRAM_FREQ; ui32Val++)
        {
            //
            // Is the system clock frequency above the break point in the table?
            //
            if(ui32SysClock >= g_psSDRAMFreq[ui32Val].ui32SysClock)
            {
                //
                // Yes - remember the frequency flag to use and exit the loop.
                //
                ui32Freq = g_psSDRAMFreq[ui32Val].ui32FreqFlag;
                break;
            }
        }
    
        //
        // Configure the SDRAM mode.  We configure the SDRAM according to our core
        // clock frequency.  We will use the normal (or full power) operating
        // state which means we will not use the low power self-refresh state.
        // Set the SDRAM size to 64MB with a refresh interval of 1024 clock ticks.
        //
        EPIConfigSDRAMSet(EPI0_BASE, (ui32Freq | EPI_SDRAM_FULL_POWER |
        		EPI_SDRAM_SIZE_256MBIT), 1024);
    
        //
        // Set the address map.  The EPI0 is mapped from 0x60000000 to 0x01FFFFFF.
        // For this example, we will start from a base address of 0x60000000 with
        // a size of 256MB.  Although our SDRAM is only 64MB, there is no 64MB
        // aperture option so we pick the next larger size.
        //
        EPIAddressMapSet(EPI0_BASE, EPI_ADDR_PER_SIZE_256MB | EPI_ADDR_PER_BASE_A);
    
        //
        // Wait for the SDRAM wake-up to complete by polling the SDRAM
        // initialization sequence bit.  This bit is true when the SDRAM interface
        // is going through the initialization and false when the SDRAM interface
        // it is not in a wake-up period.
        //
        while(HWREG(EPI0_BASE + EPI_O_STAT) &  EPI_STAT_INITSEQ)
        {
        }
    
        //
        // Set the EPI memory pointer to the base of EPI memory space.  Note that
        // g_pui16EPISdram is declared as volatile so the compiler should not
        // optimize reads out of the memory.  With this pointer, the memory space
        // is accessed like a simple array.
        //
        g_pui16EPISdram = (uint16_t *)SDRAM_MAPPING_ADDRESS;
    
        //
        // Read the initial data in SDRAM, and display it on the console.
        //
        UARTprintf("  SDRAM Initial Data:\n");
        UARTprintf("     Mem[0x6000.0000] = 0x%4x\n",
                   g_pui16EPISdram[SDRAM_START_ADDRESS]);
        UARTprintf("     Mem[0x6000.0001] = 0x%4x\n",
                   g_pui16EPISdram[SDRAM_START_ADDRESS + 1]);
        UARTprintf("     Mem[0x603F.FFFE] = 0x%4x\n",
                   g_pui16EPISdram[SDRAM_END_ADDRESS - 1]);
        UARTprintf("     Mem[0x603F.FFFF] = 0x%4x\n\n",
                   g_pui16EPISdram[SDRAM_END_ADDRESS]);
    
        //
        // Display what writes we are doing on the console.
        //
        UARTprintf("  SDRAM Write:\n");
        UARTprintf("     Mem[0x6000.0000] <- 0xabcd\n");
        UARTprintf("     Mem[0x6000.0001] <- 0x1234\n");
        UARTprintf("     Mem[0x603F.FFFE] <- 0xdcba\n");
        UARTprintf("     Mem[0x603F.FFFF] <- 0x4321\n\n");
    
        //
        // Write to the first 2 and last 2 address of the SDRAM card.  Since the
        // SDRAM card is word addressable, we will write words.
        //
        g_pui16EPISdram[SDRAM_START_ADDRESS] = 0xabcd;
        g_pui16EPISdram[SDRAM_START_ADDRESS + 1] = 0x1234;
        g_pui16EPISdram[SDRAM_END_ADDRESS - 1] = 0xdcba;
        g_pui16EPISdram[SDRAM_END_ADDRESS] = 0x4321;
    
        //
        // Read back the data you wrote, and display it on the console.
        //
        UARTprintf("  SDRAM Read:\n");
        UARTprintf("     Mem[0x6000.0000] = 0x%4x\n",
                   g_pui16EPISdram[SDRAM_START_ADDRESS]);
        UARTprintf("     Mem[0x6000.0001] = 0x%4x\n",
                   g_pui16EPISdram[SDRAM_START_ADDRESS + 1]);
        UARTprintf("     Mem[0x603F.FFFE] = 0x%4x\n",
                   g_pui16EPISdram[SDRAM_END_ADDRESS - 1]);
        UARTprintf("     Mem[0x603F.FFFF] = 0x%4x\n\n",
                   g_pui16EPISdram[SDRAM_END_ADDRESS]);
    
        //
        // Check the validity of the data.
        //
        if((g_pui16EPISdram[SDRAM_START_ADDRESS] == 0xabcd) &&
           (g_pui16EPISdram[SDRAM_START_ADDRESS + 1] == 0x1234) &&
           (g_pui16EPISdram[SDRAM_END_ADDRESS - 1] == 0xdcba) &&
           (g_pui16EPISdram[SDRAM_END_ADDRESS] == 0x4321))
        {
            //
            // Read and write operations were successful.  Return with no errors.
            //
            UARTprintf("Read and write to external SDRAM was successful!\n");
            UARTprintf("Begin Performance Test!\n");
        }
        else
        {
            //
            // Display on the console that there was an error.
            //
            UARTprintf("Read and/or write failure!");
            UARTprintf(" Check if your SDRAM card is plugged in.");
            return(0);
        }
    
        for(ui32Index=0; ui32Index < NO_OF_RAM_LOC; ui32Index++)
        {
        	g_ui32InternalRamArray[ui32Index] = 0xABCD0000 + ui32Index;
        }
    
        //
        // Configure the uDMA
        //
        SysCtlPeripheralDisable(SYSCTL_PERIPH_UDMA);
        SysCtlPeripheralReset(SYSCTL_PERIPH_UDMA);
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    
        while(!(SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)));
    
        //
        // Enable the uDMA and set the control table address
        //
        uDMAEnable();
    
        uDMAControlBaseSet(&psDMAControlTable[0]);
    
        //
        // Assign the channel 16 for ADC1 Sequencer 2 for Audio IN
        //
        uDMAChannelAssign(UDMA_CH21_EPI0TX);
    
        uDMAChannelAttributeDisable(UDMA_CH21_EPI0TX,
                                    UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST |
                                    UDMA_ATTR_REQMASK | UDMA_ATTR_HIGH_PRIORITY);
    
        //
        // Configure the control parameters for the primary and alternate control
        // structure of channel for ADC1 Sequencer-2
        //
        uDMAChannelControlSet(UDMA_CH21_EPI0TX | UDMA_PRI_SELECT,
                              UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 |
                              UDMA_ARB_4);
    
        uDMAChannelTransferSet(UDMA_CH21_EPI0TX | UDMA_PRI_SELECT,
                               UDMA_MODE_BASIC,
    						   (void *)&g_ui32InternalRamArray[0],
    						   (void *)0xA0001000,
                               NO_OF_RAM_LOC);
    
        //
        // Now enable the channel for ADC1 Sequencer-2
        //
    
        //
        // Now Transfer Data using DMA TX channel with EPI request.
        //
        EPIFIFOConfig(EPI0_BASE, EPI_FIFO_CONFIG_TX_1_4| EPI_FIFO_CONFIG_RX_1_8);
        EPIDMATxCount(EPI0_BASE, NO_OF_RAM_LOC);
    
        uDMAChannelEnable(UDMA_CH21_EPI0TX);
        //
        // Wait in while loop at the end...
        //
        while(1)
        {
        }
    }
    

    Regards

    Amit

  • Hi Amit,

    Thanks for the effort that you are putting into this, but my problem is still un-resolved.

    I tried to adapt you code to HB16 interface but nothing has changed: The uDMA write is still not working.

    I'm not sure what will be the next step, but our customers are waiting for the new board and I can't give the go ahead until this interface is working!

    Khaled.

  • Hello Khaled

    Is the iRDY holding off the bus?

    Regards
    Amit
  • I will probe it and get back to you. But most likely its not. As I mentioned before the following accesses are working fine:  Non uDMA read, Non uDMA write, and uDMA read.

    The only non working access is the uDMA write.

    If it was the iRDY, I would have seen the problem with the Non uDMA write as well.

    Both Non uDMA write and uDMA write functions shares the same code until the last few instruction.

    In the non uDMA case I do a direct write

    for(i = 0; i < count; i++) {

    word            = src_p[i];

    *g_pusEPIFPGA =  (word         ) & 0xFFFF; g_pusEPIFPGA++;

    *g_pusEPIFPGA = (word >> 16) & 0xFFFF; g_pusEPIFPGA++;

    EPIWriteFIFOEmpty(TRUE); //wait write fifo to be empty

    }

    In the uDMA case write I program the uDMA to send the data

    EPIDMATxCount( EPI0_BASE,count * 2);

    uDMAChannelTransferSet( UDMA_CH21_EPI0TX, UDMA_MODE_BASIC, src_p, (void *)g_pusEPIFPGA, count * 2);

    uDMAChannelEnable( UDMA_CH21_EPI0TX);

  • Hello Khaled

    Since you have proven that non-uDMA read write and uDMA read work fine, the interface is OK. It is a software configuration that is not working which has to be analyzed.

    I would suggest checking it with a SDRAM board if you have access to one?

    Regards
    Amit
  • Hi Amit,

    I fully agree with you: its a configuration problem. But what? that is what is driving me crazy. I checked every instruction and every register but I'm not able to find the error. I was hoping that you will be able to find it for me.


    I don't have an SDRAM that is connected to the HB16 bus. This is a home made board that connect the Cortex M4 to Ti's TMS320C6472 HPI bus.

    However, as per your instructions, I did asked our technician to solder probes to the HB16 control bus (including the iRDY). I should be able to have the modified board today.

    Khaled.

  • Hello Khaled

    I would suggest soldering the probes on the all the critical signals so that we can see what is happening on the bus for the control signals.

    Regards
    Amit
  • Hello Amit

    Did as you have suggested and I think I have the first clue: The address bus is not toggling when performing a uDMA write!

    In my case, I"m using a single address bus A0 to act as a half word strobe to the TM320C6472: A0 is low for the 1th 16bits, and high for the second 16bits.

    Now the question, is why?

    Khaled.

  • Hello Amit,

    I think I found the solution. I have to increment the destination address as follow:

    uDMAChannelControlSet(UDMA_SEC_CHANNEL_EPI0TX,  //WFIFO

            UDMA_SIZE_16          |      //data size

            UDMA_SRC_INC_16       |      //source address increment

       UDMA_DST_INC_16       |      //destination address increment

       UDMA_ARB_1);                 //arbitration size

    I will do some more tests to confirm.

    Khaled

  • Hello Khaled,

    Then it must be the device that is not responding to back-2-back access?

    Regards
    Amit
  • Hello Amit,
    Its not the external device.
    The Cortex was not incrementing the address bus when uDMA write is performed.
    I made the SAME error as before when I was writing the non uDMA Epi read and write functions (see previous post where you solved for me the manual increment of the EPI address bus): e2e.ti.com/.../1288134

    Now again, the M4, the DMA engine has to be explicitly configured to increment.
    Khaled.
  • Hi Amit,
    One last issue with the HB16.
    Now that I have uDMA write transferring data properly, the EPI interrupt handler keep triggering endlessly with EPI_INT_DMA_TX_DONE flag.
    I'm not able to clear it.
    There is a EPIIntErrorClear(EPI0_BASE, intStatus) function to clear the error flag, but no function to clear the uDMA done flag!

    Khaled.
  • Hello Khaled

    You have to use the API as follows.

    EPIIntErrorClear(EPI0_BASE, EPI_INT_ERR_DMAWRIC);

    Regards
    Amit
  • Hi Amit,
    That did not work.
    Tried
    intStatus = EPIIntStatus(EPI0_BASE, true);
    EPIIntErrorClear(EPI0_BASE, intStatus);

    and tried
    intStatus = EPIIntStatus(EPI0_BASE, true);
    EPIIntErrorClear(EPI0_BASE, EPI_INT_ERR_DMAWRIC);

    but I EPI handler keeps on triggering.
    Khaled.
  • Hello Khaled

    Can you check if the write counter in EPI is 0?

    Regards
    Amit
  • Hi Amit

    Here is the registers values captured as soon as I enter the EPI handler.

    Khaled.

  • Hello Khaled,

    The EPI register WFIFOCOUNT is not "0". Hence the EPI is requesting the DMA for more data, but since the DMA transfer size has decremented to 0 and the channel mode automatically turned to STOP, the DMA Done is being asserted by the DMA which is what is causing the Interrupt to fire again.
    You need to make sure that the Transfer Size in the control structure of the DMA and the WFIFOCOUNT register value is correctly programmed

    Regards
    Amit
  • Hi Amit,

    I'm confused. I thougth that the EPI WFIFOCNT == 4 means the the fifo IS empty.

    Here is my Epi init and Epi uDMA write function. could you please take a look.

     

    void EPI_HPI_uDMA_write(uint32_t *src_p, uint32_t  count, uint32_t *dst_p) {

     // Set pointer to EPI memory mapped window.
     g_pusEPIFPGA = (uint16_t *)0xC0000000;

     //write the data
     EPIDMATxCount(EPI0_BASE, count * 2);
     uDMAChannelTransferSet(UDMA_CH21_EPI0TX, UDMA_MODE_BASIC, src_p, (void *)g_pusEPIFPGA, count*2);
     uDMAChannelEnable(UDMA_CH21_EPI0TX);
    }


    void EPI_Init(void) {
        g_pusEPIFPGA = (uint16_t *)0xC0000000;
        EPIModeSet(EPI0_BASE,
                   EPI_MODE_DISABLE);
        EPIDividerSet(EPI0_BASE,
                   EPI_DIV_FACTOR_DATA);
        EPIModeSet(EPI0_BASE,
                   EPI_MODE_HB16);
        EPIConfigHB16Set(    EPI0_BASE,
    //             EPI_HB16_USE_TXEMPTY          |     //Tx fifo empty enable
    //             EPI_HB16_USE_RXFULL           |     //Rx fifo full enable
    //             EPI_HB16_BURST_TRAFFIC        |     //burst mode enabled
                   EPI_HB16_IN_READY_EN          |     //IRDY enabled
                   EPI_HB16_IN_READY_EN_INVERTED |     //IRDY polarity inverted
                   EPI_HB16_MODE_ADDEMUX         |     //sets up data and address as separate
                   EPI_HB16_CSCFG_ALE            |     //EPIS030 to operate as an address latch (ALE)
                   EPI_HB16_ALE_HIGH             |     //sets the address latch active high
                   EPI_HB16_WRWAIT_0             |     //sets write wait state to 2 EPI clocks.
                   EPI_HB16_RDWAIT_0             ,     //sets read wait state to 2 EPI clocks.
                   0xF0);                              //FIFO mode    maximum number of clocks
        EPIConfigHB16TimingSet(EPI0_BASE,
                   0            ,                        //specifies the chip select to configure[0-3]
                   EPI_HB16_IN_READY_DELAY_1     |       //sets the stall on input ready (EPIS032)
                                                         //to start 1 EPI clock after signaled
                   EPI_HB16_WRWAIT_MINUS_ENABLE  |       //1 EPI clock write wait state reduction
                   EPI_HB16_RDWAIT_MINUS_ENABLE);        //1 EPI clock read wait state reduction
        EPIAddressMapSet(EPI0_BASE,
                   EPI_ADDR_PER_BASE_C   |
                   EPI_ADDR_PER_SIZE_64KB);
        EPIFIFOConfig(EPI0_BASE,
                   EPI_FIFO_CONFIG_TX_1_2 |
                   EPI_FIFO_CONFIG_RX_1_2);
        EPINonBlockingReadConfigure(EPI0_BASE,
                   0,
                   EPI_NBCONFIG_SIZE_16,
                   0);

        //-------------------------------------------------------------
        // Setup the EPI interrupt to service the NBRFIFO and the WFIFO
        //-------------------------------------------------------------
        EPIIntDisable(EPI0_BASE,
                   EPI_INT_RXREQ      |
                   EPI_INT_TXREQ      |
                   EPI_INT_ERR);
        EPIIntErrorClear(EPI0_BASE,
                   EPI_INT_ERR_WTFULL |
                   EPI_INT_ERR_RSTALL |
                   EPI_INT_ERR_TIMEOUT);

        EPIIntEnable(EPI0_BASE,
    //             EPI_INT_RXREQ       |    //read FIFO above trigger level
    //             EPI_INT_TXREQ       |    //transmit FIFO below trigger level
                   EPI_INT_DMA_TX_DONE |    //transmit DMA completes
                   EPI_INT_DMA_RX_DONE |    //read DMA completes
                   EPI_INT_ERR);            //error condition
        IntEnable(INT_EPI0);

        //-------------------------------------------------------------
        // Configure the uDMA for the EPI read and write
        //-------------------------------------------------------------
        uDMAChannelAssign(    UDMA_CH20_EPI0RX);
        uDMAChannelAssign(    UDMA_CH21_EPI0TX);

        uDMAChannelAttributeDisable(UDMA_CH20_EPI0RX, UDMA_ATTR_ALL);
        uDMAChannelAttributeDisable(UDMA_CH21_EPI0TX, UDMA_ATTR_ALL);
        uDMAChannelSelectSecondary( UDMA_DEF_TMR1A_SEC_EPI0RX |
                                    UDMA_DEF_TMR1B_SEC_EPI0TX);
        uDMAChannelAttributeEnable( UDMA_CH20_EPI0RX,           //NBRFIFO
                                    UDMA_ATTR_USEBURST |        //single request is not supported
                                    UDMA_ATTR_HIGH_PRIORITY);   //needed for ADC transfers
        uDMAChannelAttributeEnable( UDMA_CH21_EPI0TX,           //WFIFO
                                    UDMA_ATTR_USEBURST);        //single request is not supported
        uDMAChannelControlSet(      UDMA_CH20_EPI0RX,           //NBRFIFO
                                    UDMA_SIZE_16       |        //data size
                                    UDMA_SRC_INC_NONE  |        //no source address increment
                                    UDMA_DST_INC_16    |        //destination address increment
                                    UDMA_ARB_4);                //arbitration size
        uDMAChannelControlSet(      UDMA_CH21_EPI0TX,           //WFIFO
                                    UDMA_SIZE_16       |        //data size
                                    UDMA_SRC_INC_16    |        //source address increment
                                    UDMA_DST_INC_16    |        //destination address increment
                                    UDMA_ARB_2);                //arbitration size
        //-------------------------------------------------------------
        //setup the uDMA interrupts
        //-------------------------------------------------------------
        IntEnable(INT_UDMA);
        IntEnable(INT_UDMAERR);
    }


    Khaled

  • Hello Khaled,

    I was looking at the EPI DMATXCNT register when I wrote the WFIFOCNT register. The whole explanation is the same, except replace WFIFOCNT with DMATXCNT register.

    Regards
    Amit
  • Hi Amit,

    I think that I found a solution: I changed the order or the commands and moved EPIDMATxCount( ) call to the end(see below).
    Does that make sens?

    void EPI_HPI_uDMA_write(uint32_t *src_p, uint32_t count, uint32_t *dst_p) {

    // Set pointer to EPI memory mapped window.
    g_pusEPIFPGA = (uint16_t *)0xC0000000;

    //write the data
    uDMAChannelTransferSet(UDMA_CH21_EPI0TX, UDMA_MODE_BASIC, src_p, (void *)g_pusEPIFPGA, count * 2);
    uDMAChannelEnable(UDMA_CH21_EPI0TX);
    EPIDMATxCount(EPI0_BASE, count * 2);
    }
    Khaled
  • Hello Khaled,

    It does make sense. The EPIDMATxCnt generates the DMA request. If the channel is not configured and enabled, then EPI generates request which results in DMA Done interrupt as the DMA does not know what to do with the transfer request.

    Regards
    Amit
  • Fair enough, but when dealing with all the Cortex M4 interfaces, it seems that each interface has a special way and special commands to make it run properly! This is a draw back and TI should change how uDMA is setup and make it the SAME for all.
    It time consuming and thus costly to figure out the setup for each interface.

    This is said, thanks Amit. You were very helpful. I have been stuck on this particular interface for 2 weeks now and I could have been stuck for another 2 weeks if it was not for your involvement.

    Khaled.
  • Hello Khaled

    We are working on an application note, where uDMA interaction with each of the modules will be better explained with examples that span re-entrant loops. This module has been one of the little explained module and I agree, it need explanation.

    Regards
    Amit