Pull to refresh

Comments 58

Дааа!

Грязные хаки в продакшне — недопустимы. Но читать про них применимо к исследованию чего-либо… Истинное наслаждение. Спасибо.
Ну как сказать недопустимы в продакшене… Бывают, знаете ли, ситуации, когда устройства уже готовы и вам нужно кровь из носу запихать прошивку в отведенные ей N килобайт ПЗУ контроллера.
Любой продакшен состоит из трёх частей: говна, палок и интеллектуальной собственности. Палки из этих трёх — самые прочные и предсказуемые.
Так как нам не нужно отвлекаться на другие задачи, то использование таймеров явно избыточно.

При несколько измененном ТЗ, как раз таймер очень уместен в подобной задаче: Мигаем светодиодом в AVR-бутлодере
Мигание таймером вполне допустимо по ТЗ, просто мне сразу показалось, что это будет занимать больше места.
А если у нас какая-никакая многозадачность, и таймер больше нигде не нужен — то предпочтительнее задействовать его, конечно!
Энергетически неэффективно, по сравнению с предыдущим автором :-)
Есть такое ))) Искусство требует жертв ©.
В последнем случае нужно считать, что размер программы — 4096 байт :)
Да, у нас в конкретном случае объём 4 KiB, взяв другой микроконтроллер с большей памятью программ мы увеличим период, однако остальные ноги порта B осциллируют с бо́льшими частотами, можем подпаяться к ним.
То есть, имея МК с большей памятью, можно обойтись вообще одной командой?
Двумя — в порт можно выводить только РОН, а РОН при включении пусты, поэтому инструкций две:
inc r16
out ddrb,r16

У МК есть еще конфигурационные биты, ими можно понизить или повысить тактовую частоту.
Верно, запрограммировав фьюз CKDIV8, можно снизить тактовую частоту в 8 раз — до 16 кГц.
Этот фьюз может здорово попить кровь, к примеру, на ATTiny2313 он выставлен по умолчанию, поэтому генератор вроде как работает на 8МГц, а контроллеру достается только один.
Делать надо это аккуратно, от тактовой частоты работает схема внутрисхемного программирования — программатор тоже надо будет замедлять чтобы контроллер оставался видимым программатору.
Несомненно, например, AVRISP mkII поддерживает частоты программирования от 50 Гц, AVRDude тоже настраивается, говорят, что 16 кГц — не проблема.
Об этом просто надо помнить, ведь программатору надо сказать что работать нужно на пониженной частоте.
Помнить — хорошо, но не всегда получается )), тогда программатор начинает ругаться и память немедленно освежается )
Классическая неприятность — запрограммироваться на тактирование от внешнего источника. После этого спасает или высоковольтный программатор, или этот самый внешний источник.

Это усугубляется следующим моментом:

Исторически, fuse обозначал пережигаемый бит в памяти контроллера и программировался ровно один раз, путем обнуления. Поэтому все даташиты atmel пестрят фразой «0 means programmed»

Разные утилиты-прошивальщики интерпретируют запрограммированный фьюз по-разному. Популярная PonyProg рисует галочку, если значение бита 1, то есть фьюз как раз не запрограммирован. От сюда путаница и куча окирпиченных контроллеров.
Нефига, мы ведь не писали все эти 4096 байт, да и прошивка контроллера заливаться будет всего 4 байта. А то что исполнятся будут все 4096 байт… на то он и хак!

Можно вообще сделать на 3 команды программу — инкрементируем регистр, выводим в порт и тут же зацикливаемся одной командой RJMP на её же. Устанавливаем бит конфигурации WDTON в активное состояние и наслаждаемся. Наш код будет выполняться каждые 16мс, 5-й бит порта будет мигать с периодом в 1 секунду.
Регистры по вачдогу не обнуляются, только состояние периферии поэтому каждое срабатывание вачдога будет изменение внутреннего состояния.

Хм. даже зацикливаться не надо, достаточно использовать команду SLEEP — заодно экономичная работа получится. Поскольку контроллер никогда не проснется… то никакого выполнения пустого кода не будет.
Пардон, вы к посту про программу из двух команд пишете «Можно вообще сделать на 3 команды».
что-то мне показалось что там на 4 команды…
Дело в том, что использовать ту память, которая не занята нашей программой для чего-то другого все равно нельзя. Потому что она таки используется нашей программой, задействована под нашу программу

В общем, тут сложный вопрос
Как же нельзя? AVR прекрасно умеет читать/писать свою собственную память программ (а иначе бутлоадер не реализовать). Там можно данные хранить.
Если туда что-то записать, то программа станет работать не так, как положено. В этом конкретном случае, имеется в виду.
Так в этом конкретном случае никто же не пишет в память программ.
Или я не понял о чём вы?
Тут просто по дороге нашелся еще один косвенный способ управления частотой генерации для четырехбайтной прошивки — передвинуть старт, укоротив прогоняемый контроллером участок кода.
Если записать последнюю прошивку 4 байта в область загрузчика, то это не повлияет на частоту — PC дойдёт до конца, переполнится, т. е. станет равен 0, снова дощёлкает до загрузчика и выполнит итерацию. Только «фаза» сместится, что мы даже не заметим.
UFO just landed and posted this here
В пересчете на байт, наверное, была самая дорогая программа в мире
Нет, не угадали. habrahabr.ru/post/147075/ — бесконечно выгодная программа.
Так GO.COM, которая состояла из 0 байтов кода и продавалась по 5 фунтов за копию, оказалась самой прибыльной в мире — любая другая программа принесла куда меньше фунтов на байт!
Это если цельная программа. А если программное решение, то у меня был случай, когда я в течении дня пялился в неработающий код, который ребята не могли заставить работать три дня, после чего удалил из него 4 буковки и всё заработало. В пересчёте на написанный байт моё исправление имело вообще отрицательную цену.
это был x86? джамп на ребут не может занимать 3 байта однако. адрес длиннее.
и опасно это — надо обязательно буфера smartdrv флашнуть на диск — он-то не в курсе
можно было через 19-ое прерывание (кажется 19-ое? я уже не помню), но тогда это не 3 байта
UFO just landed and posted this here
вызвать прерывание… два байта — команда 1 байт и номер прерывания 1 байт.
Как сейчас помню — байт-код 0xCDxx где XX — номер прерывания.
18 или 19 прерывание… одно из них сброс, а другое зарезервировано за вызовом встроенного интерпретатора бейсика, но даже со времён XT бейсика там и в помине не было, поэтому прерывание выполняло функцию сброса системы…

Но ИМХО сейчас на современных машинах это не прокатит, супервизор перехватит переход на прерывание и даст по рукам программе — «ай-яй-яй так делать нельзя!».
а я что сказал? то же самое, что это не три байта.
кроме того, совершенно нет гарантии, что какой-то резидент не перехватывает это прерывание, либо просто вектор указывает куда-то в пустоту после того как кто-то затер системную память.
так что перезагрузка таким образом не совсем надёжна.
На современных системах НИ ОДИН способ программной перезагрузки не может быть абсолютно надёжным.
Полностью согласен — помогает только железный костыль в виде сторожевого таймера.
UFO just landed and posted this here
Старинный компьютер с LPT, 12 опторазвязок Sharp PC817 — и готова станция перезапуска/включения/наблюдения для четырех серверов.

Такой себе iLO на коленке.
UFO just landed and posted this here
Любая программа содержит ошибки.
Любую программу можно укоротить хотя бы на байт.

Вывод: в результате оптимизации получаем программу длиной в 1 байт, содержащий ошибку.
В AVR команды имеют длину 2 или 4 байта, так что 1 байт не получится, зато можно 2.
Добавил в статью.
Нет, ошибся. Оставляем 2 команды.
Ну, господа, грех не использовать хардварные регистры для битовых переменных, если сам функционал хардварный не используется. Доступ за один такт например, очень пользительно. Главное бит активации не трогать. Так можно использовать spi, twi, или usart.
Даже в продакшене это не не кошерно.
А есть еще кучка хинтов, и отнють не грязных. Просто не используемых…
У AVR доступ ко всем РОН в один такт:

Регистровый файл с битовым доступом содержит 32 восьмибитных РОН с доступом за один тактовый цикл:

«The fast-access Register File concept contains 32 x 8-bit general purpose working registers with a single-clock-cycle access».
//////// Даташит на ATTiny15, страница 5.
Это у Вас переменных в программе мало. У меня вот регистры кончились на одном проекте, а дергать переменные в памяти накладно, пришлось регистры периферии запользовать, что сильно сказалось на размере и быстродействии. На 8й меге проект.
Как автор публикации про 24 байта замечу, что мной и вторым автором — рекордсменом (12 байт) были показаны чистые способы экономии байт, которые таки годятся в продакшн.

В очередной раз благодарю за проявленный интерес и усердие в исследованиях тонкостей ассемблера и AVR в частности.

т. е. после того, как процессор выходит за пределы программы ему попадаются исключительно инструкции 0xFFFF, они незадокументированы


0xFFFF = SBRS R31,7
sbrs r, b
Пропустить команду, если рязряд регистра общего назначения установлен.
Если r.b = 1, то PC = PC + 2 (3), иначе PC = PC + 1
Код операции: 1111 111r rrrr 0bbb

Следовательно, sbrs r31, 7 это 0xFFF7.

Возможно, процессор воспринимает 0xFFFF как эту команду, при r31.7 = 0 он просто переходит дальше.
Во времена 16F84 был такой способ написать HelloWorld: изменялось состояние нужного пина на обратное и выставлялся WatchDog. Через какое-то время WatchDog сбрасывал и перезагружал процессор, то все опять с начала: изменили, заснули.
Я тут выше хотел так же, только без WatchDog'а. Но оказалось, что поменять состояние пина на противоположное — это уже три команды (прочитать, поменять, записать).
Вообще-то… одна. Запись в порт PINx на новых контроллерах приводит к инверсии пина который попал в записанную маску. Это всего две команды. Но с вачдогом это не прокатит, каждый раз порт будет «обнуляться».
Sign up to leave a comment.

Articles