Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Использование portENTER_CRITICAL()
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
Cryon
Доброго времени суток!

Есть пример функции, которая посылает байт (см. ниже), используя очередь под FreeRTOS. Если ее упростить до уровня моего вопроса, то останется вот это:

portENTER_CRITICAL ();
xQueueSend (xTX0Queue, &cOutChar, xBlockTime);
portEXIT_CRITICAL ();

Внимание вопрос: portENTER_CRITICAL () запрещает прерывания в текущем режиме, причем как IRQ, так и FIQ. Тогда как же так получается, что отрабатывает xBlockTime (т.е. прерывания от таймера должны быть) в xQueueSend() ? wacko.gif

Спасибо!

Сами функции:

Код
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;
}


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++;
}
Сергей Борщ
Цитата(Cryon @ Nov 18 2008, 21:02) *
Внимание вопрос: portENTER_CRITICAL () запрещает прерывания в текущем режиме, причем как IRQ, так и FIQ. Тогда как же так получается, что отрабатывает xBlockTime (т.е. прерывания от таймера должны быть) в xQueueSend() ? wacko.gif
Если я помню правильно, то при необходимости использовать xBlockTime (т.е. когда очередь полна) происходит перепланировка. Управление передается другому процесу, у которого прерывания разрешены.
Cryon
Цитата(Сергей Борщ @ Nov 19 2008, 01:12) *
Если я помню правильно, то при необходимости использовать xBlockTime (т.е. когда очередь полна) происходит перепланировка. Управление передается другому процесу, у которого прерывания разрешены.


Да, спасибо! Похоже, так все и есть. Почитал еще форумов, порылся в коде.

Когда xBlockTime в действии задачи будут суспендиться и восстанавливаться циклически, соответственно vTaskSuspendAll() и xTaskResumeAll(). И как я понял вот как раз последняя из них передает управление задаче с более высоким приоритетом, чем текущаяя посредством taskYIELD().
yeah.gif
Тем не менее, допустим, что нет задачи с большим приоритетом и текущая задача остается активной в режиме ожидания xBlockTime. Тогда получается, что будут утеряны все тики таймера, возникшие во время xBlockTime. В этом случае вышеприведенная функция посылки данных через очередь в критической секции, не самое хорошее решение, т.к. пагубно влияет на время отклика ОС.

И всетаки это была демо функция и свою роль она сыграла правильно smile.gif

Шаблон для таймаута в xQueueGenericSend:

Код
if( xTicksToWait > ( portTickType ) 0 )
{
    vTaskSuspendAll();

    if( prvIsQueueFull( pxQueue ) )
    {
        if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
        {
            if( !xTaskResumeAll() )
            {
                taskYIELD();
            }
        }
        else
        {
            ( void ) xTaskResumeAll();
        }
    }
    else
    {
        ( void ) xTaskResumeAll();
    }
}
Сергей Борщ
Цитата(Cryon @ Nov 20 2008, 17:21) *
Тем не менее, допустим, что нет задачи с большим приоритетом и текущая задача остается активной в режиме ожидания xBlockTime.
Всегда есть такая задача. Это IdleTask (ну или созвучное название). А вот если вы решили подождать в IdleTask - то против лома ни одна лесопилка не устоит.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.