Minimum Hello Word limit on AVR is 2 bytes

For this week, two articles appeared at once on the hub and one on the blog, where the authors competed in writing the smallest possible LED flashing program for AVR microcontrollers.
In the most recent article, the author proposed a program with a length of only 4 bytes (!)
Well, how can you resist the challenge ?!
And in this article I propose a LED flashing program with a frequency that is noticeable to the eye and is only 2 bytes in size .

2 bytes is the smallest possible program length, since the size of the addressable program memory cell in the AVR microcontrollers is 16 bits or 2 bytes. Thus, the program, or rather one instruction (which can be located at absolutely any address) will occupy one cell of program memory.

But, unfortunately, the program I proposed will not work in all AVR microcontrollers, but only in some models from the Tiny and Mega families.

The secret of the program is that some microcontrollers of the Tiny and Mega families have a remarkable feature that allows you to invert the status of the bits of the registers PORTA, PORTB and PORTD with just one command. The sbi A, b

command implements this interesting feature. The sbi A, b command is used to set the bit of I / O registers that have addresses from 0 to 31.
This binary command looks like this:

1001 1010 AAAA Abbb

The first eight bits of 1001 1010 are operation code is a constant component of the command.
In bits AAAAAThe address of the I / O register is written in the I / O address space. 5 bits are allocated for an address and that is why the command has a limit on addresses (0..31).
In the lower three bits of bbb is the number of the modified bit (0..7).

Now back to the very remarkable feature that allows you to invert the status of the bits of the registers PORTB and PORTD.

Let's look at the ATtiny2313 microcontroller datasheet:

image

This feature is definitely present in the ATtiny2313, ATtiny13, ATtiny24 / 44/84 microcontrollers .
In mega microcontrollers, such a convenient feature is in the ATmega48A / PA / 88A / PA / 168A / PA / 328 / P. But in the ATmega8A / 16A / 32A this feature is missing.
And I can’t say with confidence about the rest of the microcontrollers.
In order to find out if such a function is present in the microcontroller, you can search in the dataset for the phrase Toggling the Pin .

Thus, by writing, for example, the sbi PINB, 0 command, you can invert the zero-bit state of the PORTB register.

And what will it give us?

And this gives us the on / off pull-up resistor in the zero discharge of port B (do not forget that after resetting, all the I / O registers are reset, so ports B and D are configured for input). The resistance of the built-in resistor is 30..50 kOhm. However, even such resistance is enough to light low-consuming blue, red and white LEDs. But the green LEDs will already lack current.
Personally, I use this method of powering LEDs quite often. The red and blue LEDs of sizes 0805 and 0603 light quite tolerably at a supply voltage of 5 V.

That is, in order to light up the LED, it must be turned on between the port pin and the common wire (without an external current-limiting resistor!) And turn on the internal pull-up resistor. In such a switching circuit, an external current-limiting resistor is also saved.

image


So, we learned how to control the LED with one command.
Now, if this command is written to the microcontroller’s program memory, for example, at 0х0000, the microcontroller will work as follows:
The sbi PINB command will be met at the zero address, 0 and after it is executed, the zero bit PORTB will be set to one, the pull-up resistor will turn on and the LED will light up . And then, until the end of program memory, the microcontroller will only encounter 0xFFFF. Such instructions are not known to the microcontroller, so the microcontroller will simply skip them, spending every one clock cycle and increasing the program counter by one.
After the program counter counts to the end of the memory, it will overflow and reset to zero, that is, it will go to the address 0x0000, where the sbi PINB, 0 command will be executed again. After the command is executed, the zero bit of the PORTB will reset to zero, the pull-up resistor will turn off and the LED will turn off.

Now let's calculate how fast the LED will flash. As a microcontroller, we will choose, for example, ATtiny2313. In this microcontroller, program memory is 2048 bytes. Each cell of program memory occupies 2 bytes. The address space of program memory is represented by addresses from 0 to 1023. That is, a total of 1024 addresses. After power-up, the microcontroller will start the program from address 0x0000. When the microcontroller reaches address 1023, then the next measure will reset the software counter. That is, there will be a transition to the address 0x0000.

All commands in our program are executed in one clock cycle. Therefore, the LED will switch to the opposite state once in 1024 cycles. Suppose a microcontroller operates at a frequency of 1 MHz. At this frequency, one clock cycle is 1 μs. Thus, LED switching will occur every 1024 μs. As you know, frequency is the inverse of the period. And the period of one blink is twice the time between switching LEDs 1024 μs * 2 = 2048 μs. Where do we get the blinking frequency of the LED 1 / (2048 μs) = 488 Hz.

Too much happened. The human eye will not notice at such a blinking frequency. To make the blinking frequency noticeable to the eye, you will need to lower the frequency. To do this, you can tack the microcontroller from the clock generator watchdog timer, whose frequency is about 128 kHz. But in reality, the frequency may differ by 3..4 kHz, since the timer is not designed for accurate timing.

128 kHz is 8 times lower than 1 MHz. Therefore, the flashing frequency will be 8 times lower than 488 Hz / 8 = 61 Hz. The same is a lot. Blinking on the eye will not be noticeable.

To further reduce the frequency, you should enable the fuse-bit CKDIV8, which is responsible for dividing the frequency by 8. Then the clock frequency will be 128 kHz / 8 = 16 kHz, and the blinking frequency will decrease by another 8 times and will be 61 Hz / 8 = 7.6 Hz . But such a frequency will already be quite noticeable to the eye.

But be very careful when lowering the frequency to such values!

Remember the important rule: if you program the microcontroller with a serial in-circuit programmer (programming via SPI), then the clock frequency of the microcontroller must be at least 4 times higher than the programming frequency.
That is, at a clock frequency of the microcontroller of 128 kHz, the frequency of the programmer (SPI frequency) should be below

128 kHz / 4 = 32 kHz.

And at a clock frequency of 16 kHz, the programming frequency should be below

16 kHz / 4 = 4 kHz.

Before lowering the clock frequency to 16 kHz, make sure that your serial programmer is capable of programming at a frequency below 4 kHz.
Otherwise, you risk "blocking" the microcontroller!
This limitation does not apply to parallel programmers.


Now let's finally write our program.
We will write the program in a notebook and immediately in machine codes.

We already know what the sbi A, b

1001 1010 AAAA Abbb command looks like. It

remains to substitute the necessary bits.

We will ignite the LED that is connected to the zero discharge of port B. In the microcontroller ATtiny2313, the address is PINB = 0x16. In binary form, 0x16 = 0b10110.
We will change the zero bit, so bbb = 000.

We substitute the bits and get: 1001 1010 1011 0000 or 0x9AB0

Now we will create a HEX file for the firmware of the microcontroller.

The composition of the HEX file is as follows:

image


Our HEX file will consist of two lines: the first line will contain a two-byte instruction 0x9AB0, and the second line will indicate the end of the HEX file.
As the address where our team will be located, we will choose a zero address. Although, you can select absolutely any address from the entire address space.
The checksum is calculated by subtracting all bytes of the string from zero. The low byte of the resulting value is precisely the checksum.
That is, for our case, 0x00 - 0x02 - 0xB0 - 0x9A. The low byte is 0xB4. We enter it at the end of the line.

The last line should indicate the end of the HEX file and should look like this

:: 00000001FF

And you also need to remember that in the HEX file the command bytes are reversed. That is, first write the low byte 0xB0, then the high byte 0x9A.

The final HEX file will look like this::

02000000B09AB4
: 00000001FF We


write the resulting lines into a notepad and save with the extension .hex (however, you can save with any extension).

Now it remains to flash this firmware into the microcontroller, set the clock from the watchdog timer generator and enable division by 8.

Here is an example of setting up fuse-bits in Atmel Studio 6

image


We get the result in the form of a blinking LED. It is checked in iron. Flashing properly.

Thus, the simplest program consists of two bytes, and the simplest circuit consists of a battery, a microcontroller, and an LED.

Does anyone write a flashing LED program even shorter?

Also popular now: