Pull to refresh

Comments 36

Ну и классически прошу немного кармы для переноса в тематический журнал :)
Перенес, спасибо всем участвовавшим :)
все такое делали, и делают каждый день. и что тут нового? К.О.
Мне такого обзора не хватало. Или готовый монстр типа FreeRTOS, или голая теория. Понаступал на грабли, выкристаллизовал свое виденье. Если кому-то пригодится еще — значит свою миссию этот пост выполнил.
ясно. эту штуку называют «карусель»
Монстрообразно. Вы предполагаете излишнюю динамику там где ее не будет. Набор обработчиков у вас практически статичный, для каждого можно записать инвариант выполнения, и проверят список условий запуска. Истинность инварианта само по себе является событием, которое не нужно ни где хранить и передавать далее. А вообще почитайте про конечные автоматы :). Каким компилятором пользуетесь, в котором есть typedef, но нет enum'а? Зачем мешать в кучу unsigned char, unsigned int, int (в вашем компиляторе наверняка есть нечто вроде inttypes.h c человеческим uint8_t и др.)? Работа со массивом обработчиков то же не продумана. Выберете что-то одно: либо вставляйте в пустое место в массиве (в setHandler), либо не двигайте элементы (в killHandler). То что бросилось в глаза, внимательно не смотрел :)
Начну с конца

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

Компилятор avr-gcc, есть inttypes.h, но внятного объяснения, почему надо использовать uint8_t вместо unsigned char я не уловил, кроме идеи тотальной портабельности. Не спорю, что мог нарушить какие-то рекомендации, но хотелось бы узнать, какие именно.

И по поводу динамики — да, можно сделать конечный автомат. Но когда нужно выполнять несколько действий с разной периодичностью (опрашивать датчики, перерисовывать экран, опрашивать клавиатуру, выдавать управляющие команды, и не забывать, что может прилететь из UART), то либо автомат становится монстрообразным и его уже на бумажке не отладишь, либо вырождается до трех состояний «инициализация-работа-ошибка», а все остальное впихивается в прерывания с непредсказуемыми задержками.

А что есть список условий запуска, как не организованная очередь сообщений?
Если вы всегда сдвигаете обработчики к началу массива, то при вставке нового вам не нужно искать свободное место для вставки ;)

Все дело даже не в идее глобальной портабельности, а в том, и это особенно характерно для МК, что объемы памяти там микроскопичны, и использую uint8_t и др. вы сами себе облегчаете задачу контроля использования например стека. Мне практика показала что так удобнее, сугубо личный опыт.

Знаете, старую присказку про «кошек не любите?», так и про конечные автоматы. Конечно если попытатся запихать всю логику в один автомат то получиться монстр, который корректировать вручную сложно, никогда не нужно упираться в крайности.

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

А можно на пальцах, как будет выглядеть автомат для такой задачи:
Опрос датчика 1 каждые 750 мсек
Опрос датчика 2 каждые 200 мсек
Обновление экрана каждые 500 мсек (выводятся данные датчиков)
Реакция на клавиатуру (хотя бы старт-стоп).

Как я не прикидывал, от конечного автомата остается еще меньше, чем в моей системе от классической rtos ;)
Вы лукавите ;) Редкий код занимается _только_ опросом датчиков. У меня нет ни малейшего желания вас упрекнуть или критиковать. Я уже написал ниже, что для любого решения всегда найдется достаточно аргументов, мы же здесь делимся опытом, правда?
по поводу uint8_t — когда я увидел такую строчку

typedef unsigned char uint8_t;

в stdint.h, то понял, что фатальным нарушением использовать unsigned char не будет. Тем более, просмотрел листинг, структуры все ровно того размера как и планировалось. Где надо — 1 байт, где надо — два байта.

В любом случае, спасибо за науку, в следующем цикле рефакторинга обязательно исправлюсь.
Обычно такие мысл возникают после прочтения чужого кода, «да, автор идиот, надо всё переписать !!».

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

Я в таких случаях говорю себе — постой, ведь автор вряд ли идиот, и он тоже знает про конечные автоматы. В этом случае, если я в таком тоне ему об этом скажу, про меня подумают, что я не подумал про это, ммм… плохо.

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

Автор статьи молодец, по AVR вообще мало статей, а стиль — стиль у каждого свой, и это хорошо :-)
Ничего не имею против чужого кода, приходилось поддерживать тонны всякого, скорее подход автора мне показался несколько неуместным для тех задач, которые он описал. И ни в коем случае не призываю все выкинуть и переписать, как могло показаться, в конце концов, каждый сам принимает решение, и любое принятое решение будет иметь достаточно веских аргументов в свою пользу. Про источники, вероятно на русском языке все имеют определенную специфику. Программированием микроконтроллеров и нас часто занимаются люди пришедшие из электроники, что накладывает определенную специфику :(. Для тех, кто дружит с английским, могу порекомендовать пожалуй, www.avrfreaks.net, ну и сам немного пытаюсь исправить ситуацию houndsblog.blogspot.com
Думаю, пока на русском разойдётся инфа по AVR, ARM уже будет стоить копейки :-)
Всё-таки, приятнее писать код, когда оперативной памяти больше чем 500 байт :-)
Дело не в стоимости арм, а в том, что он много где совершенно избыточен
Согласен, но унификация великая вещь. ARM имеет запас, AVR — нет. Проще один раз написать и отладить софт под более мощный процессор, такой как ARM, и потом 20 лет им пользоваться, чем писать под AVR, а когда возникнет необходимость что-то добавить, всё переделывать второпях за оч. большие деньги.
«Через 20 лет ничего не будет, будет одно телевидение» ;) Ну буду с вами спорить, каждый сам себе бобр. Не надо крайностей, вот и все. Во многих проектах и AVR много.
Билл Гейтс:

«I have to say that in 1981, making those decisions, I felt like I was providing enough freedom for 10 years. That is, a move from 64k to 640k felt like something that would last a great deal of time. Well, it didn't — it took about only 6 years before people started to see that as a real problem.»

Так что, когда мы говорим о 20 годах, вполне возможно, что речь идёт всего о 12-ти. И проекты меняются и люди, так что запас всегда нужен, не раз в этом убеждался :-)
требование гарантированного времени отклика — главное в определении осрв
так что то, что тут описано, даже не «почти осрв». просто диспетчер событий, который быстро работает
Вопрос классификации всегда спорный. Этот диспетчер гарантирует мне время отклика 1 мсек при всех возможных комбинациях входящих взаимодействий. Этого для решения моих практических задач хватает. Да, это достигнуто не только особенностью системы, но и оптимизацией функций-обработчиков, которые не занимают процессор дольше 10-100 мксек.

Вот и получилась «недоОСРВ».
Кстати про классификацию. Если речь идет про РВ, то лучше всегда формулировать то определение РВ, которое вы приняли для себя как руководствующее. Согласитесь два определения РВ: «превышение максимально допустимого времени реакции равнозначно отказу системы» и «детерминированность алгоритма по времени вне зависимости от входных данных» накладывают совершенно разные ограничения.
Отлично начало =) поскорее бы увидеть продолжение.
При выполнении установки события в очередь записывается структура. Если в этот момент будет интеррупт и там тоже будем записывать событие, то может быть конфликт с непредсказуемыми последствиями. Прерывания надо бы там запрещать.
Согласен, этот механизм уже переработан.
Но тут второй вопрос — когда разрешать прерывания? Если я разрешу прерывания в конце функции, то при возврат в обработчик прерывания будут разрешены, тоже с непредсказуемыми последствиями.

Пока реализовано так: вызываю занесение в очередь в самом конце обработчика прерываний (пока это возможно).

В принципе, вариантов два:
— предусмотреть параметр вызова — флажок, надо ли запрещать/разрешать прерывания;
— после вызова в обработчике принудительно запрещать прерывания;

Какие еще могут быть варианты?
В WinAVR есть такая интересная приблуда как atomic.h

Так вот в ней есть макросы клевые. atomic forseon и atomic restorestate

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

А вот второй хорош тем, что он запрещает прерывания однозначно, но на выходе разрешает их ТОЛЬКО если они были до этого разрешены.

Примерно то же самое только с другим синтаксисом есть в IAR. Вообще погугли по атомарным операциям. Собственно проблема у тебя именно с ними.
И приятно, что мэтр посетил пост :) AVR я изучал в основном по вашему сайту и даташитам.
Ну прям уж мэтр :))))

А сколько занимает скомпиленное ядро?
Само ядро диспетчера — чуть больше килослова. В принципе можно оптимизировать, но мне пока не критично.

А за atomic.h — спасибо, поробую применить )
Жирновато. Можно в 720 байт загнать. Могу дать пофтыкать один свой проектик.

Рекомендую избавиться от нумерации задачи и оперировать сразу же адресами. Это будет проще и эффективней.

З.Ы.
А я пожалуй себе потырю у тебя функцию kill Timer :) А то чет я до такой не догадался :)
Давай, конечно. Пофтыкать оно всегда полезно.

А по поводу нумерации — пока немного не понял. У меня ж не задачи, у меня — сообщения. Event-driven. То есть одно сообщение могут обрабатывать несколько обработчиков последовательно.
упс. Не килослова, а килобайта. 1124 байт, запутался в нумерации :)
UFO landed and left these words here
Sign up to leave a comment.

Articles