Port from CM3 to CM0 Problems

blindeye2 wrote on Thursday, May 23, 2013:

Developing under Keil.  Have been developing and executing for CM3 based NXP processor for several months.  Trying to port same code to CM0 based processor but get several compiler errors from port.c and assemble errors from my startup file.   I assume I should be using a different port.c but am unclear which one to choose from or whether there is one delivered with the standard FreeRTOS download.  I am using the port.c in the RVDS\ARM_CM3 directory and the FreeRTOS version is 7.3.0.  Below are the errors I am getting.

…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(197): error: A1874E: Specified register list cannot be loaded or stored in target instruction set
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(199): error: A1859E: Flag preserving form of this instruction not available
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(200): error: A1477E: This register combination results in UNPREDICTABLE behaviour
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(201): error: A1618E: Specified instruction is not supported by the current instruction set
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(292): error: A1874E: Specified register list cannot be loaded or stored in target instruction set
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(296): error: A1859E: Flag preserving form of this instruction not available
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(297): error: A1477E: This register combination results in UNPREDICTABLE behaviour
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(299): error: A1859E: Flag preserving form of this instruction not available
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(300): error: A1477E: This register combination results in UNPREDICTABLE behaviour
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(301): error: A1874E: Specified register list cannot be loaded or stored in target instruction set
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(305): error: A1874E: Specified register list cannot be loaded or stored in target instruction set
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(474): error: A1477E: This register combination results in UNPREDICTABLE behaviour
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(475): error: A1859E: Flag preserving form of this instruction not available
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(476): error: A1477E: This register combination results in UNPREDICTABLE behaviour
…\…\…\…\validation_framework\FreeRTOSV7.3.0\FreeRTOSV7.3.0\FreeRTOS\Source\portable\RVDS\ARM_CM3\port.c(485): error: A1477E: This register combination results in UNPREDICTABLE behaviour

rtel wrote on Thursday, May 23, 2013:

You won’t be able to use the CM3 port on a CM0.  There are official FreeRTOS CM0 ports for IAR and GCC, but unfortunately not Keil.  You may find an NXP Keil port on http://www.lpcware.com if you are lucky, but the NXP port is slightly different to the FreeRTOS distributed code.

You could probably create a port by comparing the GCC CM3 port.c and portmacro.h with their CM0 equivalents.  The main difference is going to be in the assembly code used to context switch because the CM0 needs to access the ‘high’ registers separately from the ‘low’ registers, whereas the CM3 just accesses (that is, pushes and pops) all the registers at once.

Regards.

blindeye2 wrote on Thursday, May 30, 2013:

Thanks Richard.  I ported this to CM0.  Seems to work although I haven’t done an exhaustive test suite on it.  If somebody wants the code, happy to post it.

xz8987f wrote on Thursday, July 25, 2013:

Hi blindeye2,
I porting FreeRTOS to Cortex-M0 with Keil, and I’m stuck at the same problem as you. You offered to post your solution/code, I would be happy to see how you solved the Keil assembly problem.

Thanks,
Erich

blindeye2 wrote on Thursday, July 25, 2013:

Hi Erich,

I’m currently traveling and don’t have access to the codebase.  I’ll try to get to this in the next couple of days.  Is it possible to upload files to this forum?   If not please send me an email address I can send them to.

rtel wrote on Thursday, July 25, 2013:

Regrettably it is not possible to upload code directly in this forum.  However, if you can upload code in the Interactive site (http://interactive.freertos.org), then post a link here.

Regards.

xz8987f wrote on Thursday, July 25, 2013:

Hi blindEye2,
ok, thanks for your offer. You might simply copy-paste your assembly code to reply. I think all the magic is in your implementation of vPortSVCHandler() and vPortSVCHandler(), so should be fairly short assembly code.

I’ll work until then if I can resolve the thing myself, just in case.

Thanks!
Erich

xz8987f wrote on Thursday, July 25, 2013:

Ok, I got it sorted out :slight_smile:
Still need some testing, but below is the code working with Keil and Cortex-M0+.

/*-----------------------------------------------------------*/
__asm void vPortStartFirstTask(void) {
  /* 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
  /* Call SVC to start the first task. */
  svc 0
  nop
	nop
}
/*-----------------------------------------------------------*/
__asm void vPortSVCHandler(void) {
  IMPORT pxCurrentTCB
  /* Get the location of the current TCB. */
  ldr r3, =pxCurrentTCB  /* Restore the context. */
  ldr r1, [r3]          /* Use pxCurrentTCBConst to get the pxCurrentTCB address. */
  ldr r0, [r1]          /* The first item in pxCurrentTCB is the task top of stack. */
  adds r0, #16          /* Move to the high registers. */
  ldmia r0!, {r4-r7}    /* Pop the high registers. */
  mov r8, r4 
  mov r9, r5 
  mov r10, r6
  mov r11, r7
  msr psp, r0           /* Remember the new top of stack for the task. */
  subs r0, #32          /* Go back for the low registers that are not automatically restored. */
  ldmia r0!, {r4-r7}    /* Pop low registers.  */
  mov r1, r14           /* OR R14 with 0x0d. */
  movs r0, #0x0d
  orrs r1, r0
  bx r1
}
/*-----------------------------------------------------------*/
__asm void vPortPendSVHandler(void) {
  EXTERN pxCurrentTCB
	IMPORT vTaskSwitchContext
	
  mrs r0, psp
	
  ldr r3, =pxCurrentTCB      /* Get the location of the current TCB. */
  ldr r2, [r3]
  subs r0, #32            /* Make space for the remaining low registers. */
  str r0, [r2]               /* Save the new top of stack. */
  stmia r0!, {r4-r7}         /* Store the low registers that are not saved automatically. */
  mov r4, r8                 /* Store the high registers. */
  mov r5, r9
  mov r6, r10
  mov r7, r11
  stmia r0!, {r4-r7}
  push {r3, r14}
  cpsid i
  bl vTaskSwitchContext
  cpsie i
  pop {r2, r3}               /* lr goes in r3. r2 now holds tcb pointer. */
  ldr r1, [r2]
  ldr r0, [r1]               /* The first item in pxCurrentTCB is the task top of stack. */
  adds r0, #16            /* Move to the high registers. */
  ldmia r0!, {r4-r7}         /* Pop the high registers. */
  mov r8, r4
  mov r9, r5
  mov r10, r6
  mov r11, r7
  msr psp, r0                /* Remember the new top of stack for the task. */
  subs r0, #32            /* Go back for the low registers that are not automatically restored. */
  ldmia r0!, {r4-r7}         /* Pop low registers.  */
  bx r3
}

I’m working on some details, as well supporting M4 with and without floating point unit.

Erich