12

I designed a custom AVR development board using the Atmel ATTiny1604 microcontroller. It belongs to the new Tiny-0 family, due to its recentness, some required changes to relevant toolchains have yet to be included into the stable version (I prefer to use the original upstream toolchains instead of Atmel/Microchip's SDK). Thus, I compiled the latest versions of toolchains from source. They include...

After I installed the toolchains, I wrote a LED blinking program to verify whether my toolchain was working properly. The program was built with avr-gcc -mmcu=attiny1604 -Wall -Os -o blink.elf blink.c -Wl,--section-start=.text=0x200 and uploaded via the Optiboot_X bootloader.

#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);
    }
}

However, I found that _delay_ms(500) doesn't work as expected. Instead of a 500-millisecond delay, the actual delay is closer to 3000 milliseconds as seen on the oscilloscope, it has been slowed down by a factor of 6.

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

I've double-checked my fuse settings.

$ 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

I saw pyupdi reported that the fuse OSCCFG (No. 2) has been programmed to 0x02, which according to the datasheet, means "Run at 20 MHz with corresponding factory calibration". Why do I get incorrect delays even when the system clock is running at the correct speed? Is my toolchain broken?

Note: This is a question I already solved. But consider there are relatively few tutorials about the new TinyAVR 0/1 on the web, I posted the question and answer here to serve as a reference for the community.

16

Your toolchain is not broken. In the ATTiny804/1604 datasheet, page 77, it shows the CPU clock is divided from the 20/16 MHz oscillator by a prescaler (the ATTiny1614 datasheet shows the same clock prescaler in page 80. So it's a feature found in both tinyAVR 0/1 microcontrollers).

Main Clock and Prescaler Source: Microchip ATTiny804/1604 datasheet, fair use.

The datasheet says...

10.3.3 Main Clock After Reset After any Reset, CLK_MAIN is provided by the 16/20 MHz Oscillator (OSC20M) and with a prescaler division factor of 6. Since the actual frequency of the OSC20M is determined by the Frequency Select bits (FREQSEL) of the Oscillator Configuration fuse (FUSE.OSCCFG), these frequencies are possible after Reset:

  • 16 MHz ---> 2.66 MHz
  • 20 MHz ---> 3.3 MHz

By default, the division factor is 6. It means the CPU is actually running at 3.333 MHz when the OSCCFG fuse is programmed to 20 MHz.

Solution

Use the correct F_CPU

If a slower CPU is not a problem to you, you can simply report the correct CPU frequency to the compiler by change #define F_CPU 20000000UL to #define F_CPU 3333333UL.

Or disable frequency division

Alternatively, you can disable the frequency division and run the CPU at its 20 MHz full speed.

#define F_CPU 20000000UL

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

    /* your code */
}

But don't overclock the CPU

Nevertheless, you should note that 20 MHz operation is only guaranteed by Atmel at 4.5 V and above. If you are running the microcontroller at a lower voltage, such as 3.3 V, you are overclocking the CPU by putting it outside the safe operating area designated by Atmel. See datasheet page 473.

Safe Operating CPU clock vs Voltage Source: Microchip ATTiny804/1604 datasheet, fair use.

Although an overclocked microcontroller will probably work, and in a hobby project, you are unlikely to see any issue. But still, at this point there is no guarantee of stability from the manufacturer. For example, the microcontroller is officially rated at 105°C, but an overclocked microcontroller may start crashing. Increased power consumption is also likely. The worst possible problem could be mysterious malfunction under certain rare conditions. Thus, if reliability and stability is important, you should not overclock the microcontroller.

At 3.3 V, given a 20 MHz system clock, the CPU should only operate at 10 MHz by setting the prescaler to 2x. And at 1.8 V, at 5 MHz with a 4x prescaler.

/* 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);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.