Porting HCS12 for GCC

I’m going to try to get FreeRTOS running on my C32 DIP module starting from HCS12 -> MC9S12C32 (small) http://www.freertos.org/porthcs12.html The problem is that I am using GCC instead of CodeWarrior. It’s just more available. Although I feel qualified to port the source for GCC, I wonder if anyone else is working or planning to make an official port to GCC. Some related links http://www.technologicalarts.ca/catalog/index.php/cPath/50_36 http://m68hc11.serveftp.org/

Porting HCS12 for GCC

I have not used GCC with this device, but I think the translation should be fairly straight forward.  GCC is a very flexible compiler in general and tends to make life easy. I think the original (unsupported) HCS12 port was configured so it could be built with either CodeWarrior or GCC.  It is still available here: http://www.realtimeengineers.com/hcs12.zip I should copy the code from the supported port rather than this, but it might be useful for reference to the needed GCC syntax.  It assumes the banked memory model. I have just taken a look at the HCS12 GCC manual.  One place to take care is interrupt function prologue and epilogue, and trap (SWI) function prologue and epilogue.  They are not the same.  Although the processor saves the registers it seems that GCC requires more data to be saved (soft registers).  All required data needs saving and restoring in both interrupt and SWI cases. As a tip to start I suggest setting the scheduler to use cooperative mode as this makes debugging much easier.  Then just create a single task that runs at the idle priority and calls portYIELD().  You should then get simply switching between that task and the idle task.  When you have that running you can try something more adventurous. Let us know how you get on. Regards.

Porting HCS12 for GCC

I didn’t mention before that I was working on the unsupported version before the supported version appeared. I realized that the supported version would be the better base, although I figure it will take some getting used to since 3.0 had significant changes. I will include the patch below (sorry if it’s not very readable). I felt like my work was ready for a first test, but didn’t test it. Here are some issues with portability: I addressed some interrupt details as you mentioned. I found that the gcc-m68hc1x port does not support the "naked" attribute, so I can’t tell it not to generate it’s own interrupt code. Also the code would need changed if the number of software registers (such as "._d0") changed The example is changed for no longer for CodeWarrior. The leftovers might make it hard to read. I tried to keep the port files switchable, but not sure since it’s not tested. The method of addressing IO ports is from the Ipac port in GEL examples. The file there is "gel-1.6.1/include/asm-m68hc12/arch-Ipac/arch/iodg256b.h". I added some defines to it for some popular bits used. ======== patch ========= Only in FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources: Makefile diff -r -u FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/port.c FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/port.c -– FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/port.c    2005-07-01 13:37:45.587354171 -0600 +++ FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/port.c    2005-04-08 14:48:51.000000000 -0600 @@ -1,5 +1,7 @@ /* This file is part of an "unsupported" FreeRTOS port distribution for   * Freescale MC9S12DP256B CPU. + * + * 2004-04-06 imajeff: modify to work with GCC   */ /* Scheduler include files. */ @@ -14,7 +16,7 @@     #pragma MESSAGE DISABLE C12053     #include "6812dp256b.h" #else –   #include "port.h" +   #include <arch/iodg256b.h> #endif volatile unsigned char vPortSchRunning = 0; @@ -231,7 +233,7 @@      CRGINT = (unsigned char) 0x80;      /* clear overflow interrupt flag */ –    CRGFLG_RTIF = 1; +    CRGFLG = RTIF; } /*———————————————————–*/ diff -r -u FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/portmacro.h FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/portmacro.h -– FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/portmacro.h    2005-07-01 13:37:45.584354465 -0600 +++ FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/portmacro.h    2005-04-19 09:44:36.000000000 -0600 @@ -1,5 +1,7 @@ /* This file is part of an "unsupported" FreeRTOS port distribution for   * Freescale MC9S12DP256B CPU. + * + * 2005-04-06 gcc fixes, imajeff   */ #ifndef PORTMACRO_H @@ -42,7 +44,7 @@   * or a 32 bit value.  See documentation on http://www.FreeRTOS.org to decide   * which to use.   */ -#define USE_16_BIT_TICKS                    0 +#define USE_16_BIT_TICKS                    1 /*———————————————————– @@ -72,8 +74,13 @@ #endif /*———————————————————–*/    +#ifdef __HIWARE__ #define portDISABLE_RTI_INTERRUPT()       CRGINT_RTIE = 0 #define portENABLE_RTI_INTERRUPT()        CRGINT_RTIE = 1 +#else +#define portDISABLE_RTI_INTERRUPT()       CRGINT &= ~RTIE +#define portENABLE_RTI_INTERRUPT()        CRGINT |= RTIE +#endif /*———————————————————–*/    void vPortEnterCritical(void); void vPortExitCritical(void); @@ -118,7 +125,7 @@ #define vPortIsrTail()                           {                                                /* reset pending RTI interrupt */      –      CRGFLG_RTIF = 1;                       +      CRGFLG = RTIF;                                __asm__("rti");                            } @@ -126,6 +133,7 @@ /* hardware interrupt handler saves CCR, A, B, X, Y, so there’s no need to save   * them one more time */ +#ifdef __HIWARE__ #define portSAVE_CONTEXT()                {                                             extern volatile void * pxCurrentTCB;   @@ -144,5 +152,34 @@      __asm__("stab 0x30");                  } +#else /* GNUC */ +#define portSAVE_CONTEXT()                +{                                        +    __asm__("                            n +    .globl pxCurrentTCB                    n +    movw _.frame, 2,-sp                    n +    movw _.tmp, 2,-sp                    n +    movw _.xy, 2,-sp                    n +    movw _.z, 2,-sp                        n +    movb 0x30, 1,-sp  ; PPAGE            n +    sts  pxCurrentTCB                    n +    ");                                    +} + +#define portRESTORE_CONTEXT()            +{                                        +    __asm__("                            n +    .globl pxCurrentTCB                    n +    lds  pxCurrentTCB                    n +    movb 1,+sp, 0x30  ; PPAGE            n +    movw _.z, 2,+sp                        n +    movw _.xy, 2,+sp                    n +    movw _.tmp, 2,+sp                    n +    movw _.frame, 2,+sp                    n +    ");                                    +} +#endif + + #endif /* PORTMACRO_H */ diff -r -u FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/queue.c FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/queue.c -– FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/queue.c    2005-07-01 13:37:45.594353485 -0600 +++ FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/queue.c    2005-04-14 12:22:08.000000000 -0600 @@ -109,6 +109,7 @@ void vQueueDelete( xQueueHandle xQueue ); signed portCHAR cQueueSendFromISR( xQueueHandle pxQueue, const void *pvItemToQueue, signed portCHAR cTaskPreviouslyWoken ); signed portCHAR cQueueReceive( xQueueHandle pxQueue, void *pcBuffer, portTickType xTicksToWait ); +signed portCHAR cQueueReceiveFromISR( xQueueHandle pxQueue, void *pcBuffer, signed portCHAR *pcTaskWoken ); /*   * Unlocks a queue locked by a call to prvLockQueue.  Locking a queue does not diff -r -u FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/test.c FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/test.c -– FreeRTOS-2.6.1/Source/portable/CodeWarrior/HCS12/sources/test.c    2005-07-01 13:37:45.589353975 -0600 +++ FreeRTOS-2.6.1-m/Source/portable/CodeWarrior/HCS12/sources/test.c    2005-04-18 17:22:43.000000000 -0600 @@ -1,36 +1,37 @@ -#include <6812dp256b.h>  /* derivative information */ +/* + * 2004-04-06 imajeff: modifying to test FreeRTOS with HC12/GCC + */ + +#include <arch/iodg256b.h>  /* derivative information */ #include <stddef.h> #include <stdio.h> +#include <string.h> #include "task.h" #include "semphr.h" -#pragma MESSAGE DISABLE C4002 - -const char message[] = "This is a FreeRTOS test program. "; -const char message2[] = "Semaphore work demonstration. "; -const char charTable[] = "0123456789abcdef"; +void isrDefault7 (void); +void testTask (void *); +void testTask2 (void *); +void pllConfig (void); + +const portCHAR message[] = "This is a FreeRTOS test program. "; +const portCHAR message2[] = "Semaphore work demonstration. "; +const portCHAR charTable[] = "0123456789abcdef"; xSemaphoreHandle xSemaphore; -#pragma CODE_SEG NON_BANKED -#pragma MESSAGE DISABLE C12053 -/* pay attention to _VECTOR section in PRM file */ -#pragma NO_EXIT -__interrupt void isrDefault7(void) +void isrDefault7 (void) {     vPortIsrHead(); –   +     /* do interrupt stuff… */ –    vPortIsrTail(); +   vPortIsrTail(); } -#pragma MESSAGE DEFAULT C12053 -#pragma CODE_SEG DEFAULT - -void testTask(void * p) +void testTask (void * p) {     static const char * strMsg = message;     static unsigned int count = 0; @@ -38,11 +39,6 @@     (void) p; –   /* initialize SCI: baud rate = 115200 with bus clock 16MHz */ –   SCI1CR1  = 0x00; –   SCI1CR2  = 0x0c; –   SCI1BD   = 0x09; -     while (cSemaphoreTake(xSemaphore, 100) != pdTRUE)     {        portYIELD(); @@ -50,8 +46,9 @@     for (;;)     { –      while (!SCI1SR1_TDRE) +      while (!SCI1SR1 & TDRE)        { +         // waiting for byte on SCI           portYIELD();        }        SCI1DRL = *strMsg; @@ -60,10 +57,11 @@        if (*strMsg == ‘’)        { –         sprintf(msg, "0x%04xr", count); +         strcpy(msg, ", So har"); +//         sprintf(msg, "0x%04xr", count);           for (strMsg = msg; *strMsg > 0; strMsg++)           { –            while (!SCI1SR1_TDRE) +            while (!SCI1SR1 & TDRE)              {                 portYIELD();              } @@ -83,7 +81,7 @@     } } -void testTask2(void * p) +void testTask2 (void * p) {     static const char * strMsg = message2;     static unsigned int count; @@ -91,11 +89,6 @@     (void) p; –   /* initialize SCI: baud rate = 115200 with bus clock 16MHz */ –   SCI1CR1  = 0x00; –   SCI1CR2  = 0x0c; –   SCI1BD   = 0x09; -     while (cSemaphoreTake(xSemaphore, 100) != pdTRUE)     {        portYIELD(); @@ -103,7 +96,7 @@     for (;;)     { –      while (!SCI1SR1_TDRE) +      while (!SCI1SR1 & TDRE)        {           portYIELD();        } @@ -112,10 +105,11 @@        strMsg++;        if (*strMsg == ‘’)        { –         sprintf(msg, "0x%04xr", count); +         strcpy(msg, ", So therer"); +//         sprintf(msg, "0x%04xr", count);           for (strMsg = msg; *strMsg > 0; strMsg++)           { –            while (!SCI1SR1_TDRE) +            while (!SCI1SR1 & TDRE)              {                 portYIELD();              } @@ -135,24 +129,26 @@     } } -void pllConfig(void) +void sciConfig () { –   SYNR           = 0x07; –   REFDV          = 0x01; –   while (!CRGFLG_LOCK); –   PLLCTL_AUTO    = 1; –   CLKSEL_PLLSEL  = 1; +   /* initialize SCI1: baud rate = 9615 with bus clock 24MHz */ +   SCI1CR1  = 0x00; +   SCI1CR2  = 0x0c; +   SCI1BD   = 0x009c; + } -void main(void) +int main (void) {     xTaskHandle xHandle; –   pllConfig(); +   sciConfig();     vSemaphoreCreateBinary(xSemaphore);     (void) sTaskCreate(testTask, "test", 100, NULL, tskIDLE_PRIORITY, &xHandle);     (void) sTaskCreate(testTask2, "test2", 100, NULL, tskIDLE_PRIORITY, &xHandle);     vTaskStartScheduler(portUSE_PREEMPTION); + +   return 0;    // never does }

Porting HCS12 for GCC

In studying the port, I found this initial value volatile unsigned portBASE_TYPE uxCriticalNesting = 0xff; I am puzzled. It seems it should have been initialized to 0, according to how it is being handled.         –jeffs

Porting HCS12 for GCC

This is to prevent interrupts being enabled before the scheduler has been initialised. Interrupts being enabled prior to the scheduler being initialised is only a problem if the interrupt service routine expects to be able to use the scheduler.  The demo applications install ISR’s that will attempt a context switch, so it is important that the ISR’s are not enabled prior to the scheduler being started. Creating a task will cause calls to portENTER_CRITICAL() and portEXIT_CRITICAL().  The portEXIT_CRITICAL() macro will enable interrupts if it finds uxCriticalNesting to be 0.  Initialising it to 0xff ensures this will never happen.  [In fact 0xff is a bad initial value if portBASE_TYPE is set to be a char as overflows will occur, 10 would be better.].

Porting HCS12 for GCC

I can answer this one because it tricked me during my port of FreeRTOS to PIC18/wizC During normal processing you are correct. However, to avoid interrupts from being enabled during taskcreations BEFORE the scheduler has started, this initial value is chosen. In "my" port portBASE_TYPE is a char and uxCriticalNesting is initialized to 0x7F. By setting it to a value "halfway", it can be incremented and decremented without risking it to reach zero. When the scheduler is started, this situation must end. This is done by initializing uxCriticalNesting to zero on the initial stack. This sets uxCriticalNesting to zero for every task when this task is switched in for the first time. HTH Marcel

Porting HCS12 for GCC

I finally found what you described, in pxPortInitialiseStack().  So I see what you mean about the overflow problem with 0xff.  I’ll try changing it to 10 or even half-way between. Also thank you Marcel for your explanation. I haven’t got anything ready to compile yet, but I’m making progress on the port.       –jeffs

Porting HCS12 for GCC

I’m having some trouble finding how malloc functions (i.e. pvPortMalloc() ) are defined in the CodeWarrior version. Maybe it won’t help me port to GCC anyway, since GCC-m68hc1x doesn’t come with an efficient malloc yet.

Porting HCS12 for GCC

Just include either heap_1.c or heap_2.c in your project as described on the WEB site under Configuration->Memory Management. The files are in FreeRTOS/portable/MemMang.