plinder13 wrote on Thursday, August 09, 2007:
CCE says that to mix assembler and C, always use CALLA and RETA in the assembler. This implies that all the functions use this, as otherwise a C function could be called from assembler with a CALLA that returned with a RET.
I figured out my bug - I was writing to an undefined are of the SFRs - pointer issue. The debugger was masking it as it is slow and awkward with the MSP430X.
Here are some snippets of my port. Note that the portSTACK_TYPE should be portSTACK_SHORT as in other MSP430 ports, even though some function pointers are 20-bits. This works because all stack pointers are in RAM and are 16-bit.
#define portSAVE_CONTEXT()
asm ( " pushm.a #12,r15");
asm ( " movx.w usCriticalNesting,r15");
asm ( " pushx.w r15");
asm ( " movx.w pxCurrentTCB,r12");
asm ( " movx.w r1,0(r12)");
#define portRESTORE_CONTEXT()
asm ( " movx.w pxCurrentTCB, r12");
asm ( " movx.w 0(r12),r1");
asm ( " popx.w r15");
asm ( " movx.w r15,usCriticalNesting");
asm ( " popm.a #12,r15");
asm ( " reti" );
void vPortYield( void )
{
/* We want the stack of the task being saved to look exactly as if the task
was saved during a pre-emptive RTOS tick ISR. Before calling an ISR the
msp430 places the status register onto the stack. As this is a function
call and not an ISR we have to do this manually. */
asm ( " pushx.w r2" );
_DINT();
/* Make stack look like we entered form an ISR instead of a CALLA */
asm ( " bicx.w #0xF000,0(r1)");
asm ( " swpbx.w +4(r1)");
asm ( " rlax.w +4(r1)");
asm ( " rlax.w +4(r1)");
asm ( " rlax.w +4(r1)");
asm ( " rlax.w +4(r1)");
asm ( " addx.w +4(r1),0(r1)");
asm ( " movx.w +2(r1),+4(r1)");
asm ( " movx.w 0(r1),+2(r1)" );
asm ( " incdx.a r1");
…
The pushm.x #n,Rx instruction and corresponding popm.x instruction, while placing n registers on the stack with one instruction, place the registers on the stack in the opposite order of pushing and popping one at a time. Therefore, the pxPortInitialiseStack function needs to account for this and reverse the R4 to R15 initialization values.
portSTACK_TYPE *pxPortInitialiseStack( portSTACK_TYPE *pxTopOfStack, pdTASK_CODE pxCode, void *pvParameters )
{
/*
Place a few bytes of known values on the bottom of the stack.
This is just useful for debugging and can be included if required.
*pxTopOfStack = ( portSTACK_TYPE ) 0x1111;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x2222;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x3333;
pxTopOfStack–;
*/
/* The msp430 automatically pushes the PC then SR onto the stack before
executing an ISR. We want the stack to look just as if this has happened
so place a pointer to the start of the task on the stack first - followed
by the flags we want the task to use when it starts up. */
*pxTopOfStack = ( portSTACK_TYPE ) pxCode;
pxTopOfStack–;
*pxTopOfStack = ((( portSTACK_TYPE )((((unsigned long)(pxCode)) >>4) & (0x0000F000))) | portFLAGS_INT_ENABLED);
//*pxTopOfStack = portFLAGS_INT_ENABLED;
pxTopOfStack–;
/* Next the general purpose registers. */
/* When the task starts is will expect to find the function parameter in
R15. */
*pxTopOfStack = (portSTACK_TYPE) ((((unsigned long)pvParameters)>>16) & (0x0000000F));
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) pvParameters;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000e;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0xeeee;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000d;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0xdddd;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000c;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0xcccc;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000b;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0xbbbb;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x000a;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0xaaaa;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0009;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x9999;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0008;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x8888;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0007;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x7777;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0006;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x6666;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0005;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x5555;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x0004;
pxTopOfStack–;
*pxTopOfStack = ( portSTACK_TYPE ) 0x4444;
pxTopOfStack–;
/* The code generated by the mspgcc compiler does not maintain separate
stack and frame pointers. The portENTER_CRITICAL macro cannot therefore
use the stack as per other ports. Instead a variable is used to keep
track of the critical section nesting. This variable has to be stored
as part of the task context and is initially set to zero. */
*pxTopOfStack = ( portSTACK_TYPE ) portNO_CRITICAL_SECTION_NESTING;
/* Return a pointer to the top of the stack we have generated so this can
be stored in the task control block for the task. */
return pxTopOfStack;
}
Penn