Toolchain for ATMega328p

Vineet Maheshwari, 8 July 2015, Gurgaon
Categories: atmega328p
Tags: microcontrollers embedded programming

Toochain for ATmega328p

Programming is best done on Linux workstation. This article shall help user to set the development environment for ATmega328p controller on Ubuntu 14+ machine.

Knowing your tools is the first step towards embarking journey of development. Better the knowledge of tools, easier and faster is the development and troubleshooting. Same holds true for automating scripts and programming.

Open Source

Around 20 years back, when 8051 was one of the popular controllers, it was difficult to get something in free domain,besides the cost of the controller itself. Today it costs lesser and with extensive community support across globe. Thanks to all the volunteers who have created this eco system that helps everyone to get started, if there is a desire.

avr-gcc, originally developed by TODO name of the founder and than team, has enabled working with several 8-bit processors. One can find the latest from their website

Compiler

It helps to process C/C++ language into byte code. It has intermediate steps of preprocessor, assembly. GNU gcc is ported for this processor, known as “avr-gcc”. A typical command line to compile 328p controller would be

avr-gcc -c -g -Wall -O2 -mmcu=atmega328p -D__AVR_ATmega328P__ -DF_CPU=16000000UL -I./include -Wl,-Map,$(PRG).map -o test.o test.c

  • -g flag helps to retain debugging (symbol) information in object file.
  • -D provides preprocessor definitions that might be used inside source code
  • -I helps to add to the search path for include files
  • -W helps to filter or enable warnings level
  • -o names the output file of this command.
  • -O optimization level
  • -c flag creates intermediate output of “object” file, where some of the symbols are not resolved. This happens only at the stage of linking.

Same command can help to generate the final elf file, with small modification.

avr-gcc -g -Wall -O2 -mmcu=atmega328p -D__AVR_ATmega328P__ -DF_CPU=16000000UL -I./include -Wl,-Map,$(PRG).map -o test.elf test1.o test2.o

Debugger

Write about various approaches to debug, one of them being debugger. Options available at processor itself, USART, Hardware LED Indicators. Though there are ICE (in-circuit emulators), Simulators available to experiment and learn controller, they are useful in extreme situations where fault is not traceable due to time it takes to occur, when it is not known where the fault is - hardware or software. They are something that one can do without, most of the time.

Most common way for troubleshooting has been logs across software world. In software that is closer to hardware and has time constraints, things like LEDs are used to give indications of what has happened and where the code has reached. Typically, most difficult faults are debugged by single stepping, easy to do using “gdb” type of programs. In real-time, this is achieved by putting commands that make the firmware stuck in an infinite loop at a point where one wants to checkout system state.

To this single stepping, 328p provides a processor configuration, refer to their datasheet, under fuse bits section. However, it requires, re-flashing the processor and reduces the life of flash because of frequent use.

Considering logs as the most preferred way, there are options available - a. Dump information on a LCD / LED displays b. Dump information on a dumb terminal over USART interface c. Maintain logs internally and dump them in chunks at intervals

Logs are anti-performance mechanism, so there should be switch (compilation time or runtime) to remove them or enable them depending on the need.

One of the tools commonly used for seeing serial communication is minicom

minicom -D/dev/ttyUSB0

device name can be found out by

dmesg | grep USB

TTL to RS232 to USB converter would be required. Same can be achieved by using FTTD converters as well (TTL to USB). This will be additional hardware.

Simulator

Not much has been explored. avr-gcc site does talk about “avr-sim”

Assembler

This is not used in routing software only development. Often in embedded development this is required for optimizing the code which is generated by compiler. Functions which are called often may be investigated for possible saving of feq machine cycles.

Reading assembly code is little complicated. It is difficult primarily because of the way it mixes up language with assembly code. Of course, reading mnemonics of a controllers is no easy. One has to read the .S (generated by assembler) or default output .lst, along with map file. There are multiple sections on which our code and data is mapped. Main amongst them are .text and .data (this is explained well in avr-gcc user manual). Data is where our variables go. There is another area called .bss, which holds uninitialized data.

Developer has option to define addresses and length of various sections, using command line switches.

avr-gcc ... --section-start=.data=0x802200 ...

Notice the leading 0x80 in the address. This differentiates whether the address lies in RAM or flash area. In this case, it is RAM.

Librarian

Librarian tool packages all object files into one, for linking to resolve symbols before producing final elf or executable. “avr-ar” tool is used for the purpose.

Linker

As shared briefly in section above “compiler”, linker is a stage in build process where unresolved symbols are resolved by looking at all the libaries and object files provided in command. It is at this stage, that map file is generated to capture the final addresses of the firmware.

Make

GNU “make” command can be used to automate build process. An example makefile is provided by avr-gcc.

Learn few things about make, instead of just reusing what is on internet.

  • targets. these are the words written at the begnning of a line with “:” as suffix. for example look for “all:”, “txt:”, “%.lst”. %.lst captures all files that have “lst” as suffix.
  • phony targets: which do not exist physically like “all:”
  • dependencies: this is the text that comes after target and “:”.

all: $(PRG).elf lst text eeprom

in this case, all, which is a phony target, is dependent on lst, text and eeprom phony targets again.

  • variables: these are the names to be used across makefile, where value of these are defined in the beginning of makefile. It saves time when these values need to change. for example:

MCU_TARGET = atmega328p

There are other concepts of variables, loops within makefile which make it more powerful.

ObjCopy

here flash is being programmed using .text section of the code

avr-objcopy -j .text -j .data -O ihex test.elf test.hex

for EEPROM, note that different section is being referred here “.eeprom”

avr-objcopy -j .eeprom --change-section-lma .eeprom=0 -O ihex test.elf test_e2prom.hex

Flash Programmer

Write about USB-ASP programming. Mention about other options. What are the ways to do self-programming.

“avrdude” program helps to connect with processor using SPI port interface (MSIO, MOSI, SCK, RESET and VCC + GND). MSIO, MOSI and SCK pins aquire special role when RESET is pulled low. It needs to be supplied intel hex file, generated from compilation + linking + object conversion as given above.

Libraries

This section shall be kept udpated as new libraries are learnt. Currently standard libraries like stdlib are being used. Refer to other articles here to get reusable code patterns.

For further details and understanding of related subjects, refer to avr-gcc website