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.
/* 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
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:
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.?
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.
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
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.
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
}
}