I have managed to adapt and get working correctly the FreeRtos from this repository ( IvanZuy/freertos_c28x ) on the New TMS320F280039c (TI C2000 Family) . But It works with only one task, when I add a second task it doesn’t work. When the first task that starts running calls vTaskDelay( ); The system freezes, it tries to execute an invalid instruction. With only one task running, the system works OK, even the queues and delays. I have compared the maps of both versions, and there are a lot of functions that are placed in different directions. I think that it could be a problem of misalignment that causes the crash, but I don’t know exactly what could I try in order to solve the problem. It is a pity if I have to abandon the FreeRtos being so nearly of having it ported on this new microcontroller.
Are you sure the second task gets created? Did you check the return value of xTaskCreate()? You might have just run out of heap (unless you are creating the tasks using xTaskCreateStatic()). Do you have stack overflow protection on and configASSERT() defined?
See the following link for details https://freertos.org/FAQHelp.html
Thanks for your help. I am using Static Allocation, and when the system crashes, both stack are not full as there are a lot of 0XA5 on them. The macro configAssert() is not configured, Now I am reading what I should write on that Macro. The first task starts running and the first time it calls vTaskDelay() it goes to an exception of invalid instruction. The same task with exactly the same code but without the other do nothing task created runs OK.
I added the ConfigAssert() Macro, but it doesn’t catch any error. All the assertions are OK, but it stills falls on the Invalid execution exception.
I suspect that there is some error on the portable functions but it comes out depending on the alignment / directions of the written code. It will be very helpful any Idea or trick that could help me to find the bug.
I’m not familiar with that architecture so can’t offer specific advice, only generic.
Check the stack alignment is correct when you enter a task function.
Then step through the assembly code in the debugger until you hit the invalid instruction. It’s unlikely to be in the C code that runs on all platforms, so concentrate on the yield code within vTaskDelay() - that is where the assembly gets called. Try to identify exactly where it goes wrong.
I have debugged in Assembly. When both tasks are on, it enters in the new task using the switching mechanism written in the Tick ISR. The Stack pointers has the right value but at the first MOVL that it executes it crashes. If I only enable the second task, it enters using the first restore context function. It starts with the Same Stack pointer value, but it doesn’t crash. Probably there is something wrong between Port Stack Initizialization, First Restore Context and the switching mechanism. I know that you don’t know about this architecture but just in case you see something that might be wrong, here is the code
StackType_t *pxPortInitialiseStack( StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters )
volatile uint16_t i;
base = 0;
pxTopOfStack[base++] = 0x0080; // ST0. PSM = 0(No shift)
pxTopOfStack[base++] = 0x0000; // T
pxTopOfStack[base++] = 0x0000; // AL
pxTopOfStack[base++] = 0x0000; // AH
pxTopOfStack[base++] = 0xFFFF; // PL
pxTopOfStack[base++] = 0xFFFF; // PH
pxTopOfStack[base++] = 0xFFFF; // AR0
pxTopOfStack[base++] = 0xFFFF; // AR1
pxTopOfStack[base++] = 0x8A08; // ST1
pxTopOfStack[base++] = 0x0000; // DP
pxTopOfStack[base++] = 0x2000 | IER; // IER at the moment of creating tasks, make sure INT14 is enabled
pxTopOfStack[base++] = 0x0000; // DBGSTAT
pxTopOfStack[base++] = ((uint32_t)pxCode) & 0xFFFFU; // PCL
pxTopOfStack[base++] = ((uint32_t)pxCode >> 16) & 0x00FFU; // PCH
pxTopOfStack[base++] = 0xAAAA; // Alignment
pxTopOfStack[base++] = 0xBBBB; // Alignment
// Fill the rest of the registers with dummy values.
for(i = 0; i < (2 * AUX_REGISTERS_TO_SAVE); i++)
uint16_t low = 0xAAAA;
uint16_t high = 0xAAAA;
if(i == (2 * XAR4_REGISTER_POSITION))
low = ((uint32_t)pvParameters) & 0xAAAAU;
high = ((uint32_t)pvParameters >> 16) & 0xAAAAU;
if(i == (2 * STF_REGISTER_POSITION))
uint32_t stf = getSTF();
low = stf & 0xAAAAU;
high = (stf >> 16) & 0xAAAAU;
pxTopOfStack[base + i] = low;
pxTopOfStack[base + i] = high;
base += i;
// Reserve place for ST1 which will be used in context switch
// to set correct SPA bit ASAP.
pxTopOfStack[base++] = 0x8A18; // ST1 with SPA bit set
pxTopOfStack[base++] = 0x0000; // DP
pxTopOfStack[base++] = 0x0000; // placeholder for 32 bit ulCriticalVars
pxTopOfStack[base++] = 0x0000;
// 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 + base;
; Restore stack pointer from new task control block.
MOVL XAR0, #pxCurrentTCB
MOVL XAR0, *XAR0
MOVL XAR0, *XAR0
MOV @SP, AR0
; Restore XAR4 and RPC from saved task stack.
; and return to main task function.
; SP should be set to stack start plus 2 before LRETR.
SUBB SP, #XAR4_DELTA
SUBB SP, #RPC_DELTA
SUBB SP, #SP_TOP_DELTA
CLRC INTM, DBGM ; renable global interrupts
And this is the part of Restore Context inside the ISR
.if .TMS320C2800_FPU32 = 1
MOV32 R7H, *--SP
MOV32 R6H, *--SP
MOV32 R5H, *--SP
MOV32 R4H, *--SP
MOV32 R3H, *--SP
MOV32 R2H, *--SP
MOV32 R1H, *--SP
MOV32 R0H, *--SP
MOV32 STF, *--SP
Thanks for your help. In both cases the memory from the registers are recovered is the same. The only difference is that when it starts with First Restore Conetext it only recovers RPC and XAR4. When it enters using the tick Isr it restores all the registers. Thus the registers on the core don’t have the same value.