_delay_ms() работает намного медленнее, чем ожидалось (в 6 раз) на tinyAVR 0/1 (ATTiny1604)

Я разработал специальную плату разработки AVR с использованием микроконтроллера Atmel ATTiny1604. Он принадлежит к новому семейству Tiny-0, из-за его недавности некоторые необходимые изменения в соответствующих цепочках инструментов еще не включены в стабильную версию (я предпочитаю использовать исходные восходящие цепочки инструментов вместо SDK Atmel / Microchip). Таким образом, я скомпилировал последние версии toolchains из исходных текстов. Они включают в себя ...

  • AVR GCC 10.2.0

  • avr-libc, магистраль svn, с примененным патчем avrxmega3-v10.diff

После того, как я установил цепочки инструментов, я написал программу мигания светодиодов, чтобы проверить, правильно ли работает моя цепочка инструментов. Программа была собрана с помощью avr-gcc -mmcu=attiny1604 -Wall -Os -o blink.elf blink.c -Wl,--section-start=.text=0x200 и загружена через загрузчикOptiboot_X.

#define F_CPU 20000000UL
#include <avr/io.h>
#include <util/delay.h>

int main(void)
{
    PORTB.DIRSET = 0b00000001;

    while (1) {
        PORTB.OUTSET = 0b00000001;
        _delay_ms(500);
        PORTB.OUTCLR = 0b00000001;
        _delay_ms(500);
    }
}

Однако я обнаружил, что _delay_ms(500) работает не так, как ожидалось. Вместо задержки в 500 миллисекунд фактическая задержка ближе к 3000 миллисекунд, как видно на осциллографе, она была замедлена в 6 раз.

Oscilloscope screenshot showing the delay is slowed down by a factor of 6, instead of 500 ms, it's 3000 ms.

Я дважды проверил настройки своих предохранителей.

$ pyupdi -d tiny1604 -c /dev/ttyUSB0 -fr
Device info: {'family': 'tinyAVR', 'nvm': 'P:0', 'ocd': 'D:0', 'osc': '3', 'device_id': '1E9425', 'device_rev': '0.0'}
Fuse:Value
0:0x00
1:0x00
2:0x02
3:0xFF
4:0x00
5:0xF6
6:0x07
7:0x00
8:0x02
9:0xFF
10:0xC5

Я видел сообщение pyupdi о том, что предохранитель OSCCFG (№ 2) запрограммирован на значение 0x02, что, согласно спецификации, означает "Работать на частоте 20 МГц с соответствующей заводской калибровкой". Почему я получаю неправильные задержки, даже когда системные часы работают с правильной скоростью? Моя цепочка инструментов сломана?

Примечание: Этот вопрос я уже решил. Но учитывая, что в Интернете относительно мало руководств по новому tinyAVR 0/1, я разместил вопрос и ответ здесь, чтобы служить справочником для сообщества.

, 👍13


1 ответ


Лучший ответ:

17

Ваша цепочка инструментов не сломана. В техническом описании ATTiny804 / 1604, стр. 77, показано, что частота процессора отделена от частоты генератора 20/16 МГц с помощью прескалера (в техническом описании ATTiny1614 тот же прескалер тактовой частоты показан на стр. 80. Так что эта функция присутствует в обоих микроконтроллерах tinyAVR 0/1).

Main Clock and Prescaler Источник: Спецификация микрочипа ATTiny804 / 1604, добросовестное использование.

В техническом описании сказано ...

10.3.3 Основные тактовые частоты после сброса После любого сброса CLK_MAIN обеспечивается генератором 16/20 МГц (OSC20M) с коэффициентом деления прескалера, равным 6. Поскольку фактическая частота OSC20M определяется битами выбора частоты (FREQSEL) предохранителя конфигурации генератора (FUSE.OSCCFG), эти частоты возможны после сброса:

  • 16 МГц ---> 2,66 МГц
  • 20 МГц ---> 3,3 МГц

По умолчанию коэффициент деления равен 6. Это означает, что процессор фактически работает на частоте 3,333 МГц, когда предохранитель OSCCFG запрограммирован на 20 МГц.

Решение

Используйте правильный F_CPU

Если более медленный процессор не является для вас проблемой, вы можете просто сообщить компилятору правильную частоту процессора, изменив #define F_CPU 20000000UL на #define F_CPU 3333333UL.

Или отключить частотное разделение

В качестве альтернативы вы можете отключить частотное разделение и запустить процессор на полной частоте 20 МГц.

#define F_CPU 20000000UL

int main(void)
{
    /* Set CPU clock to 20 MHz */
    _PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 0);

    /* your code */
}

Но не разгоняйте процессор

Тем не менее, вы должны отметить, что работа на частоте 20 МГц гарантируется Atmel только при напряжении 4,5 В и выше. Если вы используете микроконтроллер при более низком напряжении, например 3,3 В, вы разгоняете процессор, выводя его за пределы безопасной рабочей зоны, обозначенной Atmel. См. Таблицу на странице 473.

Safe Operating CPU clock vs Voltage Источник: Спецификация микрочипа ATTiny804 / 1604, добросовестное использование.

Хотя разогнанный микроконтроллер, вероятно, будет работать, и в хобби-проекте вы вряд ли увидите какие-либо проблемы. Но все же на данный момент нет гарантии стабильности от производителя. Например, микроконтроллер официально имеет температуру 105 ° C, но разогнанный микроконтроллер может начать давать сбои. Также вероятно повышенное энергопотребление. Наихудшей возможной проблемой может быть таинственная неисправность при определенных редких условиях. Таким образом, если важна надежность и стабильность, не следует разгонять микроконтроллер.

При напряжении 3,3 В, при тактовой частоте системы 20 МГц, процессор должен работать только на частоте 10 МГц, установив значение предварительной настройки в 2 раза. И при напряжении 1,8 В, при частоте 5 МГц с 4-кратным прескалером.

/* Set CPU clock to 10 MHz */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 
                 CLKCTRL_PDIV_2X_gc | CLKCTRL_PEN_bm);

/* Set CPU clock to 5 MHz */
_PROTECTED_WRITE(CLKCTRL_MCLKCTRLB, 
                 CLKCTRL_PDIV_4X_gc | CLKCTRL_PEN_bm);
,