// Check if the transaction is complete
if (m_spi_txIndex >= m_spi_numTransactions)
{
#if (SPI_BUSY_WAIT)
m_spi_ready = 1;
#else
// Flag the main loop
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR(m_spi_semaphore, &xHigherPriorityTaskWoken);
portYIELD_FROM_ISR(xHigherPriorityTaskWoken);
#endif
}
else
{
// Stuff more data in the SPI port
}
}
~~~
(The ISR is implemented three times, each pointing to unique data structures, and have their own interrupt vector and priority).
The sensor loop waits on the sensor as follows:
~~~
void SensorNSPITransactionSequenceWait(void)
{
#if (SPIBUSYWAIT)
while (!mspiready)
{
}
#else
const TickTypet xMaxExpectedBlockTime = portMAXDELAY;
xSemaphoreTake(mspi_semaphore, xMaxExpectedBlockTime);
#endif
}
~~~
So far, I have observed the following behavior:
a) If I have exactly one sensor operating, then the system operates indefinately
b) if I have all three sensors running, then it will crash anywhere between 10sec and 3 minutes, with no apparent activity in any thread or interrupt. configASSERT() is defined, but appears not to execute.
c) If I define SPIBUSYWAIT which uses a busy wait rather than the semaphore mechanism, then the system operates indefinately.
I suspect therefore it has something to do with yielding when multiple interrupts are pending execution.
I have checked the usual advice with respect to Cortex-M interrupt. The NXP S32K144 implements 4 priority bits. The SPI interrupts each operate at (unshifted) priority 9, although changing the priorites to be 7, 8 and 9 on each sensor makes no difference.
Stack overflow detection is enabled, and there is no evidence of any task getting close to their stack limit.
~~~
/* The lowest interrupt priority that can be used in a call to a “set priority”
function. */
Cortex-M4F: Problems with xSemaphoreGiveFromISR / portYIELD_FROM_ISR
Dear All,
I am currently attempting to debug a problem I have running stock FreeRTOS v10.1.0 on an NXP S32K144 EVK (ARM Cortex-M4F) using GCC 7.3.1:
~~~
/opt/gcc-arm-none-eabi-7-2018-q2-update/bin/arm-none-eabi-gcc –version
arm-none-eabi-gcc (GNU Tools for Arm Embedded Processors 7-2018-q2-update) 7.3.1 20180622 (release) [ARM/embedded-7-branch revision 261907]
~~~
In this application, I have a sensor sampling task triggered by a HW timer servicing 3 sensors at 3200Hz, two comms tasks (a UART and CAN), and a general debugging task triggered from the tick hook.
The problem I have is in the sensor task. The three sensors are each on their own SPI bus, which operate almost simultaneously. At the end of the SPI transaction, an interrupt is generated, where it wakes the main sensor task with a semaphore, i.e.
~~~
void SensorNSPIInterrupt(void)
{
//
Cortex-M4F: Problems with xSemaphoreGiveFromISR / portYIELD_FROM_ISR
Interesting, the initial workaround on the forum topic linked does NOT work for me, although the lock-up does seems to take much longer to manifest. That is, whereas previously it would take between 1-3 minutes to manifest, it will now run for a long as 10 minutes without locking up. Not having the task switching (i.e. using SPIBUSYWAIT in the original description) runs overnight without problems.
So, it seems to help, but it’s not the full story.
~~~
/* Select a new task to run using either the generic C or port
optimised asm code. */
__asm (“CPSID i”);
taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too. Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
traceTASK_SWITCHED_IN();
__asm (“CPSIE i”);
~~~
Cortex-M4F: Problems with xSemaphoreGiveFromISR / portYIELD_FROM_ISR
I think the conclusion of that thread was that the work around you
posted would not actually fix the issue. In the other thread the issue
manifests itself (and can be explained) when run time stats are turned
on – do you have run time stats on, or any other code inserted into the
context switch code (such as a trace macro implemented)?
Cortex-M4F: Problems with xSemaphoreGiveFromISR / portYIELD_FROM_ISR
Strangely enough, no. I’m still working on any particular configuration that appears to trigger ti more (or less) often, or not at all.
My baseline FreeRTOS config looks like this:
~~~
define configUSE_PREEMPTION 1
define configSUPPORTSTATICALLOCATION 1
define configSUPPORTDYNAMICALLOCATION 1
define configUSEIDLEHOOK 0
define configUSETICKHOOK 1
define configCPUCLOCKHZ ( 80000000UL )
define configTICKRATEHZ ((TickType_t)1000)
define configMAX_PRIORITIES ( 7 )
define configMINIMALSTACKSIZE (128)
define configTOTALHEAPSIZE ((size_t) 4096)
define configMAXTASKNAME_LEN ( 16 )
define configUSE16BIT_TICKS 0
define configUSE_MUTEXES 1
define configQUEUEREGISTRYSIZE 8
define configUSEPORTOPTIMISEDTASKSELECTION 1
define configUSETIMESLICING 0
/* Co-routine definitions. */define configUSECOROUTINES 0
define configMAXCOROUTINE_PRIORITIES ( 2 )
/* Set the following definitions to 1 to include the API function, or zero to exclude the API function. */define INCLUDE_vTaskPrioritySet 1
define INCLUDE_uxTaskPriorityGet 1
define INCLUDE_vTaskDelete 1
define INCLUDE_vTaskCleanUpResources 1
define INCLUDE_vTaskSuspend 1
define INCLUDE_vTaskDelayUntil 1
define INCLUDE_vTaskDelay 1
~~~ Note that there is no configGENERATERUNTIME_STATS defined. In this “baseline” configuration, it will generally last about 15min before locking up. if I add the following line, then it takes generally 1-3 minutes to lock up: ~~~define configCHECKFORSTACK_OVERFLOW 1
~~~ which is the only extra line that appears to add code to the FreeRTOS task switching routine.Cortex-M4F: Problems with xSemaphoreGiveFromISR / portYIELD_FROM_ISR
After spending a few days debugging, the best I can come up with is as follows:
- The lock-up is an imprecise hard fault. Setting DISDEFWBUF turns it into a precise fault.
- The HFSR reports 0x40000000, noting the FORCED bit is set.