во время выполнения FreeRTOS непонятным образом сами собой запрещались прерывания. Путем несложной трассировки выяснил, что происходят они при парном вызове vPortEnterCritical() - vPortExitCritical(), по принципу
Код
portTickType xTaskGetTickCount( void )
{
portTickType xTicks;
/* Critical section required if running on a 16 bit processor. */
taskENTER_CRITICAL();
{
xTicks = xTickCount;
}
taskEXIT_CRITICAL();
return xTicks;
}
сами процедуры с виду простейшие
Код
void vPortEnterCritical( void )
{
/* Disable interrupts first! */
__disable_interrupt();
/* Now interrupts are disabled ulCriticalNesting can be accessed
directly. Increment ulCriticalNesting to keep a count of how many times
portENTER_CRITICAL() has been called. */
ulCriticalNesting++;
}
/*-----------------------------------------------------------*/
void vPortExitCritical( void )
{
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
{
/* Decrement the nesting count as we are leaving a critical section. */
ulCriticalNesting--;
/* If the nesting level has reached zero then interrupts should be
re-enabled. */
if( ulCriticalNesting == portNO_CRITICAL_NESTING )
{
__enable_interrupt();
}
}
}
portNO_CRITICAL_NESTING разумеется = 0
однако, что я получаю при трасировке:
Код
??vPortPreemptiveTick_0:
00017E5C 004000E0 DC32 0xE0004000
__disable_interrupt();
vPortEnterCritical:
vPortEnterCritical:
00017E60 E10F0000 MRS R0, CPSR
00017E64 E38000C0 ORR R0, R0, #0xC0
00017E68 E121F000 MSR CPSR_c, R0
ulCriticalNesting++;
00017E6C E59F003C LDR R0, [PC, #+60] ; [??DataTable1 (0x17EB0)] =ulCriticalNesting (0x4000F3B8)
00017E70 E5901000 LDR R1, [R0, #+0]
00017E74 E2811001 ADD R1, R1, #0x1
до этого момента все выполняется как надо, адрес в R0, правильное значение в R1
*pxTopOfStack = portNO_CRITICAL_NESTING;
Next label is a Thumb label
?Subroutine0:
.text_19:
00017E78 6001 STR R1, [R0, #0]
не имеет никакого эффекта, значение не обновляется
return pxTopOfStack;
00017E7A 4770 BX LR
не выполняется вообще
соттветственно, дальше выполняется vPortExitCritical:
if( ulCriticalNesting > portNO_CRITICAL_NESTING )
vPortExitCritical:
vPortExitCritical:
00017E7C E59F002C LDR R0, [PC, #+44] ; [??DataTable1 (0x17EB0)] =ulCriticalNesting (0x4000F3B8)
00017E80 E5901000 LDR R1, [R0, #+0]
00017E84 E3510000 CMP R1, #0x0
поскольку значение ulCriticalNesting не было инкрементировано, проверка отрицательная, дальше выход
00017E88 0A000007 BEQ ??vPortExitCritical_0 ; 0x17EAC
ulCriticalNesting--;
00017E8C E5901000 LDR R1, [R0, #+0]
00017E90 E2411001 SUB R1, R1, #0x1
00017E94 E5801000 STR R1, [R0, #+0]
if( ulCriticalNesting == portNO_CRITICAL_NESTING )
00017E98 E5900000 LDR R0, [R0, #+0]
00017E9C E3500000 CMP R0, #0x0
__enable_interrupt();
00017EA0 010F0000 MRSEQ R0, CPSR
00017EA4 03C000C0 BICEQ R0, R0, #0xC0
00017EA8 0121F000 MSREQ CPSR_c, R0
}
??vPortExitCritical_0:
00017EAC E12FFF1E BX LR
...
итог - после выхода из vPortEnterCritical значение ulCriticalNesting нулевое, прерывания запрещены, вызов vPortExitCritical не имеет значения. При уменьшении уровня оптимизации все нормализуется. volatile не влияет на исполнение. Поскольку я в ассемблере мягко говоря не силен, одолеть эту задачку мне оказалось не по зубам