В этой статье мы рассмотрим что такое фьюзы (Fuse Bits) в платах Arduino и как их можно использовать для повышения эффективности программ для данной платформы. Если говорить точнее, то понятие фьюзы следует соотносить не с платами Arduino, а с микроконтроллерами семейства AVR, которые являются "сердцем" данных плат.
Фьюзы в микроконтроллерах семейства AVR представляют собой специальные биты конфигурации (переключатели), изменяя которые (то есть устанавливая в них 0 или 1) мы можем изменять некоторые режимы работы микроконтроллера или использовать какие либо его специальные возможности, которые недоступны в его конфигурации "по умолчанию". Эти биты расположены в отдельном адресном пространстве, доступном только при программировании. Биты объединяются в конфигурационные байты и их состав зависит от конкретной модели микроконтроллера. Фьюзы есть во всех микроконтроллерах AVR, но в данной статье мы рассмотрим работу с ними на примере микроконтроллера ATmega328P поскольку он является одним из самых распространенных микроконтроллеров семейства AVR в связи с его использованием в платах Arduino.
Фьюзы (Fuse Bits) в микроконтроллерах AVR
Как мы уже рассмотрели, фьюзы (биты конфигурации) представляют собой "маленькие переключатели", изменяя которые можно управлять логикой работы микроконтроллера. Каким образом мы можем устанавливать или сбрасывать эти биты? Ответ на этот вопрос достаточно простой – это можно сделать с помощью специальных регистров (fuse registers).
В микроконтроллере ATmega328P имеется 19 фьюзов (битов), которые объединены в 3 байта (fuse bytes), которые называются конфигурационными байтами и включают в себя “Extended Fuse Bytes” (дополнительный байт), “High Fuse Byte” (старший байт) и “Low Fuse Byte” (младший байт).
Значения конфигурационных байтов в микроконтроллере ATmega328P по умолчанию: Low: 0x62, High: 0xD9, Extended: 0xFF. Следует помнить, что это значения именно для "чистого" микроконтроллера ATmega328P , а не для платы Arduino. Значения фьюзов для платы Arduino можно найти в файле Arduino_dir\hardware\arduino\avr\Boards.txt, где Arduino_dir - это путь к Arduino IDE. Откройте файл в текстовом редакторе и найдите интересующую плату по названию, чуть ниже будет информация о фьюзах:
uno.name=Arduino/Genuino Uno
...
uno.bootloader.low_fuses=0xFF
uno.bootloader.high_fuses=0xDE
uno.bootloader.extended_fuses=0x05
Примечание: при работе с конфигурационными битами в микроконтроллерах AVR необходимо помнить один важный момент – они инверсные, то есть 1 это выкл, 0 – это вкл. То есть если бит содержит логическую единицу, то это означает что он не запрограммирован (unprogrammed), соответственно, запрограммированный (programmed) конфигурационный бит содержит логический ноль. Такая логика основана на принципе хранения данных в EEPROM: чистая микросхема памяти содержит во всех ячейках единицы, а термин запрограммирована по отношению к такой ячейке означает, что в нее записали ноль.
Если вы посмотрите на таблицу 27 даташита на ATmega328P под номером 7810D–AVR–01/15, то в ней вы можете узнать много подробностей о работе фьюзов в данном микроконтроллере. На следующем рисунке вы можете посмотреть краткий (но достаточно важный) фрагмент из данной таблицы:
Далее последовательно рассмотрим состав конфигурационных байтов в микроконтроллерах семейства AVR.
Дополнительный конфигурационный байт (Extended Fuse Byte)
В следующей таблице показан состав дополнительного байта фьюзов (Extended Fuse Byte), который также называется “EFUSE”.
Номер бита | Название | Описание | Значение по умолчанию |
7 | - | - | 1 |
6 | - | - | 1 |
5 | - | - | 1 |
4 | - | - | 1 |
3 | - | - | 1 |
2 | BODLEVEL2 | Brown-out Detector trigger level | 1 (не запрограммирован) |
1 | BODLEVEL1 | Brown-out Detector trigger level | 1 (не запрограммирован) |
0 | BODLEVEL0 | Brown-out Detector trigger level | 1 (не запрограммирован) |
Как вы можете видеть из представленной таблицы, в этом байте используются всего 3 бита, а остальные биты зарезервированы.
Конфигурационные биты BODLEVEL определяют порог срабатывания схемы BOD (Brownout Detection level), которая следит за уровнем напряжения источника питания. Схема BOD (Brownout Detection) сбрасывает микроконтроллер когда напряжения питания падает ниже определенного уровня. Когда напряжение питания вновь увеличивается до заданного порогового значения (определяемого битами BODLEVEL), то сигнал сброса снимается и происходит запуск микроконтроллера.
В следующей таблице представлены значения порога срабатывания схемы BOD в зависимости от значения битов BODLEVEL. Также в микроконтроллере ATmega328P можно полностью отключить работу схемы BOD с помощью указанных битов (комбинация битов 111).
Порог срабатывания схемы BOD (В) | Значение BODLEVEL2..0 |
Схема BOD выключена | 111 |
Vcc = 1.8 | 110 |
Vcc = 2.7 | 101 |
Vcc = 4.3 | 100 |
Старший конфигурационный байт (High Fuse Byte)
В следующей таблице представлен состав старшего конфигурационного байта в микроконтроллере ATmega328P.
Номер бита | Название | Описание | Значение по умолчанию |
7 | RSTDISBL | External Reset Disable | 1 (не запрограммирован) |
6 | DWEN | debugWIRE Enable | 1 (не запрограммирован) |
5 | SPIEN | Enable Serial Program and Data Downloading | 0 (запрограммирован) |
4 | WDTON | Watchdog Timer Always On | 1 (не запрограммирован) |
3 | EESAVE | EEPROM memory is preserved through the Chip Erase | 1 (не запрограммирован) |
2 | BOOTSZ1 | Select Boot Size | 0 (запрограммирован) |
1 | BOOTSZ0 | Select Boot Size | 0 (запрограммирован) |
0 | BOOTRST | Select Reset Vector | 0 (запрограммирован) |
Биты BOOTRST, BOOTSZ0 и BOOTSZ1 в составе данного байта отвечают за размер Flash памяти микроконтроллера, резервируемой для загрузчика, и за положение вектора сброса.
Загрузчик (начальный загрузчик) – это специальная программа, которая выполняется в самом начале работы микроконтроллера и может решать различные задачи. В случае с платами Arduino данный загрузчик обеспечивает загрузку скетча (основной программы) в память микроконтроллера. По умолчанию для загрузчика резервируется максимальный размер – 2048 слов.
Начало секции загрузчика | Размер секции (слов) | Значение BOOTSZ1..0 |
0x3F00 | 256 | 11 |
0x3E00 | 512 | 10 |
0x3C00 | 1024 | 01 |
0x3800 | 2048 | 00 |
Бит BOOTRST определяет положение вектора сброса микроконтроллера. По умолчанию он указывает на адрес 0х0000.
Бит EESAVE определяет режим стирания энергонезависимой памяти EEPROM. Если в нем логический 0 (бит запрограммирован), то при команде "стирание кристалла" информация в памяти EEPROM сохраняется, если в нем логическая 1 – то содержимое EEPROM по указанной команде стирается.
Бит WDTON отвечает за работу сторожевого таймера (Watchdog Timer). Сторожевой таймер – это таймер, который работает отдельно от всех остальных таймеров микроконтроллера AVR. Если сторожевой таймер установлен, то вам будет необходимо его сбрасывать через определенный период, иначе данный таймер будет сбрасывать микроконтроллер. Если данный бит установлен в логический 0, то работу сторожевого таймера нельзя будет запретить из программы и при переполнении он будет автоматически подавать сигнал сброса на микроконтроллер.
Бит DWEN разрешает/запрещает работу отладочного интерфейса debugWire – это предварительный протокол, который "зашит" в железо микроконтроллера и используется для его программирования и отладки. Когда он установлен (enabled) вы можете загружать программу в микроконтроллер и производить ее отладку по одиночному проводнику. Но для этого необходимы специальные программно-аппаратные средства.
Оставшиеся два бита желательно оставить в "покое" до тех пор, пока вы точно не будете знать что они делают, иначе это может привести к тому, что микроконтроллер перестанет у вас корректно работать. Бит SPIEN разрешает/запрещает программирование микроконтроллера по интерфейсу SPI. По умолчанию он запрограммирован, то есть установлен в 0. Бит RSTDISBL запрещает/разрешает внешний сброс микроконтроллера. Отключать внешний сброс целесообразно только в моделях микроконтроллеров, имеющих очень малое количество выводов (в этом случае данный вывод можно будет задействовать для каких-нибудь других целей), во всех остальных случаях данный фьюз лучше не трогать.
Младший конфигурационный байт (Low Fuse Byte)
В следующей таблице представлен состав младшего конфигурационного байта в микроконтроллере ATmega328P.
Номер бита | Название | Описание | Значение по умолчанию |
7 | CKDIV8 | Divide clock by 8 | 0 (запрограммирован) |
6 | CKOUT | Clock output | 1 (не запрограммирован) |
5 | SUT1 | Select start-up time | 1 (не запрограммирован) |
4 | SUT0 | Select start-up time | 0 (запрограммирован) |
3 | CKSEL3 | Select Clock source | 0 (запрограммирован) |
2 | CKSEL2 | Select Clock source | 0 (запрограммирован) |
1 | CKSEL1 | Select Clock source | 1 (не запрограммирован) |
0 | CKSEL0 | Select Clock source | 0 (запрограммирован) |
Бит CKDIV8 в младшем конфигурационном байте ответственен за деление тактовой частоты на 8. Если он не запрограммирован (установлен в 1), то в регистре делителя будет значение "0000", если в данном бите установить 0, то в регистре будет значение "0011", благодаря чему тактовая частота будет делиться на 8. Однако независимо от значения бита CKDIV8 частоту делителя можно будет изменять в программе в любой момент времени.
Бит CKOUT отвечает за вывод тактовой частоты "наружу" микроконтроллера, на контакт CLK0 (цифровой контакт 8 в плате Arduino Uno). Если он запрограммирован (установлен в 0), то сигнал тактовой частоты выводится наружу – это может быть полезно в случаях когда тактовая частота используется другими периферийными устройствами. При использовании делителя системной частоты на вывод CLK0 также выводится пониженная частота.
Конфигурационные биты SUT1 и SUT0 совместно с битами CKSEL устанавливают длительность задержки при включении (старте) микроконтроллера и выбор типа осциллятора (керамический или встроенный в кристалл). Задержка нужна для того, чтобы источник тактовой частоты после подачи питания стабилизировал свою работу и вошел в рабочий режим. Величина задержки может составлять от 0 до 65 мс. Возможные значения этих битов и соответствующие устанавливаемые ими параметры приведены в следующей таблице.
Биты CKSEL0 – 4 отвечают за выбор источника тактового сигнала. В представленной на следующем рисунке таблице приведены возможные значения этих битов и соответствующие этим значениям источники тактового сигнала. В следующей таблице приведены источники тактового сигнала, поддерживаемые микроконтроллером ATmega328P, и соответствующие им значения битов CKSEL.
Источник тактового сигнала | Значение CKSEL3..0 |
Экономичный кварцевый генератор | 1111-1000 |
Кварцевый генератор | 0111-0110 |
Низкочастотный кварцевый генератор | 0101-0100 |
Внутренний RC-генератор на 128кГц | 0011 |
Внутренний калиброванный RC-генератор | 0010 |
Внешний сигнал синхронизации | 0000 |
Зарезервировано | 0001 |
С составом фьюзов разобрались, теперь перейдем к способам их чтения и изменения.
Чтение фьюзов в Arduino
Для того, чтобы прочитать фьюзы в плате Arduino, нам понадобится программа под названием Avrdude. Данная программа используется для чтения, записи и модифицирования памяти в микроконтроллерах AVR. Она работает по интерфейсу SPI и поддерживает широкий список программаторов. На нашем сайте есть достаточно подробная статья по программе Avrdude, можете ознакомиться при желании, ее свежую версию вы можете скачать по следующей ссылке:
• Download Avrdude Version 6.3 Windows-ming32.
После того, как вы скачали эту программу, вы должны извлечь ее из архива и открыть окно команд Windows в этой папке. После этого подключите программатор USBasp к вашему компьютеру, убедитесь в том, что на вашем компьютере установлен правильный драйвер для программатора USBasp. После этого вы получите возможность чтения фьюзов в плате Arduino. Для этого выполните следующую команду:
avrdude.exe -c usbasp -p m328p -U lfuse:r:low_fuse_val.txt:h -U hfuse:r:high_fuse_val.txt:h -U efuse:r:ext_fuse_val.txt:h
Если все прошло нормально, эта команда прочитает байты фьюзов (fuse bytes) и поместит их в три раздельных текстовых файла. На следующем рисунке показан общий ход этого процесса.
Как видно из представленного рисунка, программа Avrdude считала фьюзы из платы Arduino Nano и поместила их в три отдельных текстовых файла. Если вы откроете эти файлы, то вы увидите считанные значения фьюзов: EFUSE – 0xFD, HFUSE – 0XDA, LFUSE – 0xFF. Это и есть значения фьюзов по умолчанию в плате Arduino Nano
Теперь, когда мы знаем значения фьюзов по умолчанию в плате Arduino, мы можем сравнить со значениями фьюзов по умолчанию в в микроконтроллере ATmega328P
Исходное состояние фьюзов в микроконтроллере ATmega328P и в плате Arduino
Сравнение значений конфигурационных байтов микроконтроллера ATmega328P и платы Arduino представлено в трех следующих таблицах.
№ бита | Low Fuse Byte | Значение по умолчанию в AVR | Значение по умолчанию в Arduino |
7 | CKDIV8 | 0 (programmed) | 1 (unprogrammed) |
6 | CKOUT | 1 (unprogrammed) | 1 (unprogrammed) |
5 | SUT1 | 1 (unprogrammed) | 1 (unprogrammed) |
4 | SUT0 | 0 (programmed) | 1 (unprogrammed) |
3 | CKSEL3 | 0 (programmed) | 1 (unprogrammed) |
2 | CKSEL2 | 0 (programmed) | 1 (unprogrammed) |
1 | CKSEL1 | 1 (unprogrammed) | 1 (unprogrammed) |
0 | CKSEL0 | 0 (programmed) | 1 (unprogrammed) |
№ бита | High Fuse Byte | Значение по умолчанию в AVR | Значение по умолчанию в Arduino |
7 | RSTDISBL | 1 (unprogrammed) | 1 (unprogrammed) |
6 | DWEN | 1 (unprogrammed) | 1 (unprogrammed) |
5 | SPIEN | 0 (programmed) | 0 (programmed) |
4 | WDTON | 1 (unprogrammed) | 1 (unprogrammed) |
3 | EESAVE | 1 (unprogrammed) | 1 (unprogrammed) |
2 | BOOTSZ1 | 0 (programmed) | 0 (programmed) |
1 | BOOTSZ0 | 0 (programmed) | 1 (unprogrammed) |
0 | BOOTRST | 1 (unprogrammed) | 0 (programmed) |
№ бита | Extended Fuse Byte | Значение по умолчанию в AVR | Значение по умолчанию в Arduino |
7 | – | 1 | 1 |
6 | – | 1 | 1 |
5 | – | 1 | 1 |
4 | – | 1 | 1 |
3 | – | 1 | 1 |
2 | BODLEVEL2 | 1 (unprogrammed) | 1 (unprogrammed) |
1 | BODLEVEL1 | 1 (unprogrammed) | 0 (programmed) |
0 | BODLEVEL0 | 1 (unprogrammed) | 1 (unprogrammed) |
Начальное состояние микроконтроллеров ATmega328/P, в котором они поставляются с завода, является следующим: микроконтроллер сконфигурирован на работу с внутренним RC генератором на 8МГц, при этом прошитый бит CKDIV8 обеспечивает деление частоты генератора на 8; внешний сброс (по низкому уровню на выводе Reset) не запрещен; разрешено программирование по интерфейсу SPI; для загрузчика отведена область памяти 2048 слов; стартовый адрес программы 0x0000; схема контроля питания отключена.
В плате Arduino Uno фьюзы микроконтроллера изменены таким образом, чтобы он был настроен на работу с экономичным кварцевым генератором без делителя частоты; для загрузчика отводится 256 слов; прошитый бит BOOTRST назначает стартовым адресом адреса начала секции загрузчика; порог срабатывания схемы BOD составляет 2.7В.
Теперь рассмотрим процесс изменения фьюзов в плате Arduino (микроконтроллере AVR).
Необходимые компоненты
Для чтения/изменения фьюзов в микроконтроллере AVR нам будут необходимы следующие компоненты:
- Плата Arduino Nano (купить на AliExpress).
- Программатор USBasp и конвертер 10-Pin в 6-Pin для AVR (купить на AliExpress - по этой ссылке можно купить как отдельно программатор).
- USB кабель.
- Светодиод (купить на AliExpress).
- Резистор 330 Ом (купить на AliExpress).
- Макетная плата.
- Соединительные провода.
- Программа Avrdude.
Внешний вид этих компонентов показан на следующем рисунке.
Схема проекта
Схема для чтения/изменения фьюзов в микроконтроллере AVR представлена на следующем рисунке.
Мы подключили плату Arduino Nano к компьютеру с помощью USB кабеля, также к компьютеру мы подключили программатор USBasp. Но нашей целью является программирование/изменение фьюзов в микроконтроллере AVR. Для этого мы подключили программатор USBasp к плате Arduino.
Внешний вид получившейся у нас конструкции показан на следующем рисунке:
Как вы видите из рисунка, к нашему ноутбуку подключена и плата Arduino, и программатор USBasp.
Программирование/изменение фьюзов в микроконтроллере AVR
Откройте Arduino IDE и загрузите в плату Arduino базовый скетч для мигания светодиодом (basic blink sketch).
Вы увидите, что встроенный в плату Arduino светодиод (подключенный к ее контакту 13) начнет мигать. Более подробно все эти процессы вы можете посмотреть в видео, приведенном в конце статьи. Теперь давайте попоробуем изменить фьюзы и посмотрим что произойдет. Как мы уже выяснили ранее, по умолчанию значения фьюзов в плате Arduino следующие: EFUSE – 0XFF, HFUSE – D9, LFUSE – 62. Изменим их с помощью Avrdude, для этого выполним следующую команду:
avrdude -c usbasp -p m328P -U lfuse:w:0x62:m -U hfuse:w:0xd9:m -U efuse:w:0xff:m
После выполнения этой команды вы увидите что скорость мигания светодиода станет значительно меньше. Дело в том, что по умолчанию частота мигания светодиода определялась частотой внешнего кварцевого генератора (16 МГц), теперь же, после изменения фьюзов, она определяется частотой внутреннего RC генератора (1 МГц). Поэтому и светодиод теперь будет мигать значительно медленнее.
Но, поскольку мы изменили фьюзы, мы изменили и настройки загрузчика. Вы можете увидеть это на следующем рисунке:
Чтобы исправить это и вернуть плату Arduino в ее исходное состояние, мы должны снова загрузить в нее загрузчик. Для этого выполните Tools -> Programmer- USBasp, после этого снова зайдите в Tools и выберите пункт "burn bootloader". После этого исходная функция загрузчика загрузится в плату Arduino и она снова начнет функционировать как обычно.
После этого светодиод на плате станет снова мигать с прежней частотой.