FreeRTOS SMP Port to VS

portYIELD() and portYIELD_CORE(xCoreID) serve different purpose -

  • portYIELD() - is used when a core want to run scheduler itself.
  • portYIELD_CORE(xCoreID) - is used when a core wants to interrupt some other core.

taskYIELD_ANY_CORE_IF_USING_PREEMPTION is called at this line which is inside a critical section - critical nesting count, therefore, must be greater than zero. Most likely your implementation of portENTER_CRITICAL and portEXIT_CRITICAL is incorrect. Did you set portCRITICAL_NESTING_IN_TCB to 1? If yes, you need to implement portENTER_CRITICAL and portEXIT_CRITICAL using vTaskEnterCritical and vTaskExitCritical. Take a look here.

Thank You very much,If it is like this,I will unify these two macros:portYIELD() and portYIELD_CORE(xCoreID)

Thank You very much, Your suggestion is extremely valuable,and I have the direction to move forward again.

First, a taskstart task was created and bound to core0 (mask 0x01), and then FreeRTOS entered vTaskStartScheduler(), creating idle tasks for the two cores respectively, and creating a daemon task for the timer on core0. Firstly, the two cores switched to their respective idletasks to run. After a period of time, core0 would switch to the taskstart task to run. In the taskstart, taska and taskb were created, one periodic timer and two one-shot timers, one semaphore, and one queue. Among them, taska was bound to core0 and taskb was bound to core1. Finally, the taskstart task was deleted. After the tasktask was finished running, taska and taskb were not found in the corresponding priority positions in the ready list, resulting in no scheduling interruption at last. The two cores have been running idle all the time. What is the reason for this?

Check the return code of the xTaskCreate API to ensure that these tasks were created successfully.

From the debugging over the past few days, it seems that the issue is not due to the tasks failing to be created. There must be another reason, but the root cause has not yet been identified. Recently, I have added trace points to the scheduling of core0 and core1, and here are the observations:

Prerequisites:

  • Tmr Svc is bound to core0.
  • Start Task is bound to core0.
  • Within Start Task, TestA task is created, and it is bound to core0.
  • Within Start Task, TestB task is created, and it is bound to core1.
  • A periodic timer C is created within Start Task.

After running the program for a while and then stopping it:

  1. From the trace, the following task switching processes are observed:

    • On core0: IDLE0 → Tmr Svc → Start Task → TestA task → Start Task
    • On core1: IDLE1 → IDLE1 → IDLE1
  2. From the call stack, it is seen that:

    • TestB task is being created within Start Task.

After restarting and running for a while, then stopping again, the same phenomenon is observed as before, meaning there are no changes in the trace and call stack.

What could be causing this? Or what debugging methods can be used to further debug the issue?

TestB task should have been scheduled on core1. Can you check why core1 is not picking it when it is running the scheduler? One way to do may be to put a conditional breakpoint in vTaskSwitchContext when xCoreID is 1.

Sure, I will try it later according to your method.

There are two questions as follows:
1.What is the scope of concern for task locks and ISR locks, respectively? Is the following understanding correct: Acquiring a task lock: First, take the lock and stop all task scheduling; Releasing a task lock: Release the lock and start all tasks; Acquiring an ISR lock: First, take the lock and stop interrupts; Releasing an ISR lock: Release the lock and start interrupts, and if the PendSV and tick interrupts are not zero, then start scheduling?
2. What is the difference between portDISABLE_INTERRUPTS() & portENABLE_INTERRUPTS() and portSET_INTERRUPT_MASK() & portCLEAR_INTERRUPT_MASK() ? Currently, portDISABLE_INTERRUPTS() & portENABLE_INTERRUPTS() are defined as empty, portSET_INTERRUPT_MASK() directly prevents all interrupt service routines from executing, and portCLEAR_INTERRUPT_MASK() restores the execution of interrupt service routines. However, during my debugging process, I found that portDISABLE_INTERRUPTS() & portENABLE_INTERRUPTS() are used extensively in task.c .