pyserial проблемы с высокой скоростью передачи данных FTDI

У меня есть следующая установка:

  • FPGA отправляет данные по UART со скоростью 3 Мбит/с. Передаваемые данные представляют собой блок из 1024 байтов, отправляемых с переменной периодичностью в диапазоне от 20 мс до 200 мс. (Так что даже в худшем случае скорость передачи данных далека от 3 Мбит/с)

  • FTDI 232RG

  • Кусок python, работающий на моем компьютере (Windows), в основном: открытие COM-порта с помощью pyserial, 3Msps, опрос in_waiting до тех пор, пока он не достигнет размера пакета (1024 байта), форматирование полученного пакета и печать его на экране

Скрипт хорошо работает при низкой частоте повторения, но я сталкиваюсь с проблемами при более высоких повторениях (обычно 20 мс). Когда периодичность в 20 мс, я в конечном итоге получаю переполнение буфера где-то перед in_waiting. Я проверил время цикла Python, и это занимает около 4 мс. Таким образом, похоже, что есть что-то восходящее (в FTDI или Windows), которое подает в буфер pyserial более одного пакета в течение 4 мс после пакета.

Я попытался изменить задержку FTDI в драйвере (с 16 мс по умолчанию до нескольких мс), но это не помогло.

В настоящее время я не знаю, что происходит. Не могли бы вы посоветовать, как лучше понять, что происходит?

Спасибо за вашу помощь!


person user1654361    schedule 11.11.2020    source источник
comment
как ты проверял время? Являются ли 4 мс средним/мин/макс? О какой ОС идет речь?   -  person Christian B.    schedule 13.11.2020
comment
nvm вопрос по ОС. Перечитал часть Windows.   -  person Christian B.    schedule 13.11.2020
comment
Привет, Кристиан, я вычисляю время цикла как разницу во времени между моментом входа в цикл (in_waiting — это как минимум размер пакета) и временем следующей оценки in_waiting. Поскольку длина пакета постоянна, а пакет постоянен, моя машина не сильно загружена, максимальное значение составляет 4 мс, в среднем около 3,8 мс, а минимальное - около 3,8 мс.   -  person user1654361    schedule 15.11.2020
comment
ааа подожди. Как определить переполнение буфера. Данные пропадают? Или просто слишком много данных сразу? Поскольку это ожидается, поскольку кластеры FTDI получают данные до тех пор, пока не будет получено достаточно для одного кадра USB или пока не будет инициирован тайм-аут. Он похож на алгоритм Nagle для TCP.   -  person Christian B.    schedule 09.12.2020
comment
Некоторые данные пропадают, потому что данные, которые я передаю, представляют собой список из 16-битных чисел, и я вижу, что в какой-то момент LSB и MSB поменялись местами, что указывает на потерю нечетного числа байтов (потеря четного числа байтов была бы потеря всего числа 16 бит, и я могу его не уловить). Я знаю, какие значения я ожидаю (в заданном диапазоне), поэтому я вижу потерю данных, когда вижу изменение порядка байтов, даже если происходит изменение порядка следования байтов, а скорее потеря части данных. Вы видите, что я имею в виду?   -  person user1654361    schedule 11.12.2020
comment
Я бы рекомендовал генерировать данные-заглушки, такие как порядковые номера, и проверять каждую часть, где может произойти потеря. т.е. используя 16-битные данные от одного FTDI к другому FTDI, от FPGA к FTDI, и то же самое только с 8-битными данными. В идеале проверять данные с помощью осциллографа со встроенным цифровым анализатором. Иногда кто-то упускал из виду незначительные вещи. Вы проверяли настройки драйвера Windows, такие как размер буфера и т. д.?   -  person Christian B.    schedule 29.12.2020
comment
Спасибо Кристиан за продолжение. Я уверен, что что-то упустил из виду. Я изменил код FPGA, чтобы отправить четкий шаблон данных для оценки размера отсутствующего фрагмента. Я вижу недостающий фрагмент переменного размера, в пределах сотен отсутствующих символов. Еще у меня подключен осциллограф, и декодирование UART вроде нормальное, даже если мне пока не удалось поймать на прицел участок, отсутствующий в моей программе. Я уменьшил задержку до 1 мс, увеличил размер буфера до максимума и просмотрел настройки, которые могли бы иметь значение. Я не уверен, как мне продолжать копать дальше.   -  person user1654361    schedule 11.01.2021
comment
Я до сих пор не нашел первопричину. Я записал данные с помощью другого ПО (замазка и студия мониторинга устройств) и вижу ту же проблему, происходящую примерно с той же скоростью. Так что это не похоже на код Python, работающий на ПК. Мне пока не удалось найти способ сохранить в осциллографе ошибочное окно... Этот шаг поможет сузить источник.   -  person user1654361    schedule 17.01.2021
comment
Вы можете воспроизвести поведение с другими ПК? Это происходит и с 8-битными словами? А что, если в качестве источника использовать другой преобразователь USB в UART вместо FPGA?   -  person Christian B.    schedule 19.01.2021


Ответы (1)


Вы можете создать петлю между TX и RX и запустить следующий код (проверено с FT2232H, поэтому, скорее всего, вам нужно изменить строку идентификатора):

import time
import serial
import serial.tools.list_ports


print([(x[0],x[2]) for x in serial.tools.list_ports.comports()])
port    = [x[0] for x in serial.tools.list_ports.comports() if "FT4Q1LJFB" in x[2]][0]
ser     = serial.Serial(port,12000000)

while True:
    t0      = time.time()
    counter = 0
    for i in range(1000):
        ser.write([1]*3000)
        recv    = ser.read(ser.inWaiting())
        delta_t = time.time() - t0
        counter += len(recv)
        
    print(counter / delta_t)
    

Для меня показан следующий вывод

[('COM7', 'USB VID:PID=0403:6010 SER=FT4Q1LJFA'), ('COM8', 'USB VID:PID=0403:6010 SER=FT4Q1LJFB')]
0.0
0.0
0.0
0.0
96787.81184093593
1201991.0268273412
1201197.0857713912
1201166.9350959768
1201445.4072856384

Вы заметите, что это 0.0 в начале. Это связано с тем, что я подключил RX и TX после запуска программы, что привело к увеличению количества полученных байтов. Это режим по умолчанию, означающий 8 бит + 1 стартовый бит + 1 стоповый бит = 10 бит на слово, что объясняет, почему передается только 1,2 Мбайт в секунду.

person Christian B.    schedule 13.11.2020
comment
Спасибо Кристиан за ваш код. Действительно полезно и даже проще в моем случае, поскольку у меня нет TX (FPGA безоговорочно отправляет событие периода). Я протестирую этот код, когда у меня будет установка (домашний офис Covid). Насколько я помню, я бы сказал, что в некоторых случаях я получаю 3000 байт, прибывающих в течение 4 мс (максимум) цикла, поэтому он сообщает о 750 КБ/с (больше, чем 3 Мбит/с). Я проверю как можно скорее. Идея может заключаться в том, чтобы просто читать без обработки, чтобы ускорить цикл и, возможно, лучше увидеть пакетное событие. - person user1654361; 15.11.2020
comment
У меня была возможность проверить вашу идею, но в основном результат такой же, как и у вас. В основном я получаю некоторое дрожание вокруг ожидаемого значения (что ожидаемо, поскольку мой поток UART является периодическим), и результат, который я получаю в тот момент, когда система выходит из строя, и после этого отличается не более чем дрожанием, которое я вижу, когда система работает. Я как бы меньше понимаю, где что-то идет не так. - person user1654361; 08.12.2020