manually write to stack

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

manually write to stack

Jump to solution
1,357 Views
dementeddigital
Contributor II

I'm working on a module to monitor the stack usage in my KE06 project (in KDS).  The concept is:

 

To detect the peak stack usage, the initialization function writes 0x00 to each unused memory location in the stack.  It writes from the bottom of the stack up to the stack pointer.  Then when the stack monitor function is called, it goes through the stack and it counts the locations still with 0x00 (presumably these were unused).  It calculates the percentage of the stack used and saves this in a variable for “live” viewing via CAN.  This same strategy is used (and works well) on other projects.  I’m getting a hard fault here during the initialization, however.

 

In the debugger, the stack pointer resolves correctly.  I get one single write to the bottom of the stack, and on the second write it hard faults.  Any thoughts as to why?

 

#define STACK_START_ADDR              0x20002C00  // MCU stack starting address

#define STACK_TOP_ADDR                0x20003000  // MCU stack top address (see Memory mapping)

#define STACK_ERASED_VALUE            0x00        // Value used to identify erase stack memory

 

void STACK_Initialize( void )

{

    uint32 u32Addr;

      register uint32 sp asm ("sp");

    for ( u32Addr=STACK_START_ADDR; u32Addr < sp; u32Addr++ )  // Fill unused stack with erased values

    {

        *(uint32*)u32Addr = STACK_ERASED_VALUE;   //<----hard faults here the the second time through the loop

    }

}

 

1 Solution
1,200 Views
ndavies
Contributor V

I'm not sure if this is your issue:

Your for loop isn't doing what you expect. You have incorrectly used the pointer.  You have defined uint32 u32Addr. It should be defined as uint32 *u32Addr. Without the * in the definition, u32Addr is only incremented by one during the u32Addr++ in the for loop. By adding the * to the definition, the compiler then understands u32Addr is a pointer and gets incremented by 4 when you do the post increment in the for loop. It should also remove the need for the cast in the for loops assignment.

Your for loop will cause 4 times as many writes as needed, misaligned writes for 3 out of 4 of the writes and corrupts your stack on the last 2 or 3 writes. You are doing a 4 byte write but only incrementing the not properly defined pointer by 1 byte.

View solution in original post

3 Replies
1,201 Views
ndavies
Contributor V

I'm not sure if this is your issue:

Your for loop isn't doing what you expect. You have incorrectly used the pointer.  You have defined uint32 u32Addr. It should be defined as uint32 *u32Addr. Without the * in the definition, u32Addr is only incremented by one during the u32Addr++ in the for loop. By adding the * to the definition, the compiler then understands u32Addr is a pointer and gets incremented by 4 when you do the post increment in the for loop. It should also remove the need for the cast in the for loops assignment.

Your for loop will cause 4 times as many writes as needed, misaligned writes for 3 out of 4 of the writes and corrupts your stack on the last 2 or 3 writes. You are doing a 4 byte write but only incrementing the not properly defined pointer by 1 byte.

1,200 Views
dementeddigital
Contributor II

Yes, this is exactly the issue.  I found it yesterday just before I went home, and your comment confirms it.

I fixed it by incrementing by 4 in the loop, but I see now _why_ the compiler didn't handle it the way I wanted.  I'll adjust the pointer definition and go back to incrementing by 1.

Thanks for the reply!  Very helpful!

0 Kudos
Reply
1,200 Views
bobpaddock
Senior Contributor III

Are interrupts turned off?

Using the correct stack for your part?

For GCC:
static __inline__ void *sp_get(void)
{
void *sp;

__asm__ __volatile__ ("mrs %0, msp" : "=r"(sp));

return( sp );
}

Replace msp with psp if using other stack.

A version in pure C that makes Lint explode for returning the address of a local variable:

/*
* void *CheckStackDepth( void )
* {
* volatile uint32_t dummy; // Put a variable on the stack
* return( (void *) &dummy ); // Return its address - therefore the (approx.) present SP value
* }
*/

Obscure GCC syntax for setting Link and Stack pointers:


static __inline__ void psp_set( void *setval )
{
__asm__ volatile ("msr psp, %[value]\n\t""dmb\n\t""dsb\n\t""isb\n\t"::[value]"r"(setval):);
__asm__ volatile ("" ::: "memory");
}

static __inline__ void lr_set(uint32_t setval)
{ __asm__ volatile ("mov lr, %[value]\n\t"::[value]"r"(setval):);
__asm__ volatile ("" ::: "memory");
}

Unless debugging is an obsession disable interrupts when doing any of the above operations:

See atomic.h.zip in this tread for the GCC ARM code to do save/restore of the IRQ state.

https://community.nxp.com/message/816609?commentID=816609#comment-816609 

0 Kudos
Reply