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

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

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

 

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

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

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

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

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

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

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

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

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

 

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

 

WBR, Sergey

 

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


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

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

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

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


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

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

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

 

Изменено пользователем SergeyTT

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


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

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

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

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

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

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

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

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

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

 

 

 

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


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

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

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

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

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

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

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

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

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

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