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 HB16 address bus is stuck at 0x00

Hi,

I have trouble getting the EPI interface to run using HB16 mode with data and address bus separate. Clock, RD, WR, ALE look OK. But the address bus is stuck to 0x00.

I need a two bits address bus that wrap when 0x03 is reached (A0 and A1).

I'm attaching a snap shot of the code

3034.EpiCodeSnapshot.c
//-----------------------------------------------------------------------
// global variables
//-----------------------------------------------------------------------
uint32_t gSysCtlClock;  			//System clock
volatile uint16_t *g_pusEPIFPGA; 	//Pointer for EPI memory window.

//-----------------------------------------------------------------------
// GPIO_Init
//-----------------------------------------------------------------------
void GPIO_Init(void) {

	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);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOR);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOR);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOS);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOS);

	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOT);
	SysCtlPeripheralReset(SYSCTL_PERIPH_GPIOT);

	GPIOPinConfigure(GPIO_PK0_EPI0S0);  //EPI D0
	GPIOPinConfigure(GPIO_PK1_EPI0S1);  //EPI D1
	GPIOPinConfigure(GPIO_PK2_EPI0S2);  //EPI D2
	GPIOPinConfigure(GPIO_PK3_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

	GPIOPinConfigure(GPIO_PL0_EPI0S16); //EPI A0
	GPIOPinConfigure(GPIO_PL1_EPI0S17); //EPI A1
	GPIOPinConfigure(GPIO_PB2_EPI0S27); //EPI CS0
	GPIOPinConfigure(GPIO_PB3_EPI0S28); //EPI RD
	GPIOPinConfigure(GPIO_PP2_EPI0S29); //EPI WR
	GPIOPinConfigure(GPIO_PP3_EPI0S30); //EPI ALE
	GPIOPinConfigure(GPIO_PK5_EPI0S31); //EPI CLK
	GPIOPinConfigure(GPIO_PK4_EPI0S32); //EPI iRDY

	GPIOPinTypeEPI(GPIO_PORTK_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_PORTL_BASE, GPIO_PIN_0 |	//EPI A0
									GPIO_PIN_1);	//EPI A1
	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
									GPIO_PIN_5);	//EPI CLOCK
}

//-----------------------------------------------------------------------
// Epi_Init
//-----------------------------------------------------------------------
void EPI_Init(void) {

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

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

	//enable the EPI interface, and use general purpose mode
	EPIModeSet(EPI0_BASE, EPI_MODE_HB16);
    EPIConfigHB16Set(	EPI0_BASE,
						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.
						0);									//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_256B  );
	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);
}
//-----------------------------------------------------------------------
// main
//-----------------------------------------------------------------------
uint16_t main(void) {

	uint16_t i;
	uint32_t word;
	uint32_t  u32DataIn[10];

	gSysCtlClock = SysCtlClockFreqSet(
						SYSCTL_USE_PLL    |
						SYSCTL_OSC_MAIN   |
						SYSCTL_XTAL_25MHZ |
						SYSCTL_CFG_VCO_480,
						120000000);		//desired system frequency
	GPIO_Init();   					//setup GPIO
	EPI_Init(); 					//setup EPI HPI interface


	for(i = 0; i < 10; i++) {
		word  = (uint32_t) *g_pusEPIFPGA;		//read lower 16bits
		word |= (uint32_t) *g_pusEPIFPGA << 16;	//read upper 16bits

		u32DataIn[i] = word;
	}

}//main
.

Can you help?

thanks.

Khaled.

  • Hello Khaled,

    I went through the code and would suggest using the following instead of the original code. The reason is because in the original code the Address is always specified as 0xC0000000 on a 32-bit bus. To get the address correctly you would need to access the locations on a half word basis.

        for(i = 0; i < 10; i++) {
            word  = (uint32_t) *g_pusEPIFPGA;        //    read lower 16bits
            g_pusEPIFPGA++;
            word |= ((uint32_t) *g_pusEPIFPGA) << 16;    //    read upper 16bits
            g_pusEPIFPGA++;

            u32DataIn[i] = word;
        }

    Regards

    Amit

  • Amit,

    Its working now :-)

    I was under the assumption that the address will AUTOMATICALLY increment with every write.

    thanks..

  • Hi Amit,

    This reporter was under the same assumption as poster Khaled.  (i.e. automatic increment/decrement of address w/each transaction {read or write})  That feature is often desirable (i.e. transacting w/memory or display controllers) - yet accommodates those occasions when an address "jump" is indicated/required - as well.  And (pardon) this auto increment/decrement of external address is (predictably) found on multiple, other ARM MCUs.

    Manually entering the address for each/every transaction seems wasteful (slowing & inefficient) - might there be some means to automate the address increment on MCUs here - just as poster Khaled seeks?

    Thanks your time/attention...

  • cb1- said:

    Manually entering the address for each/every transaction seems wasteful (slowing & inefficient) - might there be some means to automate the address increment on MCUs here - just as poster Khaled seeks?

    Is that not (part of) the purpose of DMA?

    Robert

  • Robert Adsett said:
    Is that not (part of) the purpose of DMA?

    May be - as my writing stated - auto address increment/decrement is not, "held hostage" to DMA on other Cortex M-4s... 

    Note that my post was an obvious follow-on to poster's - and sought further (perhaps insider) detail...

  • Hello cb1,

    In the original code the address pointer is not constant. So when data is accessed the address remains constant. Also since the address pointer is overloaded as uint16_t, the address though will perform a 16-bit transfer, but due to lack of change on the address itself the same address will present itself.

    Regards

    Amit

  • I think that the question that we should be asking our selfs: can we change the code such that the address will update/increment with every read/write.

    Khaled.

  • The C idiom for that is

        for(i = 0; i < 10; i++) {
            word  = (uint32_t) *g_pusEPIFPGA++;        //    read lower 16bits
            word |= ((uint32_t) *g_pusEPIFPGA++) << 16;    //    read upper 16bits

            u32DataIn[i] = word;
        }

    But that should not affect the code generation.  It does affect readability.

    I don't remember if the Cortex has auto-incrementing address mode but changing the code should not affect its use.

    The other unasked question is, does it matter?

    Robert

  • cb1- said:
    auto address increment/decrement

    Khaled - believe that's exactly what was asked (above.)

    Amit - may "automatic" inc/dec of the external bus be achieved via some MCU register setting - and w/out requiring uDMA (adds unwanted complexity & limits uDMA availability for other tasks) or manual update of the external address?

  • It appears the AHB bus may have provision or autoincrementing

    http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0337i/BABGBEEC.html

    Whether this peripheral is on the AHB bus and that register is available to program is open to question.

    Also depending on depending on access restrictions (and the particular library implementation) do not forget memcpy.

    Although the "is this worth it?" question still rises. You should probably measure the performance to see if it is adequate before optimising it further.

    Robert

  • Hello cb1,

    The Non-Block Read FIFO can be used to do the same. It consist of 3 register. EPIRSIZEn to indicate the width of the transfer, EPIRDADDRn for start address of the transaction and EPIRPSTDn which is to set the number of transfers.

    The user then has to set the threshold in the EPIFIFOLVL register so that an interrupt can be triggered when the required level is reached and CPU can use LDMIA instruction to do a burst transfer.

    Regards

    Amit

  • How about the write? If we transfer data to the write fifo (either direct write or using uDMA), will the address automatically increment as well?

    Khaled.

  • Hello Khaled,

    All write transactions go through the Write FIFO. I don't believe that is an optional path

    Regards

    Amit

  • But my question was: will the write address increment as well? and how we set it up.

    Khaled.

  • Hello Khaled,

    The Write FIFO stores the address and the data. Hence the way it is accessed on the AHB Bus Interface decides how the address will be presented on the interface.

    Regards

    Amit

  • Thanks Amit,

    I didn't understand your answer its a little bit vague. Do you have an example/documentation?

    Just to let you know, I alread have the answer for the question that I have asked originally.
    But after all those messages that has been exchanged, It became a curiosity. I want to understand how it works and change my code if I find a solution that is better than the one that I'm currently considering.

    thanks.

    Khaled.

  • Hello Khaled,

    I don't think it is documented or has an example code with it. The only documentation would exist in the data sheet chapter for EPI. To explain it better: The Write FIFO is a 4x32 bit FIFO which holds the write transaction being done from the CPU/DMA. Since it is possible that the Line Side may run slower than the system clock, to avoid stalling the bus, the FIFO holds the Address and Data. This way the CPU/DMA can do a burst write (CPU case is STMIA instruction) and then go to perform another operation with another peripheral. The EPI will schedule the transaction onto the Line Side. The manner in which the address is presented on the bus depends on the manner it has been written into the FIFO. So if the 4 units of data are written with incrementing address, the address on the line side would increment as well. If the data has been written with a constant address, the data will be sent out to a constant address.

    By Line Side I mean the Pins coming out of the device. I hope this clarifies the operation of WFIFO

    Regards

    Amit

  • How about non uDMA write?

    for the read in epi.c several function are available to configure the read fifo, read address, and read the data ( EPINonBlockingReadConfigure, EPINonBlockingReadStart, EPINonBlockingReadGet32..)

    I can't find similar function for the write!

    Khaled.

  • Hello Khaled

    There are only two system initiators for EPI. CPU and uDMA. Irrespective of source of the write data the WFIFO works in the same manner as described before. That is the reason why there are no such functions.

    Regards

    Amit

  • Amit Ashara said:
    Irrespective of source of the write data the WFIFO works in the same manner as described before. That is the reason why there are no such functions.

    Pardon - but the absence of those (reasonably) expected write functions - noted by Khaled - seems very much a vendor, "shortcut" - and one destined to derail & confound your user multitudes.

    Are the presence, highlighting and proper management of those two, "system initiators" adequately detailed w/in the MCU manual?  Seems unwise & inefficient to hold,"optimal usage methods" hostage to privileged, insider information...

  • cb-1

    I agree with you. for uDMA write I believe that the address is set using the uDMAChannelTransferSet( ) function.

    But how about CPU write! how do we set the write address?

    Khaled.

  • Hello Khaled, cb1,

    The Write FIFO is in an internal buffer management which is not exposed to user programming unlike the NBRFIFO which is also an internal buffer management with user programming.

    The Bus Masters to the EPI is mentioned in section on "Master Access to EPI" of the EPI Chapter in the Data Manual.

    As noted by Khaled, uDMA write is set by the uDMAChannelTransferSet(), while the CPU write is set by the use of address for external Bus operation in the same manner as any peripheral write operation using the address of the peripheral. For example if 0xC000.0000 is the address mapped to the Bus in EPI register, the CPU access will be done by HWREG or in the specific example the pointer set in the code for accessing the bus

    Regards

    Amit

  • Hi Amit,

    That explanation is quite good - subject is somewhat complex and (perhaps) both uDMA and EPI sections - w/in MCU manuals - would benefit from the further detail & clarity you've added, here.

    Thank you, Amit - as always - your efforts are appreciated.

    (and - as noted in the recent," ARM Peripheral comparison" post - ARM vendors implement their DMA & external bus access often by different means - adding to the challenge of simple competence - let alone full understanding or mastery by users...)

  • Amit,

    Apparently I'm not as good as cb1.

    When you sait : "For example if 0xC000.0000 is the address mapped to the Bus in EPI register, the CPU access will be done by HWREG..."

    Do I understand from your comment that the only way to perform an EPI write is by setting a memory mapped location using the EPIAddressMapSet( ) function and then write to that memory?

    In all cases, how do we set the address to a specific value? I'm not able to find EPI write example code that does not used memory mapped approach. Do you have an example code?

    thanks.
    Khaled.

  • Hello Khaled,

    Your interpretation of a write to the memory is correct. Based on what is set in the EPIAddressMapSet the memory mapped location is accessed.

    You can perhaps go through the example

    C:\ti\TivaWare_C_Series-2.1.0.12573\examples\peripherals\epi\sdram.c

    to be able to see how write is being done.

    Regards

    Amit