# AVR programming introduction/Simplistic program

In this task we will consider the two basic stages in the AVR software development: building the code and uploading of the resulting binary to the MCU.

## Before you begin

In this task, we will need the following hardware and software facilities:
* either a simplistic device based on ATmega8 (or compatible) or one of the Arduino boards (Uno or Nano);
* a development environment, including:
** GCC and GNU Binutils built for the AVR target;
** the GNU Make build automation tool;
** AVR Libc;
** the Avrdude image loading tool;
** the usual system facilities, such as GNU Bash and a Text editor (GNU nano, Vim, GNU Emacs, or some other);
    note that on Debian (and, presumably, its derivatives) it’s possible to install the AVR-specific tools listed above with a command like: # apt-get install -- avr-libc binutils-avr gcc-avr avrdude

## Blinking a LED
### Reading the code

We will start reading the code above starting with its payload.
* The PORTB ^= ((1 << PB5)); line toggles (changes to high if it was low and vice versa) the PB5 MCU output (D 13 on Arduino Uno.)
* The _delay_ms (2718L); call results in an empty loop for the duration of about 2.718 s. That requires that the F_CPU C preprocessor macro matches the actual MCU frequency used in the circuit.
* Both of the actions above are enclosed in the main loop coded as while (1) { }. Given that the condition in while is always true, the loop will continue indefinitely until the MCU is reset or the power is cut down.
* Now, the DDRB |= ((1 << DDB5)); line above configures the PB5 MCU pin we use as an output. Otherwise, this pin will be left configured as input and the PORTB change above will result in the internal pull-up resistor being connected to and disconnected from the pin. The current through such a resistor, however, is likely to be insufficient to drive the LED connected to the pin.
* The int main lines begin the definition of the “main” function, defined here as returning a value of the int type (a signed integer) and accepting an indefinite number of arguments. The return 0; line, which appears after the “endless” main loop, satisfies the formal requirement for a non-void function to return a value.
** It’s the main function specifically that the run-time C environment passes control to after completing initializations.
** Such a declaration of this function is one of the allowed by the standard.
** The return value of 0 is defined by the standard for main as the code for successful completion.
** The run-time environment actually implemented by GCC and AVR Libc for the AVR target does not pass any meaningful arguments to main and does not interpret the value returned in any way.
* Finally, the #include preprocessor directives at the top of the code request the following headers:

#### avr/io.h

    includes the definitions for the DDRB, DDB5, PORTB, PB5 macros, as used in the code;

#### util/delay.h

    includes both the declaration and definition of the (inline) _delay_ms function also used in this example.

### Building

* Create the blink.c and Makefile files as shown above.
* Build the example with make: $ make avr-gcc -O2 -Wall -std=gnu11 -mmcu=atmega8 -DF_CPU=7372800 ../blink.c -o blink avr-objcopy -O ihex blink blink.hex $

#### NB

    When using an MCU other than ATmega8, or the clock frequency other than 7.3728 MHz, the MCU and F_CPU build parameters are to be set accordingly. In particular, for the Arduino Uno board (as of revision 3), which uses an ATmega328P MCU and a 16 MHz crystal, the Make invocation could be like: $ make MCU=atmega328p F_CPU=16000000
* Check for no errors in the output, and that the blink.hex file is created, containing the image to upload in the Intel hex format.

### Uploading and observing operation

* Connect the device to the development system’s USB port. Check that the respective device file is created – either /dev/ttyUSB1 or similar.
* Check whether the Optiboot bootloader is reachable by downloading the current MCU’s flash memory image into an Intel hex format file, like: $ avrdude -P /dev/ttyUSB1 -c arduino -b 115200 -p atmega8 \ -U flash:r:"$(mktemp --suffix=.hex -- ./XXXX)":i avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e9307 avrdude: reading flash memory: Reading | ################################################## | 100% 1.02s avrdude: writing output file "96TF.hex" avrdude: safemode: Fuses OK avrdude done. Thank you. $

#### NB

    In order to start Optiboot, Avrdude tries to reset the MCU by toggling the RTS and DTR lines of the interface. If these lines are not connected to the Reset MCU pin (on some USB-to-serial adapters these lines aren’t wired at all), the MCU has to be reset manually as follows:
*   * type in the command above but do not start it with ⏎ Enter yet;
*   * press the reset button on the device;
*   * release the button and immediately press ⏎ Enter to start the command.
* Upload the image we got to the MCU flash memory, like: $ avrdude -P /dev/ttyUSB1 -c arduino -b 115200 \ -p atmega8 -U flash:w:blink.hex:i avrdude: AVR device initialized and ready to accept instructions Reading | ################################################## | 100% 0.00s avrdude: Device signature = 0x1e9307 avrdude: NOTE: FLASH memory has been specified, an erase cycle will be performed To disable this feature, specify the -D option. avrdude: erasing chip avrdude: reading input file "blink.hex" avrdude: writing flash (90 bytes): Writing | ################################################## | 100% 0.02s avrdude: 90 bytes of flash written avrdude: verifying flash memory against blink.hex: avrdude: load data flash data from input file blink.hex: avrdude: input file blink.hex contains 90 bytes avrdude: reading on-chip flash data: Reading | ################################################## | 100% 0.01s avrdude: verifying ... avrdude: 90 bytes of flash verified avrdude: safemode: Fuses OK avrdude done. Thank you. $

#### NB

    The note on starting the bootloader above remains valid in this case just as well.
* Check that the operation of the system is as expected by estimating the blinking period and comparing it to the one given in the code.

## Research

* Change the argument to _delay_ms in the code and observe how the behavior of the system changes. Also, could you name where the orignial number possibly comes from? Note that you will need to repeat the building and uploading stages after each change.