• Система автоматизации с открытым исходным кодом на базе esp8266/esp32 микроконтроллеров и приложения IoT Manager. Наша группа в Telegram

UARTs RTL00

sharikov

Active member
Т.е. у регистра RUART_LINE_STATUS_REG фифо глубиной в 5, как и у всех других регистров UART ? :) Иначе смысла то нет.
Без этого цикла успевает работать на 10 000 000 Baud, а с ним - нет.
Может и фифо но скорее всего приоритетный шифратор.
Цикл выкидывать нельзя потому что обработчик прерывания должен обслужить все накопленные прерывания что и реализовано в цикле. Проблема не в идиотах-программистах а в реализации hardware которое выдает одиночный код события вместо того что выдать битовое поле сразу со всеми флагами.
16550 отвратительный uart. В микроконтроллерах полно более удачных реализаций но менеджеры в soc всегда закупают наихудшее.

Наверняка этот цикл вписали как затычку - наобум, типа и так покатит
Скорее всего обработчик прерывания написали по образцу из linux. Там подобная реализация в половине драйверов.

Динамику сложно отлаживать с Jtag, проще вписывать метки с выводом инфы хоть в консоль, перекомпилить и заливать в RAM - это быстрее раз в десять, чем тыркаться с Jtag по шагам и точкам останова... Перекомпиляция и заливка по скорости уже приблизилась к интерактивному режиму - менее пары секунд весь процесс на сложный проект...
В случаях когда нельзя ходить по шагам расставляют брекпойнты. Это все равно быстрее перекомпиляции. При перекомпиляции еще плюсуйте время на воссоздание контекста отладки.

Это очень сильно отличает данные RTL-ы от ESP и прочих, в которых код исполняется из Flash.
BN уже едет так что отладку из флэш придется вспоминать.

Для ублюдочного modbus уже придумали как обойти отсутствие прерывания по опустошению передатчика ?
 

pvvx

Активный участник сообщества
Может и фифо но скорее всего приоритетный шифратор.
Цикл выкидывать нельзя потому что обработчик прерывания должен обслужить все накопленные прерывания что и реализовано в цикле.
Где они накоплены? :eek:
Всё делается по одному событию. Если события два, то будет 2 прерывания. А так выходит лишние 4 цикла опроса на каждое событие. Встроенный тормоз :)
Проблема не в идиотах-программистах а в реализации hardware которое выдает одиночный код события вместо того что выдать битовое поле сразу со всеми флагами.
16550 отвратительный uart. В микроконтроллерах полно более удачных реализаций но менеджеры в soc всегда закупают наихудшее.
Вполне нормальный 16550 - все с ним работет, в отличии от других MCU, куда накидали отсебятины...
В случаях когда нельзя ходить по шагам расставляют брекпойнты. Это все равно быстрее перекомпиляции. При перекомпиляции еще плюсуйте время на воссоздание контекста отладки.
Про то и говорилось - прыгать по точкам останова требует времени. Тем более никакой информации в отладчике не обрабатывается и требуется всё делать глазками.
Нафиг какой-то контекст? Чип сам в состоянии, хоть на русском языке вывести то, что вписали для отладки.
Или у вас отладка - это борьба с протектед? :)
Существует масса анализаторов и методов отладки динамических процессов. Осцил + анализатор + вставка вывода в UART или в тот-же Jtag, да дрыгание ногами. Сразу дадут картину, а в отладчике, по точкам останова невозможно проверить динамические процессы, тем более в многопотоке...
BN уже едет так что отладку из флэш придется вспоминать.
А мне не нужен BN - мне RAM нужна более 512 кило. Сколько раз писать - на Web-HTTP надо более 200 кило, иначе грубые обрезки и никаких сетевых стандартов...
Для ублюдочного modbus уже придумали как обойти отсутствие прерывания по опустошению передатчика ?
Давно. Включаете loopback при передаче и приемник генерирует прерывание тишины на шине после последнего переданного символа... Т.е. передача - это самое простое. Закинули в DMA указание, включили замыкание RX-TX и ждете прерывания конца передачи с 4.5 символа тишины и переключаете далее...
Вот только с далее бяда с нерадивыми программистами пользующие модели UART без прерывания паузы - в 60% требуется вставка доп. паузы. Нерадивые не могут четко отследить паузу и переключить приемник, да шину на прием или передачу... А в данном случае, c 16550, это работает и на 6Мбод без проблем... но для modbus на данной скорости из-за тормозов у не умеющих писать надо уже другую паузу, что и вписано в стандарт...
 
Последнее редактирование:

pvvx

Активный участник сообщества
@sharikov - Вот итого HAL к UART от Ameba:
Снимок1503.gif
Межсимвольные дыры уже на более 1Mbit (serial_send_stream()). (Отладчиком это не увидеть)
При serial_send_stream_dma() такого нет.

Замер времени передачи показывает правильно:
Код:
>atui 1000000
rs485_drv_init: 1000000, 0, 0
>atuts 1234567890
Ttx = 123 us
>atui 2764800
rs485_drv_init: 2764800, 0, 0
>atuts 1234567890
Ttx = 79 us
>atui 4000000
rs485_drv_init: 4000000, 0, 0
>atuts 1234567890
Ttx = 78 us
Т.е. для отладки нафиг не нужен Jtag. Он нужен только для быстрой загрузки :)

Теперь смотрим, что будет, если убрать циклический опрос в прерывании:
Снимок1504.gif
Ускоряет процесс вывода на ~10 us на 10 символов при 2764800 baud (все замеры на CLK CPU 166666666 Hz).
Код:
>atui 2764800
rs485_drv_init: 2764800, 0, 0
>atuts 1234567890
Ttx = 74 us
>atst
CLK CPU         166666666 Hz
Т.е. как и говорил, этот цикл в прерывании вставлен Ameba для искусственного тормоза...
 
Последнее редактирование:

pvvx

Активный участник сообщества
альтернатива? закроем глаза на даже на популярность, но чтоб проводной, и дешевый?
меня бы и 1-wire устроил, но он еще более ублюдочный :)
Он просто ждет готового исходника. Сам сделать не может, вот и подчеркивает некоторые технические нюансы Modbus RTU на RS-485 :)
В системе достаточно и таймеров, чтобы сделать любую реализацию, не прибегая к специфики UART. Дискрет таймеров там 1/32768 секунды, что для Modbus RTU за глаза.
 

pvvx

Активный участник сообщества
ну так выложите, не жадничайте)
Пока не могу. Тупо некогда вырезать из готового проекта... я же не знаю что и как надо для других вариантов, а там всё в прерывании насажено и чтобы вычистить, надо ещё описать примеры использования, всё это проверить и написать документацию, а то "местные" рычать будут :)
По этому и привел стандартное и указал, куда и что... далее сами.
 
Почитал эту тему и пришел в смущение. Мне надо реализовать пакетный обмен по RS485, типа modbus, только пауза между пакетами от 2х символов. Скорость нужна до 57к. Читая примеры из SDK вырисовывался простой план реализации:
Код:
    // прием и передача
    serial_t    sobj;
    serial_init(&sobj,UART_TX,UART_RX);
    serial_baud(&sobj,BAUD);
    serial_format(&sobj, 8, ParityNone, 1);
    serial_irq_handler(&sobj, uart_irq, (uint32_t)&sobj);

    // обнаружение паузы между пакетами, формирование паузы между пакетами
    gtimer_init(&my_timer1, TIMER1);
    gtimer_start_one_shout(&my_timer2, 1000000/BAUD*10, (void*)timer1_timeout_handler, NULL);
Т.е. все реализуется в прерываниях, взаимодействие с основной программой через средства RTOS (семафор). Немного смущает то, что UART_TX и UART_RX я могу выбрать как бы любые, хотя аппаратно уарты возможны не везде, т.е. оно формирует программный уарт? Не понятно соотношение приоритетов обработчиков прерываний уарта и таймера, т.е. кто кого может прервать, или они не могут друг друга прерывать? Не понятно на сколько велики накладные расходы при использовании этих функций, т.е. хватит ли производительности на работу на 57600, не будут ли теряться байты при приеме, или возникать паузы при передаче при таком методе передачи (через serial_irq_handler)?
Смутило то, что такой простой метод в этой теме даже не рассматривался, сразу пошла прямая запись в регистры и общение на более низком уровне. Мой метод работы не годится?
 
А от какого события начинает работать таймер? :)
Если вы про вопрос определения окончания передачи, то у меня все просто: в RS485 легко аппаратно организуется прием переданного, плюс дискретность таймера в 1мкс позволяет отсчитывать длительность передачи 1 байта с достаточной точностью. Конечно это при условии, что основная работа, т.е. поддержание сети WiFi, не создаст больших пауз для прерываний от уарта и таймера.
 

pvvx

Активный участник сообщества
Если вы про вопрос определения окончания передачи, то у меня все просто: в RS485 легко аппаратно организуется прием переданного, плюс дискретность таймера в 1мкс позволяет отсчитывать длительность передачи 1 байта с достаточной точностью. Конечно это при условии, что основная работа, т.е. поддержание сети WiFi, не создаст больших пауз для прерываний от уарта и таймера.
От куда "дискретность таймера в 1мкс"?
Дискрет таймеров там 1/32768 секунды
На 6-ти Мегабитах? (1.7 мкс символ, CLK таймеров 32кГц - 31 мкс = 32768Гц *11 бит -> один символ при 360448 baud).
Про использование флага Loopback описано ранее... Прерывание приема последнего символа приходит когда - до стоп бита, после? :)
Переключение направления шины у драйвера у вас тоже через абстрактную паузу?
 
Последнее редактирование:
От куда "дискретность таймера в 1мкс"?
Времена задаются в мкс, наивно полагал что при частоте ядра много МГц получить дискрет для таймера 1мкс не проблема. Пробовал запускать таймер с периодом 100мкс, получил немного меньше, списал на неточность своего измерителя, но возможно там и правда дискрет 30мкс. Но у меня верхний предел битовой скорости 57к, т.е. 170мкс/символ, ошибка в 30мкс допустима. Я вообще слабо представляю как может использоваться RS485 на мегабитах, только если особые кабели и не большие расстояния.
Про Loopback читал, в моем случае (да и для практически любого RS485) оно может быть сделано аппаратно, правда надо быть готовым к аппаратным коллизиям, у меня эта шина внешняя, туда что угодно может попасть. Пока не выбрал как лучше, это не самый сложный вопрос, как мне кажется.
 

pvvx

Активный участник сообщества
Времена задаются в мкс, наивно полагал что при частоте ядра много МГц получить дискрет для таймера 1мкс не проблема. Пробовал запускать таймер с периодом 100мкс, получил немного меньше, списал на неточность своего измерителя, но возможно там и правда дискрет 30мкс.
Ещё раз - от какого события начинает считать таймер?
Но у меня верхний предел битовой скорости 57к, т.е. 170мкс/символ, ошибка в 30мкс допустима. Я вообще слабо представляю как может использоваться RS485 на мегабитах, только если особые кабели и не большие расстояния.
В данном случае, при создании драйвера, его цели не ограничиваются передачей на 2 км по RS-484 пакетов. Разбиение пакетов по времени может использоваться и на одной плате, где чипы стоят в пару мм друг от друга.
Про Loopback читал, в моем случае (да и для практически любого RS485) оно может быть сделано аппаратно, правда надо быть готовым к аппаратным коллизиям, у меня эта шина внешняя, туда что угодно может попасть. Пока не выбрал как лучше, это не самый сложный вопрос, как мне кажется.
C Loopback уже у меня уже есть драйвер и проверен. Там не хватает только уверенного алго для сигнала переключения направления драйвера. Т.е. нет возможности получить сигнал или прерывание менее 4-х символов тишины, что в принципе годится, но не всегда и не для всех применений и может вызвать коллизии. Итог принципов его работы показан в https://esp8266.ru/forum/threads/uarts-rtl00.1657/page-2#post-37816. Там завершающий символ выводится по событию тишины в 4 символа после передачи любой посылки (просто для теста).
А ваш подход, аналогичный Arduino, меня не устраивает, т.к. не вписывается в нормативы Modbus. Если бы была такая возможность, то уже кинул бы готовый драйвер в общий доступ.
Для Arduino и mbed в SDK есть описываемые вами функции:
Снимок1539.gif
И там далее ещё... Реализация дана в исходниках... Но мне такого ужаса не надо.
 
Последнее редактирование:
Ещё раз - от какого события начинает считать таймер?
От приема байта (это же событие будет и окончанием передачи байта). Таймеры там действительно работают на 32768кГц, причем обработчик прерывания от таймера имеет приоритет SYS_TICK, что наводит на мысль, что все таймеры это производные от системного таймера ОС. Обработчик прерывания от уарта имеет приоритет заметно ниже.
Тишина в 4 символа для меня многовато, поэтому смотрю на таймеры. В стандарте модбаса для больших скоростей есть ремарка:
Remark :
The implementation of RTU reception driver may imply the management of a lot of interruptions due to the t1.5 and t3.5 timers. With
high communication baud rates, this leads to a heavy CPU load. Consequently these two timers must be strictly respected when the
baud rate is equal or lower than 19200 Bps. For baud rates greater than 19200 Bps, fixed values for the 2 timers should be used: it is
recommended to use a value of 750μs for the inter-character time-out (t1.5) and a value of 1.750ms for inter-frame delay (t3.5).
Но у меня не совсем модбас, 4 символа для меня много, буду делать на таймерах.
Для Arduino и mbed в SDK есть описываемые вами функции:
И там далее ещё... Реализация дана в исходниках... Но мне такого ужаса не надо.
Исходники реализации обрываются на HalRuartIntRecvRtl8195a и т.п. функциях, от которых есть только заголовки. Что там дальше можно смотреть только в отладчике, т.е. вся реализация скрыта. По описанию, эти функции работаю полингом, и время таймаута там в мс, такое и мне не подходит, буду реализовывать сам на прерываниях, но не углубляясь так сильно, как вы, пользуясь "готовыми" таймерами и интерфейсами к уарту.
 
Сверху Снизу