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.

TM4C1290NCPDT: EPI Initialization Before Application Code

Part Number: TM4C1290NCPDT

We are currently developing a project that will use the EPI to work with a SDRAM part. Our project will have a flash boot loader that will eventually call out the jump to our application binary. I can use the _system_pre_init function in our boot loader to setup the EPI before the memory initialization is done for the application code. However, I am wonder what I need to do before I JTAG debug our application code since the boot loader would not be called to setup the EPI.

If I have memory used in the SDRAM, the init will try initializing memory in the SDRAM before the EPI ever was setup, which will result in a hard fault of the processor. Does anyone have a suggestion on how to debug our application code, but also have the EPI setup before the memory initialization? We would like to avoid disabling the memory initialization if possible.

  • Our bootloader is all C, and our application code is C++. I have the following in our application main.cpp:

    extern "C" int _system_pre_init(void)
    {
        return(1);
    }

  • Hi Bryan,

      Perhaps I'm not fully clear with your issue and setup. I assume your application is stored on the SDRAM and what is stored on the MCU is only the flash-based bootloader. Is this a correct understanding? Do you use the on-chip flash for anything else other than the bootloader? Another question is how do you load the application code onto the SDRAM? Do you have some type of multiplex on the buses to the SDRAM. In another word, the MCU is only reading and executing code out of the SDRAM while there is another host writing to the SDRAM to upload the application binary. 

  • Hello Charles,

    We are not executing out of the external SDRAM. Our application code is normally kept in flash, and it executed out of the internal SDRAM of the Tiva. We have an external SDRAM that we are using to store large data sets. Our goal is to setup our application linker to have a memory area mapped to the external SDRAM. Our fear is that when the application code is pulled in, the mapped memory will be initialized before main, and that will generate a hard fault of the processor.

    We are using the EPI block to interface with the external SDRAM. I believe I could setup the _system_pre_init(void) in our flash bootloader, and that would successfully enable the EPI before our application code is executed. However, I believe when we JTAG debug, the boot loader would not be executed, meaning the EPI would not be enabled before the memory initialization is done, which would result in a hard fault.

    FWIW, the flash boot loader is set to 0x0000 in flash. The application code is set to 0x4000 in flash.

  • Bryan Radke said:
    Our fear is that when the application code is pulled in, the mapped memory will be initialized before main, and that will generate a hard fault of the processor.

    Hi Bryan,

       Perhaps this is what I'm not clear about. After reset the flash bootloader (at 0x0) is first started. It will then jump to the application starting at 0x4000. You don't need to start reading the external SDRAM (via EPI) until you are running the application starting at 0x4000. Is this correct? I'm not clear as to what you are trying to do with the external SDRAM or the EPI module when you are still in the bootloader before jumping to the application. Can you not wait until you are in the application before initializing EPI and accessing the external SDRAM? Sorry, if I'm not following the issue. Where is the hard fault coming from? Is it when you are still in the bootloader?

  • Hello Charles,

    You are correct with how our flash boot loader and application function. We jump to the application code at 0x4000 and that is where the external SDRAM will be used. The boot loader will not utilize the external SDRAM, but it could setup the EPI module so it's enabled for the application code.

    Our intent is to update our application linker command file to what's listed below:

    MEMORY
    {
        FLASH (RX) : origin = 0x00000000, length = 0x00100000
        SRAM (RWX) : origin = 0x20000000, length = 0x00040000
        EXSDRAM (RWX) : origin = 0x60000000, length = 0x00800000
    }

    It is my understanding that the initialization of the application code will attempt to initialize all mapped memory to either the user defined initialization value, or a default value. I believe there is a flag to skip this step. Regardless, I believe that any memory that we have mapped to the EXSDRAM section will be initialized before execution of our application code. If the EPI module is not enabled/configured before this initiation step, then the processor will fault due to not having access. The post at this link is where this whole plan started https://e2e.ti.com/support/microcontrollers/other/f/908/t/442360.

    When we run our debugger through JTAG, there is nothing to enable the EPI ahead of time, meaning we will run into hard faults since the memory could not be initialized. My question is how can we enable the EPI so that the memory can be mapped by the linker, and have the code able to be debugged through the JTAG.

  • The code below is what we'll need to enable the EPI to our external SDRAM:

    #define SDRAM_APP_START_ADDRESS 0x60000000
    
    //  Defines for GPIO pins for EPI0
    #define EPI_PORTA_PINS  0xC0        //  Pins 6, 7
    #define EPI_PORTB_PINS  0x0C        //  Pins 2, 3
    #define EPI_PORTC_PINS  0xF0        //  Pins 4, 5, 6, 7
    #define EPI_PORTG_PINS  0x03        //  Pins 0, 1
    #define EPI_PORTH_PINS  0x0F        //  Pins 0, 1, 2, 3
    #define EPI_PORTK_PINS  0xF0        //  Pins 4, 5, 6, 7
    #define EPI_PORTL_PINS  0x3F        //  Pins 0, 1, 2, 3, 4, 5
    #define EPI_PORTM_PINS  0x0F        //  Pins 0, 1, 2, 3
    #define EPI_PORTN_PINS  0x30        //  Pins 4, 5
    #define EPI_PORTP_PINS  0x0C        //  Pins 2, 3
    #define EPI_PORTQ_PINS  0x0F        //  Pins 0, 1, 2, 3
    
    #define EPI_PORTA_PCTL  0xFF000000
    #define EPI_PORTB_PCTL  0x0000FF00
    #define EPI_PORTC_PCTL  0xFFFF0000
    #define EPI_PORTG_PCTL  0x000000FF
    #define EPI_PORTH_PCTL  0x0000FFFF
    #define EPI_PORTK_PCTL  0xFFFF0000
    #define EPI_PORTL_PCTL  0x00FFFFFF
    #define EPI_PORTM_PCTL  0x0000FFFF
    #define EPI_PORTN_PCTL  0x00FF0000
    #define EPI_PORTP_PCTL  0x0000FF00
    #define EPI_PORTQ_PCTL  0x0000FFFF
    
    extern "C" int _system_pre_init( void )
    {
    	/* This function is called before the .bss and .data sections
    	 * have been initialized so the core here should only access
    	 * peripheral registers or local variables allocated on the stack */
    
    	//  Enable GPIO port run mode clocks for EPI
    	HWREG( SYSCTL_RCGCGPIO ) |=
    		(
    			SYSCTL_RCGCGPIO_R0 |    //  GPIO Port A
    			SYSCTL_RCGCGPIO_R1 |    //  GPIO Port B
    			SYSCTL_RCGCGPIO_R2 |    //  GPIO Port C
    			SYSCTL_RCGCGPIO_R6 |    //  GPIO Port G
    			SYSCTL_RCGCGPIO_R7 |    //  GPIO Port H
    			SYSCTL_RCGCGPIO_R9 |    //  GPIO Port K
    			SYSCTL_RCGCGPIO_R10 |   //  GPIO Port L
    			SYSCTL_RCGCGPIO_R11 |   //  GPIO Port M
    			SYSCTL_RCGCGPIO_R12 |   //  GPIO Port N
    			SYSCTL_RCGCGPIO_R13 |   //  GPIO Port P
    			SYSCTL_RCGCGPIO_R14     //  GPIO Port Q
    		);
    
    	//  Wait for the clocks to be enabled
    	while ( HWREG( SYSCTL_PRGPIO ) &
    			(
    				SYSCTL_RCGCGPIO_R0 | //  GPIO Port A
    				SYSCTL_RCGCGPIO_R1 | //  GPIO Port B
    				SYSCTL_RCGCGPIO_R2 | //  GPIO Port C
    				SYSCTL_RCGCGPIO_R6 | //  GPIO Port G
    				SYSCTL_RCGCGPIO_R7 | //  GPIO Port H
    				SYSCTL_RCGCGPIO_R9 | //  GPIO Port K
    				SYSCTL_RCGCGPIO_R10 | //  GPIO Port L
    				SYSCTL_RCGCGPIO_R11 | //  GPIO Port M
    				SYSCTL_RCGCGPIO_R12 | //  GPIO Port N
    				SYSCTL_RCGCGPIO_R13 | //  GPIO Port P
    				SYSCTL_RCGCGPIO_R14 //  GPIO Port Q
    	        ) !=
    			(
    				SYSCTL_RCGCGPIO_R0 | //  GPIO Port A
    				SYSCTL_RCGCGPIO_R1 | //  GPIO Port B
    				SYSCTL_RCGCGPIO_R2 | //  GPIO Port C
    				SYSCTL_RCGCGPIO_R6 | //  GPIO Port G
    				SYSCTL_RCGCGPIO_R7 | //  GPIO Port H
    				SYSCTL_RCGCGPIO_R9 | //  GPIO Port K
    				SYSCTL_RCGCGPIO_R10 | //  GPIO Port L
    				SYSCTL_RCGCGPIO_R11 | //  GPIO Port M
    				SYSCTL_RCGCGPIO_R12 | //  GPIO Port N
    				SYSCTL_RCGCGPIO_R13 | //  GPIO Port P
    				SYSCTL_RCGCGPIO_R14 //  GPIO Port Q
    	        )
    	        )
    	{
    	}
    
    	//  Configure EPI IO Pins
    	HWREG( GPIO_PORTA_AHB_BASE + GPIO_O_PCTL ) |= EPI_PORTA_PCTL;
    	HWREG( GPIO_PORTA_AHB_BASE + GPIO_O_DEN ) |= EPI_PORTA_PINS;
    	HWREG( GPIO_PORTA_AHB_BASE + GPIO_O_DR8R ) |= EPI_PORTA_PINS;
    	HWREG( GPIO_PORTA_AHB_BASE + GPIO_O_AFSEL ) |= EPI_PORTA_PINS;
    
    	HWREG( GPIO_PORTB_AHB_BASE + GPIO_O_PCTL ) |= EPI_PORTB_PCTL;
    	HWREG( GPIO_PORTB_AHB_BASE + GPIO_O_DEN ) |= EPI_PORTB_PINS;
    	HWREG( GPIO_PORTB_AHB_BASE + GPIO_O_DR8R ) |= EPI_PORTB_PINS;
    	HWREG( GPIO_PORTB_AHB_BASE + GPIO_O_AFSEL ) |= EPI_PORTB_PINS;
    
    	HWREG( GPIO_PORTC_AHB_BASE + GPIO_O_PCTL ) |= EPI_PORTC_PCTL;
    	HWREG( GPIO_PORTC_AHB_BASE + GPIO_O_DEN ) |= EPI_PORTC_PINS;
    	HWREG( GPIO_PORTC_AHB_BASE + GPIO_O_DR8R ) |= EPI_PORTC_PINS;
    	HWREG( GPIO_PORTC_AHB_BASE + GPIO_O_AFSEL ) |= EPI_PORTC_PINS;
    
    	HWREG( GPIO_PORTG_AHB_BASE + GPIO_O_PCTL ) |= EPI_PORTG_PCTL;
    	HWREG( GPIO_PORTG_AHB_BASE + GPIO_O_DEN ) |= EPI_PORTG_PINS;
    	HWREG( GPIO_PORTG_AHB_BASE + GPIO_O_DR8R ) |= EPI_PORTG_PINS;
    	HWREG( GPIO_PORTG_AHB_BASE + GPIO_O_AFSEL ) |= EPI_PORTG_PINS;
    
    	HWREG( GPIO_PORTH_AHB_BASE + GPIO_O_PCTL ) |= EPI_PORTH_PCTL;
    	HWREG( GPIO_PORTH_AHB_BASE + GPIO_O_DEN ) |= EPI_PORTH_PINS;
    	HWREG( GPIO_PORTH_AHB_BASE + GPIO_O_DR8R ) |= EPI_PORTH_PINS;
    	HWREG( GPIO_PORTH_AHB_BASE + GPIO_O_AFSEL ) |= EPI_PORTH_PINS;
    
    	HWREG( GPIO_PORTK_BASE + GPIO_O_PCTL ) |= EPI_PORTK_PCTL;
    	HWREG( GPIO_PORTK_BASE + GPIO_O_DEN ) |= EPI_PORTK_PINS;
    	HWREG( GPIO_PORTK_BASE + GPIO_O_DR8R ) |= EPI_PORTK_PINS;
    	HWREG( GPIO_PORTK_BASE + GPIO_O_AFSEL ) |= EPI_PORTK_PINS;
    
    	HWREG( GPIO_PORTL_BASE + GPIO_O_PCTL ) |= EPI_PORTL_PCTL;
    	HWREG( GPIO_PORTL_BASE + GPIO_O_DEN ) |= EPI_PORTL_PINS;
    	HWREG( GPIO_PORTL_BASE + GPIO_O_DR8R ) |= EPI_PORTL_PINS;
    	HWREG( GPIO_PORTL_BASE + GPIO_O_AFSEL ) |= EPI_PORTL_PINS;
    
    	HWREG( GPIO_PORTM_BASE + GPIO_O_PCTL ) |= EPI_PORTM_PCTL;
    	HWREG( GPIO_PORTM_BASE + GPIO_O_DEN ) |= EPI_PORTM_PINS;
    	HWREG( GPIO_PORTM_BASE + GPIO_O_DR8R ) |= EPI_PORTM_PINS;
    	HWREG( GPIO_PORTM_BASE + GPIO_O_AFSEL ) |= EPI_PORTM_PINS;
    
    	HWREG( GPIO_PORTN_BASE + GPIO_O_PCTL ) |= EPI_PORTN_PCTL;
    	HWREG( GPIO_PORTN_BASE + GPIO_O_DEN ) |= EPI_PORTN_PINS;
    	HWREG( GPIO_PORTN_BASE + GPIO_O_DR8R ) |= EPI_PORTN_PINS;
    	HWREG( GPIO_PORTN_BASE + GPIO_O_AFSEL ) |= EPI_PORTN_PINS;
    
    	HWREG( GPIO_PORTP_BASE + GPIO_O_PCTL ) |= EPI_PORTP_PCTL;
    	HWREG( GPIO_PORTP_BASE + GPIO_O_DEN ) |= EPI_PORTP_PINS;
    	HWREG( GPIO_PORTP_BASE + GPIO_O_DR8R ) |= EPI_PORTP_PINS;
    	HWREG( GPIO_PORTP_BASE + GPIO_O_AFSEL ) |= EPI_PORTP_PINS;
    
    	HWREG( GPIO_PORTQ_BASE + GPIO_O_PCTL ) |= EPI_PORTQ_PCTL;
    	HWREG( GPIO_PORTQ_BASE + GPIO_O_DEN ) |= EPI_PORTQ_PINS;
    	HWREG( GPIO_PORTQ_BASE + GPIO_O_DR8R ) |= EPI_PORTQ_PINS;
    	HWREG( GPIO_PORTQ_BASE + GPIO_O_AFSEL ) |= EPI_PORTQ_PINS;
    
    	//  Enable clock to EPI0 module
    	HWREG( SYSCTL_RCGCEPI ) |= ( SYSCTL_RCGCEPI_R0 );
    
    	//  Wait for EPI module to be ready
    	while (( HWREG( SYSCTL_PREPI ) & SYSCTL_PREPI_R0 ) != SYSCTL_PREPI_R0 )
    	{
    	}
    
    	//  Set the EPI divider to use half the system clock 60MHz
    	HWREG( EPI0_BASE + EPI_O_BAUD ) = 0x1;
    
    	//  Select SDRAM mode
    	HWREG( EPI0_BASE + EPI_O_CFG ) = 0x00000011;
    
    	//  Configure SDRAM mode
    	//  FREQ:
    	//      0x00000000 - 0-15 MHz
    	//      0x40000000 - 15-30 MHz
    	//      0x80000000 - 30-50 MHz
    	//      0xC0000000 - 50-100 MHz
    	//  RFSH:
    	//      0x04000000 - 1024 system ticks << 16
    	//  SIZE:
    	//      0x00000000 - 8MB
    	//      0x00000001 - 16MB
    	//      0x00000002 - 32MB
    	//      0x00000003 - 64MB
    #define EPI_FREQ            0xC0000000
    #define EPI_RFSH            0x04000000
    #define EPI_SIZE            0x00000000
    	HWREG( EPI0_BASE + EPI_O_SDRAMCFG ) = ( EPI_FREQ | EPI_RFSH | EPI_SIZE );
    
    	//  Set the SDRAM address mapping
    	HWREG( EPI0_BASE + EPI_O_ADDRMAP ) = ( EPI_ADDR_RAM_SIZE_256MB | EPI_ADDR_RAM_BASE_6 );
    
    	//  Wait for the SDRAM wake-up to complete
    	while ( HWREG( EPI0_BASE + EPI_O_STAT ) & EPI_STAT_INITSEQ )
    	{
    	}
    
    	/* Return one to indicate the C/C++ auto-initialization should occur */
    	return( 1 );
    }

  • Hi Bryan,

      I think I understand your questions now. At the moment I'm not sure if this is something to be concerned with. I just tried to modify  the linker command file for a simple TivaWare blinky example by adding the EXSDRAM (RWX) : origin = 0x60000000, length = 0x00800000. The code compiles and runs fine. In your bootloader code, if you don't declare and use any variables that are mapped to EXSDRAM then I don't think it will create the hard fault. Do you see any hard faults today just because of the EXSDRAM memory declared in the linker command file?

  • Bryan Radke said:
    When we run our debugger through JTAG, there is nothing to enable the EPI ahead of time, meaning we will run into hard faults since the memory could not be initialized. My question is how can we enable the EPI so that the memory can be mapped by the linker, and have the code able to be debugged through the JTAG.

    It is possible to create a GEL script which initialises the EPI when a debug session is started. Where GEL is a 'C' like scripting language which runs on the PC and can access memory / registers on the target.

    The use of GEL to initial the external memory interface prior to loading a program with JTAG is common for TI processors. E.g. see ccs/ccs_base/emulation/boards/beaglebone/gel/beagleboneblack.gel in a CCS installation.

  • Hello Chester,

    It sounds like this is what we'll need. I'll review the GEL tomorrow and flag your response if it corrects my issue.

  • Hey Chester,

    My install of CCS does not have the beaglebone GEL. I setup the hook function below in the script, and could see from the console it was executed. However, when the application code is run, the EPI module is disabled again. I put the same line of code in our application code before I check the module state, and it will successfully enable the module. So, it appears I have this setup in the wrong area? Any advice?

    OnPreFileLoaded()
    {
        //  Enable clock to EPI0 module
        *(int *)0x400FE610 |= ( 1 );
        
        GEL_TextOut("\nExternal EPI Initialization Complete\n");
    }
  • Bryan Radke said:
    So, it appears I have this setup in the wrong area?

    With CCS 10.1 I modified the GEL script to report when the following callbacks occurs, along with the value of the SYSCTL_RCGCEPI register (and the Program counter for OnFileLoaded):

    OnPreFileLoaded()
    {
        GEL_TextOut ("OnPreFileLoaded SYSCTL_SYSCTL_RCGCEPI=%u\n",,,,,SYSCTL_SYSCTL_RCGCEPI);
    }
    
    OnFileLoaded()
    {
        GEL_TextOut ("OnFileLoaded SYSCTL_SYSCTL_RCGCEPI=%u PC=0x%x\n",,,,,SYSCTL_SYSCTL_RCGCEPI, PC);
    }
    
    OnTargetConnect()
    {
        GEL_TextOut ("OnTargetConnect SYSCTL_SYSCTL_RCGCEPI=%u\n",,,,,SYSCTL_SYSCTL_RCGCEPI);
    }
    
    OnReset()
    {
        GEL_TextOut ("OnReset SYSCTL_SYSCTL_RCGCEPI=%u\n",,,,,SYSCTL_SYSCTL_RCGCEPI);
    }
    
    OnResetDetected()
    {
        GEL_TextOut ("OnResetDetected SYSCTL_SYSCTL_RCGCEPI=%u\n",,,,,SYSCTL_SYSCTL_RCGCEPI);
    }

    I found that GEL knows the names of the registers defined for the device under the CCS "Registers" view, which avoided having to code the address within the GEL script. The registers known to GEL are name <module_name>_<register_name> where the module name and register name are those shown in the Registers view in the CCS debugger.

    The CCS console output when starting a debug session, on a target which was running a program which had enabled the EPI interface for SDRAM access was:

    CORTEX_M4_0: GEL Output: 
    Memory Map Initialization Complete
    CORTEX_M4_0: GEL Output: OnTargetConnect SYSCTL_SYSCTL_RCGCEPI=1
    CORTEX_M4_0: GEL Output: OnPreFileLoaded SYSCTL_SYSCTL_RCGCEPI=1
    CORTEX_M4_0: GEL Output: OnReset SYSCTL_SYSCTL_RCGCEPI=1
    CORTEX_M4_0: GEL Output: OnResetDetected SYSCTL_SYSCTL_RCGCEPI=1
    CORTEX_M4_0: GEL Output: OnResetDetected SYSCTL_SYSCTL_RCGCEPI=0
    CORTEX_M4_0: GEL Output: OnFileLoaded SYSCTL_SYSCTL_RCGCEPI=0 PC=0x0x00001AFD

    And the Program Counter when the OnFileLoaded callback happened was _c_int00_noargs() which is the program entry point.

    This shows that a device reset occurs after the OnPreFileLoaded callback has occurred, which explains your observation that the EPI module was disabled when the application started.

    Looking at the Debug project properties showed that the only Reset enabled was Flash Settings -> Reset target during program load to flash memory. I tried deselecting the option to "Reset target during program load" but the program wasn't flashed correctly.

    Bryan Radke said:
    Any advice?

    Given the OnFileLoaded() callback occurs after the device has been reset following programming flash, and before the program entry point has been called, suggest moving your EPI initialisation to the OnFileLoaded() callback.

  • I am waiting on hardware availability to check this solution.