Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: [stm32f415]Согласование обмена информации между портам
Форум разработчиков электроники ELECTRONIX.ru > Cистемный уровень проектирования > Операционные системы > FreeRTOS
SergeyTT
Здравствуйте,All!

Прошу помочь в разрешении следующей проблемы:
нужно сопрячь 2 устройства, имеющих скорости по компорту отличающуюся в 30 раз (1М5 и 56К)
тип информации - пакеты,разной длины,могут рваться на пол-дороги и приходить по 2 и более в пачке. Они имеют известный хидер, я их парсю без проблем на лету в обработчике прерывания,благо скорострельности камня хватает.
Все это крутится под FreeRTOS на stm32f415.
В обработчике прерывания кладу символ в кольцевой буфер и отдаю его парсеру(инлайн в обработчике). Если парсер собрал пакет - отдаю указатель на начало пакета и его длину через очередь гейткиперу сопряженного порта. Гейт копирует пакет в свой буфер передачи и разрешает передачу по порту.
Все прекрасно работает до неопределенного момента - может зависнуть вся система,а может тупо перейти в вызовы
задач каждую миллисекунду.
Неопределенный момент может возникнуть как и через 10 сек после старта , так и через несколько часов.
Ход процесса я смотрю с помощью SEGGER SYSVIEW,очень полезная вещь.

Буду рад,если кто либо поможет мне разобраться,где же порылась собака.

WBR, Sergey
Kabdim
Ну что ж начнем сеанс спиритизма и телепатии. Переполненение буфера? Другие длинные обработчики прерываний? Слишком длинный пакет? Где-то бьётся память?
ЗЫ Когда читаешь такой пост с описанием как-то подсознательно ождиаешь увидеть либо минмальный кусок кода на котором воспроизводится баг, либо попытки автора использовать data breakpoints в критичных для его алгоритма местах.
SergeyTT
Цитата(Kabdim @ Feb 5 2017, 17:12) *
Ну что ж начнем сеанс спиритизма и телепатии. Переполненение буфера? Другие длинные обработчики прерываний? Слишком длинный пакет? Где-то бьётся память?
ЗЫ Когда читаешь такой пост с описанием как-то подсознательно ождиаешь увидеть либо минмальный кусок кода на котором воспроизводится баг, либо попытки автора использовать data breakpoints в критичных для его алгоритма местах.

Да,сорри.
Буферы по 2К

Код
// Буфер приема сырых данных:
uint8_t                             modem_buffer[MODEM_RX_BUFLEN];
__IO uint8_t*                         modem_buffer_head;
__IO uint8_t*                         modem_buffer_tail;
// Буфер передачи
uint8_t                             modem_tx_buffer[MODEM_TX_BUFLEN];
__IO uint8_t*                         modem_tx_head;
__IO uint8_t*                         modem_tx_tail;

// Буфер приема сырых данных:
uint8_t pilot_buffer[PILOT_RX_BUFLEN];
__IO uint8_t* pilot_buffer_head;
__IO uint8_t* pilot_buffer_tail;

// Буфер передачи
uint8_t pilot_tx_buffer[PILOT_TX_BUFLEN];
__IO uint8_t* pilot_tx_head;
__IO uint8_t* pilot_tx_tail;


Инициализация портов

Код
    HAL_UART_MspInit( &modem_port );
    modem_port.Instance = USART2;
    modem_port.Init.BaudRate = MODEM_BAUDRATE;                     // 57600
    modem_port.Init.WordLength = UART_WORDLENGTH_8B;
    modem_port.Init.StopBits = UART_STOPBITS_1;
    modem_port.Init.Parity = UART_PARITY_NONE;
    modem_port.Init.Mode = UART_MODE_TX_RX;
    modem_port.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    modem_port.Init.OverSampling = UART_OVERSAMPLING_16;
    if( HAL_UART_Init( &modem_port ) != HAL_OK )
        ErrorHandler();
    HAL_NVIC_SetPriority( USART2_IRQn, 15, 0 );
    HAL_NVIC_EnableIRQ( USART2_IRQn);

    HAL_UART_MspInit( &ptm_port );
    ptm_port.Instance = USART6;
    ptm_port.Init.BaudRate = AP_TM1_BAUDRATE;                           //1M5
    ptm_port.Init.WordLength = UART_WORDLENGTH_8B;
    ptm_port.Init.StopBits = UART_STOPBITS_1;
    ptm_port.Init.Parity = UART_PARITY_NONE;
    ptm_port.Init.Mode = UART_MODE_TX_RX;
    ptm_port.Init.HwFlowCtl = UART_HWCONTROL_NONE;
    ptm_port.Init.OverSampling = UART_OVERSAMPLING_16;
    if( HAL_UART_Init( &ptm_port ) != HAL_OK )
        ErrorHandler();        
    HAL_NVIC_SetPriority( USART6_IRQn, 15, 0 );
    HAL_NVIC_EnableIRQ( USART6_IRQn);


Создание задач и очередей
#define MAX_PENDING_PACKETS (32)
#define configMINIMAL_STACK_SIZE ((portBASE_TYPE) 128)
Код
  xTaskCreate ( pilotGateKeeper, "p gate", configMINIMAL_STACK_SIZE,
          NULL, tskIDLE_PRIORITY + 1, pilotGateKeeperHandle );
  xTaskCreate ( modemGateKeeper, "modem gate", configMINIMAL_STACK_SIZE,
          NULL, tskIDLE_PRIORITY + 1, modemGateKeeperHandle );

pilotQueue = xQueueCreate ( MAX_PENDING_PACKETS, sizeof(packet_t) );
modemQueue = xQueueCreate ( MAX_PENDING_PACKETS, sizeof(packet_t) );


Гейткиперы почти одинаковы,вот один из них
Код
/*
* Получив сообщение из очереди,берем оттуда адрес начала пакета в сыром буфере,
* его длину, и дописываем в кольцевой буфер передачи порта.Оттуда он будет выдан в
* прерывании передачи
**/
void modemGateKeeper ( void* pvParameters )
{
    uint16_t len;
    uint16_t idx;
    uint8_t* src;
    packet_t packet;

    // Инициализация буферов
    modem_buffer_head = modem_buffer_tail = (uint8_t*)&modem_buffer;
    modem_tx_head = modem_tx_tail = (uint8_t*)&modem_tx_buffer;

    // Разрешаем прерывания приема символов,передатчик уже включен при инициализации порта
    modem_port.Instance->CR1 |= USART_CR1_RXNEIE;

    while(1)
    {
        xQueueReceive ( modemQueue, &packet, portMAX_DELAY );
        {
            //SEGGER_SYSVIEW_PrintfHost("%d",packet.origin);
            //SEGGER_SYSVIEW_PrintfHost("MQ = %d",uxQueueMessagesWaiting(modemQueue) );
            len = packet.len;
            src = packet.head;

            if(packet.origin == PILOT_CHANNEL )
            {                
                for(idx = 0; idx < len;idx++)
                {
                    *modem_tx_tail = *src;
                    modem_tx_tail++;
                    if(modem_tx_tail == (uint8_t*)&modem_tx_buffer + MODEM_TX_BUFLEN)
                        modem_tx_tail = (uint8_t*)&modem_tx_buffer;
                    src++;
                    if(src == (uint8_t*)&pilot_buffer + PILOT_RX_BUFLEN )
                        src = (uint8_t*)&pilot_buffer;
                }
                // разрешаем передачу
                modem_port.Instance->CR1 |= USART_CR1_TXEIE;
            }
        }    
}


Обработчики прерываний - то же

Код
/*
* Обработчик прерываний приема/передачи символов порта модема.
***/
void USART2_IRQHandler(void)
{
    uint8_t        current_symbol;
    packet_t        packet;
    uint8_t*        src;
    uint8_t*         last_symbol;
    uint16_t        idx;
    uint32_t        state = modem_port.Instance->SR;
    portBASE_TYPE    xHigherPriorityTaskWoken = pdFALSE;

    // Передача символа по указателю на голову буфера
    if( ( state & USART_SR_TXE ) && (modem_port.Instance->CR1 & USART_CR1_TXEIE) )
        {
            modem_port.Instance->DR = *modem_tx_head++;

            if(modem_tx_head == (uint8_t*)&modem_tx_buffer + MODEM_TX_BUFLEN )
                modem_tx_head = (uint8_t*)&modem_tx_buffer;

            if(modem_tx_head == modem_tx_tail)
            {
                modem_port.Instance->CR1 &= ~USART_CR1_TXEIE;
                SEGGER_SYSVIEW_PrintfHost("Mdone");
            }
        }


    /* Указатели на голову и хвост приемника инициализированы на начало буфера при
     * старте таска модема
     **/

    // Прием символа
    if( state & USART_SR_RXNE )
    {
        // Проверка ошибок
        if( !( state & ( USART_SR_PE | USART_SR_ORE | USART_SR_NE | USART_SR_FE ) ) )
        {
            GREEN_LED_TOGGLE;

            // принятый символ пишем в буфер
            *modem_buffer_tail = modem_port.Instance->DR;

            // и отдаем его на анализ
            if(parse_char(MODEM_CHANNEL, *modem_buffer_tail,
                    &message[MODEM_CHANNEL],&status[MODEM_CHANNEL]) )
            {
                // собран пакет,отдадим его длину в месседж
                packet.len = (uint16_t)message[MODEM_CHANNEL].len + MAVLINK_NUM_NON_PAYLOAD_BYTES;
                packet.msgid = message[MODEM_CHANNEL].msgid;
                packet.origin = MODEM_CHANNEL;

                // запомним указатель на последний символ пакета
                // и продвинем указатель хвоста на свободное место
                last_symbol = modem_buffer_tail++;

                if(modem_buffer_tail == (uint8_t*)&modem_buffer + MODEM_RX_BUFLEN)
                    modem_buffer_tail = (uint8_t*)&modem_buffer;

                // найдем указатель на голову
                packet.head = ( (last_symbol > modem_buffer_head) ?
                        (last_symbol - packet.len + 1 ) :
                        (last_symbol + MODEM_RX_BUFLEN - packet.len + 1 ) );

                packet.tail = last_symbol;

                modem_buffer_head = modem_buffer_tail;

#ifdef USE_PILOT
                xQueueSendToBackFromISR(pilotQueue,&packet,&xHigherPriorityTaskWoken);
#endif

            }

            // пакет еще не собран,подготовим место для следующего символа
            modem_buffer_tail++;
            if(modem_buffer_tail == (uint8_t*)&modem_buffer + MODEM_RX_BUFLEN)
                modem_buffer_tail = (uint8_t*)&modem_buffer;
        }
        else
        {
            char dummy = (char)modem_port.Instance->DR;
        }
    }
    

    if(xHigherPriorityTaskWoken)
        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);

}



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

Забыл добавить: использую Eclipse Kepler + arm-none-eabi_5.4_2016q3 + FreeRTOS 9.0.0
k155la3
Симптомы похожи на "наезд" в RAM чего-то на что-то (так как слетает работа OS)
Можно конечно анализировать правильность Вашего кода,
но можно пойти другим путем. На один порт PC сделайте тест-запросчик, который
будет выдавать на Ваш девайс случайные (или не случайные) наборы данных,
которые параллельно пишутся в лог. На другой порт PC - приемник-анализатор
работы Вашего девайса.
Если удасться получить устойчивый влет в ошибку в приемлемое время
- то найти причину будет делом техники.


Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.