All wonderful suggestions, I appreciate it. None of your questions are silly @hs2 as they probably are leading me to what is going wrong. Regarding the main stack, it is definitely big enough, as I have it relocated to live above the .text section. This causes a stack overflow to trigger a memory fault, as it tries to write to a read only section.
There is one other task that I didn’t tell people about…the one that needs to run every 3 motor control iterations (you can see my original post for the description). When I removed that task, the issue went away. Seems odd, given that its priority was lower than the motor control task so it should always be preempted…so looks like all this might just be an issue with my configuration or task initialization?
I have the following configs of interest (taken from the configuration for the demo app in my port)
#define configUSE_PREEMPTION 1
#define configUSE_TIME_SLICING 0
#define configUSE_TIMERS 1
// no define for optimized task selection in my port
// removed bitwise operations for clarity
#define configLIBRARY_LOWEST_INTERRUPT_PRIORITY 15
#define configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY 2
#define configKERNEL_INTERRUPT_PRIORITY 240 // (0xFO)
#define configMAX_SYSCALL_INTERRUPT_PRIORITY 32 // (0x20)
Again, these are how NXP set them in the example app for my port. Are any of them inappropriate?
I initialize the two tasks like so:
MODULE_mctrl_th =
xTaskCreateStatic(motor_control_task, /* Function that implements the task. */
"mctrl_task", /* Text name for the task. */
STACK_SIZE, /* Number of indexes in the xStack array. */
(void*)1, /* Parameter passed into the task. */
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY, /* Priority at which the task is created. */
MODULE_mctrl_stack, /* Array to use as the task's stack. */
&MODULE_mctrl_tb); /* Variable to hold the task's data structure. */
MODULE_dof_ctrl_th =
xTaskCreateStatic(dof_control_task, /* Function that implements the task. */
"dof_ctrl_task", /* Text name for the task. */
STACK_SIZE, /* Number of indexes in the xStack array. */
(void*)1, /* Parameter passed into the task. */
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY + 1, // one less than the motor control priority
MODULE_dof_ctrl_stack, /* Array to use as the task's stack. */
&MODULE_dof_ctrl_tb);
The slower “every third time” task is dispatched through another direct-to-task event from within the hi_prio_motor control task like so (adding to my original pseudocode):
// initialized to a task priority of configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
MOTOR_CONTROL_TASK() {
while (1)
{
// block on direct to task notification
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
// (see oscilloscope trace)
BLUE_SCOPE_TRACE_HIGH()
complete_nonblocking_data_acquisition();
run_motor_control_algo()
static int divider = 0;
if (++divider >= 3)
{
divider = 0;
// unblock 3.3 kHz control task
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
vTaskNotifyGiveFromISR(MODULE_dof_ctrl_th, &xHigherPriorityTaskWoken);
}
// (see oscilloscope trace)
BLUE_SCOPE_TRACE_LOW()
}
}
The DOF ctrl task is also just a NOP loop, in the same manner as the motor control task.
void dof_control_task(void* p)
{
while (1)
{
ulTaskNotifyTake(pdTRUE, portMAX_DELAY);
do_dof_control() // NOP loop
}
}
Do you think the config values would cause this situation?
EDIT: oh to answer your question @hs2 the actual hardware IRQ priorities are set correct, because they preempt things as expected. The task priorities are shown above – hi prio motor control at configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
, and the slower “every third PWM IRQ control loop” task set to configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY+1