# How To Program Your Micro-Controller This is about using `avr-dude`, `make` and getting a high-level understanding of what's happening under the hood so that you can tune your micro-controller yourself. In practice, you can just read most of what is linked in the **Embedded Programming** class [there](http://academy.cba.mit.edu/classes/embedded_programming/index.html). In fact, you should have done that already. But for those who are overwhelmed, we will try to disect some of the content ## References * [HTMAA's Embedding Programming](http://academy.cba.mit.edu/classes/embedded_programming/index.html) * [Makefiles](https://makefiletutorial.com/) for executing pre-written commands * [avrdude](https://www.ladyada.net/learn/avr/avrdude.html) (by Lady Ada) for programming through a programmer * Existing tutorials for various programmers: * [Sparkfun's avr programmer](https://learn.sparkfun.com/tutorials/pocket-avr-programmer-hookup-guide/al) * [AdaFruit's USBTinyISP](https://learn.adafruit.com/usbtinyisp/avrdude) * [List of AVR IC's and their packages](https://en.wikipedia.org/wiki/ATtiny_microcontroller_comparison_chart) * [ATtiny10](http://www.digikey.com/product-detail/en/ATTINY10-TS8R/ATTINY10-TS8RCT-ND) * [ATtiny45V](http://www.digikey.com/product-detail/en/ATTINY45V-10SU/ATTINY45V-10SU-ND) * [ATtiny44A](http://www.digikey.com/product-detail/en/ATTINY44A-SSU/ATTINY44A-SSU-ND) * [ATtiny814](http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42721C-AVR-ATtiny417-814-816-817-Datasheet_Complete.pdf) * [ATmega328P](http://www.digikey.com/product-detail/en/ATMEGA328P-AU/ATMEGA328P-AU-ND) (same as [Arduino Uno](https://en.wikipedia.org/wiki/Arduino_Uno)), ([datasheet](http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf)) * [ATmega16U2](http://www.digikey.com/product-detail/en/ATMEGA16U2-AU/ATMEGA16U2-AU-ND) (with 16**U** for USB support) * [ATxmega16E5](http://www.digikey.com/product-detail/en/ATXMEGA16E5-AUR/ATXMEGA16E5-AURCT-ND) * [ATxmega16A4U](http://www.digikey.com/product-detail/en/ATXMEGA16A4U-AUR/ATXMEGA16A4U-AURCT-ND) (USB support) ## What are those files? For most base projects of HTMAA, you are provided with a set of different files: * `file.png` are typically images for tracing (trace) or cutting (outline) * `file.c` is a C file that contains a C program, which runs on a micro-controller * `file.make` (or anything ending in `.make`, so here typically `file.c.make` too) is to use the program `make` to call commands that allow you to do things ## What does `XXX` do? First thing first, you should try reading the manual. On Mac / Linux, you can access the manual of a specific command typically by typing ```bash man fancycommand ``` For example, we want to learn about `make`, so let's do that: ```bash man make ``` That should give you an interactive stream that you can go over (down/up arrows) and search through (`/` character, followed by search query). <img src="images/man_make.png" width="800"> To exit that manual, just press `q` (quit). To get some help and figure out how to use the manual functions, press `h` (help). <img src="images/man_help.png" width="400"> Now, we're ready to start looking at those commands. ## What is [Make](https://www.gnu.org/software/make/manual/html_node/Introduction.html#Introduction) References: * [Online make manual](https://www.gnu.org/software/make/manual/make.html) * `man make` Make allows you to automate some commands and simplify what you have to type to program things (though it can be used for programming anything, not just programs). Typically, you'll be using the following pattern: ```bash make targetname ``` where `targetname` is a specific target to execute. Targets are just names, behind which are defined sets of commands to do something. Let's have a look at the basic FTDI echo files: * [hello.ftdi.44.echo.c](http://academy.cba.mit.edu/classes/embedded_programming/hello.ftdi.44.echo.c) - the c program file (i.e. the code to compile and run onto the micro-controller) * [hello.ftdi.44.echo.c.make](http://academy.cba.mit.edu/classes/embedded_programming/hello.ftdi.44.echo.c.make) - the makefile The `.make` file contains the following (in the terminal: `cat hello.ftdi.44.echo.c.make`): ```bash PROJECT=hello.ftdi.44.echo SOURCES=$(PROJECT).c MMCU=attiny44 F_CPU = 20000000 CFLAGS=-mmcu=$(MMCU) -Wall -Os -DF_CPU=$(F_CPU) $(PROJECT).hex: $(PROJECT).out avr-objcopy -O ihex $(PROJECT).out $(PROJECT).c.hex;\ avr-size --mcu=$(MMCU) --format=avr $(PROJECT).out $(PROJECT).out: $(SOURCES) avr-gcc $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES) program-bsd: $(PROJECT).hex avrdude -p t44 -c bsd -U flash:w:$(PROJECT).c.hex program-dasa: $(PROJECT).hex avrdude -p t44 -P /dev/ttyUSB0 -c dasa -U flash:w:$(PROJECT).c.hex program-avrisp2: $(PROJECT).hex avrdude -p t44 -P usb -c avrisp2 -U flash:w:$(PROJECT).c.hex program-avrisp2-fuses: $(PROJECT).hex avrdude -p t44 -P usb -c avrisp2 -U lfuse:w:0x5E:m program-usbtiny: $(PROJECT).hex avrdude -p t44 -P usb -c usbtiny -U flash:w:$(PROJECT).c.hex program-usbtiny-fuses: $(PROJECT).hex avrdude -p t44 -P usb -c usbtiny -U lfuse:w:0x5E:m program-dragon: $(PROJECT).hex avrdude -p t44 -P usb -c dragon_isp -U flash:w:$(PROJECT).c.hex program-ice: $(PROJECT).hex avrdude -p t44 -P usb -c atmelice_isp -U flash:w:$(PROJECT).c.hex program-ice-fuses: $(PROJECT).hex avrdude -p t44 -P usb -c atmelice_isp -U lfuse:w:0x5E:m ``` The **targets** we mentions are all the blocks starting like `targetname:`. When calling for example ```bash make -f hello.ftdi.44.echo.c.make program-usbtiny ``` It ... Wait a second, what's that command? Unfortunately, you cannot just use `make targetname` all the time. It only works when the configuration for make (`.make` file) is actually named `Makefile` and available where you run `make`. Most examples in the class are not named with that single same name because it would create lots of conflicts and there is nothing that associates that file. By naming the file `myprogram.c.make`, we know that the makefile is associated with the program `myprogram.c`, but then we have to specify the `makefile` that makes uses. Here is that argument in the manual: <img src="images/man_make_f.png" width="600"> Back to the command, `make -f hello.ftdi.44.echo.c.make program-usbtiny` ends up running the target `program-usbtiny` in the makefile. ```bash program-usbtiny: $(PROJECT).hex avrdude -p t44 -P usb -c usbtiny -U flash:w:$(PROJECT).c.hex ``` * `program-usbtiny` is the target name (for the argument to `make`) * `$(PROJECT).hex` (on the right of the target, after the `:` separator) is the list of dependencies that needs to be `made` before we can run the actual script below. * `avrdude -p t44 -P usb -c usbtiny -U flash:w:$(PROJECT).c.hex` is the actual command being run * Beware, those lines must start with a tabulation character `\t`, which is not visible but is different from a blank space If we look at the dependency, it's name is actually using a MACRO definition that is available at the top of the make file: ```bash PROJECT=hello.ftdi.44.echo ``` The dependency name is either another *target* or a *file*, i.e. `hello.ftdi.44.echo.hex`. If it's a file and the file is the last version, then it doesn't need to be computed again. The rules are based on the existence of [the file dependencies and their relative timestamps](https://stackoverflow.com/questions/35588153/where-does-make-store-its-cache). What about the target name? There is no explicit matching target name, but there is if we compute the MACROS (i.e. `$(PROJECT).hex:`) And this has another dependency on the `.out` file, which is the object output from compiling the c file. Fortunately, make outputs all the commands it runs, so you can just follow what's written on the terminal. <img src="images/make_hex.png" width="600"> ```bash avr-gcc -mmcu=attiny44 -Wall -Os -DF_CPU=20000000 -I./ -o hello.ftdi.44.echo.out hello.ftdi.44.echo.c avr-objcopy -O ihex hello.ftdi.44.echo.out hello.ftdi.44.echo.c.hex;\ avr-size --mcu=attiny44 --format=avr hello.ftdi.44.echo.out ``` The first command compiled the C file with `avr-gcc`. * `-mmcu=attiny44` because assumes an attiny44 as mcu * `-Wall` enables all **w**arnings * `-Os` optimizes for **s**ize * `-DF_CPU=20000000` defines the MACRO F_CPU and sets it to `20000000` (20MHz) * `-I./` adds the current directory to search for included files (`#include "file"`) * `-o hello.ftdi.44.echo.out` specifies the output name * `hello.ftdi.44.echo.c` is the input file Then the second command creates a `hex` file from the program output. See [.hex vs .out](https://electronics.stackexchange.com/questions/417648/whats-the-difference-between-a-generated-hex-file-and-a-binary-file-in-embedded) for the difference. TL;DR hex files are easy to read and used for not only programming but also checking that the programming went well, whereas out files are binary codes to be transferred to the memory for execution. The last command computes information about the size that the program is going to take. This is important if you are creating your own program, because you need to make sure it will fit in memory. ## AVRDUDE! `avrdude` is a tool that allows us to send programs onto avr chips through a programmer interface such as the usbtiny (e.g., [FabTinyISP](http://fab.cba.mit.edu/classes/863.16/doc/projects/ftsmin/index.html)), or an [Atmel ICE](https://www.microchip.com/DevelopmentTools/ProductDetails/ATATMEL-ICE). Here, the manual of `avrdude` is quite large, so instead, let's start by reading the help summary, which you can typically get by running the command with the argument `-h` or `--help`: <img src="images/avrdude_h.png" width="600"> * `-p device` specify the type of device to program (in our case, it's an ATTiny44) * `-P port` selects the port for programming (typically `usb`) * `-c programmer` selects the programmer (e.g. `usbtiny`) * `-U ...` requests a memory update (this is the actual action we're doing with avrdude) ```bash avrdude -p t44 -P usb -c usbtiny -U flash:w:hello.ftdi.44.echo.c.hex ``` How did we know the device label was `t44`? Well, the manual tells you that you can just query for the available names / devices with `avrdude -p ?`, which gives you a long list. <img src="images/avrdude_p.png" height="400"> You can do the same to find the list of available programmers (and you'll find `usbtiny`). Finally, the real deal - the memory programming through `-U`. There are different actions: `-e` erases memory, likely not what you want, and `-U` updates the memory. ## `avrdude -U ...` The format of the argument is (according to the help): ```bash avrdude -U <memtype>:r|w|v:<filename>[:format] ``` The manual is slightly more verbose and tells us what's available for the memory types, formats and operations: <img src="images/avrdude_u.png" width="600"> In our case, `program-usbtiny` uses the following update command: ```bash -U flash:w:hello.ftdi.44.echo.c.hex ``` which means: * Updating the `flash` memory * **W**riting to it (not **r**eading nor **v**erifying) * Using the hex file `hello.ftdi.44.echo.c.hex` that got generated Why the `flash` memory? You should read this [memory part](https://en.wikibooks.org/wiki/Embedded_Systems/Atmel_AVR#Memory) of the Embedded Systems from Wikibooks. And you will definitely need to read the *datasheet* of your target micro-controller. As a summary, there are different types of memory available. For the simple AVR systems, there are: * **data** memory, I/O registers and SRAM - those are dynamic, changing during execution, and vanishing upon shutdown (aka *volatile* memory) * **flash** program memory - this is where your program goes * **[EEPFROM](https://en.wikipedia.org/wiki/EEPROM)** aka Electrically Eraseable Programmable Read-Only Memory, which allows you to store data that survives a restart / shutdown * **fuses** are special types of memory that cannot be modified by the program and must be programmed separately For interested readers: * [flash vs eeprom](https://electronics.stackexchange.com/questions/69234/what-is-the-difference-between-flash-memory-and-eeprom/69275) ### avrdude and fuses Fuses are specific bits of the memory that specify low-level configurations. Thoses have to be programmed separately from the main program memory. In our previous example with the ATTiny44, the fuse programming was done with the `program-usbtiny-fuses` target: ```bash program-usbtiny-fuses: $(PROJECT).hex avrdude -p t44 -P usb -c usbtiny -U lfuse:w:0x5E:m ``` Here, the `-U` command targets the **low** bits of the fuse memory for the ATTiny44. The actual value is specified as a hex number: `0x5E`. ### Hexadecimal Numbers Hex numbers are numbers in hexadecimal base (16) and are typically prefixed with `0x`. The symbols are: | Decimal | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | | ------- | - | - | - | - | - | - | - | - | - | - | -- | -- | -- | -- | -- | -- | | Hexa | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | A | B | C | D | E | F | | Bin | 0000 | 0001 | 0010 | 0011 | 0100 | 0101 | 0110 | 0111 | 1000 | 1001 | 1010 | 1011 | 1100 | 1101 | 1110 | 1111 | Looking at the individual bits (in groups of 4 since `2^4 = 16`) is typically the main reason for hexadecimal.