воскресенье, 30 декабря 2018 г.

Тактирование Ардуино от внутреннего RC-генератора

Arduino ATmega328P тактирование от внутреннего RC-генератора

При написании публикации про ATtiny85 я обратил внимание на то, как реализовано изменение частоты микроконтроллера: достаточно выбрать нужное значение тактовой частоты в меню IDE Ардуино и затем выполнить команду "Записать загрузчик". А почему бы не сделать так же для Ардуино? Чтобы можно было простыми действиями настроить ее на тактирование либо от внешнего резонатора на 16МГц, либо от внутреннего RC-генератора на 8МГц. Кстати при тактировании от внутреннего генератора микроконтроллер можно извлечь из Ардуино, тем самым значительно снизить энергопотребление. В общем, тема весьма интересная, подробности под катом.

Содержание

Что нужно знать о тактировании AVR микроконтроллеров

AVR микроконтроллеры способны работать с различными источниками тактового сигнала. Это может быть внешний резонатор, RC-цепочка (внутренняя или внешняя), а так же внешний сигнал синхронизации. Источник тактирования выбирается исходя из требований к устройству. Так для построения точных микроконтроллерных систем следует использовать внешние кварцевые или керамические резонаторы, так как они обладают высокой стабильностью и не чувствительны к изменениям температуры. В этом плане им уступают генераторы на основе времязадающей RC-цепочки: они менее стабильны и чувствительны к изменениям температуры и напряжения. С другой стороны внутренний RC-генератор присутствует практически во всех AVR микроконтроллерах и его использование будет наиболее простым и экономичным решением в системах, не предъявляющих высоких требований к стабильности тактового сигнала.

Настройка микроконтроллера на работу с тем или иным источником тактового сигнала осуществляется установкой конфигурационных битов (фьюзов) при помощи программатора. Применительно к нашей ситуации установка фьюзов происходит при выполнении команды "Записать загрузчик" из меню IDE Ардуино, значения фьюзов берутся из файла boards.txt. Он же отвечает за добавление новых пунктов в меню Инструменты. Поэтому доработка IDE Ардуино для добавления в нее меню выбора частоты начинается с редактирования файла boards.txt

Редактирование файла boards.txt

Перейдите в каталог Arduino_dir\hardware\arduino\avr\, где Arduino_dir - это каталог, в который установлена среда разработки Ардуино. У меня этот путь выглядит так: d:\Arduino\arduino-1.6.12\hardware\arduino\avr\. Перед внесением изменений в файл boards.txt я рекомендую сделать его резервную копию. Теперь открываем файл boards.txt в текстовом редакторе (подойдет notepad++ или другой, поддерживающий кодировку UTF-8, чтобы не было проблем с отображением русских букв в IDE Ардуино)  и добавляем в него строку menu.clock=Тактирование

Редактирование boards.txt Ардуино

Затем находим секцию для Ардуино Уно (я опишу порядок действий применительно к Ардуино Уно, но таким же образом можно скорректировать секции других плат с поправкой на микроконтроллер):

Редактирование boards.txt Ардуино

Здесь нужно добавить наше подменю для выбора источника тактирования и частоты. Для этого сперва удалим строки, определяющие:
  1. скорость загрузки - uno.upload.speed;
  2. значения фьюзов - uno.bootloader.low_fuses, .high_fuses, .extended_fuses;
  3. имя файла загрузчика - uno.bootloader.file;
  4. частоту микроконтроллера - uno.build.f_cpu.
Эти параметры мы перенесем в подменю, в основной же секции останутся только общие параметры. Ниже приведен фрагмент, добавляющий подменю выбора источника тактирования,  вставьте его в свой файл.

uno.menu.clock.external16=Внешний резонатор 16МГц
uno.menu.clock.external16.upload.speed=115200
uno.menu.clock.external16.bootloader.low_fuses=0xFF
uno.menu.clock.external16.bootloader.high_fuses=0xDE
uno.menu.clock.external16.bootloader.extended_fuses=0xFF
uno.menu.clock.external16.bootloader.file=optiboot/optiboot_atmega328.hex
uno.menu.clock.external16.build.f_cpu=16000000L

uno.menu.clock.internal8=Внутренний RC-генератор 8МГц
uno.menu.clock.internal8.upload.speed=57600
uno.menu.clock.internal8.bootloader.low_fuses=0xE2
uno.menu.clock.internal8.bootloader.high_fuses=0xDE
uno.menu.clock.internal8.bootloader.extended_fuses=0xFF
uno.menu.clock.internal8.bootloader.file=optiboot/optiboot_atmega328_8.hex
uno.menu.clock.internal8.build.f_cpu=8000000L

uno.menu.clock.internal1=Внутренний RC-генератор 1МГц
uno.menu.clock.internal1.upload.speed=4800
uno.menu.clock.internal1.bootloader.low_fuses=0x62
uno.menu.clock.internal1.bootloader.high_fuses=0xDE
uno.menu.clock.internal1.bootloader.extended_fuses=0xFF
uno.menu.clock.internal1.bootloader.file=optiboot/optiboot_atmega328_1.hex
uno.menu.clock.internal1.build.f_cpu=1000000L

Для наглядности я приведу скриншот моего файла boards.txt, каким он был и каким стал после выполнения описанных изменений:

Редактирование boards.txt Ардуино

Таким образом мы описали меню из трех пунктов, для каждого из них указали скорость загрузки скетчей, значения фьюзов, имя файла загрузчика (об этом чуть позже) и частоту микроконтроллера. При помощи онлайн калькулятора вы можете расшифровать приведенные значения фьюзов и увидеть, как происходит выбор источника тактирования. И что для получения тактовой частоты 1МГц при работе от внутреннего RC-генератора используется деление частоты на 8 (фьюз CKDIV8).

Сохраните файл в кодировке UTF-8 без BOM и запустите IDE. Если все сделано правильно, то при выборе платы Arduino Uno вам станет доступно меню Инструменты->Тактирование. Но этих изменений пока еще мало. Если сейчас выбрать в меню, например, Внутренний RC-генератор 8МГц и выполнить запись загрузчика, то новые значения фьюзов, конечно, запишутся в микроконтроллер и он начнет работать с внутренним RC-генератором. Но мы потеряем возможность загружать в Ардуино новые скетчи, потому что записанный в нее загрузчик рассчитан на частоту 16МГц. Выход - скомпилировать загрузчик для работы на частотах 8МГц и 1МГц. Если у вас нет желания заморачиваться с компиляцией загрузчика, то можете скачать уже скомпилированные файлы отсюда, поместить их в каталог Arduino_dir\hardware\arduino\avr\bootloaders\optiboot\ и перейти к пункту Изменение частоты и источника тактирования Ардуино. А кому интересно могут скомпилировать их самостоятельно. О том как это сделать описано далее.

Что такое Optiboot


Optiboot - это загрузчик для AVR микроконтроллеров, созданный Питером Найтом (Peter Knight). В его основу легли труды нескольких разработчиков и групп (Jason P. Kyle, Arduino group, Spiff , AVR-Libc group, Ladyada), впоследствии он значительно развился. Загрузчик получился настолько удачным, что компания-разработчик Ардуино стала использовать его в своей плате Ардуино Уно. С недавнего времени Optiboot является официальным загрузчиком и для других плат на базе ATmega328p (Нано, Мини). По сравнению с использовавшимся в них старым загрузчиком Optiboot обладает рядом преимуществ:

  • занимает всего 512 байт, освобождая 1,5кб для программ пользователя;
  • значительно быстрее выполняет загрузку скетчей;
  • поддерживает альтернативные серийные порты, скорости загрузки и частоты микроконтроллера.

С 2011 года поддержкой Optiboot занимается  Билл Вестфилд (Bill Westfield). Это самостоятельный проект, не финансируемый какими-либо организациями.

Компиляция Optiboot для работы на частотах 8МГц и 1МГц

Исходные файлы Optiboot входят в состав IDE Ардуино и находятся в каталоге Arduino_dir\hardware\arduino\avr\bootloaders\optiboot\. Там же расположен батник omake.bat для сборки загрузчика. Вот только для его сборки в составе IDE Ардуино (начиная с версий 1.5.x) не хватает утилиты make.exe. Наиболее простое решение - это скопировать ее из старой версии. Для этого:
  1. скачайте IDE версии 1.0.6;
  2. распакуйте архив и перейдите каталог \arduino-1.0.6\hardware\;
  3. скопируйте или переместите каталог tools в Arduino_dir\hardware\arduino\ вашей рабочей IDE;
  4. IDE 1.0.6 больше не нужна, ее можно удалить.
Перейдите в каталог optiboot и откройте файл Makefile в Блокноте. В нем нужно найти секцию для atmega328:

Компиляция optiboot для Ардуино

Между ней и началом следующей секции для Sanguino вставляем код:

atmega328_8: TARGET = atmega328
atmega328_8: MCU_TARGET = atmega328p
atmega328_8: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=57600'
atmega328_8: AVR_FREQ = 8000000L
atmega328_8: LDSECTIONS  = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_8: $(PROGRAM)_atmega328_8.hex
atmega328_8: $(PROGRAM)_atmega328_8.lst

atmega328_1: TARGET = atmega328
atmega328_1: MCU_TARGET = atmega328p
atmega328_1: CFLAGS += '-DLED_START_FLASHES=3' '-DBAUD_RATE=4800'
atmega328_1: AVR_FREQ = 1000000L
atmega328_1: LDSECTIONS  = -Wl,--section-start=.text=0x7e00 -Wl,--section-start=.version=0x7ffe
atmega328_1: $(PROGRAM)_atmega328_1.hex
atmega328_1: $(PROGRAM)_atmega328_1.lst

Это копии секции atmega328. От исходной они отличаются частотой микроконтроллера и скоростью загрузки скетчей. Эти значения соответствуют указанным нами ранее в файле boards.txt. Думаю, можно указать и большую скорость загрузки, но я не экспериментировал с этим. Однозначно, при слишком высокой скорости ошибки будут неизбежны, поэтому с уменьшением частоты микроконтроллера я уменьшаю и скорость загрузки.

Теперь нужно скомпилировать загрузчик для работы на пониженной частоте. Для этого, находясь в каталоге Arduino_dir\hardware\arduino\avr\bootloaders\optiboot\, запустите командную строку, введите и выполните по очереди команды:
omake.bat atmega328_8
omake.bat atmega328_1

Компиляция optiboot для Ардуино

Загрузчики для работы на частоте 8МГц и 1МГц готовы! Теперь нужно удалить папку tools, которую мы позаимствовали из IDE Ардуино 1.0.6. Если этого не сделать, то среда не запустится. Связано это с тем, что содержимое Arduino_dir\hardware\arduino\ должно иметь определенную структуру и папке tools здесь не место.

Изменение частоты и источника тактирования Ардуино

Для изменения частоты и источника тактирования необходимо записать в Ардуино новый загрузчик. Для выполнения этой процедуры нужен программатор. Если у вас его нет, то можете использовать в качестве программатора другую плату Ардуино, в статье Arduino as ISP - программатор из Ардуино эта тема подробно расписана. Я для записи загрузчика воспользуюсь программатором USBasp.

Итак, запускаем среду разработки Ардуино, выбираем в списке плат Arduino/Genuino Uno, в меню Инструменты->Тактирование выбираем значение Внутренний RC-генератор 8МГц. Подключаем программатор к компьютеру, выставляем соответствующее значение в меню Инструменты->Программатор. Записываем загрузчик. После этого отключаем программатор, подключаем Ардуино напрямую к компьютеру и в меню Инструменты->Программатор выставляем стандартное значение - AVRISP mkII. Теперь можете проверить работу платы, загрузив в нее скетч Blink из стандартных примеров. Когда решите снова изменить частоту, нужно будет повторно выполнить запись загрузчика, выбрав соответствующее значение в меню Тактирование.

Если при записи загрузчика на 1МГц через USBasp у вас возникнет следующая ошибка:

USBasp ошибка при записи загрузчика

- не пугайтесь, просто нужно установить перемычку JP3 на программаторе. При использовании Ардуино в качестве программатора такая ошибка не возникает.

Теперь было бы интересно вынуть ATmega328P из Ардуино и измерить его энергопотребление при работе на 8МГц / 1МГц, а также в режиме PowerDown. Но это я оставлю для будущей публикации - Энергопотребление ATmega328P при тактировании от внутреннего RC-генератора

14 комментариев:

  1. Здравия , спасибо за статью.
    Пришли с Али про мини 10шт.
    И как то не правильно работают.
    Нашел скетч, проверил платы, а кварцы стоят на 12мгц.
    Попробую по вашему методу добавить выбор для 12мгц кварца.

    ОтветитьУдалить
    Ответы
    1. Добрый день!
      Напишите о результатах когда попробуете.

      Удалить
  2. Доброй ночи.
    Прошел по ссылке в статье на калькулятор фьюзов - не все понял по инглишу.
    Нашел наш сайт по русски. http://fusecalc.mirmk.ru/
    Не знаю как вставить картинку. Оставлю вам ссылку на картинку в моем гугл диске
    https://drive.google.com/file/d/1WNwAR7cZNer5GB_v2GqG78Yd9JyqBqER/view?usp=sharing
    _________________________________________________
    "Режимы синхронизации и задержки запуска (CKSEL, SUT)"
    ---------------------------------------------------
    -"выбор кварца 8мгц и выше" - получается не важно 16 или 12 мгц кварц.

    Проверял примером с блинком. 10 морганий время: при 16мгц - 20с, 12мгц - 16с, 8мгц - 10с. Использовал две про мини 328p 5v с кварцем 16мгц и 12мгц. результат одинаковый.

    Редактировал только boards.txt
    Это было
    ## Arduino Pro or Pro Mini (5V, 16 MHz) w/ ATmega328P
    ## --------------------------------------------------
    pro.menu.cpu.16MHzatmega328=ATmega328P (5V, 16 MHz)

    pro.menu.cpu.16MHzatmega328.upload.maximum_size=30720
    pro.menu.cpu.16MHzatmega328.upload.maximum_data_size=2048
    pro.menu.cpu.16MHzatmega328.upload.speed=57600

    pro.menu.cpu.16MHzatmega328.bootloader.low_fuses=0xFF
    pro.menu.cpu.16MHzatmega328.bootloader.high_fuses=0xDA
    pro.menu.cpu.16MHzatmega328.bootloader.extended_fuses=0xFD
    pro.menu.cpu.16MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex

    pro.menu.cpu.16MHzatmega328.build.mcu=atmega328p
    pro.menu.cpu.16MHzatmega328.build.f_cpu=16000000L


    Поменял только последнюю строку значение с 16000000 на 12000000

    ## Arduino Pro or Pro Mini (5V, 12MHz) w/ ATmega328P

    pro.menu.cpu.12MHzatmega328=ATmega328P (5V, 12 MHz)

    pro.menu.cpu.12MHzatmega328.upload.maximum_size=30720
    pro.menu.cpu.12MHzatmega328.upload.maximum_data_size=2048
    pro.menu.cpu.12MHzatmega328.upload.speed=57600

    pro.menu.cpu.12MHzatmega328.bootloader.low_fuses=0xFF
    pro.menu.cpu.12MHzatmega328.bootloader.high_fuses=0xDA
    pro.menu.cpu.12MHzatmega328.bootloader.extended_fuses=0xFD
    pro.menu.cpu.12MHzatmega328.bootloader.file=atmega/ATmegaBOOT_168_atmega328.hex

    pro.menu.cpu.12MHzatmega328.build.mcu=atmega328p
    pro.menu.cpu.12MHzatmega328.build.f_cpu=12000000L

    ОтветитьУдалить
    Ответы
    1. "Проверял примером с блинком. 10 морганий время: при 16мгц - 20с, 12мгц - 16с, 8мгц - 10с. Использовал две про мини 328p 5v с кварцем 16мгц и 12мгц. результат одинаковый."

      Хрень какая-то. Чем ниже частота кварца, тем длиннее должны быть интервалы

      Удалить
    2. Товарищ пишет, что и f_cpu тоже менял. Тогда бы при соответствии кварца указанному в f_cpu значению время мигания должно быть одинаковым.

      Похоже будто f_cpu действительно изменяли, а кварц во всех случаях оставался на 16:
      F_cpu 16мгц - 20с - норм.
      F_cpu 8мгц - 10с - обманули МК вдвое, он быстрее и выполнил.
      F_cpu 12мгц - 16с - смысл как в предыдущем пункте с разницей примерно в четверть.

      И возвращаясь к исходному предположению о кварце на 12МГц в пришедших из Китая про мини - оно ошибочно, кварцы стоят на 16, тогда всё сходится

      Удалить
  3. Еще обнаружил что только половина из 10 этих про мини с 12-м кварцем, остальные с 16-м
    Будет свободное время залью еще раз скетч, во все эти про мини.
    Так они вроде рабочие, а пины D6 D7 на которые идет сигнал не работают.

    ОтветитьУдалить
  4. Ссылка на ARDUINO 1.0.6 не работает (устарела?), сейчас такая ссылка: https://downloads.arduino.cc/arduino-1.0.6-windows.zip

    ОтветитьУдалить
  5. Здравствуйте! Вот у меня та же проблема с тактированием и временем. Я собрал плату, на ней стоит кварц 16 Мгц. Для удобства программирования и проверки на лету в DIP28 в который потом встанет Atmega8 вставил Nano (сделал отладочную на базе NANO). Боролся за каждый байт, чтобы влезло на AM8. И вот все заработало на NANO, я радостный заливаю скетч Arduino SPI в AM8 и... чехарда из звуков. Ладно, - напутал наверное. Раньше звуки из пищалки не нужны были. На NANO яркие и звонкие, на AM8 дребезг. Стал играться тактовой частотой, и как я только не заливал и с внутренним и внешним, но ВЫХОДИТ ОДНО И ТО ЖЕ. 1 секунда в скетче (напр. delay(1000)) при 8Мгц хоть при внутреннем, хоть при внешнем тактировании равна 8 сек. Аналогично, 16Мгц - 16 секунд. Пересмотрел кучу видео и прочита уйму статей, вот и тут я о этому самому поводу. Перепробовал десятки вариантов, убил несколько МК, результ нулевой.
    Пришлось установить внутреннюю тактовую частоту 1 Мгц. Только так 1 сек = 1 сек реального времени.
    Кстати, совершенно нет разницы, стоит внешний кварц или нет.
    Как вывод, устройство хорошо работает только на AM328 на 1 Мгц внутреннего тактирования.
    На АМ8 на 1Мгц программа работает, но звуки всегда - однотонный дребезг.
    Есть какие нибудь предложения?

    ОтветитьУдалить
  6. Этот комментарий был удален автором.

    ОтветитьУдалить
    Ответы
    1. Добрый день!
      Несоответствие указанных в программе задержек реальным значениям - это несоответствие реальной частоты микроконтроллера и указанной в IDE (в случае с IDE Arduino - это файл boards.txt, параметры build.f_cpu). Вот прям к гадалке не ходи. И к этой ситуации 2 пути: неверные значения фьюзов или неверное значение f_cpu в этом самом boards.txt. Проверьте оба варианта.

      Удалить
  7. Этот комментарий был удален автором.

    ОтветитьУдалить
  8. Этот комментарий был удален автором.

    ОтветитьУдалить
  9. Всем доброго времени суток!
    Итак что я выяснил. Мои МК 8 на заводе прошиты как (проверил чтением avrdude_prog-v.3.3):
    Внутренний RC генератор 1МГц; Запуск: 6 CK + 0 мс; [CKSEL=0001 SUT=00]
    Проблема в том, что если перепрошивать фьюзы USBisp в avrdude под другую частоту, например Внешний кварц 16 Мгц, то МК убивается, (штук 5 выбросил и 8 и 328). Сначала появляется сообщение что всё ОК, но повторное чтение сообщает ОШИБКА! (avrdude.exe: warning: cannot set sck period. please check for usbasp firmware update.
    avrdude.exe: error: programm enable: target doesn't answer. 1
    avrdude.exe: initialization failed, rc=-1
    Double check connections and try again, or use -F to override
    this check.
    )
    Та же проблема и с прошиванием Загрузчика в среде Arduino IDE программатором Arduino ISP. Сначала, вроде, МК даже читается с новыми фьзами в avrdude_prog-v.3.3 и потом тут же можно Запрограммировать залив hex файл со своим скетчем, но пусть вас это не радует, установив МК в свою плату он не заработает. Повторное тестирование в avrdude_prog-v.3.3 покажет ту же ошибку!
    !!!! А выбросил зря, ибо нашел ролик где рассказывается (в рунете и англоязычном сайте), что эта проблема из за проседания 5v во время процедуры прошивки, и стоит только к МК подключить внешнее питание 5v (только VCC, земля ОБЩАЯ). Прошивается на УРА.

    Итак действия для новичков!

    Для прошивки своих DIP28 Atmega8 328 можно использовать старую UNO.
    У USBasp программатора на шлейфе отпаиваете питание VCC, вообщем питание Atmega должно быть внешнее- свое, но Земля общая!!!
    Если прошиваете в Arduino IDE, то сначала создаете в конструкторе прошивку - это и есть ЗАГРУЗЧИК. ВАЖНО ПОНИМАТЬ, например вы создали несколько прошивок для своей Atmega8

    1. внешний кварц резонатор 16Мгц
    2. внешний кварц резонатор 8Мгц
    3. внутренний генератор 1Мгц
    4. внутренний генератор 4Мгц

    и загрузили Загрузчик в свой МК.

    Так вот, надо точно помнить какой свой МК как вы прошили, ибо если вы потом захотите свой МК в котором прошивка на внутренний генератор 8Мгц установить скетч выбрав плату с установками "внешний кварц резонатор 16Мгц", то скетч зальется, но начнется белиберда со временем как у меня, ибо я сразу не уловил, что загрузчик вшитый никуда не девается. полагал, что выбирая плату с новыми установками меняю автоматом и загрузчик, в чем и ошибался.
    Но и про отдельное питание для МК не забываем (только VCC? Земля общая).

    Владимиру за свой блог жму руку, СПАСИБО!
    Мне под 60 лет, программируемой электроний занялся года 4 назад, когда купил 3D принтер, тогда и узнал об Arduino и ее возможностях.
    В 60 теория дается тяжело, опыт накопленный блокирует ее.

    ОтветитьУдалить