Прошивка и программирование ATtiny13 при помощи Arduino UPD 17.03.2016



Всем привет. Уже давно появился способ программировать маленькие, дешёвые, экономичные к питанию и доступные микроконтроллеры ATtiny13A.

Вот собственно всё то что ниже, только в видео формате:



Сегодня расскажу, как я зашиваю Arduino'вские скетчи в ATtiny13A.

Итак, для начала нам нужно скачать вот этот архив (взято и совсем чуть-чуть доделано отсюда), положить файлы по адресу "\Documents\Arduino\hardware\". Должно получится что-то типа «C:\Users\Администратор\Documents\Arduino\hardware\attiny13\avr\cores\core13».

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


Обязательно проверяем, правильно ли у нас выбрано «расположение папки со скетчами» (посмотреть можно во вкладке «Файл/Настройки»):

image

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

Теперь прошьём в дуинку ArduinoISP из примеров Arduino IDE:

image

Потом подключаем ATtiny13 к Arduino, как показано на картинке:

image

Потом нужно изменить тип программатора на Arduino as ISP, как показано на скриншоте:

image

Теперь мы можем выбрать, на какой частоте может работать микроконтроллер ATtiny13.
С завода ATtiny13 работает на частоте в 1.2 МГц, то есть микроконтроллер тактируется от внутренней RC- цепочки на частоте в 9.6 МГц и включён делитель на 8, поэтому я указал частоту в 1.2 МГц как дефолтную:

image

Как видим, доступные частоты — 1.2 МГц, 4.8 МГц и 9.6 МГц. Для изменения частоты нам нужно нажать на кнопку «Записать загрузчик», которая располагается в вкладке «Сервис».

Что же среда делает при нажатии на кнопку «Записать загрузчик»?

Arduino IDE в данном случае просто выставляет нужные фьюзы микроконтроллера.
К примеру, мне нужно, чтобы ATtiny13 работал на частоте в 4.8 мГц, я выбираю нужную мне частоту и только один раз жму кнопку «Записать загрузчик» — всё. Теперь микроконтроллер будет всегда работать на заданной частоте, если будет нужно изменить частоту опять — проделываем описанную выше процедуру.

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

image

Минимальное рабочее напряжение, при котором ATtiny13 сохраняет работоспособность — 1.8 В, причем гарантировано будет работать, в данном случае, только на частоте в 1.2 МГц.

Итак, зашьем для начала почти родной начинающим ардуинщикам пример blink, ну как же без него?

image

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

поддерживаются следующие функции:

pinMode()
digitalWrite()
digitalRead()
analogRead()
analogReference(INTERNAL) / (EXTERNAL)
shiftOut()
pulseIn()
analogWrite()
millis()
micros()
delay()
delayMicroseconds()

Итак, как мы только что увидели, нам доступно всего 1024 байта. Мало ли это? Ну, смотря для каких задач. Если, например, для каких-то там мигалок, пищалок или индикаторов, думаю, будет вполне достаточно, хотя можно даже что-то посерьёзней сварганить, особенно если познакомится с AVR-Cи.

Распиновка микроконтроллера из даташита:

image

К примеру, PB4 — это то же, что и pin 4, или просто 4.
Аналоговые входы — все, на которых пишет ADC*, например PB4 — это есть ADC2, то есть для того, чтобы считать напряжение, пишем analogRead(A2); или просто analogRead(2);, аппаратный ШИМ поддерживают только порты 0 и 1.

UPD0: добавил ссылку как экономить место на микроконтроллере и как моделировать Arduino в программе Proteus:

image

Как экономить место на микроконтроллере?;

Ветка на форуме Arduino;

Моделирование Arduino в программе Proteus(на примереATtiny13);

Вот пример применения — Музыкальный дверной звонок на ATtiny13;

Все мои публикации.

UPD1 17.03.2016 Файлы ядра ищите теперь тут:
Дополнение статьи от товарища legos.

image
Поделиться публикацией

Комментарии 52

    0
    Вот собственно весь процесс в видео формате:
    www.youtube.com/watch?v=MS5i7fnlPBM
      +1
      Встроил видео в статью.
      +4
      40% памяти на мигание светодидом! С таким количеством памяти надо гораздо больше внимания уделять оптимизации. Мне кажется Processing/Wiring здесь крайне не уместен.
        +1
        Согласен, но если вы начинающий ардуинщик?
        Заодно и будет дополнительный стимул обучаться оптимизации размеров кода и изучения как языка Си так и регистров микроконтроллера.
          –3
          Асемблера. Для такой мелкотни нужен ассемблер, тут даже С тяжеловат.
            +7
            В 1 килобайт на Си очень много чего влезает. У меня на ATtiny13 собран термостат для аквариума с датчиком DS18B20, с отображением температуры на семисегментном индикаторе и двумя кнопками для ввода температуры. Прошивка написана на Си.
              0
              Я уже тоже думаю переходить на Си, потихоньку осваиваюсь.
              Поначалу с регистрами было сложно, но сейчас маленько понимаю…
                +1
                В мире микроконтроллеров, от Си до Ассемблера один шаг. И сделать его, пожалуй, стоит. Тогда мигание светодиодом не станет занимать 382 байта, а в килобайт смогут уместиться не только мигалки и пищалки, но и серьезные приложения.
                Ардуина потрясающа для прототипирования и обучения, но будьте готовы к тому, что как только появится необходимость удешевить конечный железный продукт или позаботиться о стабильности его работы — придется писать на Cи или Ассемблере.
                  +3
                  image
                0
                Да, безусловно.
                А в крайнем случае всегда можно скомпилировать C в ассемблер, вручную оптимизировать и уже потом залить.
                И это в большинстве случаев окажется быстрее, чем сразу писать с нуля на ассемблере.
                  +1
                  Это врятли. получится программа без комментариев, структуры и осмысленных переменных. Попробуй потом в этом разобраться. А на ассемблере можно писать не хуже чем на чистом С ловко используя макроопределения и дефайны.
            +2
            Ну чего уж, мигалку позволяет сделать и то прогресс. Не ставить же 28-выводный контроллер для «мигалок» на два светодиода. Оно конечно в целом не практично, но свою нишу найдёт.
              +4
              Есть множество небольших проектов которые встанут в тини13 как в родную.
              +2
              Спасибо автору за статью, мне подобная статья помогла в свое время ввязаться в борьбу с размером скетча для ATTiny и, как следствие, перейти с Arduino IDE на Сю.
                +1
                Добавил ссылку как экономить место на микроконтроллере.
                  0
                  Это ссылка про то, что пора потихоньку переходить на С
                    0
                    Согласен
              • НЛО прилетело и опубликовало эту надпись здесь
                  0
                  Вы немного не поняли. В Attiny13 в предложенном методе нет загрузчика
                    0
                    Да, он тут не нужен.
                +1
                Спасибо, мне очень понравилось, в том плане, что это из тех любительских технологий, которые при малобюджетных разработка крайне полезны. А я этим теперь и занимаюсь. Я как бы и не электронщик и не программист, а на таких простеньких примерах управление сваять очень здорово. И цена девайса впечатляет.
                  0
                  Согласен, цена небольшая, а потенциал неплохой.
                  +2
                  Правильно я понимаю, что алгоритм такой (после закидывания файлов в директории)
                  — прошиваем любую ардуино обычную в ISP программатор
                  — цепляем tiny13 к этой обычной ардуине
                  — «прошиваем» загрузчик для выставления фьюзов
                  — прошивка в дальнейшем идет через ту же самую ардуину в режиме isp программатора?

                  По идее, если не использовать специфичных функций ардуино (типа digitalWrite), а обращаться напрямую к регистрам, код будет намного компактнее?

                    +1
                    Это скорей если не использовать сложные функции вроде delay. digitalWrite это по сути та же работа с портом, парочка ассемблерных команд только с более понятным человеку видом.
                      0
                      Да, будет очень компактно.
                      +3
                      Молодец. Многие будут давать быть может и резкие комментарии, но начать всегда нужно с малого. Я лично тоже в свое время моргал blink-ом на Ардуино и радовался как ребенок) — не скрываю.
                        +1
                        UPD: добавил ссылку как экономить место на микроконтроллере.
                          0
                          Правда при использовании функции _delay_ms(*); если сравнивать и delay(*); размеры hex-файла увеличиваются, хотя должны бы наоборот уменьшатся… не могу понять этого…
                          Может кто из местных пользователей хабра мне поможет разобраться?
                            0
                            _delay_ms это макроподстановка, это не вызов функции а впихивание всего кода целиком конкретно в этом месте.
                            0
                            И мы пришли к тому, что смысла программить Тиньку в arduino ide нет. В данном примере используется обычный С) На котором обычно и писали для нее
                            0
                            Ребят, строго не судите, я в этой теме ноль, но может кому полезно будет: только сегодня наткнулся на обзор USB программатора, который поддерживает ATTiny13(V). Автор брал за $2,56. В обзоре куча поддерживаемых микроконтроллеров.
                            P.S.: Не реклама ни в коей мере.
                              0
                              А он без проблем подключается к вирингу?
                                0
                                Я понятия не имею что такое виринг и подключается ли он к нему.
                                Просто время от времени читаю ресурс, посвещенный покупкам на китайщине. И сегодня наткнулся на обзор тот. И на хабре тоже программирование ATTiny13. Вот и скинул ссылку, вдруг кому пригодится.
                                Повторюсь — я абсолютный ноль в программировании, тем более микроконтроллеров:)
                                  0
                                  Ну так проблем прошивки как таковой для TINY13 не существует, тема-то про прошивку ТИНИ13 из-под стандартной среды под ардуино.
                                  0
                                  Вы наверно имеете ввиду Wiring?
                                0
                                Знакомый ник ))) ATtiny13 конечно неплохо программируются в Arduino IDE, но к сожалению прошивка получается по размеру не такая минимальная как чем писать прямо в С# даже если не использовать ардуиновские функции то впустую сжирается 50-100 байт(точно не помню).
                                Потенциал ATtiny13 вообще не плохой, его цена где-то у китайцев от 50 центов и если уметь, то реализовать можно много чего, например беспроводные датчики на 433/315 мгц модулях…
                                  0
                                  А вы наверное Маским из форума ардуино, или не угадал?
                                    0
                                    Нет, там ник точно такой же как тут…
                                  0
                                  1.2 мГц — > 1.2 МГц
                                    0
                                    Понял, в первом случае милли во втором мега. Спасибо за поправку.
                                    +1
                                    Очень сильное ограничение у Attiny13, и вообще у многих контроллеров, это малое количество ОЗУ. А программы на Си очень неэкономно его используют. В итоге смотришь, вроде занято 20% флеш-памяти, а после включения самые невообразимые глюки из-за срыва стека. Так что рекомендуется тестировать в эмуляторе AVRStrudio или в Протеусе, и посматривать на количество занятого ОЗУ. К сожалению Ардуиновская среда разработки эмулятора не имеет (насколько я знаю), и заигрывая с маленкой Аттини можно словить сюрприз очень легко.
                                      0
                                      Я недавно снимал видео про моделирование Arduino в программе Proteus на примере Attiny13.

                                      www.youtube.com/watch?v=gj5koMNtKwI
                                        0
                                        У ATTINY13 есть отладочный интерфейс, debugwire. Вопрос лишь в востребованности. На столь высокоуровневом языке на котором пишут скетчи для ардуины нет необходимости в низкоуровневой отладке а высокоуровневую можно прикрутить и самому при помощи банальной printf и задержки выполнения алгоритма пока не нажмешь внешнюю кнопку.
                                        0
                                        Ждём продолжения про прошивку ардуиновских скетчей в STM32F4!
                                          +2
                                          Видео вполне может быть интересным и полезным для многих начинающих, но есть небольшое пожелание автору:

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

                                          Кстати, про обучение и интересные видео — рекомендую этих парней — learn.sparkfun.com/
                                          Ребята клевые.
                                            +2
                                            UPD 03.12.2014:

                                            Вышла новая версия «ядра» для ATtiny13 core13_19. Почему то опять с некоторыми недочётами в функциях analogWrite() и pulseIn(), вот ядро ссылка с исправленными недочётами:

                                            Скачать.

                                            Список поддерживаемых Arduino'вских функций взятый из официальной страница проекта:

                                            map()
                                            random()
                                            randomSeed()
                                            millis()
                                            micros()
                                            delay()
                                            delayMicroseconds() *
                                            analogRead()
                                            analogWrite()
                                            pinMode()
                                            digitalRead()
                                            digitalWrite()
                                            pulseIn() (Untested)
                                            shiftIn() (Untested)
                                            shiftOut() (Untested)


                                            Собственно официальная страница проекта:

                                            http://forum.arduino.cc/index.php/topic,89781.0.html.

                                            При обнаружении каких либо багов пишите сюда, но всё же лучше ветку русскоязычного форума Arduino.
                                              0
                                              Спасибо, прошил тиньку) Но пришлось повозиться. На маке и линуксе нужно отключать auto-reset у arduino,
                                              Без этого пишет что-то вроде out of sync 0x15.
                                              После гугления обнаружился вот такой мануал:
                                              playground.arduino.cc/Main/DisablingAutoResetOnSerialConnection

                                              120 Ом резистор причем не помог (может потому что у меня funduino?).
                                              А конденсатор на 10мкФ помог.
                                                +1
                                                # лочит тинки, не зачёт
                                                #attiny13int.name=ATtiny13 @ 128 KHz, BOD 2.7 V
                                                #attiny13int.upload.using=arduino:arduinoisp
                                                #attiny13int.upload.speed=250 # important for not losing connection to a slow processor
                                                #attiny13int.bootloader.low_fuses=0x7B
                                                #attiny13int.bootloader.high_fuses=0xFB # BOD 2.7 В. по умолчанию FF
                                                #attiny13int.upload.maximum_size=1024
                                                #attiny13int.build.mcu=attiny13
                                                #attiny13int.build.f_cpu=128000L
                                                #attiny13int.build.core=core13

                                                Если вдруг кто напоролся на проблему пропадания связи с attiny после прошивки ее на частоту 128 KHz, то решение этой проблемы очень простое. Суть ее в том, что attiny13 после этого начинает работать на обозначенной слишком маленькой частоте, и для программатора она выглядит не просто как тормозная, а как мегатормозная. А раз программатору она вовремя (с точки зрения быстрого программатора) не отвечает, он ничего с ней сделать и не может.
                                                Решение в том, чтобы затормозить программатор, чтобы он работал с такой attiny очень медленно, и attiny13 на частоте 128КГц успевала ему отвечать. В сети полно таких модифицированных скетчей из примера, искать по словам slow Arduino ISP.

                                                Ссылки:
                                                forum.arduino.cc/index.php?topic=89781.msg2097406#msg2097406 — Библиотека ATtiny13 library install для Arduino IDE 1.6.X (по сравнению с 1.0.X у среды поменялся немного формат, и если у вас возникают ошибки, связанные с bootloader.upload.tool, то проблема именно в версии среды).
                                                forum.arduino.cc/index.php?topic=89781.msg2160449#msg2160449 — А тут разъяснение, что делать, если вы таки переключили attiny в режим 128КГц и теперь не можете до микросхемы достучаться: там изменения для файла boards.txt и заторможенная версия скетча Arduino ISP. У меня все сработало, и я переключил микросхему обратно из режима 128КГц. А кто-то только в этом режиме и работает, потому что, подозреваю, потребление в этом режиме еще меньше.
                                                  +1
                                                  Спасибо за ссылки.
                                                  +1
                                                  Обновил «ядро»(core13_20), пока что нужно протестировать, нужна ваша помощь. Добавил поддержку как старых версий Arduino IDE так и новых, теоретически должно работать.

                                                  Скачать ядро можно тут.

                                                  Установка та же:

                                                  image

                                                  ! Для работы с частотами ниже 1 мГц используем скетч Arduino slow ISP, но я не тестировал, так что тоже теоретически.

                                                  Arduino slow ISP
                                                  // this sketch turns the Arduino into a AVRISP
                                                  // using the following pins:
                                                  // 10: slave reset
                                                  // 11: MOSI
                                                  // 12: MISO
                                                  // 13: SCK
                                                   
                                                  // Put an LED (with resistor) on the following pins:
                                                  // 9: Heartbeat - shows the programmer is running
                                                  // 8: Error - Lights up if something goes wrong (use red if that makes sense)
                                                  // 7: Programming - In communication with the slave
                                                  //
                                                  // October 2009 by David A. Mellis
                                                  // - Added support for the read signature command
                                                  //
                                                  // February 2009 by Randall Bohn
                                                  // - Added support for writing to EEPROM (what took so long?)
                                                  // Windows users should consider WinAVR's avrdude instead of the
                                                  // avrdude included with Arduino software.
                                                  //
                                                  // January 2008 by Randall Bohn
                                                  // - Thanks to Amplificar for helping me with the STK500 protocol
                                                  // - The AVRISP/STK500 (mk I) protocol is used in the arduino bootloader
                                                  // - The SPI functions herein were developed for the AVR910_ARD programmer
                                                  // - More information at code.google.com/p/mega-isp
                                                  #include <SPI.h>
                                                  #include "pins_arduino.h"  // defines SS,MOSI,MISO,SCK
                                                  #define RESET SS
                                                   
                                                  #define LED_HB 9
                                                  #define LED_ERR 8
                                                  #define LED_PMODE 7
                                                   
                                                  #define HWVER 2
                                                  #define SWMAJ 1
                                                  #define SWMIN 18
                                                   
                                                  // STK Definitions
                                                  #define STK_OK 0x10
                                                  #define STK_FAILED 0x11
                                                  #define STK_UNKNOWN 0x12
                                                  #define STK_INSYNC 0x14
                                                  #define STK_NOSYNC 0x15
                                                  #define CRC_EOP 0x20 //ok it is a space...
                                                   
                                                  void pulse(int pin, int times);
                                                   
                                                  void setup() {
                                                    Serial.begin(19200);
                                                    pinMode(7, OUTPUT);
                                                    pulse(7, 2);
                                                    pinMode(8, OUTPUT);
                                                    pulse(8, 2);
                                                    pinMode(9, OUTPUT);
                                                    pulse(9, 2);
                                                    pinMode(SS, OUTPUT);
                                                    pinMode(MISO, INPUT);
                                                    pinMode(MOSI, OUTPUT);
                                                    pinMode(SCK, OUTPUT);
                                                   
                                                  //  SPI.setClockDivider(SPI_CLOCK_DIV128);
                                                   
                                                  }
                                                   
                                                  int error=0;
                                                  int pmode=0;
                                                  // address for reading and writing, set by 'U' command
                                                  int here;
                                                  uint8_t buff[256]; // global block storage
                                                   
                                                  #define beget16(addr) (*addr * 256 + *(addr+1) )
                                                  typedef struct param {
                                                    uint8_t devicecode;
                                                    uint8_t revision;
                                                    uint8_t progtype;
                                                    uint8_t parmode;
                                                    uint8_t polling;
                                                    uint8_t selftimed;
                                                    uint8_t lockbytes;
                                                    uint8_t fusebytes;
                                                    int flashpoll;
                                                    int eeprompoll;
                                                    int pagesize;
                                                    int eepromsize;
                                                    int flashsize;
                                                  }
                                                  parameter;
                                                   
                                                  parameter param;
                                                   
                                                  // this provides a heartbeat on pin 9, so you can tell the software is running.
                                                  uint8_t hbval=128;
                                                  int8_t hbdelta=8;
                                                  void heartbeat() {
                                                    if (hbval > 192) hbdelta = -hbdelta;
                                                    if (hbval < 32) hbdelta = -hbdelta;
                                                    hbval += hbdelta;
                                                    analogWrite(LED_HB, hbval);
                                                    delay(40);
                                                  }
                                                   
                                                   
                                                  void loop(void) {
                                                    // is pmode active?
                                                    if (pmode) digitalWrite(LED_PMODE, HIGH);
                                                    else digitalWrite(LED_PMODE, LOW);
                                                    // is there an error?
                                                    if (error) digitalWrite(LED_ERR, HIGH);
                                                    else digitalWrite(LED_ERR, LOW);
                                                   
                                                    // light the heartbeat LED
                                                    heartbeat();
                                                    if (Serial.available()) {
                                                      avrisp();
                                                    }
                                                  }
                                                   
                                                  uint8_t getch() {
                                                    while(!Serial.available());
                                                    return Serial.read();
                                                  }
                                                  void readbytes(int n) {
                                                    for (int x = 0; x < n; x++) {
                                                      buff[x] = Serial.read();
                                                    }
                                                  }
                                                   
                                                  #define PTIME 30
                                                  void pulse(int pin, int times) {
                                                    do {
                                                      digitalWrite(pin, HIGH);
                                                      delay(PTIME);
                                                      digitalWrite(pin, LOW);
                                                      delay(PTIME);
                                                    }
                                                    while (times--);
                                                  }
                                                   
                                                  void spi_init() {
                                                    /*uint8_t x;
                                                    SPCR = 0x53;
                                                    x=SPSR;
                                                    x=SPDR;*/
                                                  }
                                                   
                                                  void spi_wait() {
                                                    do {
                                                    }
                                                    while (!(SPSR & (1 << SPIF)));
                                                    delay(100);
                                                  }
                                                  //unsigned char msk[] = {0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80};
                                                  unsigned char msk[] = {0x80, 0x40, 0x20, 0x10, 0x8, 0x4, 0x2, 0x1};
                                                  #define PCK() (bits[0] << 7 | bits[1] << 6 | bits[2] << 5 | bits[3] << 4 | bits[4] << 3 | bits[5] << 2 | bits[6] << 1 | bits[7])
                                                  uint8_t spi_send(uint8_t b) {
                                                    uint8_t reply=0;
                                                    char bits[8] = {0, 0, 0, 0, 0, 0, 0, 0};
                                                    /*SPDR=b;
                                                    spi_wait();
                                                    reply = SPDR;
                                                    return reply;*/
                                                  //  digitalWrite(SS, LOW);
                                                  //  delayMicroseconds(20);
                                                  //cli();
                                                    for(uint8_t _bit = 0;_bit < 8;_bit++){
                                                     digitalWrite(MOSI, !!(b & msk[_bit]));
                                                     delayMicroseconds(50);
                                                     digitalWrite(SCK, HIGH);
                                                     delayMicroseconds(50);
                                                     bits[_bit] = digitalRead(MISO);
                                                     delayMicroseconds(50);
                                                     digitalWrite(SCK, LOW);
                                                     delayMicroseconds(50);
                                                  //  delayMicroseconds(50);
                                                    }
                                                  //  digitalWrite(SS, HIGH);
                                                    delayMicroseconds(50);
                                                    reply = PCK();
                                                    return reply;
                                                   
                                                   
                                                  }
                                                   
                                                  uint8_t spi_transaction(uint8_t a, uint8_t b, uint8_t c, uint8_t d) {
                                                    uint8_t n;
                                                    spi_send(a);
                                                    n=spi_send(b);
                                                    //if (n != a) error = -1;
                                                    n=spi_send(c);
                                                    return spi_send(d);
                                                  }
                                                   
                                                  void empty_reply() {
                                                    if (CRC_EOP == getch()) {
                                                      Serial.print((char)STK_INSYNC);
                                                      Serial.print((char)STK_OK);
                                                    }
                                                    else {
                                                      Serial.print((char)STK_NOSYNC);
                                                    }
                                                  }
                                                   
                                                  void breply(uint8_t b) {
                                                    if (CRC_EOP == getch()) {
                                                      Serial.print((char)STK_INSYNC);
                                                      Serial.print((char)b);
                                                      Serial.print((char)STK_OK);
                                                    }
                                                    else {
                                                      Serial.print((char)STK_NOSYNC);
                                                    }
                                                  }
                                                   
                                                  void get_version(uint8_t c) {
                                                    switch(c) {
                                                    case 0x80:
                                                      breply(HWVER);
                                                      break;
                                                    case 0x81:
                                                      breply(SWMAJ);
                                                      break;
                                                    case 0x82:
                                                      breply(SWMIN);
                                                      break;
                                                    case 0x93:
                                                      breply('S'); // serial programmer
                                                      break;
                                                    default:
                                                      breply(0);
                                                    }
                                                  }
                                                   
                                                  void set_parameters() {
                                                    // call this after reading paramter packet into buff[]
                                                    param.devicecode = buff[0];
                                                    param.revision = buff[1];
                                                    param.progtype = buff[2];
                                                    param.parmode = buff[3];
                                                    param.polling = buff[4];
                                                    param.selftimed = buff[5];
                                                    param.lockbytes = buff[6];
                                                    param.fusebytes = buff[7];
                                                    param.flashpoll = buff[8];
                                                    // ignore buff[9] (= buff[8])
                                                    //getch(); // discard second value
                                                   
                                                    // WARNING: not sure about the byte order of the following
                                                    // following are 16 bits (big endian)
                                                    param.eeprompoll = beget16(&buff[10]);
                                                    param.pagesize = beget16(&buff[12]);
                                                    param.eepromsize = beget16(&buff[14]);
                                                   
                                                    // 32 bits flashsize (big endian)
                                                    param.flashsize = buff[16] * 0x01000000
                                                      + buff[17] * 0x00010000
                                                      + buff[18] * 0x00000100
                                                      + buff[19];
                                                   
                                                  }
                                                   
                                                  void start_pmode() {
                                                    spi_init();
                                                    // following delays may not work on all targets...
                                                    pinMode(RESET, OUTPUT);
                                                    digitalWrite(RESET, HIGH);
                                                    pinMode(SCK, OUTPUT);
                                                    digitalWrite(SCK, LOW);
                                                    delay(50);
                                                    //delay(250);
                                                    digitalWrite(RESET, LOW);
                                                    delay(50);
                                                  //delay(250);
                                                    pinMode(MISO, INPUT);
                                                    pinMode(MOSI, OUTPUT);
                                                    spi_transaction(0xAC, 0x53, 0x00, 0x00);
                                                    pmode = 1;
                                                  }
                                                   
                                                  void end_pmode() {
                                                    pinMode(MISO, INPUT);
                                                    pinMode(MOSI, INPUT);
                                                    pinMode(SCK, INPUT);
                                                    pinMode(RESET, INPUT);
                                                    pmode = 0;
                                                  }
                                                   
                                                  void universal() {
                                                    int w;
                                                    uint8_t ch;
                                                   
                                                    for (w = 0; w < 4; w++) {
                                                      buff[w] = getch();
                                                    }
                                                    ch = spi_transaction(buff[0], buff[1], buff[2], buff[3]);
                                                    breply(ch);
                                                  }
                                                   
                                                  void flash(uint8_t hilo, int addr, uint8_t data) {
                                                    spi_transaction(0x40+8*hilo,
                                                    addr>>8 & 0xFF,
                                                    addr & 0xFF,
                                                    data);
                                                  }
                                                  void commit(int addr) {
                                                    spi_transaction(0x4C, (addr >> 8) & 0xFF, addr & 0xFF, 0);
                                                  }
                                                   
                                                  //#define _current_page(x) (here & 0xFFFFE0)
                                                  int current_page(int addr) {
                                                    if (param.pagesize == 32) return here & 0xFFFFFFF0;
                                                    if (param.pagesize == 64) return here & 0xFFFFFFE0;
                                                    if (param.pagesize == 128) return here & 0xFFFFFFC0;
                                                    if (param.pagesize == 256) return here & 0xFFFFFF80;
                                                    return here;
                                                  }
                                                  uint8_t write_flash(int length) {
                                                    if (param.pagesize < 1) return STK_FAILED;
                                                    //if (param.pagesize != 64) return STK_FAILED;
                                                    int page = current_page(here);
                                                    int x = 0;
                                                    while (x < length) {
                                                      if (page != current_page(here)) {
                                                        commit(page);
                                                        page = current_page(here);
                                                      }
                                                      flash(LOW, here, buff[x++]);
                                                      flash(HIGH, here, buff[x++]);
                                                      here++;
                                                    }
                                                   
                                                    commit(page);
                                                   
                                                    return STK_OK;
                                                  }
                                                   
                                                  uint8_t write_eeprom(int length) {
                                                    // here is a word address, so we use here*2
                                                    // this writes byte-by-byte,
                                                    // page writing may be faster (4 bytes at a time)
                                                    for (int x = 0; x < length; x++) {
                                                      spi_transaction(0xC0, 0x00, here*2+x, buff[x]);
                                                      delay(45);
                                                    }
                                                    return STK_OK;
                                                  }
                                                   
                                                  void program_page() {
                                                    char result = (char) STK_FAILED;
                                                    int length = 256 * getch() + getch();
                                                    if (length > 256) {
                                                        Serial.print((char) STK_FAILED);
                                                        return;
                                                    }
                                                    char memtype = getch();
                                                    for (int x = 0; x < length; x++) {
                                                      buff[x] = getch();
                                                    }
                                                    if (CRC_EOP == getch()) {
                                                      Serial.print((char) STK_INSYNC);
                                                      if (memtype == 'F') result = (char)write_flash(length);
                                                      if (memtype == 'E') result = (char)write_eeprom(length);
                                                      Serial.print(result);
                                                    }
                                                    else {
                                                      Serial.print((char) STK_NOSYNC);
                                                    }
                                                  }
                                                  uint8_t flash_read(uint8_t hilo, int addr) {
                                                    return spi_transaction(0x20 + hilo * 8,
                                                      (addr >> 8) & 0xFF,
                                                      addr & 0xFF,
                                                      0);
                                                  }
                                                   
                                                  char flash_read_page(int length) {
                                                    for (int x = 0; x < length; x+=2) {
                                                      uint8_t low = flash_read(LOW, here);
                                                      Serial.print((char) low);
                                                      uint8_t high = flash_read(HIGH, here);
                                                      Serial.print((char) high);
                                                      here++;
                                                    }
                                                    return STK_OK;
                                                  }
                                                   
                                                  char eeprom_read_page(int length) {
                                                    // here again we have a word address
                                                    for (int x = 0; x < length; x++) {
                                                      uint8_t ee = spi_transaction(0xA0, 0x00, here*2+x, 0xFF);
                                                      Serial.print((char) ee);
                                                    }
                                                    return STK_OK;
                                                  }
                                                   
                                                  void read_page() {
                                                    char result = (char)STK_FAILED;
                                                    int length = 256 * getch() + getch();
                                                    char memtype = getch();
                                                    if (CRC_EOP != getch()) {
                                                      Serial.print((char) STK_NOSYNC);
                                                      return;
                                                    }
                                                    Serial.print((char) STK_INSYNC);
                                                    if (memtype == 'F') result = flash_read_page(length);
                                                    if (memtype == 'E') result = eeprom_read_page(length);
                                                    Serial.print(result);
                                                    return;
                                                  }
                                                   
                                                  void read_signature() {
                                                    if (CRC_EOP != getch()) {
                                                      Serial.print((char) STK_NOSYNC);
                                                      return;
                                                    }
                                                    Serial.print((char) STK_INSYNC);
                                                    uint8_t high = spi_transaction(0x30, 0x00, 0x00, 0x00);
                                                    Serial.print((char) high);
                                                    uint8_t middle = spi_transaction(0x30, 0x00, 0x01, 0x00);
                                                    Serial.print((char) middle);
                                                    uint8_t low = spi_transaction(0x30, 0x00, 0x02, 0x00);
                                                    Serial.print((char) low);
                                                    Serial.print((char) STK_OK);
                                                  }
                                                  //////////////////////////////////////////
                                                  //////////////////////////////////////////
                                                   
                                                   
                                                  ////////////////////////////////////
                                                  ////////////////////////////////////
                                                  int avrisp() {
                                                    uint8_t data, low, high;
                                                    uint8_t ch = getch();
                                                    switch (ch) {
                                                    case '0': // signon
                                                      empty_reply();
                                                      break;
                                                    case '1':
                                                      if (getch() == CRC_EOP) {
                                                        Serial.print((char) STK_INSYNC);
                                                        Serial.print("AVR ISP");
                                                        Serial.print((char) STK_OK);
                                                      }
                                                      break;
                                                    case 'A':
                                                      get_version(getch());
                                                      break;
                                                    case 'B':
                                                      readbytes(20);
                                                      set_parameters();
                                                      empty_reply();
                                                      break;
                                                    case 'E': // extended parameters - ignore for now
                                                      readbytes(5);
                                                      empty_reply();
                                                      break;
                                                   
                                                    case 'P':
                                                      start_pmode();
                                                      empty_reply();
                                                      break;
                                                    case 'U':
                                                      here = getch() + 256 * getch();
                                                      empty_reply();
                                                      break;
                                                   
                                                    case 0x60: //STK_PROG_FLASH
                                                      low = getch();
                                                      high = getch();
                                                      empty_reply();
                                                      break;
                                                    case 0x61: //STK_PROG_DATA
                                                      data = getch();
                                                      empty_reply();
                                                      break;
                                                   
                                                    case 0x64: //STK_PROG_PAGE
                                                      program_page();
                                                      break;
                                                     
                                                    case 0x74: //STK_READ_PAGE
                                                      read_page();    
                                                      break;
                                                   
                                                    case 'V':
                                                      universal();
                                                      break;
                                                    case 'Q':
                                                      error=0;
                                                      end_pmode();
                                                      empty_reply();
                                                      break;
                                                     
                                                    case 0x75: //STK_READ_SIGN
                                                      read_signature();
                                                      break;
                                                   
                                                    // expecting a command, not CRC_EOP
                                                    // this is how we can get back in sync
                                                    case CRC_EOP:
                                                      Serial.print((char) STK_NOSYNC);
                                                      break;
                                                     
                                                    // anything else we will return STK_UNKNOWN
                                                    default:
                                                      if (CRC_EOP == getch())
                                                        Serial.print((char)STK_UNKNOWN);
                                                      else
                                                        Serial.print((char)STK_NOSYNC);
                                                    }
                                                  }
                                                  



                                                  Взято отсюда.

                                                  Если что-то не будет получатся, всегда есть верный способ — Как восстановить неправильно выставленные фьюзы в ATtiny.

                                                  Поддерживаемые функции:

                                                  * = Partial support

                                                  • map()
                                                  • random()
                                                  • randomSeed()
                                                  • millis()
                                                  • micros()
                                                  • delay()
                                                  • delayMicroseconds() *
                                                  • analogRead()
                                                  • analogWrite()
                                                  • pinMode()
                                                  • digitalRead()
                                                  • digitalWrite()
                                                  • pulseIn() (Untested)
                                                  • shiftIn() (Untested)
                                                  • shiftOut() (Untested)


                                                  P.S. За ссылки отдельное спасибо товарищу grigorym.
                                                    0
                                                    Привет! Воспользовался твоим ядром (версия 0.22), и при прошивке контроллера и установке фьюзов столкнулся с кучей ошибок и предупреждений.
                                                    Исправил, и заодно причесал меню (вынес выбор частоты в отдельное меню, как это сделано для ардуиновских плат).

                                                    Закинул вот сюда: github.com/orlv/at13
                                                    Изменения в файлах boards.txt и platform.txt

                                                    Насчёт ошибок в соединении с attiny13 при установке частоты ниже 1 МГц — можно использовать более свежий ArduinoISP, тот, что идёт в комплекте со средой (у меня среда версии 1.6.6).
                                                    Для этого в нём надо изменить одну строчку:

                                                    #define SPI_CLOCK (1000000/6)

                                                    меняем на:

                                                    #define SPI_CLOCK (128000/6)

                                                    После этого всё прошивается и работает.
                                                      0
                                                      Спасибо. Закрепил Ваш комментарий в статье.

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

                                                    Самое читаемое