Как стать автором
Обновить

Безопасное использование ножки RESET на Arduino

Время на прочтение 7 мин
Количество просмотров 57K
Картинка для привлечения внимания

Здравствуйте, уважаемые хабравчане!

В этой статье я опишу способ безопасного использования ножки 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 <util/delay.h>

Для проверки правильности всех действий с бутлоадером лучше всего создать тестовую прошивку, заменив в коде прошивки указатель на ножку. Допустим, так (PCINT10 – это ножка A2):
#define PIN_BOOT PCINT10
Тогда на тестовой прошивке, не затрагивая фьюзов, можно убедиться, что мы все делаем правильно.

Объясню, что тут происходит. Мы убрали переход на основную программу, который происходит после программного сброса и сброса по низкому питанию. PCINT14 – это адрес нашей ножки RESET в регистре PORTC. С помощью прямого обращения к регистру DDRC мы установили для этой ножки pinMode INPUT и подали туда 5 вольт через внутреннее сопротивление (регистр PORTC, так называемое pinMode INPUT_PULLUP). Немного подождали, пока через резистор не перетечет достаточное количество электрончиков, и посмотрели сигнал на ножке через регистр PINC. Если на ноге нет сигнала, значит она заземлена, – приступаем к перепрошивке основной программы. В ином случае, переводим ножку в дефолтный режим INPUT и запускаем основную программу.

Теперь надо это все откомпилировать. В файле 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» на беспаечной макетной плате
«Atmega fusebit doctor» на беспаечной макетной плате

Используя калькулятор фьюзов [8] и даташит [9], создадим командный скрипт flash_fuse.bat для установки правильных фьюзов в наш многострадальный чип:
flash.bat -u -U lfuse:w:0xFF:m -U hfuse:w:0x56:m -U efuse:w:0x05: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=0x56
pro328o16.bootloader.extended_fuses=0x04
pro328o16.bootloader.file=optiboot/optiboot_atmega328.hex
pro328o16.bootloader.unlock_bits=0x3F
pro328o16.bootloader.lock_bits=0x0F
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]. Структура каталогов сохранена.

Замечания принимаются в личке или комментах.

Полезные ссылки:


  1. Мало выводов? Используем RESET
  2. optiboot – An optimised bootloader for Arduino platforms
  3. Arduino watchdog или автоматический RESET в случае зависания
  4. Русская документация к AVRDUDE
  5. Прошивка Arduino Pro Mini через Nano
  6. Fuse-биты — это не страшно
  7. Исправляем AVR фьюзы при помощи «Atmega fusebit doctor»
  8. Калькулятор фьюзов AVR
  9. ATmega328P datasheet
  10. Arduino Pro Mini schematic
  11. Архив со всеми затронутыми файлами для Arduino IDE 1.5.8
Теги:
Хабы:
+20
Комментарии 25
Комментарии Комментарии 25

Публикации

Истории

Ближайшие события

Московский туристический хакатон
Дата 23 марта – 7 апреля
Место
Москва Онлайн
Геймтон «DatsEdenSpace» от DatsTeam
Дата 5 – 6 апреля
Время 17:00 – 20:00
Место
Онлайн