Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Двоичный семафор, ядро Cortex-M3
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
MiG-3
Добрый день!
Возникла проблемка, которую пока не могу решить. Может кто-то с такой сталкивался.
Пока код не буду постить.
Делаю прием данных из UARTa в оброботчике прерывания. По приему всего пакета отдаю из обработчика двоичный семафор в задачу. В задаче принимаю семафор с ограниченным ожиданием. Все работает нормально, но через какое-то время (1 час, 12 часов, сутки - по разному) происходит зависон задачи. Из отладки выяснил, что этот двоичный семафор не ждет ни прием семафора, ни отдачи, его длинна 1 элемент. Т.е., как я понимаю, он уже получил из обработчика прерывания семафор, но отдавать в задачу не хочет (даже по таймауту задача не продолжается). Что это??? Как это???
Т.е. вроде все класически, но...
demiurg_spb
Цитата(MiG-3 @ Apr 8 2013, 09:16) *
Как вариант, может где-то в обработчике не хватает __DSB()
MiG-3
Вот коллега не поверите - даже не знаю. Специально такую команду я в обработчик от UARTa не вставлял. Если не сложно ответьте - как это влияет на взаимодействие обработчика прерывания и семафора? Я пишу на С, стоит глянуть дизассемблер, может компилятор сам это генерит для обработчика?

Приведу, чтобы было от чего отталкиваться:

Инит-код для UARTa:
Код
  ***************************************************************************
***
Инициализация аппаратных средств для RS-485
**/
void RS485_Setup(void)
{
  /* Конфигурируем GPIO pins для RS-485 */
  GPIO_PinModeSet(RS485_TX_PORT, RS485_TX_PIN, gpioModePushPull, 1);
  GPIO_PinModeSet(RS485_RX_PORT, RS485_RX_PIN, gpioModeInputPull,  1);
  GPIO_PinModeSet(RS485_CX_PORT, RS485_CX_PIN, gpioModePushPull, 0);  // на прием
  /* Инициализация UART для RS-485, тактирование USART должно быть включено
        - BaudRate = 19200 baud  
        - Word Length = 9 Bits
        - One Stop Bit
        - No parity
  Don't enable UART upon intialization */
  const USART_InitAsync_TypeDef init =
  {
    usartDisable,   // Disable RX/TX when init completed
    0,              // Provide information on reference frequency. When set to 0, the reference frequency is
    19200,          // Baud rate
    usartOVS16,     // Oversampling. Range is 4x, 6x, 8x or 16x
    usartDatabits9, // Number of data bits. Range is 4 to 10
    usartNoParity,  // Parity mode
    usartStopbits1, // Number of stop bits. Range is 0 to 2
    false,          // Disable majority voting
    false,          // Disable USART Rx via Peripheral Reflex System
    usartPrsRxCh0   // Select PRS channel if enabled
  };
  
  USART_InitAsync(RS485_USART, &init);      // Инициализируем асинхронный режим
    /* Вкл автоформирование CS для драйвера RS-485,
       устанавливаем Multi-processor mode, 9-бит = 1 - адрес устройства */
  RS485_USART->CTRL |=   USART_CTRL_AUTOCS | USART_CTRL_CSINV | USART_CTRL_MPM
                       | USART_CTRL_MPAB | USART_CTRL_TXDELAY_TRIPLE;
    /* Enable signals TX, RX, CS */
  RS485_USART->ROUTE |= USART_ROUTE_TXPEN | USART_ROUTE_RXPEN | USART_ROUTE_CSPEN;
  // | USART_ROUTE_LOCATION_LOC0 - подразумеваем (т.к. = 0);

  /* Prepare UART Rx and Tx interrupts */
  RS485_USART->IFC = _USART_IF_MASK;      // сбрасываем флаги прерывания от UARTa
  // вкл прерывания RX - на прием и MPAF-адрес мультипроцессорной системы
  RS485_USART->IEN |= USART_IEN_RXDATAV | USART_IEN_MPAF;  
  NVIC_ClearPendingIRQ(RS485_RX_IRQn);
  NVIC_EnableIRQ(RS485_RX_IRQn);
  // Включаем UART на прием с блокировкой RX - работает только прием адресов
  RS485_USART->CMD = USART_CMD_RXEN | USART_CMD_RXBLOCKEN;
}


Обработчик прерывания:
Код
/**
  ***************************************************************************
***
Обработчик прерывания на прием RS-485
**/
void RS485_RX_IRQHandler(void)
{
  uint8_t  rxData;
  /* Обработка прерывания по адресу */
  if (RS485_USART->IF & _USART_IF_MPAF_MASK)  
  {
    rxData = (uint8_t)(RS485_USART->RXDATA);  // Считываем адрес из буфера UART
    RS485_USART->IFC = USART_IFC_MPAF;        // Очистить флаг MPAF interrupt
    if(rxData == SVO_ADR)                     // Совпадение с адресом СВО
    {    
      RX_Counter = 0;
      RX_Length = PR_POS_TYPE;                 // Минимум данных до длинны
      RS485_USART->CMD = USART_CMD_RXBLOCKDIS; // Разблокируем прием RX
    }
    else
      return;
  }
  /* Обработка прерывания по приему данных */
  if (RS485_USART->IF &  _USART_IF_RXDATAV_MASK)
  {
    rxData = (uint8_t)(RS485_USART->RXDATA);   // Считываем адрес из буфера UART
    switch (RX_Counter)                        // На лету декодируем заголовок пакета
    {
    case PR_POS_LENGTH:
      if (rxData >= RS485_RX_BUFFERSIZE)
      {
        RS485_USART->CMD = USART_CMD_RXBLOCKEN;
        return;
      }
      RX_Length = rxData;
      break;
    case PR_POS_TYPE:         // Если не для СВО пакет, останавливаем прием, ждем следующего флага начала пакета
      if (rxData != SVO_TYPE)
      {
        RS485_USART->CMD = USART_CMD_RXBLOCKEN;
        return;
      }
    }
   }
  RS485_RX_Buf[RX_Counter] = rxData;
  RX_Counter++;
  if (RX_Counter == RX_Length)
  {
    RS485_USART->CMD = USART_CMD_RXDIS;   // Блокируем прием по RX

    /* Выдаем двоичный семофор в задачу-обработчик по приему полного пакета */
    portBASE_TYPE xHigherPriorityTaskWoken;
    xHigherPriorityTaskWoken = pdFALSE;
    xSemaphoreGiveFromISR(xRxSemaphore ,&xHigherPriorityTaskWoken );
    if( xHigherPriorityTaskWoken == pdTRUE )
      vPortYieldFromISR();
  }
}


Задача:
Код
/**
  ***************************************************************************
***
Задача работы с RS-485
**/
void taskRS485_ISR(void * pvParameters)
{                                      
  portBASE_TYPE xStatus;
  extern xQueueHandle xQueueRelay;      // Очередь на реле в модуле Board.с
  extern uint16_t TermoArray[];
  extern tDiscreteInput DiscreteArray[];
  extern uint8_t DIPackByte;
  uint16_t CRC;
  uint8_t* TxPacket;
  uint8_t i, ContNum, ReadCount, idx;

   vSemaphoreCreateBinary(xRxSemaphore);
   vQueueAddToRegistry(xRxSemaphore, "SEM");

  vTaskDelay( TimeoutBeforeStart );     // Пауза для точной идентификации перезагрузки СВО
                                        // и прихода паспортного пакета от контроллера

  for (;; )
  {
    xStatus = xSemaphoreTake(xRxSemaphore, 200);   // Ждем приема пакета от ISR по RX
    if (xStatus == pdPASS)
    {
      CRC = GetCRC(RS485_RX_Buf, RS485_RX_Buf[PR_POS_LENGTH]-2);    // Проверяем CRC пакета
      if (CRC == PACK_WORD(RS485_RX_Buf[RS485_RX_Buf[PR_POS_LENGTH]-2],  RS485_RX_Buf[RS485_RX_Buf[PR_POS_LENGTH]-1]))
      {
   ................................................................................
.........................................................

        SendPacket( TxPacket, TxPacket[PR_POS_LENGTH] );
      }
      // Включаем UART на прием с блокировкой RX - работает только прием адресов
      RS485_USART->CMD = USART_CMD_RXEN | USART_CMD_RXBLOCKEN;
    }
  }
  vTaskDelete( NULL );
}
demiurg_spb
Цитата(MiG-3 @ Apr 8 2013, 11:34) *
Вот коллега не поверите - даже не знаю. Специально такую команду я в обработчик от UARTa не вставлял. Если не сложно ответьте - как это влияет на взаимодействие обработчика прерывания и семафора? Я пишу на С, стоит глянуть дизассемблер, может компилятор сам это генерит для обработчика?
Хорошо что на си пишете... Какой компилятор используете?
Барьер в обработчике нужен для того, чтобы не залететь в него повторно и так бесконечно из-за того, что, например, флаг запроса на прерывание физически не успевает очиститься до выхода из обработчика. Ну а в контексте семафоров... не могу дать вам развёрнутого ответа, не использую free-rtos.
MiG-3
Цитата(demiurg_spb @ Apr 8 2013, 13:12) *
Хорошо что на си пишете... Какой компилятор используете?
Барьер в обработчике нужен для того, чтобы не залететь в него повторно и так бесконечно из-за того, что, например, флаг запроса на прерывание физически не успевает очиститься до выхода из обработчика. Ну а в контексте семафоров... не могу дать вам развёрнутого ответа, не использую free-rtos.


Использую IAR для армов. Понял, спасибо за совет, и это попробуем.
Непомнящий Евгений
Не заметил установки приоритета прерывания по уарту.

Функции freertos можно дергать только из прерываний с приоритетом не выше, чем настроено в конфиге freertos-а. Обратите внимание, что приоритет тем выше, чем меньше его числовое значение.
MiG-3
Спасибо! Похоже это и есть косячок. Еще вчера занялся этим вопросом. Приоритет установил 7-ку (для 3-битного поля). Тестю! Еще раз спасибо!
ViKo
Цитата(MiG-3 @ Apr 8 2013, 08:16) *
Делаю прием данных из UARTa в оброботчике прерывания. По приему всего пакета отдаю из обработчика двоичный семафор в задачу. В задаче принимаю семафор с ограниченным ожиданием.

FreeRTOS не использую. Но - зачем ограниченное ожидание? Если семафора нет, нечего делать в задаче. Поставьте бесконечное ожидание.
MiG-3
Цитата(ViKo @ Apr 9 2013, 12:45) *
FreeRTOS не использую. Но - зачем ограниченное ожидание? Если семафора нет, нечего делать в задаче. Поставьте бесконечное ожидание.


Проблема решилась - именно приоритет прерывания, если из него есть вызовы функции API оси. Теперь почему не бесконечное ожидание семафора. Тут просто в коде задачи не хватает строчек для WDT. Т.е. задача переодически должна говорить, что она не зависла.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.