MiG-3 0 8 апреля, 2013 Опубликовано 8 апреля, 2013 · Жалоба Добрый день! Возникла проблемка, которую пока не могу решить. Может кто-то с такой сталкивался. Пока код не буду постить. Делаю прием данных из UARTa в оброботчике прерывания. По приему всего пакета отдаю из обработчика двоичный семафор в задачу. В задаче принимаю семафор с ограниченным ожиданием. Все работает нормально, но через какое-то время (1 час, 12 часов, сутки - по разному) происходит зависон задачи. Из отладки выяснил, что этот двоичный семафор не ждет ни прием семафора, ни отдачи, его длинна 1 элемент. Т.е., как я понимаю, он уже получил из обработчика прерывания семафор, но отдавать в задачу не хочет (даже по таймауту задача не продолжается). Что это??? Как это??? Т.е. вроде все класически, но... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
demiurg_spb 0 8 апреля, 2013 Опубликовано 8 апреля, 2013 · Жалоба Как вариант, может где-то в обработчике не хватает __DSB() Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiG-3 0 8 апреля, 2013 Опубликовано 8 апреля, 2013 · Жалоба Вот коллега не поверите - даже не знаю. Специально такую команду я в обработчик от 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 0 8 апреля, 2013 Опубликовано 8 апреля, 2013 · Жалоба Вот коллега не поверите - даже не знаю. Специально такую команду я в обработчик от UARTa не вставлял. Если не сложно ответьте - как это влияет на взаимодействие обработчика прерывания и семафора? Я пишу на С, стоит глянуть дизассемблер, может компилятор сам это генерит для обработчика?Хорошо что на си пишете... Какой компилятор используете? Барьер в обработчике нужен для того, чтобы не залететь в него повторно и так бесконечно из-за того, что, например, флаг запроса на прерывание физически не успевает очиститься до выхода из обработчика. Ну а в контексте семафоров... не могу дать вам развёрнутого ответа, не использую free-rtos. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiG-3 0 8 апреля, 2013 Опубликовано 8 апреля, 2013 · Жалоба Хорошо что на си пишете... Какой компилятор используете? Барьер в обработчике нужен для того, чтобы не залететь в него повторно и так бесконечно из-за того, что, например, флаг запроса на прерывание физически не успевает очиститься до выхода из обработчика. Ну а в контексте семафоров... не могу дать вам развёрнутого ответа, не использую free-rtos. Использую IAR для армов. Понял, спасибо за совет, и это попробуем. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Johnny81 0 9 апреля, 2013 Опубликовано 9 апреля, 2013 · Жалоба Не заметил установки приоритета прерывания по уарту. Функции freertos можно дергать только из прерываний с приоритетом не выше, чем настроено в конфиге freertos-а. Обратите внимание, что приоритет тем выше, чем меньше его числовое значение. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiG-3 0 9 апреля, 2013 Опубликовано 9 апреля, 2013 · Жалоба Спасибо! Похоже это и есть косячок. Еще вчера занялся этим вопросом. Приоритет установил 7-ку (для 3-битного поля). Тестю! Еще раз спасибо! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
ViKo 1 9 апреля, 2013 Опубликовано 9 апреля, 2013 · Жалоба Делаю прием данных из UARTa в оброботчике прерывания. По приему всего пакета отдаю из обработчика двоичный семафор в задачу. В задаче принимаю семафор с ограниченным ожиданием. FreeRTOS не использую. Но - зачем ограниченное ожидание? Если семафора нет, нечего делать в задаче. Поставьте бесконечное ожидание. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
MiG-3 0 11 апреля, 2013 Опубликовано 11 апреля, 2013 · Жалоба FreeRTOS не использую. Но - зачем ограниченное ожидание? Если семафора нет, нечего делать в задаче. Поставьте бесконечное ожидание. Проблема решилась - именно приоритет прерывания, если из него есть вызовы функции API оси. Теперь почему не бесконечное ожидание семафора. Тут просто в коде задачи не хватает строчек для WDT. Т.е. задача переодически должна говорить, что она не зависла. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться