[Из песочницы] Безопасное использование ножки RESET на Arduino
Здравствуйте, уважаемые хабравчане! В этой статье я опишу способ безопасного использования ножки RESET на плате Ардуино для собственных нужд.
Собственно, на поиски решения данного вопроса меня сподвиг некоторый недостаток ножек в разрабатываемой мной системе (которую я надеюсь описать на Хабре, как закончу реализацию) на основе Arduino Pro Mini.Итак, задача ясна, а требования таковы:
Возможность загружать скетчи обычными для Ардуины способами Возможность использовать в своей программе ножку RESET как digital I/O pin Внимание: в статье приводятся команды, неаккуратное использование которых может привести Ардуину в неработоспособное состояние.Гугление по данному вопросу поставит новичков в тупик — вроде бы везде пишут, что такое невозможно, но изредка упоминается, что есть способы обойти это ограничение, как, например, здесь [1].
Итак, чтобы получить желаемый результат, нам надо изменить код бутлоадера, прошить его в Ардуину и изменить фьюзы! Именно в такой последовательности! Это очень важно! Вы готовы?
Шаг первый Тогда начнем с бутлоадера. В сети можно найти множество бутлоадеров для Ардуины с различными возможностями. Я взял самый маленький — optiboot [2]. Он не только освобождает для кода основной программы дополнительные 1,5 килобайта, но и позволяет использовать Watchdog [3]. Скачиваем с сайта последнюю версию с исходниками (архив), распаковываем и копируем папку »\optiboot-9e0c0b9db6fe\optiboot\bootloaders\optiboot» в папку «pathToArduino\hardware\arduino\avr\bootloaders\». Я использую версию Arduino IDE 1.5.8. Если у вас версия Arduino IDE 1.0.5, то найдите папку bootloaders самостоятельно.Открываем файл «pathToArduino\hardware\arduino\avr\bootloaders\optiboot\optiboot.c» в текстовом редакторе или в имеющейся среде программирования (я использую Atmel Studio 6.2). Следующие строчки надо закомментировать:
ch = MCUSR;
MCUSR = 0;
if (ch & (_BV (WDRF) | _BV (BORF) | _BV (PORF)))
appStart (ch);
А вслед за ними вставить такой код:
//ch = MCUSR;
//MCUSR = 0;
//if (ch & (_BV (WDRF) | _BV (BORF) | _BV (PORF)))
//appStart (ch);
#define PIN_BOOT PCINT14
DDRC &= ~_BV (PIN_BOOT);
PORTC |= _BV (PIN_BOOT);
_delay_us (4);
if (_BV (PIN_BOOT)&PINC) {
PORTC &= ~_BV (PIN_BOOT);
appStart (MCUSR);
}
Также в шапке программы найдите #include и после всех инклюдов вставьте:
#include
Теперь надо это все откомпилировать. В файле omake.bat надо заменить путь к make.exe. В моем случае (версия Arduino IDE 1.5.8) — это »…\…\…\sam\system\CMSIS\Examples\cmsis_example\gcc_atmel\make.exe». Я добавил еще пару опций, так что строчка запуска компиляции выглядит так:
…\…\…\sam\system\CMSIS\Examples\cmsis_example\gcc_atmel\make.exe OS=windows ENV=arduino LED_DATA_FLASH=1 BAUD_RATE=57600%* Сначала запускаем omake.exe c параметром clean, затем с параметром atmega328 и внимательно читаем ответ. Если там не упоминаются ошибки «error:», то в папке должна появиться наша прошивка optiboot_atmega328.hex. Замечательно! Шаг второй Приступим к перепрошивке бутлоадера. Использовать функцию перепрошивки в среде Arduino IDE в данном случае не самый лучший вариант — это, скорее всего, приведет к неработоспособности Ардуины. Для прошивки бутлоадера будем использовать avrdude.exe. Это консольная программа находится в папке «pathToArduino\hardware\tools\avr\bin\». Прочитать про используемые параметры можно здесь [4]. Для ее использования в папке с прошивкой создадим один командный скрипт flash.bat следующего содержания: …\…\…\…\tools\avr\bin\avrdude.exe -C »…\…\…\…\tools\avr\etc\avrdude.conf» -c stk500v1 -p m328p -b 19200 -P COM5%* И второй — flash_boot.bat: flash.bat -e -U flash: w: optiboot_atmega328.hex: i Пути к файлам подставьте свои. COM-порт укажите тот, который используется вашим SPI-программатором или Ардуиной, заменяющей программатор. Я же использовал еще одну Pro Mini через COM-программатор PL2303HXA. В нее я закачал стандартный скетч ArduinoISP, который эмулирует работу SPI-программатора по протоколу STK500 v1. Примерная схема подключения показана в этой стате [5].После того, как все подключено, можно проверить связь с программируемой Ардуиной с помощью запуска flash.bat: он покажет сигнатуру микроконтроллера и другую информацию. Теперь можно запустить второй скрипт flash_boot.bat. Если скажет «столько-то bytes of flash verified», значит все ОК, бутлоадер на месте.
На этом шаге можно проверить работу тестовой прошивки: например, загрузить стандартный Blink и, во время запуска Ардуины, заземлять тестовую ножку (A2 в данном случае). Должно наблюдаться беспорядочное мигание встроенного светодиода — это Watchdog рестартует микроконтроллер на этапе неудачных попыток бутлоадера прочесть из Serial-порта команду для перезаписи основной программы.
Шаг третий Наконец, самая ответственная стадия — это установка фьюзов. Перед тем, как с ними работать, о них надо в обязательном порядке прочитать, например, тут [6].Хочу заметить, что неправильные фьюзы можно вылечить с помощью «Atmega fusebit doctor» [7]. «Atmega fusebit doctor» на беспаечной макетной платеИспользуя калькулятор фьюзов [8] и даташит [9], создадим командный скрипт flash_fuse.bat для установки правильных фьюзов в наш многострадальный чип:
flash.bat -u -U lfuse: w:0xFF: m -U hfuse: w:0×56: m -U efuse: w:0×05: m Цифра 5 в hfuse отвечает за отключение функции RESET на соответствующей ножке. Остальные фьюзы на ваше усмотрение (сверяемся с даташитом!). Этот момент настал, можно еще вернуться на светлую сторону к стандартной Ардуине, но мы не станем. После установки фьюзов данной командой стандартных способов поменять фьюзы или бутлоадер не будет! Но, если мы все сделали правильно, то основную программу мы можем шить как обычно при помощи заземления ноги RESET (или же просто зажимая кнопку RESET на плате Ардуины). При включении Ардуины встроенный светодиод будет хаотично мигать — это сигнал к тому, чтобы начать загрузку скетча.Шаг четвертый Преодолев множество трудностей, мы скомпилировали правильный бутлоадер, прошили его в микроконтроллер и установили правильные фьюзы. Теперь надо исправить кое-что в файле «pathToArduino\hardware\arduino\avr\boards.txt», чтобы Arduino IDE смогла общаться с нашей платой.Добавим свои настройки в конец файла (для версии Arduino IDE 1.0.5 они немного другие):
##############################################################
pro328o16.name=[Optiboot] Arduino Pro Mini (5V, 16MHz) w/ ATmega328p pro328o16.upload.tool=avrdude pro328o16.upload.protocol=arduino pro328o16.upload.maximum_size=32256 pro328o16.upload.speed=57600 pro328o16.bootloader.tool=avrdude pro328o16.bootloader.low_fuses=0xff pro328o16.bootloader.high_fuses=0×56 pro328o16.bootloader.extended_fuses=0×04 pro328o16.bootloader.file=optiboot/optiboot_atmega328.hex pro328o16.bootloader.unlock_bits=0×3F pro328o16.bootloader.lock_bits=0×0F pro328o16.build.mcu=atmega328p pro328o16.build.f_cpu=16000000L pro328o16.build.board=AVR_PRO pro328o16.build.core=arduino: arduino pro328o16.build.variant=arduino: eightanaloginputs Название платы »[Optiboot] Arduino Pro Mini (5V, 16MHz) w/ ATmega328p» появится в меню «Tools/Board» в самом конце списка.Ограничения Как вы помните, кнопка RESET на плате Ардуино замыкает ножку RESET на землю [10]. С помощью нее мы вводим микроконтроллер в режим перепрошивки основной программы. Именно поэтому я не рекомендую использовать эту ножку в режиме вывода пяти вольт. Если надо управлять «силовой» нагрузкой, то лучше вывести на ножку землю, а на вторую линию питания нагрузки завести пять вольт. Отключение питания происходит переводом ножки в режим ввода. Так мы избежим возможного короткого замыкания. Остальные режимы можно использовать без проблем.Второе замечание касается сторонних библиотек: если мы передаем ножку как параметр, то нам неизвестно в каком режиме она будет работать. Тут уж ничего не поделать. Разве, что использовать ножку только на очень простой логике, которую сами пишем. И еще рекомендую ставить паузу в начале инициализации программы, чтобы было понятно по светодиоду, что кнопку RESET лучше отпустить немедленно, если кнопка вдруг не сработала, как ожидалось.
Третье замечание касается стандартной нумерации ножек. Да, у ножки RESET нету номера! Есть только регистры микроконтроллера, которыми она управляется. Эта проблема легко решается несколькими правками файла «pathToArduino\hardware\arduino\avr\variants\standard\pins_arduino.h»:
static const uint8_t RST = 20; const uint8_t PROGMEM digital_pin_to_port_PGM[] = { … PC, /* 20 */ }; const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[] = { … _BV (6), /* 20, port C */ }; const uint8_t PROGMEM digital_pin_to_timer_PGM[] = { … NOT_ON_TIMER, /* 20 — port C */ }; После этого все стандартные функции, кроме analogRead (), будут работать с ножкой RESET под номером 20 (RST), как и с любой другой. И даже если у вас имеется дополнительные аналоговые ножки A6 и A7, то они работают отдельно по своему принципу. Можете сами убедиться в этом, написав такой скетч: void setup () { Serial.begin (9600); pinMode (RST, INPUT_PULLUP); // Устанавливаем на ножке RST уровень HIGH в режиме INPUT } void loop () { Serial.println (digitalRead (RST)); // Читаем с ножки RST число 1, если кнопка не нажата Serial.println (analogRead (A6)); // Читаем с ножки A6 «случайное» число, зависящее от прикосновения delay (500); } Заключение Надеюсь, что моя статья не будет для вас единственно возможным выходом из сложной ситуации в ваших проектах на Ардуино. Но буду весьма рад, если кого-нибудь она подтолкнет к тому, чтобы копать еще глубже и находить интересные решения.Архив со всеми затронутыми файлами для Arduino IDE 1.5.8 вы можете скачать по ссылке [11]. Структура каталогов сохранена.
Замечания принимаются в личке или комментах.
Полезные ссылки: Мало выводов? Используем RESET optiboot — An optimised bootloader for Arduino platforms Arduino watchdog или автоматический RESET в случае зависания Русская документация к AVRDUDE Прошивка Arduino Pro Mini через Nano Fuse-биты — это не страшно Исправляем AVR фьюзы при помощи «Atmega fusebit doctor» Калькулятор фьюзов AVR ATmega328P datasheet Arduino Pro Mini schematic Архив со всеми затронутыми файлами для Arduino IDE 1.5.8