Есть пример функции, которая посылает байт (см. ниже), используя очередь под FreeRTOS. Если ее упростить до уровня моего вопроса, то останется вот это:
portENTER_CRITICAL ();
xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
portEXIT_CRITICAL ();
Внимание вопрос: portENTER_CRITICAL () запрещает прерывания в текущем режиме, причем как IRQ, так и FIQ. Тогда как же так получается, что отрабатывает xBlockTime (т.е. прерывания от таймера должны быть) в xQueueSend() ?

Спасибо!
Сами функции:
Код
signed portBASE_TYPE uart0PutChar (signed portCHAR cOutChar, portTickType xBlockTime)
{
signed portBASE_TYPE xReturn = 0;
portENTER_CRITICAL ();
{
//
// Is there space to write directly to the UART?
//
if (*plTHREEmpty0 == (portLONG) pdTRUE)
{
*plTHREEmpty0 = pdFALSE;
UART0_THR = cOutChar;
xReturn = pdPASS;
}
else
{
//
// We cannot write directly to the UART, so queue the character. Block for a maximum of
// xBlockTime if there is no space in the queue.
//
xReturn = xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
//
// Depending on queue sizing and task prioritisation: While we were blocked waiting to post
// interrupts were not disabled. It is possible that the serial ISR has emptied the Tx queue,
// in which case we need to start the Tx off again.
//
if ((*plTHREEmpty0 == (portLONG) pdTRUE) && (xReturn == pdPASS))
{
xQueueReceive (xTX0Queue, &cOutChar, serNO_BLOCK);
*plTHREEmpty0 = pdFALSE;
UART0_THR = cOutChar;
}
}
}
portEXIT_CRITICAL ();
return xReturn;
}
{
signed portBASE_TYPE xReturn = 0;
portENTER_CRITICAL ();
{
//
// Is there space to write directly to the UART?
//
if (*plTHREEmpty0 == (portLONG) pdTRUE)
{
*plTHREEmpty0 = pdFALSE;
UART0_THR = cOutChar;
xReturn = pdPASS;
}
else
{
//
// We cannot write directly to the UART, so queue the character. Block for a maximum of
// xBlockTime if there is no space in the queue.
//
xReturn = xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
//
// Depending on queue sizing and task prioritisation: While we were blocked waiting to post
// interrupts were not disabled. It is possible that the serial ISR has emptied the Tx queue,
// in which case we need to start the Tx off again.
//
if ((*plTHREEmpty0 == (portLONG) pdTRUE) && (xReturn == pdPASS))
{
xQueueReceive (xTX0Queue, &cOutChar, serNO_BLOCK);
*plTHREEmpty0 = pdFALSE;
UART0_THR = cOutChar;
}
}
}
portEXIT_CRITICAL ();
return xReturn;
}
portENTER_CRITICAL() продифайнен так:
#define portENTER_CRITICAL() vPortEnterCritical();
Код
void vPortEnterCritical( void )
{
/* Disable interrupts as per portDISABLE_INTERRUPTS(); */
asm volatile (
"STMDB SP!, {R0} \n\t" /* Push R0. */
"MRS R0, CPSR \n\t" /* Get CPSR. */
"ORR R0, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */
"MSR CPSR, R0 \n\t" /* Write back modified value. */
"LDMIA SP!, {R0}" ); /* Pop R0. */
/* 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++;
}
{
/* Disable interrupts as per portDISABLE_INTERRUPTS(); */
asm volatile (
"STMDB SP!, {R0} \n\t" /* Push R0. */
"MRS R0, CPSR \n\t" /* Get CPSR. */
"ORR R0, R0, #0xC0 \n\t" /* Disable IRQ, FIQ. */
"MSR CPSR, R0 \n\t" /* Write back modified value. */
"LDMIA SP!, {R0}" ); /* Pop R0. */
/* 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++;
}