Undertanding Context switch of ARM v7

i have beaglebone black board and i am tring to port it.. i found some coding about context switch like ~~~

define portRESTORE_CONTEXT()

{ extern volatile void * volatile pxCurrentTCB; extern volatile unsigned portLONG ulCriticalNesting; /* Set the LR to the task stack. */ __asm volatile ( “LDR R0, =pxCurrentTCB nt” “LDR R0, [R0] nt” “LDR LR, [R0] nt” /* The critical nesting depth is the first item on the stack. */ /* Load it into the ulCriticalNesting variable. */ “LDR R0, =ulCriticalNesting nt” “LDMFD LR!, {R1} nt” “STR R1, [R0] nt” /* Get the SPSR from the stack. */ “LDMFD LR!, {R0} nt” “MSR SPSR, R0 nt” /* Restore all system mode registers for the task. */ “LDMFD LR, {R0-R14}^ nt” “NOP nt” /* Restore the return address. */ “LDR LR, [LR, #+60] nt” /* And return – correcting the offset in the LR to obtain the */ /* correct address. */ “SUBS PC, LR, #4 nt” ); ( void ) ulCriticalNesting; ( void ) pxCurrentTCB; } ~~~ in the following code we have switched to system mode (because the first task has 0x1F as SPSR) ~~~ /* Get the SPSR from the stack. */ “LDMFD LR!, {R0} nt” “MSR SPSR, R0 nt” ~~~ but the next instruction read LR still from Supervisor Mode ~~~ LDR LR, [LR, #+60] ~~~ can someone tell how this happend. i expected after setting SPSR to 0x1F that LR point to banked LR of System mode and not of Supervisor Mode. the LR in system mode has a dummy value like 0x0a0a0a0a.

Undertanding Context switch of ARM v7

ARMv7 what? Not M so probably A. Is the problem on the first context switch? What mode was the Cortex in when vTaskSwitchContext() is called?

Undertanding Context switch of ARM v7

beaglebone black come with AM335x which is ARMv7 Cortex-A 8. there is no problem with the code .. it works for the first context switch. i have made some research and understanfs now what LDMFD LR, {R0-R14}^ exactly what ‘^’ means. in ARM Manual :
^
is an optional suffix. You must not use it in User mode or System mode. It has two purposes:

    If op is LDM and reglist contains the pc (r15), in addition to the normal multiple register transfer, the SPSR is copied into the CPSR. This is for returning from exception handlers. Use this only from exception modes.

    Otherwise, data is transferred into or out of the User mode registers instead of the current mode registers.
but what i am still not understand the code was running in supervisor mode and the code ~~~ “LDMFD LR!, {R0} nt” “MSR SPSR, R0 nt” ~~~ only store the SPSR but not change the execution mode. after changing PC to call the first task code the execution mode changed to system mode .. this what i still not understands

Undertanding Context switch of ARM v7

Using a LPC2132 board with working: LCD driver LED port driver (8 segments) Keypad driver (interrupt driven using vector irq or firq) I try to initialize minimal hardware (which makes no difference) and make a call to xPortStartScheduler(). In portRESTORECONTEXT() macro I am getting a DATAABORT exception: LR = 0x0aaaaaaaa SPSR = 0x200000df Addr = the following line in portRESTORE_CONTEXT() /* Restore the return address. */ “LDR LR, [LR, #+60]”
The LR has a value of 0xaaaaaaaa which is why the exception occurs.
That address is in the reserved area on chip.
The 0xaaaaaaaa is written to a stack area in pxPortInitialiseStack() 

StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
{ StackType_t *pxOriginalTOS;
    pxOriginalTOS = pxTopOfStack;

    /* To ensure asserts in tasks.c don't fail, although in this case the assert
    is not really required. */
    pxTopOfStack--;

    /* Setup the initial stack of the task.  The stack is set exactly as
    expected by the portRESTORE_CONTEXT() macro. */

    /* First on the stack is the return address - which in this case is the
    start of the task.  The offset is added to make the return address appear
    as it would within an IRQ ISR. */
    *pxTopOfStack = ( StackType_t ) pxCode + portINSTRUCTION_SIZE;
    pxTopOfStack--;

    *pxTopOfStack = ( StackType_t ) 0xaaaaaaaa;     /* R14 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) pxOriginalTOS; /* Stack used when task starts goes in R13. */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x12121212;     /* R12 */
    pxTopOfStack--;
    *pxTopOfStack = ( StackType_t ) 0x11111111;     /* R11 */
    pxTopOfStack--;

The call stack is:

xPortStartScheduler():
  vPortISRStartFirstTask();
    portRESTORE_CONTEXT();
I am using FreeRTOSv9.0.0/FreeRTOS/Source/portable/GCC/ARM7_LPC2000/port.c Any idea what to change?

Undertanding Context switch of ARM v7

Its been a while since I used an ARM7 port, but from memory I would say your problem is almost certainly due to having the MCU in the wrong mode when xPortStartScheduler() is called. Make sure the MCU is in Supervisor mode, and definitely not in User mode. The mode is normally set in the start up code before main() is called.

Undertanding Context switch of ARM v7

I see that in section 6.3 (Troubleshooting). I made the change to supervisor mode and still get a data abort with spsr = 0x200000d3. It has been a while since I used an ARM7 too, last projects were a LPC1769 (Cortex M3) and a STM32f7Discovery (Cortex M7). SPSR = 0x200000d3 C flag I flag F flag Mode = 0x13 (SVC)

Undertanding Context switch of ARM v7

Please attach your start up file (the file that sets up the stacks for each CPU mode).

Undertanding Context switch of ARM v7

Here is the relevant section. I can attach the entire contents of the startup file if necessary.
.equ USR_MODE,   0x10
.equ FIQ_MODE,   0x11
.equ IRQ_MODE,   0x12
.equ SVC_MODE,   0x13
.equ ABT_MODE,   0x17
.equ UND_MODE,   0x1B
.equ SYS_MODE,   0x1F

.equ UND_STACK_SIZE,  0x00000010
.equ ABT_STACK_SIZE,  0x00000010
.equ FIQ_STACK_SIZE,  0x00000080
.equ IRQ_STACK_SIZE,  0x00000080
.equ SVC_STACK_SIZE,  0x00000400
.equ SYS_STACK_SIZE,  0x00000400

.equ IRQ_DISABLE,  (1 << 7)
.equ FIQ_DISABLE,  (1 << 6)

ldr r0, STACK_START

/* Undefined mode stack */
msr CPSR_c, #UND_MODE | IRQ_DISABLE | FIQ_DISABLE
mov sp, r0
sub r0, r0, #UND_STACK_SIZE

/* Abort mode stack */
msr CPSR_c, #ABT_MODE | IRQ_DISABLE | FIQ_DISABLE
mov sp, r0
sub r0, r0, #ABT_STACK_SIZE

/* FIQ mode stack */
msr CPSR_c, #FIQ_MODE | IRQ_DISABLE | FIQ_DISABLE
mov sp, r0
sub r0, r0, #FIQ_STACK_SIZE

/* IRQ mode stack */
msr CPSR_c, #IRQ_MODE | IRQ_DISABLE | FIQ_DISABLE
mov sp, r0
sub r0, r0, #IRQ_STACK_SIZE

/* Supervisor mode stack */
msr CPSR_c, #SVC_MODE | IRQ_DISABLE | FIQ_DISABLE
mov sp, r0
sub r0, r0, #SVC_STACK_SIZE

/* System mode stack */
msr CPSR_c, #SYS_MODE | IRQ_DISABLE | FIQ_DISABLE
mov sp, r0

/* Start in supervisor mode */
msr CPSR_c, #SVC_MODE | IRQ_DISABLE | FIQ_DISABLE
bl  main
b    .

STACK_START:.word   __stack_start__

__stack_start__ equates to __ram_end__ which is 0x40004000

/*
 * Linker script for LPC2132 ARM7 MCU
 *
 *
 * __ram_end__       +--------------+ __stack_start__
 *                   |              |
 *                   |     Stack    |
 *                   |              |
 *                   +--------------+ __stack_end__
 *                   |              |
 *                   |     heap     |
 *                   |              |
 *                   +--------------+ __bss_end__
 *                   |              |
 *                   |     .bss     |
 *                   |              |
 *                   +--------------+ __bss_start__
 *                   |    .data     | __data_end__
 *                   |Virtual Memory|
 *                   | Address (VMA)|
 * __ram_start__     +--------------+ __data_start__
 *
 * __flash_end__     +--------------+
 *                   |              |
 *                   |     empty    |
 *                   |              |
 *                   +--------------+
 *                   |    .data     |
 *                   | Load Memory  |
 *                   | Address (LMA)|
 *                   +--------------+ __text_end__
 *                   |              |
 *                   |   .rodata    |
 *                   |              |
 *                   +--------------+
 *                   |              |
 *                   |    .text     |
 *                   |              |
 *                   +--------------+
 *                   |   .startup   |
 *  __flash_start__  +--------------+ __text_start__
 */

Undertanding Context switch of ARM v7

I found a typing fix for this file: FreeRTOSv9.0.0/FreeRTOS/Source/portable/GCC/ARM7_LPC2000/portmacro.h” line 120 of 269 /* * portRESTORECONTEXT, portRESTORECONTEXT, portENTERSWITCHINGISR * and portEXITSWITCHINGISR can only be called from ARM mode, but * are included here for efficiency. An attempt to call one from * THUMB mode code will result in a compile time error. */ Edit the second “portRESTORECONTEXT” to read as “portSAVECONTEXT”.

Undertanding Context switch of ARM v7

After removing the “^” from the line in portRESTORE_CONTEXT() to see what difference it made: LDMFD LR, {R0-R14}^ I had not restored it. Then adjusted the CSPR to SVC mode before calling main. Still got a data abort. After I restored the “^” things worked. Thanks for your time.

Undertanding Context switch of ARM v7

Refering to your start up file: The IRQ mode stack is much too small, and there is no need to set up a System mode stack as it will nevery be used.

Undertanding Context switch of ARM v7

I was going to tune the stack sizes later, but since you brought it up I really appreciate what you suggest and I will make the changes. The previous code I borrowed this from was a lpc2148 project I worked on about 8 years ago and the code started in SYS_MODE.

Undertanding Context switch of ARM v7

Look at the examples in the download, and copy them.



Undertanding Context switch of ARM v7

I have a few tasks running: 1. RTC timer values (seconds, minutes. etc) are read from RTC registers. 2. LED bank displays seconds and tenths of seconds. 3. 16 key keypad detects entry interrupt and decodes a key. 4. A LCD is printing the elapsed time, key entry, led count. It can run for a few hours with no hang up. A few times I have noticed a data abort within portISR.c at portRESTORE_CONTEXT.
void vPortYieldProcessor( void )
{
   /* Within an IRQ ISR the link register has an offset from the true return
address, but an SWI ISR does not.  Add the offset manually so the same
ISR return code can be used in both cases. */
__asm volatile ( "ADD       LR, LR, #4" );

/* Perform the context switch.  First save the context of the current task. */
portSAVE_CONTEXT();

/* Find the highest priority task that is ready to run. */
__asm volatile ( "bl vTaskSwitchContext" );

/* Restore the context of the new task. */
portRESTORE_CONTEXT();
} I was thinking that I might have to have some synchronization between reading the RTC registers and servicing the rtc interrupt. As the problems become fewer the complexity increases. As it is I am only using a 4 line with 20 characters per line LCD display. I just print out R13, R14, SPSR at the abort.

Undertanding Context switch of ARM v7

Did you increase the size of the IRQ stack, as per the comment a few posts above?

Undertanding Context switch of ARM v7

This happened twice in a row, same exact registers: Data Abort Exception: FreeRTOSv9.0.0/FreeRTOS/Source/portable/GCC/ARM7_LPC2000/portISR.c r0 = 0x40000024 (ulCriticalNesting) r1 = 0x40000060 (pxCurrentTCB + 4) r2 = 0x00000001 r3 = 0x4000013c (pxCurrentTCB + e0) r4 = 0x0000000e r5 = 0x05050505 r6 = 0x06060606 r7 = 0x400004f0 (in the heap) r8 = 0x08080808 r9 = 0x09090909 r10=0x10101010 r11=0x40003fec (Abort stack area , start = 0x40003ff0 length = 0x10) r12=0x0000320d r13=0x40003fcc (IRQ stack area, start = 0x40003fd0 length = 0x800) r14=0x00004a34 spsr=0x20000093
    /* Restore the context of the new task. */
    portRESTORE_CONTEXT();
4a20:       e59f01fc        ldr     r0, [pc, #508]  ; 4c24 <vPortExitCritical+0x64>
4a24:       e5900000        ldr     r0, [r0]
4a28:       e590e000        ldr     lr, [r0]
4a2c:       e59f01f4        ldr     r0, [pc, #500]  ; 4c28 <vPortExitCritical+0x68>
4a30:       e8be0002        ldm     lr!, {r1}
4a34:       e5801000        str     r1, [r0]
4a38:       e8be0001        ldm     lr!, {r0}
4a3c:       e169f000        msr     SPSR_fc, r0
4a40:       e8de7fff        ldm     lr, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, sl, fp, ip, sp, lr}^
4a44:       e1a00000        nop                     ; (mov r0, r0)
4a48:       e59ee03c        ldr     lr, [lr, #60]   ; 0x3c
4a4c:       e25ef004        subs    pc, lr, #4
4a50:       e59f300c        ldr     r3, [pc, #12]   ; 4a64 <swi_handler+0xa8>
4a54:       e5933000        ldr     r3, [r3]
4a58:       e59f3008        ldr     r3, [pc, #8]    ; 4a68 <swi_handler+0xac>
4a5c:       e5933000        ldr     r3, [r3]
}
4a60:       e1a00000        nop                     ; (mov r0, r0)
4a64:       40000024        .word   0x40000024
4a68:       4000005c        .word   0x4000005c
After adding code to display exception registers and use the the stack checking feature I found that I had to adjust comfigMINIMALSTACKSIZE. Since I’m only working with 16K sram I have to careful with memory use. I’m planning to make a few modifications so that a certain key press will display the stack high water marks for the running tasks. Thank you to Real Time Engineers for your comments.