Hardfault on LPC4357 when external Ram used as heap

meowww1988 wrote on Tuesday, April 12, 2016:

Hi,

I am using MT48LC4M32B2P-128MBit ram on the board. It is interfaced with 32bit databus. I am able to write and read from the ram, hence I am sure the initialisation is proper.

When I use internal ram with heap_4.c my code runs perfectly fine, but when I use heap_5.c to use the external ram as heap, I get a hardfault. I did step by step debugging and found that whenever there is a xTaskCreate or xQueueCreate call, there is some activity in the Ram, I can see it in the memory window, I am assuming there is no problem in creation of Queues and Task. On further stepping through I found that the code goes to hard fault at the svc 0 instruction in prvStartFirstTask.

I am initialising the heap as below and then calling the function in main before any calls to RTOS functions.

static void prvInitialiseHeap( void )
{
const HeapRegion_t xHeapRegions[] =
{

	{(uint8_t*)0x28000000UL,0x20000},
	{ NULL, 0 }
    
};

vPortDefineHeapRegions( xHeapRegions );

}

Hardfault come here

__asm void prvStartFirstTask( void )
{
PRESERVE8

/* Use the NVIC offset register to locate the stack. */
ldr r0, =0xE000ED08
ldr r0, [r0]
ldr r0, [r0]
/* Set the msp back to the start of the stack. */
msr msp, r0
/* Globally enable interrupts. */
cpsie i
cpsie f
dsb
isb
/* Call SVC to start the first task. */
svc 0   <--------<--------<-------<-------<--------<
nop
nop

}

Can anybody help regarding the issue? Thanks.

rtel wrote on Tuesday, April 12, 2016:

static void prvInitialiseHeap( void )
{
const HeapRegion_t xHeapRegions =
{

 {(uint8_t*)0x28000000UL,0x20000},
 { NULL, 0 }

};

If you only have one memory region then you can do this with heap_4.c
too - look at the configAPPLICATION_ALLOCATED_HEAP configuration
constant, which allows you to declare the array used as the heap
yourself, and so place it where you like. HOWEVER, if you place it in
external RAM, make sure you do not place it in a linker segment that
means the C start up code tries to access it (to, for example, clear it
to 0) before the external RAM has been configured.

/* Call SVC to start the first task. */
svc0<--------<--------<-------<-------<--------<

Normally this would be because the SVC handler was not installed in the
vector table correctly, but the fact that the code runs with the heap in
internal RAM discounts that possibility (assuming everything else is the
same).

Two thoughts come to mind:

  1. If the heap is in external RAM then the stack will be in external RAM
    too. Is it permitted to have the stack in external RAM with regards to
    speed, access cycles, etc.?

  2. The SVC instruction might not be the place where the error actually
    occurs - but the instruction is jumping to a task and the abort happens
    in the task instead. Have you tried debugging the abort using the code
    fragment on this page:
    Debugging and diagnosing hard faults on ARM Cortex-M CPUs
    Also, determine which task is going to run first, and place a break
    point at the very top of that task (before the function prologue code
    executes) to see if the break point is ever hit.

meowww1988 wrote on Tuesday, April 12, 2016:

I tried the first option of using heap_4.c, but getting the same results as earlier. As of now I am trying with only one task without any block statements/conditions. To confirm ram write speeds, I made a task and wrote 1MB of data as below, my tick rate is 1000Hz

	ramdata = (uint32_t *)SDRAM_ADDR_BASE;
	for(;;)
	{
		
			timeFrame = xTaskGetTickCount();
			for(i=0;i<0x40000;i++)
			{
				*ramdata++=i;
			}
			timeFrame = xTaskGetTickCount() - timeFrame;	
			ramdata = (uint32_t *)SDRAM_ADDR_BASE;
			tinySprintf(txBuffer,"\r\nW %0d",timeFrame);
			printString(txBuffer);
			
			timeFrame = xTaskGetTickCount();
			for(i=0;i<0x40000;i++)
			{
				*ramdata++=0;
			}
			timeFrame = xTaskGetTickCount() - timeFrame;	
			ramdata = (uint32_t *)SDRAM_ADDR_BASE;
			tinySprintf(txBuffer,"\r\nO %0d",timeFrame);
			printString(txBuffer);			
			
	}

This gives me values of 1MB of data per 8ms if I use a uint32_t pointer and 1MB of data per 30ms if I use uint8_t pointer. So 125MB/s for 32 bit writes and 33MB/s for 8 bit writes. My microcontroller is running at 204MHz. Are the write speeds good enough for the requirement.

I am trying to implement your 2nd suggestion of using the hard fault exception to catch some data. Will get back with the results.

davedoors wrote on Tuesday, April 12, 2016:

Try also a breakpoint on vPortSVCHandler() in port.c. If it executes you can step from there to see where the fault comes.

meowww1988 wrote on Tuesday, April 12, 2016:

After a lot of single stepping, I think I figured where the code is actually hanging. It is hanging in this function. Although the same function was called many times during the single stepping, didn’t count at what call it managed to cause a fault.

static portFORCE_INLINE void vPortRaiseBASEPRI( void )
{
uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;

	__asm
	{
		/* Set BASEPRI to the max syscall priority to effect a critical
		section. */
		msr basepri, ulNewBASEPRI
		dsb
		isb
	}
}

Any clues why it might be happening?

davedoors wrote on Tuesday, April 12, 2016:

Do you have the MPU turned on? Maybe you dropped out of privileged mode and fault when accessing the basepri register?

meowww1988 wrote on Tuesday, April 12, 2016:

No, I have not turned ON the MPU, by default it is Off I presume.

meowww1988 wrote on Wednesday, April 13, 2016:

I tried compiling the code given at the link. Got this code from a friend, will this work. I am not well versed in assembly.

void HardFault_Handler(unsigned long *hardfault_args){
                volatile unsigned long stacked_r0 ;
                volatile unsigned long stacked_r1 ;
                volatile unsigned long stacked_r2 ;
                volatile unsigned long stacked_r3 ;
                volatile unsigned long stacked_r12 ;
                volatile unsigned long stacked_lr ;
                volatile unsigned long stacked_pc ;
                volatile unsigned long stacked_psr ;
                volatile unsigned long _CFSR ;
                volatile unsigned long _HFSR ;
                volatile unsigned long _DFSR ;
                volatile unsigned long _AFSR ;
                volatile unsigned long _BFAR ;
                volatile unsigned long _MMAR ;

                stacked_r0 = ((unsigned long)hardfault_args[0]) ;
                stacked_r1 = ((unsigned long)hardfault_args[1]) ;
                stacked_r2 = ((unsigned long)hardfault_args[2]) ;
                stacked_r3 = ((unsigned long)hardfault_args[3]) ;
                stacked_r12 = ((unsigned long)hardfault_args[4]) ;
                stacked_lr = ((unsigned long)hardfault_args[5]) ;
                stacked_pc = ((unsigned long)hardfault_args[6]) ;
                stacked_psr = ((unsigned long)hardfault_args[7]) ;

        // Configurable Fault Status Register
        // Consists of MMSR, BFSR and UFSR
                _CFSR = (*((volatile unsigned long *)(0xE000ED28))) ;     
                                                                                                                                                                                
                // Hard Fault Status Register
                _HFSR = (*((volatile unsigned long *)(0xE000ED2C))) ;

                // Debug Fault Status Register
                _DFSR = (*((volatile unsigned long *)(0xE000ED30))) ;

                // Auxiliary Fault Status Register
                _AFSR = (*((volatile unsigned long *)(0xE000ED3C))) ;

                // Read the Fault Address Registers. These may not contain valid values.
                // Check BFARVALID/MMARVALID to see if they are valid values
                // MemManage Fault Address Register
                _MMAR = (*((volatile unsigned long *)(0xE000ED34))) ;
                // Bus Fault Address Register
                _BFAR = (*((volatile unsigned long *)(0xE000ED38))) ;

                __asm("BKPT #0\n") ; // Break into the debugger

}

meowww1988 wrote on Monday, April 18, 2016:

I captured the data as required from the hard fault. My external ram is situated at 0x28000000

Captured values as below

stacked_r0 = 0x28000978
stacked_r1 = 0x00000000
stacked_r2 = 0x00000003
stacked_r3 = 0x00000000
stacked_r12 = 0x00000003
stacked_lr = 0x00000001
stacked_pc = 0x00000000
stacked_psr = 0x00000000

CFSR = 0x00000400
HFSR = 0x40000000
DFSR = 0x00000000
AFSR = 0x00000000
BFAR = 0xE000ED38
MMAR = 0xE000ED34