FreeRtos works on TI's C2000 TMS320F280039 with 1 Task but not with 2 Tasks

Hi all,

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.

I really appreciate any help you can provide.

Regards

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

Hi Richard,
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.

Regards

Hi again,
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.

Regards,
Fernando

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.

Hi again,
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 defined(__TMS320C28XX_FPU32__)
    if(i == (2 * STF_REGISTER_POSITION))
    {
      uint32_t stf = getSTF();

      low  = stf & 0xAAAAU;
      high = (stf >> 16) & 0xAAAAU;
    }
#endif

    pxTopOfStack[base + i] = low;
    i++;
    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;
}

portRESTORE_FIRST_CONTEXT
; 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
  POP    XAR4
  SUBB   SP, #RPC_DELTA
  POP    RPC
  SUBB   SP, #SP_TOP_DELTA
  CLRC    INTM, DBGM    ; renable global interrupts
  LRETR
  .endasmfunc

And this is the part of Restore Context inside the ISR
RESTORE_CONTEXT:
  POP     DP:ST1
  .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
  POP     RB
  .endif
  POP     XAR7
  POP     XAR6
  POP     XAR5
  POP     XAR4
  POP     XAR3
  POP     XAR2
  POP     XT
  POP     RPC
  POP     AR1H:AR0H
  NASP
  IRET

I will continue studying the problem
Regards

Do the contents of the stack differ or are they also the same?

Hi aggarg,
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.

Regards