Маленький Hello World для маленького микроконтроллера — в 24 байта (и чужое решение в 12 байт)

Классической тестовой программой для большинства программистов на системах, имеющих хоть какой-то дисплей, является Hello World. Такая традиция была введена Керниганом и Ритчи в 1978 году.

Для микроконтроллеров аналогичным примером уже давно стала программа, которая мигает светодиодом. В этой статье я покажу результат эксперимента по максимальному сокращению такой программы на примере контроллера ATTiny15 фирмы Атмел.

image

UPD: В комментариях привели ссылку на рекордное решение в 12 байт. Браво!
UPD2: Путем насилия над контролером, удалось выиграть еще 2 байта.
UPD3: И еще одно решение, с еще большим насилием над контроллером.
UPD4: Еще один вариант — в одну инструкцию (но исполняется при этом вся память программ), как и в вариантах 2 и 3.
UPD5: Вариант с использованием возможности выдать тактовый генератор на один из пинов контроллера, при помощи FUSE-бита


О контроллере


Возможности контроллера невелики. Тактовая частота — 1.6МГц от внутреннего генератора. Свободных выводов, которые можно использовать без отказа от возможности аппаратного сброса и перепрошивки по SPI — всего пять. Имеется два таймера и АЦП. Память — 64 байта EEPROM. ОЗУ нет, только 32 регистра общего назначения и стек, глубина которого не может быть больше трех. AVR-GCC отказывается работать с таким контроллером — предлагает использовать ассемблер.

image

Инструментарий


Операционная система — Open Suse Linux 13.1. Среда разработки — AVR Studio 4.12, выполняется под Wine. Программатор — USBASP под управлением AVRDUDE. Программатор непосредственно соединен с контроллером, давая ему питание и во время прошивки, и во время экспериментов.

Проблема — программатор держит RESET


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

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

image

Мигаем светодиодом


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

Банальная реализация задержки состоит в организации цикла из пустых инструкций, в котором будет вертеться контроллер между переключениями пина. Это классический delay_ms, столь любимый ардуинщиками. Минусов тут два как минимум: короткий минус — контроллер не получится усыпить, длинный — контроллер не сможет выполнять другие задачи. Действительно, любое прерывание приведет к тому, что тщательно высчитанное для задержки количество тактов ее уже не обеспечит: время, проведенное контроллером в обработчике добавится ко времени задержки. Можно, конечно, в обработчике предусмотреть коррекцию, а потом коррекцию коррекции (если в обработчике есть ветвление с ветвями разной длины) — в итоге получится весьма непростой код, о доказательстве корректности которого говорить достаточно тяжело.

Именно поэтому любые задержки стоит реализовывать на таймерах. У контроллера ATTiny15 таких таймеров два. Оба таймера могут считать до 255, после чего выдавать запрос на прерывание. Источником тактов для таймеров может служить внешний сигнал или делитель внутреннего тактового генератора. Делитель позволяет получать дробные частоты от тактовой — F/1, F/8, F/64, F/256, F/1024. По умолчанию контроллер работает на частоте 1.6МГц, если использовать делитель на 1024, получим частоту приращения таймера 1562,5Гц. Так как прерывание таймер будет выдавать на каждый 256-ой инкремент, мы получим дополнительное деление на 256 и итоговую частоту около 6Гц. Вполне приемлемо для мигания светодиодом.

Первая версия прошивки — по всем правилам хорошего тона


В начале прошивки у всех AVR должны находиться инструкции перехода к обработчикам прерываний. Это очень похоже на состояние дел у x86, но у них в начале памяти хранятся не инструкции, а адреса обработчиков.

У ATTiny15 таких инструкций должно быть девять. Первый обработчик, например — обработчик сброса, фактически — точка входа в прошивку.

rjmp reset
reti
reti
reti
reti
rjmp timer0
reti
reti
reti


На месте отсутствующих обработчиков стоят инструкции возврата из прерывания. Но они никогда вызваны не будут — соответствующие прерывания запрещены. То есть эти четыре штуки reti после rjmp reset нужны только для того, чтобы rjmp timer0 оказалась на своем месте.

Работа программы состоит в настройке предделителя для таймера,
	ldi r31,(1<<cs00 ) | (1<<cs02)
	out tccr0,r31


разрешении прерывания от таймера,
ldi r31,1<<toie0
out timsk,r31


разрешении обработки прерываний процессором,
sei


переключении вывода 7 контроллера в режим push-pull,
ldi r31,0b100
out ddrb,r31


и зависания в бесконечном цикле
	lp:
		rjmp lp


Обработка прерывания состоит в инверсии регистра и выводе этого значения на ножку контроллера
timer0:
	com r31
	out portb,r31
	reti


После сборки получили 40 байт машинного кода:

image

Сокращаем программу


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

.include "tn15def.inc"

//вместо переходов на обработку прерываний сразу помещаем 4 инструкции
	ldi r31,(1<<cs00 ) | (1<<cs02)
	out tccr0,r31
	ldi r31,1<<toie0
	out timsk,r31
//но обработчик таймера надо оставить на своем месте
rjmp reset
rjmp timer0

//обработчик сброса (продолжение)
reset:
	
//разрешение обработки прерываний
	 sei
	//запись в регистр битовой маски, которая при работе программы будет инвертироваться
	//при переполнении таймера и выдаваться в порт B
	ldi r31,0b100
	//переключение режима порта B, пин 2 (счет с 0) на вывод push-pull
	//даташит, страница 51
	out ddrb,r31

	//бесконечный цикл
	lp:
		rjmp lp
//обработчик прерывания  по переполнению таймера 0, вызывается с частотой около 6Гц
timer0:	
	com r31 			//инверсия битов r31
	out portb,r31		//выдача значения в порт - либо высокий уровень, либо низкий
	reti				//возврат из прерывания	


image

Получили 26 байт, можем еще?

Можем!

Разместим обработчик прерывания от таймера сразу на своем месте, избавившись от перехода и сэкономив целых два байта:

ldi r31,(1<<cs00 ) | (1<<cs02)
out tccr0,r31
ldi r31,1<<toie0
sbr timsk,toie0
//перепрыгиваем обработчик прерывания при переполнении таймера 0
rjmp reset
//обработчик прерывания  по переполнению таймера 0, вызывается с частотой около 6Гц
com r31 //инверсия битов r31
out portb,r31	//выдача значения в порт - либо высокий уровень, либо низкий
reti	//возврат из прерывания
//обработчик сброса (продолжение)
reset:
//разрешение обработки прерываний
sei
//запись в регистр битовой маски, которая при работе программы будет инвертироваться
//при переполнении таймера и выдаваться в порт B
ldi r31,0b100
//переключение режима порта B, пин 2 (счет с 0) на вывод push-pull
//даташит, страница 51
out ddrb,r31
//бесконечный цикл
lp:
rjmp lp	


После сборки получилось 24 байта:

image

Сбережем немножко энергии ценой всего шести байт


Так как контроллер у нас кроме обработки прерывания ничем не занимается, стоит усыпить ядро процессора, оставив при этом таймер работающим. Это делает инструкция SLEEP, которая управляется флагами SE, SM1, SM0 регистра MCUCR. Режимов сна у контроллера несколько, начиная от самого глубокого Power Down, при котором контроллер может разбудить только сторожевой таймер, сброс или изменение состояния вывода, и заканчивая ожиданием, при котором ядро остановлено, но таймеры, АЦП и некоторая другая переферия — работают. Это тот режим, который нам подходит, он задается, если стоит только флаг SE.

Важно помнить, что после пробуждения и обработки прерывания контроллер попытается исполнить следующую после SLEEP инструкцию, значит усыпление необходимо зациклить:

.include "tn15def.inc"

//подготовка таймера 0 - выбор источника тактирования
	//источник - тактовый генератор 1.6 МГц с делителем на 1024
	//дает инкремент таймера каждый 1024 такт
	//выполняется путем записи в регистр TCCR0 комбинации флагов CS00 и CS02
	//даташит, страница 27, таблица 9
	ldi r31,(1<<cs00 ) | (1<<cs02)
	out tccr0,r31
	
	//Разрешение обработки прерывания по переполнению таймера 0
	//выполняется путем записи в регистр TIMSK флага TOIE0
	//даташит, страница 20
	ldi r31,1<<toie0
	out timsk,r31
	//перепрыгиваем обработчик прерывания при переполнении таймера 0
	rjmp reset


////////////////////////////////////////////////////////
//обработчик прерывания по переполнению таймера 0, вызывается с частотой около 6Гц
	com r31 			//инверсия битов r31
	out portb,r31		//выдача значения в порт - либо высокий уровень, либо низкий
	reti				//возврат из прерывания
////////////////////////////////////////////////////////


//обработчик сброса (продолжение)
reset:
	//запись в MCUCR флага разрешения перехода в спящий режим
	ldi r31,(1<<SE)
	out mcucr,r31

	//разрешение обработки прерываний
	sei

	//запись в регистр битовой маски, которая при работе программы будет инвертироваться
	//при переполнении таймера и выдаваться в порт B
	ldi r31,0b100
	//переключение режима порта B, пин 2 (счет с 0) на вывод push-pull
	//даташит, страница 51
	out ddrb,r31

	//бесконечный цикл сна
	lp:		
		sleep	
		rjmp lp	
	



image

Программирование на ассемблере является наиболее трудоемким способом получения программ, оптимизированных по размеру и скорости выполнения. Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.

В следующей статье — конвертер USART <-> 1wire на основе этого же контроллера.

Интересно почитать


Проект на гитхабе;
Эдсгер Дейкстра. Избранные статьи;
Даташит на контроллер;
Электроника для всех.

UPD: В комментариях привели ссылку на рекордное решение в 12 байт.
Коротко — идея состоит в использовании сторожевого таймера и того факта, что РОН при сбросе от него не обнуляются.
LDI R16,(1<<WDE) | (1<<WDP2) | (1<<WDP1)
OUT WDTCR,R16
OUT DDRB,R16
COM R17
OUT PORTB,R17
L:  RJMP L


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

В соединении с усыплением контроллера сторожевой таймер — мощное средство для реализации энергосбережения. Причем вместе с ним можно использовать самый глубокий сон — Power Down. Ценой дополнительных четырех байт сэкономим пару микроватт:

  LDI R16,(1<<WDE) | (1<<WDP2) | (1<<WDP1)
  OUT WDTCR,R16
  ldi r16,(1<<SM1) | (1<<SE) 
  out mcucr,r16
  OUT DDRB,R16
  COM R17
  OUT PORTB,R17
  SLEEP


И да, можно поступить совсем по-свински — убрать из рекорда финальное зацикливание, получив решение в 10 байт.

UPD: В комментариях привели ссылку на рекордное решение в 12 байт. Браво!
UPD2: Путем насилия над контролером, удалось выиграть еще 2 байта.
UPD3: И еще одно решение, с еще большим насилием над контроллером.
UPD4: Еще один вариант — в одну инструкцию (но исполняется при этом вся память программ), как и в вариантах 2 и 3.
Share post
AdBlock has stolen the banner, but banners are not teeth — they will be back

More
Ads

Comments 41

    +1
    Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.

    А смысл?
    Современные компиляторы (IAR, Keil, avr-gcc) выдают код, оптимизированный с большим набором ключей и параметров.
    «Впихать невпихуемое», также как и использовать каждый такт считается при нынешних ценах моветоном.

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

    На практике же разработка на ассемблере считается дурным тоном, если на то нет особых причин. А многие продвинутые разработчики перешли с си на с++ и на практике показывают, что оверхед если и есть, то небольшой (для современных контроллеров класса хотя бы Cortex-M), а на некоторых проектах получается даже выигрыш за счет большей структуризации.

    Упс… пропустил…
    ОЗУ нет, только 32 регистра общего назначения и стек

    Тогда просится forth :)
      +5
      Разумеется, я с вами согласен, так как человекочас работы программиста стоит много дороже тактов и ячеек памяти. Однако есть еще на вскидку три области, где экономия на тактах актуальна — программирование для развлечения/обучения, встраиваемые системы для жестких условий (космос, роботы для ликвидации аварий на АЭС и подобное) и жесткое энергосбережение.
      Замечание в сторону — отсутствием экономии на тактах несознательные граждане доводят Андроид до посадки батареи за полсуток.
        +2
        Про встраиваемые системы и программирование с преждевременной оптимизацией, а также экономии на байтах не надо — почитайте «историю одного байта». Всегда берут с необходимым запасом. И главные критерии здесь не малый размер и быстрота кода, а надёжность и предсказуемость.

        Да ресурсы там ограничены, однако за код на месте векторов прерывания, и за отсутствие всех обработчиков вас там вряд ли похвалят. (Это если мы говорим про нормальную разработку а не «Back to Sovet Union»).
        +1
        Форта не будет — стек реализован отдельно от регистров, в него можно поместить только три значения и этими значениями может быть только девятибитный указтатель инструкции (даташит, страница 9)
          +2
          На С++ оверхэд есть, и большой, я с трудом впихал свой проект в память Cortex M3 (LPC1768), хотя предыдущая версия, написанная на С, размещалась без проблем. Больше всего был расход ОЗУ: кучи и стека, их С++-программа ест гораздо больше чистого С.

          А ассемблер — зло. Неподдерживаемый и немодифицируемый код.
            +1
            А ассемблер AVR это ещё большее зло, т.к. у него зачастую яркая несовместимость между моделями, не говоря уже о сериях МК.
              –1
              Сложность поддержки и модификации кода в малой степени определяется языком — она определяется в первую очередь качеством документации и логичностью идей, выраженных в коде. В целом, нужно следовать советам Мартина Голдинга — «Пишите код так, как будто сопровождать его будет склонный к насилию психопат, который знает, где вы живёте».
              Увы, на ассемблере труднее, следуя Кнуту, реализовывать грамотное программирование, но это расплата за тотальный контроль над оборудованием.

              Более важно то, что ассемблер ставит жирный крест на переносимости. Однако история x86 — яркий пример того, как вовремя установленные владельцами платформы подпорки позволяют спасти положение. Увы, ценой технологической красоты.
                0
                Если вы пишете под микроконтроллер без ОС, на «голом железе», то вы имеете полный контроль над оборудованием и на С и на С++, т.к. все регистры, отображаемые на память, доступны. Если проект пишется под какую-либо ОС (RTOS), то часть аппаратных ресурсов может быть занята системой, и они могут быть не доступны напрямую, опять же независимо от языка.

                Что касается документации, я придерживаюсь идеи самодокументируемого кода, то есть все переменные должны иметь ясные и развёрнутые имена, алгоритм должен ясно прослеживаться, никакого спагетти-кода. На ассемблере следовать этим принципам затруднительно.

                Писать на асме не стоит затраченных усилий.
                  0
                  Уже при использовании языка высокого уровня приходится либо обкладываться документацией на компилятор, либо смотреть листинг, который этот компилятор сотворил. Иначе может оказаться так, что при входе в прерывание компилятор «на всякий случай» решит положить все 32 РОН на стек, что приведет к драматическому снижению скорости отклика на это прерывание.

                  Я бы не стал заявлять столь категорично — каждая конкретная задача требует своего инструмента.
                    0
                    Это так, если вам критичны микросекунды скорости отклика на прерывание. В моих приборах такой задачи не стояло, поэтому я листингов специально не смотрел, и даже если компилятор кладёт все регистры на стек, то и пусть себе. Хотя ассемблерный листинг в IAR виде сразу же при запуске, и проблем с его просмотром нет никаких. К тому же IAR имеет очень интеллектуальный оптимизатор.

                    Задачи, требующие очень быстрой и предсказуемой до такта реакции, лучше решать на DSP, и там реально имеет смысл писать на асме руками (особенно простые, но очень быстрые алгоритмы).
                +1
                А есть люди, которые под тот же AVR пишут на плюсах и другим советуют.
                Кстати, чего далеко ходить — ардуино. Фактически, обертка вокруг avr-g++
                Тут скорее вопрос владения инструментом.
                  0
                  Да, разложение Фурье сигнала с АЦП (на частоте около 16 кГц) для ATMega8 я писал на C. Однако моментально напоролся на желание компилятора сохранять все РОН при входе в прерывания, из-за чего 16 кГц превратились в примерно 9. Желание было выявлено путем анализа ассемблерного листинга, компилятору была выписана строгая директива больше так не делать, проект был сдан.

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

                  В случае же с мелким контроллером без ОЗУ, GCC умывает руки:
                  image
                    0
                    Да, я знаю, что ардуиновские библиотеки написаны на плюсах. Ардуино предназначен для запуска небольших скетчей и быстрого прототипирования, не больше.
                      0
                      Добавлю ещё, что я совсем не против плюсов, в случаях, когда:
                      1. Позволяют ресурсы памяти
                      2. Код получается более простым и ясным, чем на С, а не наоборот.
                0
                Программирование на ассемблере является наиболее трудоемким способом получения программ, оптимизированных по размеру и скорости выполнения. Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.


                К сожалению, из проблемы останова следует невозможность существования алгоритма, который в общем случае генерирует программу минимального размера, эквивалентную заданной. Более того, не может существовать даже алгоритма, который генерирует минималтную программу, просто выводящую заданную строку.
                  0
                  Интуитивно чувствуется, что здесь палки в колеса поставит или упомянутая вами теорема с громким именем, или теорема Геделя о неполноте. Однако быть может имеет смысл поискать условия, при которых поиск всех эквивалентных программ сведется к перебору?
                    0
                    не может существовать даже алгоритма, который генерирует минималтную программу, просто выводящую заданную строку.

                    — прекрасный результат слепого применения теории: во первых, выглядит абсурдно, во — вторых, легко опровергается — делаем железку с одной инструкцией — «печатай эту самую строку», тогда программа будет состоять из одной этой инструкции.
                      0
                      Строку, очевидно, не наперёд заданную.
                      Ещё раз. Не существует алгоритма A, такого, что он для любого S находит B=A(S), такое что B()->S, и не существует алгоритма C, такого что C()->B и |C|<|B|.

                      На хабре была неплохая статья для человека, не знакомого близко с CS: habrahabr.ru/post/189742/
                        0
                        Вы утверждаете:
                        не может существовать даже алгоритма, который генерирует минималтную программу, просто выводящую заданную строку.

                        Далее, вы утверждаете:
                        Строку, очевидно, не наперёд заданную.

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

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

                        В частности, если мы имеем граф потока управления, и он не содержит циклов, или эквивалентными преобразованиями сводится к графу без циклов, то очевидно, что для данной программы мы сразу можем сказать — она завершится.
                          +1
                          Давайте не будем из себя Бурбаки строить, а?

                          Понятно, что captain_obvious хотел сказать, что
                          ¬∃f ∀s f(s)=g ∀h len(h) ⩾ len(g)
                          но будет ли вам легче это читать и понимать?

                          И да, разумеется, если мы в выражении вверху немного «пошевелим» кванторы, то выражение стант неверным. Отказ от циклов, в частности, сводит неразрешимую задачу к тривиальной.
                            0
                            Предлагаю спуститься с теоретических небес на практическую землю:

                            Утверждение: Единственная программа на компьютере, которая никогда не останавливается — операционная система (в том числе и драйверы, системные службы и так далее).

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

                            Прикладные же программы устроены так, что непременно завершатся:

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

                            -все прочие причины находятся под контролем автора программы. Критерий корректности такой программы предлагает Дейкстра в своей работе. Коротко он формулируется так — работа прикладной программы должна завершиться решением прикладной задачи, либо сообщением с описанием причин, почему задача не была решена.

                            Согласитесь, что навечно зависающая программа бесполезна как минимум?

                            Даже те ситуации, когда зацикливание неизбежно и выход из цикла зависит только от входных данных, которые априорно проверить невозможно (тут теорема Геделя о неполноте высовывается), будут охвачены сторожевым счетчиком «разумного числа итераций», исчерпание которого будет приводить к остановке программы с ошибкой.
                              0
                              Спор с SIGKILL ещё никого ни к чему хорошему не приводил…

                              Согласитесь, что навечно зависающая программа бесполезна как минимум?
                              Можно ли сказать, что, скажем, демон nginx — бесполезен (в нормальных условиях он не завершается никогда)? Висит себе, ждет соединений.

                              Завершение выдергиванием штепселя (уничтожение машины Тьюринга etc) — не является завершением программы в терминах теоремы останова.
                                0
                                Поправка — навечно зависающая прикладная программа.
                                  0
                                  Они бывают интерактивными. Например, /bin/sh. Сидит и ждёт ввода от пользователя. Ждать может до скончания вечности.
                                    0
                                    Или пока ему не напишут exit.
                                    Стоит отделить зацикливание в процессе ожидания некоего события (пакета по сети, активности пользователя, и так далее) от зацикливания на некорректных данных — когда извне программа уже ничего не ожидает, а продолжает вертеться в цикле.

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

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

                            Наиболее интересная задача здесь — разработка такого компилятора и ЯВУ, который бы выдавал оптимизированный код (по какому-то критерию) и доказательство того, что на данном устройстве получить лучший код — невозможно.


                            — такого не будет, если критерием считать размер программы.

                            Поскольку в этом комментарии я не написал ничего нового, считаю диалог завершённым.
                      +1
                      О, этот маленький восьминогий жучок на самом деле не так уж плох, хоть и древен до обсолетности — у меня на нем сделаны несколько конструкций, от очень простых, до довольно заковыристых, использующих почти под завязку программную и регистровую память девайса, и практически всю его периферию — описания двух из них есть на хабре вот и вот.
                        +1
                        Именно под такие цели Атмел и позиционирует этот замечательный контроллер. А его высокочастотный (25МГц) ШИМ дает еще больше свободы для творчества.
                          +1
                          А дифференциальный АЦП с предусилителем и программной коррекцией нуля?
                            +1
                            … помещен в контроллер специально для того, чтобы творить умные зарядные устройства, мониторы питания и приемники аналоговых сигналов.

                            Очень жаль, что Атмел отказалась от ATTiny15 — шестая студия о нем не знает, а фирма выпустила документ с рекомендациями о замене на ATTiny25
                      • UFO just landed and posted this here
                          0
                          У меня как раз получилось все скачать с официального сайта — меня лишь попросили заполнить небольшую форму и верифицировали почту, прислав ссылку. После этого я смог скачать и шестую, и четвертую версии студии.
                          • UFO just landed and posted this here
                              +1
                              Там есть неприметная ссылка, ведущая в архив
                              • UFO just landed and posted this here
                            0
                            Одна беда — Atmel больше не даёт скачать старые версии AVR Studio

                            А зачем, если есть расово верный Eclipse или Code::Blocks в качестве оболочки, а компилятор в любом случае avr-gcc aka winavr
                            А уж в линуксе сам бог велел.
                              +3
                              Eclipse — это извините, пздц. Тормоза на каждом шаге. Конечно, машина была 2-ух башковое среднее решение, но чтоб так — это не. Лучше в блокноте писать код, чем в этом. Снес нахер и никогда больше не поставлю.
                                0
                                Студия замечательна тем, что содержит прекрасный симулятор/отладчик, с встроенным справочником по регистрам и периферии контроллера. То есть многие вопросы можно решить, глядя на подсказки студии, без зарывания в даташит.

                                С Эклипс другая проблема — я для разработки долгое время использовал старинный Dell Latitude CPx (только из-за наличия на нем более чем удобного для электронщика LPT)

                                image
                                (он засветился в одном из эпизодов Секретных материалов).

                                Так вот, этот прекрасный старикан просто не тянул столь прожорливую IDE, а с четвертой студией — справлялся.
                                +1
                                Я искренне рад, что моя статья сподвигла автора того топика на исследование применения сторожевого таймера.

                                Вот только никакой надежды на авось нет — ну не будет прерывание INT0 работать, коль скоро оно выключено в GIMSK.
                                  +1
                                  Я дополнил статью ссылками на рекорд, и даже (хоть и путем издевательства над контроллером), побил его, уменьшив прошивку до 10 байт — Контроллер встает, дойдя до конца программной памяти, исполняя одну и ту же инструкцию SBRS R31, 7 (ее опкод — 0xFFFF).

                                Only users with full accounts can post comments. Log in, please.