Что делать, кто виноват и почему оно не работает?

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

В России, как известно, два главных вопроса: "Кто виноват?" и "Что делать?". Наш форум добавляет к ним третий, не менее, а может и более сложный - "Почему оно не работает?". И вот я в этих трёх вопросах немного заблудился.

Вот, допустим, надо организовать работу с AT-командами из монитора порта. Ну, что, берём Uno, цепляем модуль с которым надо работать на софтверный сериал и пишем маленький скетч-прокси. Оно, понятно, что Uno здесь лишняя и никаких прокси не надо, но вот такая задача.

#include <SoftwareSerial.h>

#define	ssRX	8
#define	ssTX	7

SoftwareSerial ss(ssRX, ssTX);

void setup(void) {
	Serial.begin(115200);
	ss.begin(9600);
}

void loop(void) {
	if (Serial.available()) ss.write(Serial.read());
	if (ss.available()) Serial.write(ss.read());
}

и оно не работает! Вернее, работает, но глючит безбожно.

Ну, вроде, "Почему оно не работает?" - понятно (если подумать немного). "Кто виноват?" - в общем-то тоже понятно (и это не коммунисты, не евреи и даже не криворукие китайцы!). А вот "Что делать?" ... вернее, как сделать софтверный сериал, чтобы таких глюков не было ... в общем это вопрос.

Вопрос, правда, философский, т.к. делать его я не собираюсь. Но потрындеть было бы интересно.

P.S.
В топике умышленно не разжёвано почему оно не работает. Тех, кто это понимает, приглашаю к дискуссии "как делать сфотсериал, чтобы такого не было". А тех, кто не понимает ... без обид, ребята, но Ваше мнение в этой дискуссии неинтересно.

Komandir
Offline
Зарегистрирован: 18.08.2018

А скорости умышленно в 12 раз отличаются ?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Ворота пишет:

 как сделать софтверный сериал, чтобы таких глюков не было .

дык напишите грамотно свою библиотеку чтоб работал только с парой пинов PCINT, а не всем МК atmega - как минимум половина интернет сообщества вам спасибо скажут.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

В 12 - случайно. Достаточно в два. По идее, эти скорости друг на друга влиять не должны (но влияют). Ну, хочешь, поставь flush после каждого write

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Дело не в пинах PCINT.

В этом легко убедиться. PCINT там используется только для чтения. Убери чтение из моего примера (строку 15) и гони данные только в одну сторону "сериал -> софтсериал". Всё равно будет глючить. Так что не в PCINT проблема.

sadman41
Offline
Зарегистрирован: 19.10.2016

Софтсериал - штука капризная в принципе. Если его использовать в сценариях сложнее, чем "послал и слушаешь во while()" и на высоких (>38400) скоростях, то предсказывать результат работы вообще сложновато. Он, мерзавец, внутре себя и прерывания отключает...

Хотя вот в данном случае всё, в принципе, работать должно - последние версии SoftwareSerial являются Interrupt driven и сам луп не нагружен.

Какие симптомы-то?

 

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

sadman41 пишет:

Какие симптомы-то?

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

Мой пример начинает нормально работать, если в софтсериале cli закомментировать. Но тогда, если кто другой прервёт и будет полчаса в прерывании сидеть, тайминги сломаются.

Вот и задумался я как его можно по уму-то сделать.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

ну вот аналогичный старинный пример, аппаратный 115200, с модемом общение 9600 

http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-ni...

если скорости поменять - все ломается и не работает.

Лечение вижу только такие - замена библиотеки (на что?), обработка данных off line (где ж столько памяти на хранение взять?), замена МК.

 

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andycat пишет:
замена библиотеки (на что?)
Так это есть тема, заявленная ТС. Решил человек порассуждать как бы такую библиотеку по уму сделать. Зазудело :-) Ничего, пива хлопнет вечерком - пройдёт :-)

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

andycat пишет:

http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-376729

чтения русских и / или длинных СМС

Неленивый, однако! Я почитал как оно там всё и решил, да ну его в жопу столько расписывать - нахрена мне читать русские/длинные смс-ки? Для управления чем-нибудь обойдусь DTMF или короткими на латинице :-)

Izvekoff
Offline
Зарегистрирован: 02.03.2020

ЗЫ ...поступающие в виде частых прерываний запросы на посимвольную обработку входящих данных стали большой проблемой, поэтому последовательные порты в IBM PS/2 стали реализовываться с использованием 16550(A) UART, имеющего FIFO-буфер ёмкостью 16 байт для хранения поступающих символов

вопрос только в его количестве я так понимаю?

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

ЕвгенийП пишет:

andycat пишет:

http://arduino.ru/forum/apparatnye-voprosy/vse-o-sim800l-i-vse-chto-s-nim-svyazano?page=1#comment-376729

чтения русских и / или длинных СМС

Неленивый, однако! Я почитал как оно там всё и решил, да ну его в жопу столько расписывать - нахрена мне читать русские/длинные смс-ки? Для управления чем-нибудь обойдусь DTMF или короткими на латинице :-)

Я же только учусь :)
Хорошая практика парсинга online, жизни в ограниченных ресурсах МК и т.д.....

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

Izvekoff пишет:

ЗЫ ...поступающие в виде частых прерываний запросы на посимвольную обработку входящих данных стали большой проблемой, поэтому последовательные порты в IBM PS/2 стали реализовываться с использованием 16550(A) UART, имеющего FIFO-буфер ёмкостью 16 байт для хранения поступающих символов

вопрос только в его количестве я так понимаю?

Как оказалось из практики (сейчас мучаю stm32) - буфер в несколько десятков байт вообще ни о чем, логика МК отрабатывает настолько быстро, что узкое место оказывается периферия, закинуть пару килобайт данных в какой нибудь SIM7500E занимает микросекунды, а отправляется гораздо медленнее, поэтому алгоритмы работы программ и выходят на первое место, распараллеливание потоков и т д.

andriano
andriano аватар
Онлайн
Зарегистрирован: 20.06.2015

andycat][quote=Izvekoff пишет:

Как оказалось из практики (сейчас мучаю stm32) - буфер в несколько десятков байт вообще ни о чем ...  поэтому алгоритмы работы программ и выходят на первое место, распараллеливание потоков и т д.

Ну, насчет распараллеливания в рамках МК - это как-то совсем уж круто, но над алгоритмами задумываться приходится.

Сейчас в работе проект, где МК отправляет наружу (на внешний синтезатор) MIDI-файл. Естественно, делается это все строго по времени и поэтому в прерывании. Но вот ведь зараза! Оказалось, в MIDI файле можно встретить одновременно более 30 команд. В реальности сделать такое абсолютно невозможно. Но вот настучать мышкой в MIDI-редакторе - запросто. 

Т.е. из прерывания происходит попытка отправки порядка 100 байтов. Естественно, на 65-м байте функция записи начинает тормозить прерывание до освобождения буфера передачи. Ну и прерывания наползают друг на друга, в результате чего МК виснет.

Тоже думал, что делать, увеличить размер буфера порта (с одной стороны, для stm32 его увеличение в 2/4/8 раз - не проблема, но останавливает то, что это изменение нельзя сделать локально, в отдельно взятом проекте), но в результате решил бороться именно алгоритмически, - прогнозируя заполнение порта и при необходимости перенося команды в следующее прерывание.

andycat
andycat аватар
Offline
Зарегистрирован: 07.09.2017

При отправке отказался от прерываний, сделал в цикле каждого прохода проверку флагов аппаратного uart, не уверен что правильное решение. При выкладывании байта в fifo буфер приходилось запрещать прерывания т к в этот же момент могло сработать прерывание отправки и байт терялся. Учитывая что один такт МК примерно 14 наносекунд, while ожидания флага готовности отправки занимает непозволительное время, мне это не понравилось. Пока логика работает, посмотрим что дальше будет при усложнение программы. Возможно все будет меняться.

sadman41
Offline
Зарегистрирован: 19.10.2016

Ворота пишет:

Вот и задумался я как его можно по уму-то сделать.


Я бы выбрал 328PB в качестве затычки. Создавать генерализованное решение для ардуины - а это, видимо, занять один таймер и дёргаться по нему для отправки байта - слишком расточительно по ресурсу и затратам времени.

Morroc
Offline
Зарегистрирован: 24.10.2016

Ворота пишет:
Но тогда, если кто другой прервёт и будет полчаса в прерывании сидеть, тайминги сломаются.

Кто, например ? Если у вас несколько процессов настолько критичных по времени, то проблемы неизбежны, возьмите ардуину пожирнее и не парьтесь.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

sadman41 пишет:
Я бы выбрал 328PB
Таки да. Или любой другой МК с двумя юартами.

sadman41 пишет:
Создавать генерализованное решение для ардуины - а это, видимо, занять один таймер

На самом деле сама идея "генерализованного решения" порочна. Он исходит и предпосылок, сформировавшихся при программировании больших машин.

Вот смотрите - типичное рассуждение о таких идеях: «Ну, да, если взять таймер под это дело, то не будет необходимости закрывать прерывания и я никому не нагажу. Но, стоит кому-нибудь закрыть прерывания, как он нагадит мне – сломает тайминги»

Здесь изначально неверный посыл в слове «кому-нибудь». Кому именно? Это что, мультипользовательская система, где кроме меня ещё 10+ юзеров свои задачи гоняют? Или мультизадачная и в ней есть какие-то демоны, которых я не запускал?

Никаких «кому-нибудь» здесь нет! Здесь есть я и только я! Если я сам себе не нагажу, то никто мне не нагадит.

Потому, надо просто признать, что никаких универсальных, на все случаи жизни, библиотек не бывает в природе. Пихать в код чужие библиотеки, которые ты сам не знаешь построчно, категорически нельзя – только своё или такое, что ты буквально покомандно разобрал и целиком знаешь.

Тогда можно делать то, что нужно под конкретную задачу (закрывать прерывания или сидеть в обработчиках по часу) и точно знать, что никто тебе не нагадит и ты никому не нагадишь по очень простой причине – кроме тебя там никого нет.

А чтобы делать более или менее универсальные решения с такой философией, явно не хватает продвинутого препроцессора – просто ещё одного прохода перед компиляцией, где можно было бы полноценно генерировать и разворачивать код. По крайней мере мне этого точно не хватает. Вот этим бы заняться и в тулчейн его встроить – цены б не было.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Morroc пишет:
возьмите ардуину пожирнее
Да, пожирнее - не спортивно. Я вот часто делаю что-то на тиньках (и мучаюсь) просто потому, что "на меге и дурак сделает".

Morroc пишет:
Кто, например ?
А вот это прекрасный вопрос! Как раз только что я написал развёрнутый пост на эту тему (см. выше).

sadman41
Offline
Зарегистрирован: 19.10.2016

ЕвгенийП пишет:

На самом деле сама идея "генерализованного решения" порочна. Он исходит и предпосылок, сформировавшихся при программировании больших машин.

Вот смотрите - типичное рассуждение о таких идеях: «Ну, да, если взять таймер под это дело, то не будет необходимости закрывать прерывания и я никому не нагажу. Но, стоит кому-нибудь закрыть прерывания, как он нагадит мне – сломает тайминги»

Согласен по всем пунктам. Всё, что не имеет возможности исполняться автономно, не завися от основного процессора, является потенциальным местом появления "багов". Переход на таймер в данном случае - только способ увеличения количества девяток после запятой в надёжности системы, а не панацея.

Logik
Offline
Зарегистрирован: 05.08.2014

sadman41 пишет:
занять один таймер и дёргаться по нему для отправки байта - слишком расточительно по ресурсу и затратам времени.

А по другому не сделаешь. Я делал так. Таймер щелкает в 4 раза чаще длительности бита. Если прием не ведется, в каждом вызове прерывания контролируем RX и при обнаружении старта переходим в режим приема, отсчитываем 5 вызовов и принимаем первый бит, затем каждые 4 вызова очередной. С передачей проще, там просто каждые 4 такта плюем бит. Просится вроде перенастраивать длительность таймера, но нельзя т.к. если во время передачи начнется прием то ошибка будет. Ну и понятно что другие прерывания должны отрабатывать не дольше периода таймера. С учетом системных часов ардуины выходит ограничение скорости порядка 2400бод.

Ворота
Ворота аватар
Offline
Зарегистрирован: 10.01.2016

Спасибо, мужики! Разговор пошёл именно в том русле, на которое я расчитывал.

Так что, все считают, что универсальных решений не бывает? 

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

Morroc
Offline
Зарегистрирован: 24.10.2016

Возможно. Я так глубоко копаю редко и тинек хитрым кодом не насилую )