Перейти к содержанию
    

Двоичный семафор, ядро Cortex-M3

Добрый день!

Возникла проблемка, которую пока не могу решить. Может кто-то с такой сталкивался.

Пока код не буду постить.

Делаю прием данных из UARTa в оброботчике прерывания. По приему всего пакета отдаю из обработчика двоичный семафор в задачу. В задаче принимаю семафор с ограниченным ожиданием. Все работает нормально, но через какое-то время (1 час, 12 часов, сутки - по разному) происходит зависон задачи. Из отладки выяснил, что этот двоичный семафор не ждет ни прием семафора, ни отдачи, его длинна 1 элемент. Т.е., как я понимаю, он уже получил из обработчика прерывания семафор, но отдавать в задачу не хочет (даже по таймауту задача не продолжается). Что это??? Как это???

Т.е. вроде все класически, но...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Как вариант, может где-то в обработчике не хватает __DSB()

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот коллега не поверите - даже не знаю. Специально такую команду я в обработчик от 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 );
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вот коллега не поверите - даже не знаю. Специально такую команду я в обработчик от UARTa не вставлял. Если не сложно ответьте - как это влияет на взаимодействие обработчика прерывания и семафора? Я пишу на С, стоит глянуть дизассемблер, может компилятор сам это генерит для обработчика?
Хорошо что на си пишете... Какой компилятор используете?

Барьер в обработчике нужен для того, чтобы не залететь в него повторно и так бесконечно из-за того, что, например, флаг запроса на прерывание физически не успевает очиститься до выхода из обработчика. Ну а в контексте семафоров... не могу дать вам развёрнутого ответа, не использую free-rtos.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Хорошо что на си пишете... Какой компилятор используете?

Барьер в обработчике нужен для того, чтобы не залететь в него повторно и так бесконечно из-за того, что, например, флаг запроса на прерывание физически не успевает очиститься до выхода из обработчика. Ну а в контексте семафоров... не могу дать вам развёрнутого ответа, не использую free-rtos.

 

Использую IAR для армов. Понял, спасибо за совет, и это попробуем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не заметил установки приоритета прерывания по уарту.

 

Функции freertos можно дергать только из прерываний с приоритетом не выше, чем настроено в конфиге freertos-а. Обратите внимание, что приоритет тем выше, чем меньше его числовое значение.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Спасибо! Похоже это и есть косячок. Еще вчера занялся этим вопросом. Приоритет установил 7-ку (для 3-битного поля). Тестю! Еще раз спасибо!

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Делаю прием данных из UARTa в оброботчике прерывания. По приему всего пакета отдаю из обработчика двоичный семафор в задачу. В задаче принимаю семафор с ограниченным ожиданием.

FreeRTOS не использую. Но - зачем ограниченное ожидание? Если семафора нет, нечего делать в задаче. Поставьте бесконечное ожидание.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

FreeRTOS не использую. Но - зачем ограниченное ожидание? Если семафора нет, нечего делать в задаче. Поставьте бесконечное ожидание.

 

Проблема решилась - именно приоритет прерывания, если из него есть вызовы функции API оси. Теперь почему не бесконечное ожидание семафора. Тут просто в коде задачи не хватает строчек для WDT. Т.е. задача переодически должна говорить, что она не зависла.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...