Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Протокол modbus. Вопросы по интерфейсу
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Интерфейсы
Страницы: 1, 2
@Ark
Ну, хорошо, давайте продолжим...
Цитата
А что будет с вашей "минимальной временной задержкой", случись, скажем, ошибка при передаче?

Ничего страшного -"выпадет" одно из значений. Ошибки при передаче случаются при любом протоколе. При необходимости, мастер заменит выпавшее значение его аппроксимацией.
Цитата
Минимальным задержкам место внутри одного устройства, а не в распределенной системе, связанной протоколом сорокалетней давности.

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

А что Вас смущает? Вполне нормальная стратегия : обнаружили ошибку - прекратили выполнение команды и перешли обработке ошибки. А если нет ошибки, то результат готов сразу по завершению обработки команды.
Например, процессор в Вашем компьютере поступает примерно так же - очень много чего считает, забегая вперед, а потом лишь выбирает нужный результат. Если бы этого не было, то, возможно, Винда на Вашем ПК ползала бы как черепаха...
aaarrr
Цитата(@Ark @ Nov 8 2009, 20:15) *
Ничего страшного -"выпадет" одно из значений. Ошибки при передаче случаются при любом протоколе. При необходимости, мастер заменит выпавшее значение его аппроксимацией.

Выпадет просто, да? А таймаут ответа "сверхточную" времянку, конечно, не сместит.

Цитата(@Ark @ Nov 8 2009, 20:15) *
А вот это разработчику системы решать - какие устройства использовать, какими каналами их связать, какими протоколами воспользоваться и где какие допустимые задержки установить. И при этом, нужно еще помнить о стоимости системы...

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

Цитата(@Ark @ Nov 8 2009, 20:15) *
А что Вас смущает? Вполне нормальная стратегия : обнаружили ошибку - прекратили выполнение команды и перешли обработке ошибки. А если нет ошибки, то результат готов сразу по завершению обработки команды.

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

Цитата(@Ark @ Nov 8 2009, 20:15) *
Например, процессор в Вашем компьютере поступает примерно так же - очень много чего считает, забегая вперед, а потом лишь выбирает нужный результат. Если бы этого не было, то, возможно, Винда на Вашем ПК ползала бы как черепаха...

Не считает, а считывает, и не очень много.
@Ark
Цитата
Выпадет просто, да? А таймаут ответа "сверхточную" времянку, конечно, не сместит.

С чего вдруг? Точность обеспечиватется, заранее известной, точной задержкой от завершения измерений до начала передачи ответа.
Цитата
Ну, мне вот всегда казалось, что решение применить модбас можно принять разве что при наличии административного давления, если клиент очень того хочет.

Бывает и так. Мне и самому MODBUS не нравится. Но если клиент настаивает - как ему отказать? К тому же MODBUS - промышленный стандарт, все-таки.
Цитата
Меня лично смущает принесение здравого смысла в жертву за три копейки, только и всего.

Это нужно считать отдельно, в каждом конкретном случае. Иногда стоимость "здравого смысла" - отнюдь не три копейки.
Цитата
Не считает, а считывает, и не очень много.

И считывает, и считает (вычисляет). А потом еще "довычисляет", если нужно. И все равно, в итоге, получается быстрее...
defunct
Цитата(rezident @ Nov 8 2009, 18:02) *
И не про канальный уровень, а про физический,

Выше Вы привели ссылку на модель OSI, вы ее читали?

Физический уровень
Самый нижний уровень модели предназначен непосредственно для передачи потока данных. Осуществляет передачу электрических или оптических сигналов в кабель или в радиоэфир и, соответственно, их приём и преобразование в биты данных в соответствии с методами кодирования цифровых сигналов. Другими словами, осуществляет интерфейс между сетевым носителем и сетевым устройством.


Канальный уровень
Этот уровень предназначен для обеспечения взаимодействия сетей на физическом уровне и контроля за ошибками, которые могут возникнуть. Полученные с физического уровня данные он упаковывает во фреймы, проверяет на целостность, если нужно исправляет ошибки (посылает повторный запрос поврежденного кадра) и отправляет на сетевой уровень.


Физический уровень это сугубо природа сигналов, трансивер и иже с ним сдвиговый регистр и схема битового кодированая (манчестер, инверсия и т.п.). А выделением из мусора битов входного потока осмысленных данных, проверкой ошибок, занимается уже канальный уровень, на ступеньку выше. Прерывание от UART "кадр принят" это не физ, а канальный уровень.

Цитата
когда обработка прерывания по времени должна занимать как можно меньше времени. Потому, что могут быть и другие прерывания тоже критичные ко времени. Ничего не имею против вашего мнения, но получается, что вы сами себе возражали, т.к. переиначили мое сообщение так, чтобы вам было удобно возражать smile.gif
просто показал что имеет смысл собирать пакеты побайтово прямо в прерывании, а не наваливать бездумно все байты в буфер перекладывая тем самым работу канального уровня на сетевой уровень. Для примера взял PPP который в отличие от Modbus является протоколом строго канального уровня.
aaarrr
Цитата(@Ark @ Nov 8 2009, 20:43) *
С чего вдруг? Точность обеспечиватется, заранее известной, точной задержкой от завершения измерений до начала передачи ответа.

То есть процесс считывания АЦП в вашей системе выглядит так:
1. Мастер через строго определенные промежутки времени дает запрос на считывание АЦП
2. Слейв считывает/накапливает, возвращает отсчет мастеру
3. Если ответ не получен, мастер восстанавливает данные интерполяцией
Я правильно понял?

Как вы считаете, сколько времени будет сэкономлено, если предоставить слейву минимальную самостоятельность, и забирать данные не по семплу, а блоками с гарантированной доставкой?

Цитата(@Ark @ Nov 8 2009, 20:43) *
Это нужно считать отдельно, в каждом конкретном случае. Иногда стоимость "здравого смысла" - отнюдь не три копейки.

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

Цитата(@Ark @ Nov 8 2009, 20:43) *
И считывает, и считает (вычисляет). А потом еще "довычисляет", если нужно. И все равно, в итоге, получается быстрее...

Ну, расскажите мне про современные процессоры, как они "очень много чего считают, забегая вперед".
rezident
Цитата(defunct @ Nov 8 2009, 22:48) *
Выше Вы привели ссылку на модель OSI, вы ее читали?
Вот потому, что я ее читал (и неоднократно) и не называю его канальным. Т.к. часть характеристики
Цитата
Полученные с физического уровня данные он упаковывает во фреймы, проверяет на целостность, если нужно исправляет ошибки (посылает повторный запрос поврежденного кадра) и отправляет на сетевой уровень.
в моем описании отсутствует. Вообще сетевая модель OSI это лишь идеал. В реальности крайне мало (стеков) протоколов которые бы полностью укладывались в эту модель. Возможно я вообще зря ее упомянул. cranky.gif
@Ark
Цитата
Как вы считаете, сколько времени будет сэкономлено, если предоставить слейву минимальную самостоятельность, и забирать данные не по семплу, а блоками с гарантированной доставкой?

То есть, как я понял, Вы настойчиво предлагаете передавать все данные мастеру, отказавшись от их обработки в устройстве? Сделать канал побыстрее, увеличить траффик, нагрузить мастера дополнительными задачами... Я это уже комментировал, повторятся не буду.
Цитата
Стоимость потери здравого смысла здесь определяется двумя байтами CRC, время на получение которых вы так упорно хотите сэкономить, наворотив при этом кучу ненужного кода. По сравнению с тем оверхедом, который в принципе дает использование модбаса, это - ноль.

Это всего лишь Ваше мнение, основанное видимо, на Вашем личном опыте программирования А когда оно еще и не привязано к условиям конкретной задачи - его ценность, увы, нулевая.
Цитата
Ну, расскажите мне про современные процессоры...

http://ru.wikipedia.org/wiki/%D0%9F%D1%80%...%BE%D1%80%D1%8B
aaarrr
Цитата(@Ark @ Nov 8 2009, 22:24) *
То есть, как я понял, Вы настойчиво предлагаете передавать все данные мастеру, отказавшись от их обработки в устройстве? Сделать канал побыстрее, увеличить траффик, нагрузить мастера дополнительными задачами... Я это уже комментировал, повторятся не буду.

Да нет же, все с точностью до наоборот. Это вы пытаетесь нагрузить шину "реалтаймовыми" и предельно неэффективными передачами по одному семплу. Я предлагаю снабдить слейв минимальным интеллектом, и работать блоками данных (накопленных, нормализованных и т.д. и т.п.), но не в реальном времени.

Цитата(@Ark @ Nov 8 2009, 22:24) *

Не надо меня пугать википедией. Что я там должен был увидеть - прогнозирование ветвлений? Но в этом случае речь идет только о загрузке конвейера, а никак не о забегающих вперед вычислениях.
defunct
Цитата(rezident @ Nov 8 2009, 20:39) *
Вот потому, что я ее читал (и неоднократно) и не называю его канальным. Т.к. часть характеристики
в моем описании отсутствует.

Не совсем, у Вас в описании просматривается часть характеристки канального уровня - проверка правильности принятых данных (по крайней мере четность).

Цитата
Вообще сетевая модель OSI это лишь идеал. В реальности крайне мало (стеков) протоколов которые бы полностью укладывались в эту модель. Возможно я вообще зря ее упомянул. cranky.gif
Согласен, однако если грань между верхними тремя уровнями (session/presentation/app) настолько мала что ее часто трудно найти особенно в embedded сфере, то границы между нижними уровнями физ, канал, транспорт - просматриваются довольно четко. И хотя бы на этих трех уровнях можно пытаться стремиться к идеалу:

<физ уровень> --> сводится к драйверу железа или эмулятору железа (программый UART/ программный SPI)
<канальный уровень> ---> разбиение пакетов на голые байты и передача их драйверу железа, прием голых данных от железа и укладка в пакеты
<сеть> --> маршрутизация (проверка сетевого адреса).
<транспорт> --> укладка и выделение пользовательских данных в/из пакетов.

сетевой уровень (который лежит между транспортом и каналом) можно взависимости от конкретного протокола, объединять или с транспортным или с канальным уровнем. В случае одноранговой сети Modbus его выгоднее объединить с канальным уровнем, в случае многоранговой IP сети - с транспортным.
@Ark
Цитата
Я предлагаю снабдить слейв минимальным интеллектом, и работать блоками данных (накопленных, нормализованных и т.д. и т.п.), но не в реальном времени.

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

Да, действительно. О том, что команды из конвейеров могут выполняться не по порядку - ничего не сказано.
rezident
Цитата(defunct @ Nov 9 2009, 00:51) *
Не совсем, у Вас в описании просматривается часть характеристки канального уровня - проверка правильности принятых данных (по крайней мере четность).
В некоторых UART есть возможность отсеивать неправильно принятые байты, при этом (ошибках приема) прерывания просто не будет. И хотя это не очень правильно, но возможно.
Цитата(defunct @ Nov 9 2009, 00:51) *
<физ уровень> --> сводится к драйверу железа или эмулятору железа (программый UART/ программный SPI)
<канальный уровень> ---> разбиение пакетов на голые байты и передача их драйверу железа, прием голых данных от железа и укладка в пакеты
<сеть> --> поиск и проверка маршрутов
<транспорт> --> укладка и выделение пользовательских данных в/из пакетов.
ОК. Достаточно. Я вас понял. Вы канальный уровень вешаете на прерывания. Я где-то раньше так тоже делал. Но в других проектах мне показалось это нецелесообразным.
aaarrr
Цитата(@Ark @ Nov 8 2009, 23:07) *
Ну, а как быть с реальным временем?

А реальное время будет спокойно жить в слейве.

Цитата(@Ark @ Nov 8 2009, 23:07) *
Да, действительно. О том, что команды из конвейеров могут выполняться не по порядку - ничего не сказано.

Ну, это вообще не из той оперы - выполняются они не по порядку как раз для того, чтобы не получить результат, который потом придется выбросить.
Так что с "потом лишь выбирает нужный результат" вы несколько переборщили.
@Ark
Цитата
А реальное время будет спокойно жить в слейве.

Я опять не понял. Вы не могли бы излагать яснее. То есть Вы предлагаете передавать данные блоками, снабжая их метками реального времени, и с возможной неопределенной задержкой при передаче. Какая же это работа в реальном времени?
Цитата
Ну, это вообще не из той оперы - выполняются они не по порядку как раз для того, чтобы не получить результат, который потом придется выбросить. Так что с "потом лишь выбирает нужный результат" вы несколько переборщили.

Почему же? Если уже обработаны и выполнены команды за ветвлением, тогда если ветвление не состоялось, эти результаты используются. А если "вдруг" состоялось, то что еще делать с результатами этих команд - только выбросить. smile.gif
aaarrr
Цитата(@Ark @ Nov 8 2009, 23:38) *
Я опять не понял. Вы не могли бы излагать яснее. То есть Вы предлагаете передавать данные блоками, снабжая их метками реального времени, и с возможной неопределенной задержкой при передаче. Какая же это работа в реальном времени?

Наверное, я не совсем удачно выразился. Под передачей "не в реальном времени", следует понимать лишь то обстоятельство, что данные будут получены с некоторой апертурной задержкой.
Понятие работы в реальном времени при этом никак не пострадает.

Цитата(@Ark @ Nov 8 2009, 23:38) *
Почему же? Если уже обработаны и выполнены команды за ветвлением, тогда если ветвление не состоялось, эти результаты используются. А если "вдруг" состоялось, то что еще делать с результатами этих команд - только выбросить. smile.gif

OMG! Да не выполняет их никто, естественно, в конвейер только грузят.
@Ark
Цитата
... что данные будут получены с некоторой апертурной задержкой.

С какой? Это критичный параметр. В реальном времени задержка должна быть минимальна, насколько это позволяет канал и используемый протокол. В чем, в данном случае, преимущество блочной передачи, при прочих равных? Я ее не вижу.
Цитата
... Да не выполняет их никто, естественно, в конвейер только грузят.

В пентиумах - не только грузят в конвейер, но и декодируют, и выполняют (в непонятно каком порядке), по мере возможности и наличия свободных аппаратных ресурсов...
aaarrr
Цитата(@Ark @ Nov 9 2009, 00:24) *
С какой? Это критичный параметр. В реальном времени задержка должна быть минимальна, насколько это позволяет канал и используемый протокол. В чем, в данном случае, преимущество блочной передачи, при прочих равных? Я ее не вижу.

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

Цитата(@Ark @ Nov 9 2009, 00:24) *
В пентиумах - не только грузят в конвейер, но и декодируют, и выполняют (в непонятно каком порядке), по мере возможности и наличия свободных аппаратных ресурсов...

Да, а потом специальный "выпиливатель" удаляет результаты выполнения ненужных операций из регистров/памяти.
@Ark
Цитата
Преимущество блочной передачи вполне очевидно - меньшее количество запросов-ответов на единицу передаваемых полезных данных.

Здесь мы с Вами расходимся принципиально. Предпочтительнее минимальная возможная задержка от момента измерения до получения данных. И естественно, точно известное, фиксированное, значение этой задержки. А не поступление значений блоками с известными задержками. Хотя, здесь уже все зависит от задачи...
Цитата
Да, а потом специальный "выпиливатель" удаляет результаты выполнения ненужных операций из регистров/памяти.

Примерно так.
aaarrr
Цитата(@Ark @ Nov 9 2009, 00:51) *
Здесь мы с Вами расходимся принципиально.

Да, я все же не могу понять, зачем делать задержку меньше минимально достаточной. Ну да ладно.

Цитата(@Ark @ Nov 9 2009, 00:51) *
Примерно так.

Не совсем: выполнить и безболезненно удалить результат выполнения можно только в очень ограниченном ряду случаев. На практике, как я понимаю, используется только для некоторых команд типа загрузки регистров, так что до полноценных вычислений и уж тем более записи результатов дело все равно не доходит.
defunct
Цитата(rezident @ Nov 8 2009, 22:08) *
Вы канальный уровень вешаете на прерывания. Я где-то раньше так тоже делал. Но в других проектах мне показалось это нецелесообразным.

Можно полюбопытствовать - почему? - Какие объективные причины подтолкнули к такому решению? (требования к латентности прерываний, особенность ОС, особенности аппаратуры)?

Цитата(aaarrr @ Nov 9 2009, 00:17) *
Да, я все же не могу понять, зачем делать задержку меньше минимально достаточной.

Есть две разные задачи.
1. обеспечить Real-time - см. real-time protocol который с помощью меток времени и блочной передачи, вне зависимости от задержек канала и межпакетного джиттера, гарантирует real-time воспроизведение медиа потока.
2. обеспечить максимально возможный КПД использования канала.

То о чем говорите Вы решает 1), то о чем говорит @Ark решает 2).
@Ark
Цитата
Цитата(aaarrr @ Nov 9 2009, 00:17)
Да, я все же не могу понять, зачем делать задержку меньше минимально достаточной.

Цитата
Цитата(defunct @ Nov 9 2009, 00:51)
Есть две разные задачи...

Да, с этим полностью согласен. Это совершенно разные задачи. Передача потока данных с метками реального времени, для его последующего анализа или воспроизведения, и прямое управление устройствами в режиме реального времени. В первом случае задержки не так важны, в пределах допустимого. А во втором - критичны, так как они определяют время реакции системы на внешние события. И добиваться минимальной задержки нужно, в частности, для того, чтобы оставить мастеру как можно больше времени для принятия решения. Поэтому, есть прямой смысл "выжать" из канала максимальный КПД (пусть даже вопреки "здравому смыслу"). Так как альтернатива этому - только использование более быстрых каналов, что, обычно, напрямую сказывается на стоимости системы.

Цитата
Цитата(aaarrr @ Nov 9 2009, 00:17)
... выполнить и безболезненно удалить результат выполнения можно только в очень ограниченном ряду случаев. На практике, как я понимаю, используется только для некоторых команд типа загрузки регистров, так что до полноценных вычислений и уж тем более записи результатов дело все равно не доходит.

Доходит и до вычислений, и до записи. Основная идея современных процессоров - ничто не должно простаивать. Если в конвейере есть команда, которую можно выполнить заранее, и есть ресурсы - она будет выполнена. Даже если ее результат, возможно, не потребуется. До записи результатов в память - конечно не доходит, а в регистры... современные процессоры, по моему, давно не используют пересылки типа регистр-регистр, как неэффективные. Регистры просто переназначаются.
rezident
Цитата(defunct @ Nov 9 2009, 04:12) *
Можно полюбопытствовать - почему? - Какие объективные причины подтолкнули к такому решению? (требования к латентности прерываний, особенность ОС, особенности аппаратуры)?
Требования к джиттеру часто вызываемых некоторых прерываний вкупе с энергопотреблением. Т.е. ядро "спит" и просыпается лишь от внешних событий. Но одно из прерываний требует быстрой реакции на его возникновение. И прерывание от UART (которое асинхронно по отношению к нему) не должно занимать много времени, чтобы не слишком влиять на джиттер первого.
koyodza
Цитата(defunct @ Nov 8 2009, 02:09) *
Стандарты порой устаревают. А сильно распространненные нарушения часто становятся частью страндарта.
Грубых нарушений стандарта в упор не вижу, если CRC сошлась ложно, то пакет отбракуется по длине и прием продолжится.

Данное нарушение пока не стало частью стандарта. И пока это является именно грубым нарушением.
Вы никогда не получали совпадение CRC внутри пакета? Значит Вы не использовали ModBus в реальных проектах. Или Вам просто пока крупно везло.
Или Вы предлагаете после получения совпадения CRC продолжать принимать пакет, параллельно пересчитывая CRC и убеждаясь (по другим признакам) что пакет битый, после чего ждать нового совпадения CRC? cranky.gif

Цитата(defunct @ Nov 8 2009, 02:09) *
С другой стороны, на кой в холостую ждать 3.5 символьных интервала (это ж вагон и еще маленькая тележка времени особенно на 9600 и ниже), когда их можно потратить с пользой, например на вычитку архива из медленного eeprom'а по текущему запросу мастера.

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

Полностью поддерживаю идеи, изложенные коллегой rezident: не нужно смешивать разные уровни обмена в одну кучу. Прерывание по приему/передаче байта должно быть максимально коротким (взять или положить в буфер и всё). Как в принципе и любое другое прерывание.

Цитата(defunct @ Nov 8 2009, 02:09) *
Может для "Копилки Вечности" у вас найдется способ отмерить таймаут в 1.75ms под Windows?

Windows вообще никакого отношения к ModBus не имеет. Ну а если в качестве мастера у Вас выступает РС - никто не запрещает сделать интервал больше, чем 1,75 мсек. Приемлемые таймауты в единицы мсек отрабатываются нормально.


Цитата(defunct)
Есть две разные задачи.
1. обеспечить Real-time - см. real-time protocol который с помощью меток времени и блочной передачи, вне зависимости от задержек канала и межпакетного джиттера, гарантирует real-time воспроизведение медиа потока.
2. обеспечить максимально возможный КПД использования канала.

То о чем говорите Вы решает 1), то о чем говорит @Ark решает 2).

Минимальное время реакции на прерывания по разным причинам приходится обеспечивать в большинстве достаточно крупных проектов.
А вот понятия modbus и "максимально возможный КПД использования канала" - не вполне совместимы. Обычно modbus применяется там, где загрузка канала не очень высока. Иначе - нужно выбирать другой протокол, а (возможно) и другую "физику" (т.е. не 485)
defunct
Цитата(koyodza @ Nov 9 2009, 19:17) *
Или Вы предлагаете после получения совпадения CRC продолжать принимать пакет, параллельно пересчитывая CRC и убеждаясь (по другим признакам) что пакет битый, после чего ждать нового совпадения CRC?

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

Цитата
Данное нарушение пока не стало частью стандарта. И пока это является именно грубым нарушением.

Нет никакого нарушения стандарта, тем более грубого:
Код
1. При совпадении CRC текущего пакета background task создает копию принимаемого пакета,
    и записывает перекресную ссылку (друг на друга) в текщий пакет и его копию,
    а также взводит callback c таймаутом на отправку копии пакета.
2. background task приступает к формированию ответа на запрос незамедлительно,
    ответ на запрос формируется в этой же копии пакета.
3. Взависимости от того что наступит раньше - вызов callback'а по таймауту
    или прием символа по уарту:

     a. вызов callback'а наступает раньше.
          - удаляется перекресная ссылка из пакета и копии пакета (т.е. копия отвязывается от приемника)
          - приемник (оригинал пакета) обнуляется - переход к приему нового пакета
          - проверяется полностью ли сформирован ответ на запрос:
            если ответ сформирован, тогда
            он нативно отправляется ровно через указанный в стандарте минимальный межпакетный интервал
            (в 99% случаев имеет место именно этот случай).
          - если ответ еще не сформирован - повторно взводится callback с таймаутом в одно-символьный интервал.
     b. eсли раньше примется символ, прошло не более 1.5 символьного интервала от последнего принятого символа,
         копия помечается как бракованая (при вызове callback'a удалится автоматически), а символ добаляется к текущему
         пакету и подсчет CRC продолжается.
     с. если раньше примется символ, но 1.5 символьный таймаут уже пройден -
         копия пакета помечается как бракованая и оригинальный пакет обнуляется.


Собсно вот так у меня реализовано, алгоритм ниоткуда не слизанный, просто устройств в сети много, и опрашиваются непрерывно. Эти 1-2% КПД канала это +1..2 устройства в сети без ухудшения характеристик всей системы.

Цитата
Вычитка" архива (да пусть хоть даже и запись) никакого отношения к процедуре обмена не имеет. Даже если вычитываются запрошенные данные, лучше не начинать "вычитку" не приняв до конца запрос.

Расскажите это мастеру который хочет прочитать данные со слейва которые лежат в i2c eeprom'е. Если быть точнее - расскажете мастеру почему ответ на его запрос появляется не через 3.5 символьных интервала, а через 7 (4-5ms - среднее время i2c транзакции).

Цитата
Минимальное время реакции на прерывания по разным причинам приходится обеспечивать в большинстве достаточно крупных проектов.
А вот понятия modbus и "максимально возможный КПД использования канала" - не вполне совместимы. Обычно modbus применяется там, где загрузка канала не очень высока. Иначе - нужно выбирать другой протокол, а (возможно) и другую "физику" (т.е. не 485)

Я считаю, гоняться за наносекундами в обработчиках прерываний - нет смысла. Что 32 регистра в стек будет сохраняться что 1, какая разница? это вопрос микросекунды. А если что-то совсем совсем критичное ко времени реакции - проще поставить плиску или какой-нибудь мелкий МК в помощь, чем лишать себя свободы в обработчиках прерываний. Тобиш минимальное время реакции это удел мелких проектов. В крупных проектах бывает удобно уменьшать число прерываний как таковых за счет пакетной обработки нескольких прерываний от нескольких периферийных модулей за один заход. Реакция возрастает, но накладные расходы на вход-выход в обработчик снижаются пропорционально количеству обработанных за один заход прерываний.

А вот там где счет идет на миллисекунды, предпочитаю их не терять.
Максимальный КПД канала он к любому протоколу применим, в т.ч. и к Модбас, т.к. в нем минимальное время между пакетами оговоренно стандартом, вот к нему надо стремиться.
Да и на 485-м можно иметь вполне причную скорость ~2Mbps.
defunct
Цитата(koyodza @ Nov 9 2009, 19:17) *
Полностью поддерживаю идеи, изложенные коллегой rezident: не нужно смешивать разные уровни обмена в одну кучу. Прерывание по приему/передаче байта должно быть максимально коротким (взять или положить в буфер и всё). Как в принципе и любое другое прерывание.

Разные уровни обмена не нужно смешивать разумеется. Только вот идеи на которые Вы ссылаетесь примерно такого плана: а давайте чтобы сократить время реакции прерывания разобъем канальный уровень на два подуровня, первый подуровень канального уровня будем обслуживать в прерывании, а второй - постобработкой. Ничего что для этого придется обзавестись большим буфером памяти, зато реакция на прерывание будет быстрой. И ради чего? Разница ведь в нано-, микро- секундах исчисляется. Снижаем реакцию на прерывание просто ради получения минимальной реакции?! Дык с тем же успехом можете просто разрешить другие прерывания в обработчике текущего, реакция будет еще быстрее.


Ethernet MAC - пример канального уровня, выдает пакеты, а не байты которые надо собирать в пакеты. И выдает прерывания "пакет" принят а не байт принят. Так вот объясните мне доходчиво если можно, почему модель программиста канального уровня Ethernet должна отличаться от модели канального уровня PPP или того же Modbus? И зачем делать двойную работу? Зачем накапливать в памяти что-то непотребное, - escaped chars, пакеты нам не адресованые, метки времени на каждый принятый символ для определения таймаутов, и прочее г. которое можно отсеяться сразу в прерывании.
Verifi
Цитата(defunct @ Nov 10 2009, 08:00) *
Зачем накапливать в памяти что-то непотребное, - escaped chars, пакеты нам не адресованые, метки времени на каждый принятый символ для определения таймаутов, и прочее г. которое можно отсеяться сразу в прерывании.

Совершенно согласен по началу принятия пакета проверяете адрес ежли это не ваше ,то просто проверяете CRC в буфере приёма,и только если CRC не правильная или ставите флаг и обрабатываете в обработчике ошибки, либо сразу выходите из прерывания с подменой стека со смещением стека на обработчик соответствующий ошибке и соответственно надолго в прерывании не задерживаетесь.
Данным образом реализовал мастер модбус на 51 ядре с буфером приёма-передачи в 128байт интервалы пакетов контролируются в прерываниях по таймеру и по UART.
forever failure
Прально, зачем ждать на светофоре зелёного, если на дороге никого нет.
rezident
Цитата(defunct @ Nov 10 2009, 10:00) *
Ничего что для этого придется обзавестись большим буфером памяти, зато реакция на прерывание будет быстрой. И ради чего? Разница ведь в нано-, микро- секундах исчисляется. Снижаем реакцию на прерывание просто ради получения минимальной реакции?! Дык с тем же успехом можете просто разрешить другие прерывания в обработчике текущего, реакция будет еще быстрее.
Я же написал для чего это мне нужно было. Да, для этого требуется буфер на максимальную длину пакета. Но точно такой же буфер требуется и для формирования ответа, если запрошены данные максимального размера. Так что размер буфера тут рояли не играет. Ловить микросекунды по связи у меня не было задачи. Во-первых, связь была малоприоритетным фоновым процессом. Во-вторых, в реализации протокола были сразу заложены настраиваемые задержки и таймауты ожидания выдачи ответа. Так что и сверхбыстрый ответ по связи не играл никакой роли. В-третьих, я уже ответил, что не отвергаю ваших доводов по поводу реализации канального уровня, но всякому сверчку свой шесток. Я не вижу необходимости свербыстродействующей реакции на запрос мастером журнальной записи. Для измерительных же целей целесообразность выбора modbus как протокола связи уже обсудили, повторяться не стоит.
rezident
На досуге я тут кое-что обдумывал и вернулся вот к этой части сообщения
Цитата(defunct @ Nov 10 2009, 10:00) *
Разные уровни обмена не нужно смешивать разумеется. Только вот идеи на которые Вы ссылаетесь примерно такого плана: а давайте чтобы сократить время реакции прерывания разобъем канальный уровень на два подуровня, первый подуровень канального уровня будем обслуживать в прерывании, а второй - постобработкой. Ничего что для этого придется обзавестись большим буфером памяти, зато реакция на прерывание будет быстрой. И ради чего? Разница ведь в нано-, микро- секундах исчисляется. Снижаем реакцию на прерывание просто ради получения минимальной реакции?! Дык с тем же успехом можете просто разрешить другие прерывания в обработчике текущего, реакция будет еще быстрее.

defunct, поясните, пожалуйста, как вы обеспечиваете реентерабельность вашей функции канального уровня, описанной в посте #44? То бишь в каком там месте можно поставить оператор, разрешающий вложенные прерывания? Моя ИМХА почему-то упорно мне доказывает, что это прерывание (от UART) делать вложенным нельзя, если только заранее неизвестно, что сумма всех возможных вложенных прерываний не превысит величины символьного интервала для максимальной скорости передачи (т.е., например, скорость передачи достаточно низкая).
defunct
Цитата(rezident @ Nov 15 2009, 03:53) *
defunct, поясните, пожалуйста, как вы обеспечиваете реентерабельность вашей функции канального уровня, описанной в посте #44? То бишь в каком там месте можно поставить оператор, разрешающий вложенные прерывания?

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

Цитата
Моя ИМХА почему-то упорно мне доказывает, что это прерывание (от UART) делать вложенным нельзя,
Ваша ИМХА верна, само прерывание "байт принят" просто сделать вложенным нельзя. Необходимо либо перед тем как разрешать все остальные, - замаскировать текущее, либо - см. ниже.

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

Справедливо если UART буферизирует только 1 символ. Но если UART обладает RX FIFO (16550 и подобные) требования к интервалу снижаются в FIFO size раз.
Это FIFO можно организовать и программно (и оно потребует куда меньше памяти чем толстый приемный буфер обрабатываемый в background)

Код
__interrupt RxHandler(void)
{
     static int write_index = 0;
     static int read_index = 0;
     static char lock = 0;
     static char fifo_buf[ сумма всех прерываний / символьный интервал ];

     fifo_buf[ write_index++ ] = UART_RX_REG;
     if (write_index >= sizeof( fifo_buf))
         write_index = 0;

     if (lock)
        return;
     else    
        lock = 1;
     // здесь можем разрешать вложенные прерывания включая текущее
     __enable_interrupt();
          
     while (read_index != write_index)
     {
           rx_cb( fifo_buf[ read_index++ ])
           ...
     }
     lock = 0;
}
rezident
Ну вот и консенсус наметился smile.gif Считайте, что у меня реализован программный буфер FIFO. Только память, выделяемая под него, не только канальным уровнем используется, но и уровнем приложения. Для сокращения расхода RAM и потому, что ответов с микросекундной задержкой не требуется по условиям моего задания.
defunct
Цитата(rezident @ Nov 15 2009, 05:19) *
Считайте, что у меня реализован программный буфер FIFO. Только память, выделяемая под него, не только канальным уровнем используется, но и уровнем приложения.

smile.gif
Только объем буфера в десятки-сотни раз больший требуется, чем величина fifo.


Цитата
Для сокращения расхода RAM и потому, что ответов с микросекундной задержкой не требуется по условиям моего задания.

Где ж тут сокращение расхода RAM? Когда наоборот.
У меня командная консолько и та разбита на канальный уровень, на канальном уровне обслуживаются CR, LF, UP, DOWN, CTRL-H, CTRL-C, CTRL-... служебные символы.
Самой консольке же идут только осмысленные команды. Требования к буферу - строго детерминированны макс длиной команды, а если просто складывать все принятое подряд какой размер буфера брать?..
rezident
Цитата(defunct @ Nov 15 2009, 08:22) *
Только объем буфера в десятки-сотни раз больший требуется, чем величина fifo.
Не преувеличивайте. Размер буфера определяется максимальной длиной фрейма ответа. Для случая ModBus RTU это 256 байт.
defunct
Цитата(rezident @ Nov 15 2009, 05:27) *
Не преувеличивайте. Размер буфера определяется максимальной длиной фрейма ответа. Для случая ModBus RTU это 256 байт.

А где преувеличение? Сколько байт fifo потребуется? 2? 4? 8? 256 / 8 = 32. В 32 раза.

Следуя вашей схеме - сетевые адреса в прерывании у вас не обслуживаются и таймауты тоже - значит приемный буфер должен покрывать два RTU пакета - а это 256x2 байт.
А что с консолькой? Что с PPP? и там и там управляющие символы есть. Даже при известном MRU наличие упр. символов увеличивают требования к буферу - 2*MRU, а если учесть что ранжирование на пакеты делается приложением получается требования к буферу 4 * MRU.
rezident
Цитата(defunct @ Nov 15 2009, 08:33) *
Следуя вашей схеме - сетевые адреса в прерывании у вас не обслуживаются и таймауты тоже - значит приемный буфер должен покрывать два RTU пакета - а это 256x2 байт.
Это ваша схема выходит, а не моя. Зачем 2*256? Пока уровень приложения обрабатывает запрос, переданный ему с канального уровня, прием вообще запрещен. По истечение времени, выделенного уровню приложения на обработку запроса, если ответ еще не готов, то автоматически формируется типовой ответ "BUSY". Для него большого буфера не нужно.
defunct
Цитата(rezident @ Nov 15 2009, 05:59) *
Это ваша схема выходит, а не моя.

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

Цитата
Зачем 2*256?

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

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

Не вопрос пусть так, но ведь в RX прерывании складываете все подряд, в т.ч. пакеты адресованные другому слейву и ответы других слейвов.

Цитата
По истечение времени, выделенного уровню приложения на обработку запроса, если ответ еще не готов, то автоматически формируется типовой ответ "BUSY". Для него большого буфера не нужно.

Это же TX буфер, а мы вроде как про RX...
rezident
Цитата(defunct @ Nov 15 2009, 09:10) *
Да ну, я то как раз за то, чтобы выделять пакеты адресованные слейву в прерывании.
или все-таки сетевые адреса и таймауты у вас обслуживаются в прерывании? Тогда Вы противоречите сами себе.
В прерывании. Только не в UARTовом, а в таймерном. Например, 1мс-ном или 1-секундном. Не принципиально. Зависит от требуемой точности определения паузы.
Цитата(defunct @ Nov 15 2009, 09:10) *
Если не распознавать адрес и не обслуживать таймаут в прерывании.
То как Вы определяете, когда прекращать прием?
Если в RTU, то как только между двумя (или большим кол-вом, в зависимости от требуемой длительности паузы) 1мс-ыми прерываниями буфер перестал пополняться, то значит нужно считать CRC и при совпадении можно передавать указатель на начало фрейма в буфере на уровень приложения. Если другой формат. то ищутся маркеры начала/конца фрейма в буфере. И адресация тоже определяется нормально. Если адрес был получен не свой, то в таймерном прерывании буфер каждый раз очищается до тех пор, пока не обнаружится начало следующего фрейма.
Цитата(defunct @ Nov 15 2009, 09:10) *
Не вопрос пусть так, но ведь в RX прерывании складываете все подряд, в т.ч. пакеты адресованные другому слейву и ответы других слейвов.
Нет. Зачем мне пакеты, адресованные другому слейву, если только у меня не организовано маркерное кольцо для доступа к шине?
Цитата(defunct @ Nov 15 2009, 09:10) *
Это же TX буфер, а мы вроде как про RX...
При формате обмена запрос-ответ второй буфер не нужен. Слейв не будет обрабатывать второй и последующий запросы до тех пор, пока не готов ответ на первый или выделенное ему для формирования ответа время не вышло.
И еще вопрос-уточнение. А как вы обеспечиваете атомарность при проверке условия
Код
while (read_index != write_index)

? Ведь если атомарность не будет обеспечена, то последний байт, попавший в буфер в прерывании, может быть пропущен функцией обработки канального уровня.
defunct
Цитата(rezident @ Nov 15 2009, 20:15) *
Нет. Зачем мне пакеты, адресованные другому слейву, если только у меня не организовано маркерное кольцо для доступа к шине?

Но вы же их принимаете и складываете их данные в буфер... Анализируете свой-чужой - уже в приложении.

Цитата
При формате обмена запрос-ответ второй буфер не нужен. Слейв не будет обрабатывать второй и последующий запросы до тех пор, пока не готов ответ на первый или выделенное ему для формирования ответа время не вышло.

Т.е. отдельный TX буфер не нужен? А куда будем складывать отложенный ответ (тот который формируется, в момент когда уже шлется busy)?
После отправки busy, не будем ждать еще одного запроса мастера, чтобы отдать сформированный ответ?

Цитата
И еще вопрос-уточнение. А как вы обеспечиваете атомарность при проверке условия
Код
while (read_index != write_index)

? Ведь если атомарность не будет обеспечена, то последний байт, попавший в буфер в прерывании, может быть пропущен функцией обработки канального уровня.

Не пропушен (пропущен - это равнозначно потерян), а отложен до следующего прерывания! Да в приведенном варианте есть проблема последнего символа, но она тоже решается, например, запретом прерываний перед очередной проверкой индексов:

Код
     while (read_index != write_index)
     {
           __enable_interrupt();
           rx_cb( fifo_buf[ read_index++ ])
           ...
           __disable_interrupt();
     }
     ...


Можно и другим путем.

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

относится и к обычному (невложенному обработчику) в точно такой же мере? Приоритет прерывания UART'а в системе как правило далеко не самый высокий, т.о. необходимо чтобы сумма всех возможных и более приоритетных прерываний не превышала символьного интервала для макс скорости передачи, что есть практически одно и тоже с суммой всех возможных вложенных прерываний.
rezident
Цитата(defunct @ Nov 16 2009, 03:27) *
Но вы же их принимаете и складываете их данные в буфер... Анализируете свой-чужой - уже в приложении.
Нет. Анализ уже во втором слое канального уровня, как вы его охарактеризовали, происходит. Та функция которая в 1мс прерывании вызывается и работает с буфером UART.
Цитата(defunct @ Nov 16 2009, 03:27) *
Т.е. отдельный TX буфер не нужен? А куда будем складывать отложенный ответ (тот который формируется, в момент когда уже шлется busy)?
Дык в тот же буфер. Или в другой. Маленький, но отдельный.
Цитата(defunct @ Nov 16 2009, 03:27) *
После отправки busy, не будем ждать еще одного запроса мастера, чтобы отдать сформированный ответ?
В такой реализации - нет, не будем. Если предусматривать такую возможность, то нужны раздельные буферы, как вы и предлагали.
Цитата(defunct @ Nov 16 2009, 03:27) *
Да в приведенном варианте есть проблема последнего символа, но она тоже решается, например, запретом прерываний перед очередной проверкой индексов:
Вот. Все-таки не так все просто, как вы вначале описали. wink.gif
Цитата(defunct @ Nov 16 2009, 03:27) *
Вот что более интересно, а вам не кажется, что:

относится и к обычному (невложенному обработчику) в точно такой же мере?
К которому именно обработчику? Если к тому, который таймерный, то я там такую же фишку с обходом вызова функции применяю. Почему вам можно, а мне нельзя?
И еще. У меня точно также как и у вас канальный уровень абстрагирован от железа. Но в HAL я уложил еще и буфер UART и атомарность доступа к буферу я обеспечиваю там же - в функции работы с буфером UART. При этом решается проблема как с наличием аппаратного FIFO, так и с "отложенными" байтами.
P.S. на всякий случай напомню с чего началась дискуссия и ваши возражения.

Цитата(rezident @ Nov 8 2009, 07:32) *
Ради справедливости хотелось бы заметить, что не всегда есть возможность разбирать пакет "на лету" по причине многоуровневой организации связи.
defunct
Цитата(rezident @ Nov 16 2009, 00:50) *
Нет. Анализ уже во втором слое канального уровня, как вы его охарактеризовали, происходит. Та функция которая в 1мс прерывании вызывается и работает с буфером UART.

Понял. Применительно к modbus-slave я тоже так делал (выделял пакет в обработчике таймера). Но потом отказался от этого пути, потому что один уровень получается размазанным по нескольким обработчикам. И что самое печальное не все протоколы можно эффективно втиснуть в такую модель. Потом получается сложнее портировать код между МК.

Цитата
Вот. Все-таки не так все просто, как вы вначале описали. wink.gif

Ну а в чем сложность? Сорри допустил ошибку вчера (еще забыл static переменные объявить как volatile), - каюсь sad.gif
Но код же ж не стал после исправления ошибки, много сложнее? И эффективность ведь не потерялась.

Цитата
К которому именно обработчику?

К обработчику UART'а разумеется.

Цитата
Если к тому, который таймерный, то я там такую же фишку с обходом вызова функции применяю. Почему вам можно, а мне нельзя?

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

Ну а вторая причина - вы про таймер не рассказывали. Я думал у вас обработка делается в аппликейшн.

Цитата
P.S. на всякий случай напомню с чего началась дискуссия и ваши возражения.
Да да, я помню. По прежнему стою на том, что выделять пакеты удобнее всего в обработчике посимвольного приема, т.к. это упрощает разбивку и снижает расход памяти.
rezident
Цитата(defunct @ Nov 16 2009, 04:08) *
Функция в таймере которая обрабатывает весь пакет - у вас много сложнее моей, обслуживающей строго 1 символ. Поэтому если Вы выделяете целый пакет из кучи принятых байт, вам не то что можно-нельзя, а просто необходимо поступать так и только так, т.к. время выполнения функции будет диким! А вот мне можно и обойтись без вложенности вовсе.
Ничуть не сложнее. Обработка зависит от темпа поступления данных. Если темп такой же как частота вызова таймерного прерывания, то также посимвольно получится. Почему нельзя обойтись без вложенности я уже писал.
Цитата(defunct @ Nov 16 2009, 04:08) *
Да да, я помню. По прежнему стою на том, что выделять пакеты удобнее всего в обработчике посимвольного приема, т.к. это упрощает разбивку и снижает расход памяти.
С вашего разрешения по второму кругу дискуссию пускать не буду laughing.gif
defunct
Цитата(rezident @ Nov 16 2009, 02:20) *
Ничуть не сложнее. Обработка зависит от темпа поступления данных. Если темп такой же как частота вызова таймерного прерывания, то также посимвольно получится. Почему нельзя обойтись без вложенности я уже писал.

темп будет ведь не такой (для 115200 к примеру темп у вас 1:10), потому и нельзя получается.


Цитата
P.S. на всякий случай напомню с чего началась дискуссия и ваши возражения.
Цитата
(rezident @ Nov 8 2009, 07:32)
Ради справедливости хотелось бы заметить, что не всегда есть возможность разбирать пакет "на лету" по причине многоуровневой организации связи.

Уточно, что "на лету" я предлагаю не разбирать, а выделять пакет из in-stream'a. Разбирать пакет должен следующий уровень работающий в app thread'е.
demiurg_spb
Цитата(defunct @ Nov 8 2009, 03:09) *
у вас найдется способ отмерить таймаут в 1.75ms под Windows?
Performance timer...
defunct
Цитата(demiurg_spb @ Nov 28 2009, 22:54) *
Performance timer...

Согласен, начиная с P4 Northwood отмерять можно.
На более старых Intel'aх его не было.

В AMD вообще есть такой?
demiurg_spb
Цитата(defunct @ Dec 8 2009, 23:45) *
В AMD вообще есть такой?
Есть. Ещё на семпроне пробовал. Попробуйте сами.
Код
#include <windows.h>
...
bool TPerformanceCounter::Init()
{
     LARGE_INTEGER Cnt;

     if (QueryPerformanceFrequency(&Cnt))
      {
           ...
           return (1);
      }
     return (0);
}
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.