Первые две недели я шил по памяти чужой инструкции и дважды ошибался в одном и том же. Сначала нажимал галочку «Проверить» и ждал, что плата начнёт мигать: полоса пробежала, статус зелёный, а на плате тишина. Я решил, что загрузка сломалась, и пять раз подряд жал стрелку. Потом испугался обратного: дочитался, что флеш переживает ограниченное число перезаписей, и недели две экономил загрузки, будто каждая стачивает плату. Оба заблуждения стоят одного абзаца теории, которого мне тогда не хватило.
Кнопка Upload — не одно действие, а цепочка из четырёх: компиляция, ресет, запись, проверка. Каждое звено видно, если знать, куда смотреть: полоса статуса, вспышки L, мигающие Rx и Tx, строки в выводе. Когда цепочка знакома, место обрыва само указывает диагноз: молчит компиляция — код, не мигает L — ресет не дошёл, тишина на RxTx — плате ничего не передают. Ниже — скетч-подопытный, на котором всю цепочку можно посмотреть в симуляторе до того, как нажимать что-то на живой плате.
Пройдём путь целиком: что делает компилятор до кабеля, кто такой avrdude и при чём тут бутлоадер, почему монитор порта перезапускает скетч и какие ошибки бывают. Ритуал первой загрузки мы уже проходили в уроке про первый скетч в IDE — здесь то, что под капотом.
Компиляция: всё, что происходит до кабеля
Компиляция — превращение вашего текста в машинный код: avr-gcc собирает, линкер склеивает, на выходе hex-файл, прошивка в чистом виде. В конце сборки среда печатает две строки, которые стоит читать: Sketch uses 924 bytes (2%) of program storage space — из 32256 доступных, и Global variables use 9 bytes (0%) of dynamic memory — из 2048. У Uno 32 КБ флеша, из которых 512 байт занимает бутлоадер, и 2 КБ ОЗУ под переменные. Первая компиляция после установки идёт десятки секунд — собирается всё ядро целиком: та же одноразовая цена входа, что и в уроке про установку на Windows, после неё каждая сборка летает на кэше. Путь к готовому hex-файлу виден в подробном выводе: среда складывает его во временную папку рядом с ядром, и файл этот пригодится, когда захочется сравнить две сборки по байтам.
Галочка на панели — компиляция без загрузки: сборка и всё, ни один байт не улетает на плату. Ждать после неё вспышек L — ошибка, которую я и сделал в первый вечер. Зачем она тогда: быстро поймать синтаксическую ошибку и посмотреть размер, не трогая плату. Стрелка Upload компилирует заново и шьёт — галочку она не отменяет, а включает в себя как первый этап. Кстати, 924 байта для мигалки с Serial — не расточительство: библиотека связи и стартовый код весят заметно больше пустого цикла, поэтому следить за процентами полезно заранее, а не когда среда впервые напишет про нехватку места.
int blinks = 0; void setup() { Serial.begin(9600); pinMode(13, OUTPUT); Serial.println("start: setup done");} void loop() { blinks = blinks + 1; digitalWrite(13, HIGH); Serial.print("led=1 blinks="); Serial.println(blinks); delay(1000); digitalWrite(13, LOW); Serial.print("led=0 blinks="); Serial.println(blinks); delay(1000);}Дальше в работу вступает avrdude — утилита, которая шьёт по протоколу STK500. Но сначала плату нужно заставить слушать. Стрелка Upload открывает порт и опускает линию DTR: мост 16U2 видит это и дёргает ресет главного чипа. Стартует бутлоадер: L мигает два-три раза, и около секунды bootloader слушает порт, ожидая команду записи. Если в это окно приходят данные, начинается загрузка: мигают светодиоды Rx и Tx возле разъёма, полоса статуса переходит в «Загрузка…». Файл в девятьсот байт при скорости порта 115200 бод — меньше сотни миллисекунд чистого эфира, но с протокольными подтверждениями и записью по страницам на это уходит пара секунд.
После записи avrdude читает флеш обратно и сверяет с hex-файлом — это и есть верификация, последняя реплика цепочки. Если сошлось, avrdude отпускает ресет, секунда ожидания бутлоадера проходит впустую — и запускается ваш setup. Отсюда же ответ на вопрос, почему при открытии монитора порта скетч начинается заново: открытие порта на Uno тоже дёргает DTR и ресетит плату. Она не глючит — она честно перезапускается; как читать её показания дальше — урок про монитор порта. Пары led= и blinks= в подопытном скетче — та же привычка чтения с платы: числа с именами задерживаются в голове дольше, чем столбец безымянных цифр.
| Этап | Что вы видите | Что происходит |
|---|---|---|
| Компиляция | Полоса «Компиляция скетча…», затем размеры в байтах | avr-gcc собирает hex; на плату ещё ничего не идёт |
| Ресет | L мигнула 2–3 раза | DTR дёрнул ресет; бутлоадер слушает порт около секунды |
| Запись | «Загрузка…», мигают Rx и Tx | avrdude передаёт hex по STK500, чип пишет флеш постранично |
| Проверка | Строка верификации в подробном выводе | Флеш прочитана обратно и сверена с hex-файлом |
| Запуск | Через пару секунд скетч начинает работать | Бутлоадер уступил очередь вашему setup |
Когда Upload не идёт: ошибки по месту обрыва
Типовая ошибка — avrdude: stk500_getsync(): not in sync. В девяти случаях из десяти это не код и не плата, а адресат: в шапке выбран не тот порт либо порт занят открытым монитором. Вторая по частоте причина — кабель без линии данных, третья — не вставший драйвер клона, полный разбор в уроке про драйвер CH340. Мой порядок действий: взгляд в шапку, закрыть монитор порта, переткнуть кабель, посмотреть на Rx и Tx — если они не мигают даже при попытке загрузки, до платы команда ресета не доходит. Монитор, кстати, сам держит порт, пока открыто его окно: я закрываю его перед Upload всегда — привычка на минуту, а экономит она и таймауты, и лишние вопросы к плате.
Чего загрузка сделать не может — сломать плату. Скетч перезаписывается целиком при каждом Upload, а ресурс флеша измеряется десятками тысяч циклов перезаписи: за жизнь проекта вы не израсходуете и процента. Бутлоадер при обычной загрузке не трогается, EEPROM остаётся при своих данных, и худшее, что способен сделать неудачный скетч, — зависнуть или забить всю память переменными: лечится следующим Upload. Совсем тяжёлый случай, затёртый бутлоадер, чинится записью через ISP-разъём, но новичку до этого дела не доходит годами.
После удачной загрузки компьютер можно отключать: скетч живёт во флеше и стартует при каждом поданном питании — от USB, от блока питания на круглом разъёме или от батареи на Vin. Своим свойством он обязан той же архитектуре: флеш хранит код без питания, и включение — это просто ещё один ресет. Урок про мигание светодиодом был первым, кто этим воспользовался: плата мигает сама, без всякого компьютера, и готовая мигалка потом служит индикатором жизни в будущих сборках. Показания же через Serial требуют слушателя: без открытого монитора строки всё равно печатаются в пустоту — плата об этом не знает и продолжает работу. EEPROM — отдельная память для настроек — загрузкой не трогается: счётчики и калибровки переживают перепрошивку. Всё вместе это значит, что кнопка Upload меняет поведение платы целиком и надолго — до следующей загрузки, и бояться её стоит ровно настолько, насколько вы не проверили порт в шапке.
- 1. Нажали галочку «Проверить», полоса пробежала, статус зелёный, плата молчит. Это поломка?
- 2. Почему у Uno под скетч доступно 32256 байт, а не все 32768?
- 3. Что заставляет плату уйти в бутлоадер в момент нажатия Upload?
- 4. avrdude пишет stk500_getsync(): not in sync. С чего начать?
- 5. Что происходит в последний этап загрузки, после записи hex в флеш?
- Upload — цепочка из четырёх этапов: компиляция, ресет через DTR, запись avrdude по STK500, верификация чтением флеша
- Галочка Verify только собирает hex и показывает размеры: 32256 байт под скетч и 2048 под переменные у Uno
- Бутлоадер живёт в 512 байтах флеша и около секунды после ресета слушает порт — ваши вспышки L при каждом включении — это он
- not in sync — ошибка адресата: шапка, закрытый монитор, кабель; Rx и Tx молчат — до платы не доходит даже ресет
- Сломать плату кнопкой Upload нельзя: флеш переживает десятки тысяч перезаписей, бутлоадер и EEPROM при шитье не трогаются
Частые вопросы по теме урока
- Нажали галочку «Проверить», полоса пробежала, статус зелёный, плата молчит. Это поломка?
- Галочка — сборка без шитья: ловим ошибки синтаксиса и смотрим размер. После неё вспышек L и запуска скетча ждать нельзя — их даёт только стрелка Upload. Нет: Verify только компилирует, на плату ничего не отправляется
- Почему у Uno под скетч доступно 32256 байт, а не все 32768?
- Из 32 КБ флеша 512 байт заняты бутлоадером — программой, которая слушает порт после ресета и принимает новый скетч. Остальное — ваше. 512 байт флеша занимает бутлоадер
- Что заставляет плату уйти в бутлоадер в момент нажатия Upload?
- Среда открывает порт и опускает DTR, мост превращает это в ресет. Поэтому же скетч начинается заново при каждом открытии монитора порта. Сигнал на линии DTR: мост 16U2 дёргает ресет главного чипа
- avrdude пишет stk500_getsync(): not in sync. С чего начать?
- not in sync — проблема адресата, а не прошивки: неверный порт, занятый монитор или кабель. Код начинает интересовать последним. Взгляд в шапку и закрыть монитор порта: не тот адресат или порт занят
- Что происходит в последний этап загрузки, после записи hex в флеш?
- Верификация: флеш читается обратно и сверяется байт в байт. Только после неё плата перезапускается, и через секунду бутлоадера стартует ваш setup. avrdude читает флеш обратно и сверяет с hex-файлом — верификация