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

    

Помогите разобраться с PRINTF

Не хочется создавать большой кольцевой буфер для PRINTF. Поступил по - другому. С задержкой.

 

Посчитав что PRINTF работает через int fputc(int ch, FILE *f), в ней и написал:

 

int fputc(int ch, FILE *f)                  //Внутри функции реализована задержка заполнения
{                                            //буфера для уменьшения размера буфера.
static unsigned int StreamWaitCnt = 0;        //
    StreamWaitCnt++;                        //Счетчик числа передаваемых байт
    if (StreamWaitCnt > PC_TxBufSize-5)        //Если счеттчик достиг размера буфера
        {                                    //
            StreamWaitCnt = 0;                //Обнулить счетчик
            HAL_Delay(30);                    //Задержка пока буфер улетит в порт
        }                                    //
    return (PC_Putchar(ch));                 //
}                                            //

 

Т.е. когда буфер заполняется, происходит задержка для ожидания завершения передачи буфера в порт. Передача осуществляется через прерывание:

 

 

int PC_Putchar(int ch)                         //Передача. Функция помещает Ch в кольцевой буфер.
{                                             //Указатель головы кольцевого буфера перемещается на
    int tmphead = (PC_TxHead + 1) & PC_TX_BUFFER_MASK; //одну позицию, символ помещается в кольцевой буфер.
    PC_TxBuf[tmphead] = (char)ch;               //Если передача первая после опустошения
    PC_TxHead = tmphead;                    //буфера(переданы все символы), взводится флаг L86_Complete,
        if (PC_Complete==0)                    //Передаваемый символ помещается в передающий регистр порта
        {                                     //(L86_UsartTx();) и инициируется первая передача
            PC_Complete = 1;                //в цепочке - разрешением прерывания.
            PC_UsartTx();                     //Флаг начала цепочки передач
            PC_En_Tranfer_Interrupt;        //Положить первый символ в DR
        }                                     //
    return (ch);                            //
}                                             //

 

 

Само прерывание:

 

void USART2_IRQHandler(void)
{
    if (USART2->ISR & USART_ISR_TC)                 //Bit 6 TC: Transmission complete
    {                                             //
        PC_UsartTx();                             //
    }                                            //
    if (USART2->ISR & USART_ISR_RXNE)             //Bit 5 RXNE: Read data register not empty
    {                                             //
        PC_UsartRx();                            //Функция кладет байт из приёмного регистра в кольцевой буфер
    }                                             //
  HAL_UART_IRQHandler(&huart2);
}

 

 

void PC_UsartTx(void)                         //
{                                             //
    if (PC_TxHead != PC_TxTail)                //Check if all data is transmitted
    {                                         //
        PC_TxTail = (PC_TxTail + 1) & PC_TX_BUFFER_MASK;//Перемещение указателя по кольцевому буферу
        USART2->TDR = (int)PC_TxBuf[PC_TxTail];    //Start transmition
    }                                         //
    else                                    //
    {                                        //
        PC_Complete=0;                        //Цепочка передачи окончена
        PC_Dis_Tranfer_Interrupt;            //Запретить прерывание на передачу Bit 6 TCIE:
    }                                        //
}                                             //

 

Самой задержки (30мс) по идее должно хватать. Т.е. при скорости 115200 за 1 секунду улетает 10килобайт. Примерно. Значит за милисекунду - 10 байт. Итого - 300байт при буфере в 256.

 

Такой подход по идее должен разрешать иметь любой малый (в разумных пределах) буфер для передачи. На практике же это не работает - часть выводимой информации теряется. И только когда я делаю #define PC_TxBufSize 8192, передача осуществляется без потерь.

 

Где же я не прав, может кто подскажет?

Изменено пользователем Димон Безпарольный

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


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

Я бился с такой проблемой, не решил. Сделал так. Отказался от передачи ТХ в прерывании, то есть перешёл на поллинг. В терминальной программе поставил задержку после передачи новой строки на 1 миллисекунду. Увеличение буфера до 8кБ помогает, но не всегда. Причём это в Виндоуз и в Линуксе. А файл 1кБ отлично передавался и с буфером 256 байт.

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


Ссылка на сообщение
Поделиться на другие сайты
часть выводимой информации теряется.

А вы уверены, что теряет не приемная сторона?

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


Ссылка на сообщение
Поделиться на другие сайты
А вы уверены, что теряет не приемная сторона?

Я делал USB-UART на STM32F103 и на CC2511. RX замкнут на TX. На CC2511 нормально работало до 1 МГц, на STM32F103 после 9600 были сбои на длинных файлах. Так и не разобрался.

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


Ссылка на сообщение
Поделиться на другие сайты
Я бился с такой проблемой, не решил. Сделал так. Отказался от передачи ТХ в прерывании, то есть перешёл на поллинг. В терминальной программе поставил задержку после передачи новой строки на 1 миллисекунду. Увеличение буфера до 8кБ помогает, но не всегда. Причём это в Виндоуз и в Линуксе. А файл 1кБ отлично передавался и с буфером 256 байт.

Вы правы. В случае поллинга все работает исправно.

 

USART2->TDR = ch;
if(UART_WaitOnFlagUntilTimeout(&huart2, UART_FLAG_TC, RESET, 100) != HAL_OK)
    {

    }

 

 

 

Но поллинг накладывает временные ограничения на выполнение. Я пишу код MBED TLS и в этом случае не проходит даже handshake. Либо в моем софте еще один глюк...

 

Видимо без буфера не обойтись.

 

Я делал USB-UART на STM32F103 и на CC2511. RX замкнут на TX. На CC2511 нормально работало до 1 МГц, на STM32F103 после 9600 были сбои на длинных файлах. Так и не разобрался.

У меня были сбои на 460800 пока я не перешел на кварц. Хотя на 9600 смещение частоты вряд ли скажется...

 

А вы уверены, что теряет не приемная сторона?

Уверен что приемная сторона нипричем. Сделал поллинг - вывод сработал исправно.

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


Ссылка на сообщение
Поделиться на другие сайты
на STM32F103 после 9600 были сбои на длинных файлах. Так и не разобрался.

Я при помощи STM32F103C8 гнал поток 2.25 Мбод (RX замкнут с TX). Ни один байт не потерялся за значительное время.

 

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


Ссылка на сообщение
Поделиться на другие сайты
Я при помощи STM32F103C8 гнал поток 2.25 Мбод (RX замкнут с TX). Ни один байт не потерялся за значительное время.

Конечно не будет теряться, если код написан правильно.

Я на 926000 тоже нормально гонял на другое устройство.

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


Ссылка на сообщение
Поделиться на другие сайты
Конечно не будет теряться, если код написан правильно.

Я писал так

void USART2_IRQHandler(void)
{
    if(USART2->ISR & (1 << USART_ISR_TXE))
    {
        if(con.tx_t != con.tx_b) USART2->TDR = bl_export.bl_sp_tx_pop(&con);
        else USART2->CR1 &= ~(1 << USART_CR1_TXEIE);
    }
    if(USART2->ISR & (1 << USART_ISR_ORE))
    {
        USART2->ICR = (1 << USART_ISR_ORE);
    }
    if(USART2->ISR & (1 << USART_ISR_RXNE))
    {
        con.rx_tm = 0;
        bl_export.bl_sp_rx_push(&con, USART2->RDR);
    }
}

push и pop помещают и извлекают байты из кольцевых буферов tx и rx.

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


Ссылка на сообщение
Поделиться на другие сайты
Самой задержки (30мс) по идее должно хватать.

Задержки - типичный ардуино-подход, дилетантский.

Для вывода в поток с помощью printf() никаких задержек вообще не нужно. И размер буфера может быть абсолютно любым, хоть 1 байт. Буфер только даёт возможность более эффективно использовать быстродействие CPU - в среднем уменьшает загрузку CPU.

Если у Вас что-то не работает из-за изменения размеров буфера или требует каких-то задержек - правьте консерваторию.

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


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

Я делал совсем по простому

2 буфера линейных

ПДП

таймер

всё пузЫрилось на ура.

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


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

Проверяйте в функции отправки сообщения статус возврата! Если ошибка — либо пропускайте (сообщение некритичное), либо ждите подтверждения отправки.

Соответственно, функция, заполняющая буфер просто будет возвращать OK если место есть и ошибку, если буфер полностью заполнен и надо подождать, пока "уедет".

 

Если используете линейный буфер (тогда удобней делать двойную буферизацию), отправка реализуется при помощи DMA, а буферы меняются местами по флагу, выставленному в прерывании по окончании DMA.

Если буфер кольцевой, придется в обработчике прерывания TXE выполнять основную работу.

 

Но в любом случае ни в коем случае не надо лепить паузы! Это же не абдурина!!! Если буфер заполняется слишком быстро, либо повышайте скорость передачи, либо увеличивайте буфер.

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


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

Очень может быть, что сбои (потери) байтов из-за плохой трассировки печатной платы. Изменение буферов, скоростей, поллинга-прерываний изменяют наводки от фронтов Rx-Tx и уменьшение скорости тогда единственный выход.

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


Ссылка на сообщение
Поделиться на другие сайты
Задержки - типичный ардуино-подход, дилетантский.

Для вывода в поток с помощью printf() никаких задержек вообще не нужно. И размер буфера может быть абсолютно любым, хоть 1 байт. Буфер только даёт возможность более эффективно использовать быстродействие CPU - в среднем уменьшает загрузку CPU.

Если у Вас что-то не работает из-за изменения размеров буфера или требует каких-то задержек - правьте консерваторию.

Интересная точка зрения. Ну допустим буфер 128 байт. Кольцевой. За пару милисекунд проц настрочил 5кб текста и выплюнул все это в кольцевой буфер. А с одним байтом будет еще прикольнее. Наверно только первый байт от 5кб и попадет в терминал. Мож и не первый...

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


Ссылка на сообщение
Поделиться на другие сайты
За пару милисекунд проц настрочил 5кб текста и выплюнул все это в кольцевой буфер.

Сам он это не выплюнет, он сделает так, как ему разработчик велел. И если разработчик не проверяет коды возврата из процедур, это его личные проблемы!

Если хочется использовать printf (хотя эта штука ну слишком уж жирная!), то она, если что, тоже возвращает количество принятых символов. И вместо фиксированного времени ожидания можно лишь подождать, пока буфер не освободится и закинуть в него критическое сообщение. Некритическое же вообще можно опустить (но для этого придется дописать простой макрос, возвращающий количество свободных символов в буфере).

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


Ссылка на сообщение
Поделиться на другие сайты
Сам он это не выплюнет, он сделает так, как ему разработчик велел. И если разработчик не проверяет коды возврата из процедур, это его личные проблемы!

Если хочется использовать printf (хотя эта штука ну слишком уж жирная!), то она, если что, тоже возвращает количество принятых символов. И вместо фиксированного времени ожидания можно лишь подождать, пока буфер не освободится и закинуть в него критическое сообщение. Некритическое же вообще можно опустить (но для этого придется дописать простой макрос, возвращающий количество свободных символов в буфере).

printf использует библиотека MBEDTLS, нужен форматирванный вывод.

 

Суть во всем это одна -

 

можно лишь подождать, пока буфер не освободится

 

Я так и делал, но другим способом - наблюдая за головой и хвостом.

 

В данном случае это ПОКА неприемлимо. Сервер выкидывает HandShake, следом сертификаты. Так вот. С выводом debug информации не получается успевать декодировать первое сообщение - его затирает втрое.

Изменено пользователем Димон Безпарольный

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


Ссылка на сообщение
Поделиться на другие сайты
Гость
Эта тема закрыта для публикации ответов.
Авторизация