Jump to content

    
Sign in to follow this  
ur4lvn

[stm32f415]Согласование обмена информации между портам

Recommended Posts

Здравствуйте,All!

 

Прошу помочь в разрешении следующей проблемы:

нужно сопрячь 2 устройства, имеющих скорости по компорту отличающуюся в 30 раз (1М5 и 56К)

тип информации - пакеты,разной длины,могут рваться на пол-дороги и приходить по 2 и более в пачке. Они имеют известный хидер, я их парсю без проблем на лету в обработчике прерывания,благо скорострельности камня хватает.

Все это крутится под FreeRTOS на stm32f415.

В обработчике прерывания кладу символ в кольцевой буфер и отдаю его парсеру(инлайн в обработчике). Если парсер собрал пакет - отдаю указатель на начало пакета и его длину через очередь гейткиперу сопряженного порта. Гейт копирует пакет в свой буфер передачи и разрешает передачу по порту.

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

задач каждую миллисекунду.

Неопределенный момент может возникнуть как и через 10 сек после старта , так и через несколько часов.

Ход процесса я смотрю с помощью SEGGER SYSVIEW,очень полезная вещь.

 

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

 

WBR, Sergey

 

Share this post


Link to post
Share on other sites

Ну что ж начнем сеанс спиритизма и телепатии. Переполненение буфера? Другие длинные обработчики прерываний? Слишком длинный пакет? Где-то бьётся память?

ЗЫ Когда читаешь такой пост с описанием как-то подсознательно ождиаешь увидеть либо минмальный кусок кода на котором воспроизводится баг, либо попытки автора использовать data breakpoints в критичных для его алгоритма местах.

Share this post


Link to post
Share on other sites
Ну что ж начнем сеанс спиритизма и телепатии. Переполненение буфера? Другие длинные обработчики прерываний? Слишком длинный пакет? Где-то бьётся память?

ЗЫ Когда читаешь такой пост с описанием как-то подсознательно ождиаешь увидеть либо минмальный кусок кода на котором воспроизводится баг, либо попытки автора использовать 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

 

Edited by SergeyTT

Share this post


Link to post
Share on other sites

Симптомы похожи на "наезд" в RAM чего-то на что-то (так как слетает работа OS)

Можно конечно анализировать правильность Вашего кода,

но можно пойти другим путем. На один порт PC сделайте тест-запросчик, который

будет выдавать на Ваш девайс случайные (или не случайные) наборы данных,

которые параллельно пишутся в лог. На другой порт PC - приемник-анализатор

работы Вашего девайса.

Если удасться получить устойчивый влет в ошибку в приемлемое время

- то найти причину будет делом техники.

 

 

 

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this