AVR microcontroller resources
IN PROGRESS
Detailing open hardware and free software for the use and programming of Atmel's AVR family of microcontrollers and boards, including the ATmega8/128/168 microcontrollers, AVR-HID, Byron , various Atmel USB micros, Arduino/Freeduino//alikes and scrying platforms.
Table of Contents
- 1 overview
- 2 Hardware/software solutions
- 3 generic programming and development environment
- 3.1 In C/C++
- 3.2 In assembly [also notes relevant to C code]
- 3.2.1 compile and linking of assembly to elf
- 3.2.2 elf to hex:
- 3.2.3 disassembly (use this to get linked full assembly!):
- 3.2.4 __exit is an endless loop.
- 3.2.5 memory management: flash/rom and SRAM sections
- 3.2.6 concrete memory explorations (ATmega8)
- 3.2.7 Code to show heap and stack pointers
- 3.2.8 links:
- 3.3 Other languages
- 3.4 alternatives to the Arduino IDE
- 4 Code upload/the programmer
- 5 links
1 overview
- range of possibilities.
- questions of diversity
2 Hardware/software solutions
2.1 AVR family
2.1.1 ATmega8:
2.1.2 ATmega168:
2.1.3 ATmega128:
2.2 Arduino
2.3 Barebone and Arduino-alikes
Of note:
JeeNode: http://news.jeelabs.org/docs/jn4.html
Boardunio: http://www.ladyada.net/make/boarduino/
and see:
2.4 xxxxx-AVR-HID
2.4.1 surface mount (SMD) version
2.4.2 through hole version
2.5 Byron [the board]
Byron is a flexible, low budget open hardware and free software platform for fast, multiple sensor input and control over USB. Byron differs from other solutions in terms of speed, simplicity and low cost.
Using a pre-flashed bootloader, Byron is able to assume new identities, for example functioning one moment as a microcontroller programmer to flash new devices, the next as a straightforward keyboard device. Byron is based on Objective Development's V-USB software.
Please visit: byron for more details.
2.6 scrying
2.7 Alternative platforms
2.7.1 Making use of USB AVRs:
micropendous: http://code.google.com/p/micropendous/
Nanduino: http://www.makestuff.eu/wordpress/?page\_id=569
Benito: http://www.dorkbotpdx.org/wiki/benito
Bumble-b: http://fletchtronics.net/bumble-b
teensy: http://www.pjrc.com/teensy/
3 generic programming and development environment
3.1 In C/C++
3.1.1 Example project code
- Arduino vs straight C
- Arduino code
- Equivalent C code
- Arduino code
3.1.2 Developing using avr-gcc and commandline
3.1.3 toolchain
- avr-gcc and avr-objcopy
Compile:
avr-gcc -g -Os -mmcu=atmega8 -c test.c
Link:
avr-gcc -g -mmcu=atmega8 -o test.elf test.o
Generate .hex (ihex format):
avr-objcopy -j .text -j .data -O ihex test.elf test.hex
- Makefile
To automate compiling and linking of code files. The Makefile can also be used to automate program upload, and disassembly.
- Other tools
3.1.4 Makefile example/s
- 1]
Not sure where this came from but it's a generic Makefile - only need to change microcontroller and programmer if different from specified (here for the Atmega8). It will compile,link all files in the directory and generate the necessary .hex file.
make flash
will also upload the code.
NAME := main HEX := $(NAME).hex OUT := $(NAME).out MAP := $(NAME).map SOURCES := $(wildcard *.c) HEADERS := $(wildcard *.h) OBJECTS := $(patsubst %.c,%.o,$(SOURCES)) MCU := atmega8 MCU_AVRDUDE := m8 CC := avr-gcc OBJCOPY := avr-objcopy SIZE := avr-size -A DOXYGEN := doxygen CFLAGS := -Wall -pedantic -mmcu=$(MCU) -std=c99 -g -Os all: $(HEX) clean: rm -f $(HEX) $(OUT) $(MAP) $(OBJECTS) rm -rf doc/html flash: $(HEX) avrdude -y -c usbasp -p $(MCU_AVRDUDE) -U flash:w:$(HEX) $(HEX): $(OUT) $(OBJCOPY) -R .eeprom -O ihex $< $@ $(OUT): $(OBJECTS) $(CC) $(CFLAGS) -o $@ -Wl,-Map,$(MAP) $^ @echo @$(SIZE) $@ @echo %.o: %.c $(HEADERS) $(CC) $(CFLAGS) -c -o $@ $< %.pp: %.c $(CC) $(CFLAGS) -E -o $@ $< %.ppo: %.c $(CC) $(CFLAGS) -E $< doc: $(HEADERS) $(SOURCES) Doxyfile $(DOXYGEN) Doxyfile .PHONY: all clean flash doc
- 2] A more advanced Makefile with more options and possibility to generate a disassembly of the C code:
See: http://electrons.psychogenic.com/articles/Makefile.tpl
and use:
make disasm
To show assembly code.
3.1.5 using GNU/Emacs as an IDE
M-x compile
executes current/local Makefile
3.1.6 Other
- Use of progmem
To place a static variable (eg. string, set of values) in flash memory, to save SRAM. Within a function definition:
static prog_uchar gps0[] PROGMEM ={0x10,0x7A,0x00,0x01,0x00,0x00,0x00,0x01,0x10,0x03};
read with:
pgm_read_byte(gps0+j);
in this case.
3.2 In assembly [also notes relevant to C code]
3.2.1 compile and linking of assembly to elf
avr-gcc -Os -mmcu=atmega8 -Wa,-gstabs -I/usr/lib/avr/include/avr/ -o test.elf test.S
3.2.2 elf to hex:
avr-objcopy -j .text -j .data -O ihex test.elf test.hex
3.2.3 disassembly (use this to get linked full assembly!):
avr-objdump -S test.elf
(only if we compile with -g // debugging // and not -Os (for size optimisation)??)
avr-gcc -g -mmcu=atmega8 -I/usr/lib/avr/include/avr/ memtest.c -o memtest.elf
also to note:
avr-gcc -g -mmcu=atmega8 -Wl,-Map,demo.map -o demo.elf demo.o
3.2.4 __exit is an endless loop.
26c: ff cf rjmp .-2 ; 0x26c <__stop_program>
3.2.5 memory management: flash/rom and SRAM sections
[for the 128]
- The .text Section
The .text section contains the actual machine instructions which make up your program. Includes:
- The .initN Sections
init code
- The .finiN Sections
exit code
- The .finiN Sections
- The .data Section
This section contains static data which was defined in your code.
- The .bss Section
Uninitialized global or static variables end up in the .bss section. Includes:
- The .noinit Section
- The .noinit Section
- The .eeprom Section
- avr-size
The avr-size program (part of binutils), coming from a Unix background, doesn't account for the .data initialization space added to the .text section, so in order to know how much flash the final program will consume, one needs to add the values for both, .text and .data (but not .bss), while the amount of pre-allocated SRAM is the sum of .data and .bss.
- malloc?
The variables __malloc_heap_start and __malloc_heap_end can be used to restrict the malloc() function to a certain memory region. These variables are statically initialized to point to __heap_start and __heap_end, respectively, where __heap_start is filled in by the linker to point just beyond .bss, and __heap_end is set to 0 which makes malloc() assume the heap is below the stack.
- what is the heap?
The standard RAM layout is to place .data variables first, from the beginning of the internal RAM, followed by .bss. The stack is started from the top of internal RAM, growing downwards. The so-called "heap" available for the dynamic memory allocator will be placed beyond the end of .bss.
- note from scrying makefile:
EXTERNAL_RAM = -Wl,-Tdata=0x801100,–defsym=__heap_end=0x80ffff
and we use memory pointer directly from 1100 - how do we avoid writing over variables (in serialtest.c case).
- test serialtest code in scrying
in new code - also PORTE is set strangely (for gplog to 0x00 , for main log to 0xff)
same in noise2.c where we write to 1100+ and don't set PORTE
possible answer as using:
avr-size noise2.o
we see:
text data bss dec hex filename 8336 4 10 8350 209e noise2.o
how can we see what is in data and bss (-s switch)?
avr-objdump -sh -S noise2.o
gives:
0000 0ad7233c
but in the case of serialtest.o we have 621 bytes of data which is all text messages (for help and so on) which we know doesn't get overwritten???
only conclusion is that data segment is not moved by Makefile (or possibility that as it is stored in ROM/FLASH????)
- perhaps because…
The ld (linker) user manual states that using -Tdata=<x> is equivalent to using –section-start,.data=<x>. However, you have to use –section-start as above because the GCC frontend also sets the -Tdata option for all MCU types where the SRAM doesn't start at 0x800060. Thus, the linker is being faced with two -Tdata options. Starting with binutils 2.16, the linker changed the preference, and picks the "wrong" option in this situation.
From: http://www.nongnu.org/avr-libc/user-manual/malloc.html
So, where does sram start on the atmega128?
At 0x0100 -> 0x10FF so we start at 0x1100
and we shouldn't relocate anything there! (heap is only for malloc)…
3.2.6 concrete memory explorations (ATmega8)
;; x[0]=1; ;; compiles to: 68: 81 e0 ldi r24, 0x01 ; 1 6a: 80 93 60 00 sts 0x0060, r24
The .data segment (where initialized static variables are stored) starts at location 0x60, which is the first address after the register bank on a 2313 processor.
Also:
Direct Addressing Mode : For example the 128 bytes of SRAM in the atmel at90s2313 is all directly accessible for reading and writing you can simply specify the address you wish to store data at and read data from in the instruction . The ram starts at 0x60 ( look up previous tutorials to see why ) so after the 0x60 you can simply read and write using the LDS and STS instructions by simply sepcifying the address which goes something like this ..
LDS R16,0x60 ;move the value at 0x60 to R16 STS 0x60,R16 ;move the value of R16 to 0x60
from: http://www.roboticsindia.com/
Compile: avr-gcc -g -Os -mmcu=atmega8 -c memtest.c
Linking: avr-gcc -g -mmcu=atmega8 -o memtest.elf memtest.o
Map: avr-gcc -g -mmcu=atmega8 -Wl,-Map,memtest.map -o memtest.elf memtest.o
Here we can see:
.data 0x00800060 0x400 load address 0x00000064 0x00800060 PROVIDE (__data_start, .) *(.data) .data 0x00800060 0x0 /usr/lib/gcc/avr/4.3.2/../../../avr/lib/avr4/crtm8.o .data 0x00800060 0x400 memtest.o 0x00800060 x .data 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) .data 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_copy_data.o) .data 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_clear_bss.o) *(.data*) *(.rodata) *(.rodata*) *(.gnu.linkonce.d*) 0x00800460 . = ALIGN (0x2) 0x00800460 _edata = . 0x00800460 PROVIDE (__data_end, .) .bss 0x00800460 0x0 load address 0x00000464 0x00800460 PROVIDE (__bss_start, .) *(.bss) .bss 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/../../../avr/lib/avr4/crtm8.o .bss 0x00800460 0x0 memtest.o .bss 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) .bss 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_copy_data.o) .bss 0x00800460 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_clear_bss.o)
Note data->.bss is 0x0400 = 1024 in decimal = size of array we initialised:
unsigned char x[1024]="1234";
Note also: Because of the Harvard architecture of the AVR devices, you must manually add 0x800000 to the address you pass to the linker as the start of the section. Otherwise, the linker thinks you want to put the .noinit section into the .text section instead of .data/.bss and will complain.
How this map translates into hex format?
Hmm, looking at disassambly using:
avr-objdump -m avr -zxhD memtest.hex
- Examples
- memtest.c
#include <stdlib.h> unsigned char x[128]="1234"; int main(void){ /* unsigned char *x; x = malloc(1024); *x =255;*/ return; }
- memtest.hex
:1000000012C02CC02BC02AC029C028C027C026C0BF :1000100025C024C023C022C021C020C01FC01EC0D4 :100020001DC01CC01BC011241FBECFE5D4E0DEBF25 :10003000CDBF10E0A0E6B0E0E4E6F0E002C005903D :100040000D92A03EB107D9F710E0A0EEB0E001C0DC :100050001D92A03EB107E1F702D002C0D1CF0895B2 :04006000F894FFCF42 :1000640031323334000000000000000000000000C2 :10007400000000000000000000000000000000007C :10008400000000000000000000000000000000006C :10009400000000000000000000000000000000005C :1000A400000000000000000000000000000000004C :1000B400000000000000000000000000000000003C :1000C400000000000000000000000000000000002C :1000D400000000000000000000000000000000001C :00000001FF
See: http://www.scienceprog.com/shelling-the-intel-8-bit-hex-file-format/
10 = byte count 0064 (for example) = address followed by record type (eg. 00) then data and finally checksum (last byte)
notes: 0x01FF is closing record, from 0064(?) we have the 1,2,3,4 in ASCII (disassembled to instructions below) followed by the zeroed memory
why is data starting at 0064 and not 0060?
- memtest.map
snipped!
.text 0x0000005c 0x2 /usr/lib/gcc/avr/4.3.2/../../../avr/lib/avr4/crtm8.o 0x0000005c __vector_1 0x0000005c __vector_12 0x0000005c __bad_interrupt 0x0000005c __vector_6 0x0000005c __vector_3 0x0000005c __vector_11 0x0000005c __vector_13 0x0000005c __vector_17 0x0000005c __vector_7 0x0000005c __vector_5 0x0000005c __vector_4 0x0000005c __vector_9 0x0000005c __vector_2 0x0000005c __vector_15 0x0000005c __vector_8 0x0000005c __vector_14 0x0000005c __vector_10 0x0000005c __vector_16 0x0000005c __vector_18 .text 0x0000005e 0x2 memtest.o 0x0000005e main .text 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) .text 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_copy_data.o) .text 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_clear_bss.o) 0x00000060 . = ALIGN (0x2) *(.text.*) .text.libgcc 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) .text.libgcc 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_copy_data.o) .text.libgcc 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_clear_bss.o) 0x00000060 . = ALIGN (0x2) *(.fini9) .fini9 0x00000060 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) 0x00000060 exit 0x00000060 _exit *(.fini9) *(.fini8) *(.fini8) *(.fini7) *(.fini7) *(.fini6) *(.fini6) *(.fini5) *(.fini5) *(.fini4) *(.fini4) *(.fini3) *(.fini3) *(.fini2) *(.fini2) *(.fini1) *(.fini1) *(.fini0) .fini0 0x00000060 0x4 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) *(.fini0) 0x00000064 _etext = . .data 0x00800060 0x80 load address 0x00000064 0x00800060 PROVIDE (__data_start, .) *(.data) .data 0x00800060 0x0 /usr/lib/gcc/avr/4.3.2/../../../avr/lib/avr4/crtm8.o .data 0x00800060 0x80 memtest.o 0x00800060 x .data 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) .data 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_copy_data.o) .data 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_clear_bss.o) *(.data*) *(.rodata) *(.rodata*) *(.gnu.linkonce.d*) 0x008000e0 . = ALIGN (0x2) 0x008000e0 _edata = . 0x008000e0 PROVIDE (__data_end, .) .bss 0x008000e0 0x0 load address 0x000000e4 0x008000e0 PROVIDE (__bss_start, .) *(.bss) .bss 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/../../../avr/lib/avr4/crtm8.o .bss 0x008000e0 0x0 memtest.o .bss 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_exit.o) .bss 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_copy_data.o) .bss 0x008000e0 0x0 /usr/lib/gcc/avr/4.3.2/avr4/libgcc.a(_clear_bss.o) *(.bss*) *(COMMON) 0x008000e0 PROVIDE (__bss_end, .) 0x00000064 __data_load_start = LOADADDR (.data) 0x000000e4 __data_load_end = (__data_load_start + SIZEOF (.data))
- disassembly from hex using avr-objdump(skipping 00s)
avr-objdump -m avr -sxhD memtest.hex > memtest.disasm
memtest.hex: file format ihex memtest.hex architecture: UNKNOWN!, flags 0x00000000: start address 0x00000000 Sections: Idx Name Size VMA LMA File off Algn 0 .sec1 000000e4 00000000 00000000 00000000 2**0 CONTENTS, ALLOC, LOAD SYMBOL TABLE: no symbols Contents of section .sec1: 0000 12c02cc0 2bc02ac0 29c028c0 27c026c0 ..,.+.*.).(.'.&. 0010 25c024c0 23c022c0 21c020c0 1fc01ec0 %.$.#.".!. ..... 0020 1dc01cc0 1bc01124 1fbecfe5 d4e0debf .......$........ 0030 cdbf10e0 a0e6b0e0 e4e6f0e0 02c00590 ................ 0040 0d92a03e b107d9f7 10e0a0ee b0e001c0 ...>............ 0050 1d92a03e b107e1f7 02d002c0 d1cf0895 ...>............ 0060 f894ffcf 31323334 00000000 00000000 ....1234........ 0070 00000000 00000000 00000000 00000000 ................ 0080 00000000 00000000 00000000 00000000 ................ 0090 00000000 00000000 00000000 00000000 ................ 00a0 00000000 00000000 00000000 00000000 ................ 00b0 00000000 00000000 00000000 00000000 ................ 00c0 00000000 00000000 00000000 00000000 ................ 00d0 00000000 00000000 00000000 00000000 ................ 00e0 00000000 .... Disassembly of section .sec1: 00000000 <.sec1>: 0: 12 c0 rjmp .+36 ; 0x26 2: 2c c0 rjmp .+88 ; 0x5c 4: 2b c0 rjmp .+86 ; 0x5c 6: 2a c0 rjmp .+84 ; 0x5c 8: 29 c0 rjmp .+82 ; 0x5c a: 28 c0 rjmp .+80 ; 0x5c c: 27 c0 rjmp .+78 ; 0x5c e: 26 c0 rjmp .+76 ; 0x5c 10: 25 c0 rjmp .+74 ; 0x5c 12: 24 c0 rjmp .+72 ; 0x5c 14: 23 c0 rjmp .+70 ; 0x5c 16: 22 c0 rjmp .+68 ; 0x5c 18: 21 c0 rjmp .+66 ; 0x5c 1a: 20 c0 rjmp .+64 ; 0x5c 1c: 1f c0 rjmp .+62 ; 0x5c 1e: 1e c0 rjmp .+60 ; 0x5c 20: 1d c0 rjmp .+58 ; 0x5c 22: 1c c0 rjmp .+56 ; 0x5c 24: 1b c0 rjmp .+54 ; 0x5c 26: 11 24 eor r1, r1 28: 1f be out 0x3f, r1 ; 63 2a: cf e5 ldi r28, 0x5F ; 95 2c: d4 e0 ldi r29, 0x04 ; 4 2e: de bf out 0x3e, r29 ; 62 30: cd bf out 0x3d, r28 ; 61 32: 10 e0 ldi r17, 0x00 ; 0 34: a0 e6 ldi r26, 0x60 ; 96 36: b0 e0 ldi r27, 0x00 ; 0 38: e4 e6 ldi r30, 0x64 ; 100 3a: f0 e0 ldi r31, 0x00 ; 0 3c: 02 c0 rjmp .+4 ; 0x42 3e: 05 90 lpm r0, Z+ 40: 0d 92 st X+, r0 42: a0 3e cpi r26, 0xE0 ; 224 44: b1 07 cpc r27, r17 46: d9 f7 brne .-10 ; 0x3e 48: 10 e0 ldi r17, 0x00 ; 0 4a: a0 ee ldi r26, 0xE0 ; 224 4c: b0 e0 ldi r27, 0x00 ; 0 4e: 01 c0 rjmp .+2 ; 0x52 50: 1d 92 st X+, r1 52: a0 3e cpi r26, 0xE0 ; 224 54: b1 07 cpc r27, r17 56: e1 f7 brne .-8 ; 0x50 58: 02 d0 rcall .+4 ; 0x5e 5a: 02 c0 rjmp .+4 ; 0x60 5c: d1 cf rjmp .-94 ; 0x0 5e: 08 95 ret 60: f8 94 cli 62: ff cf rjmp .-2 ; 0x62 64: 31 32 cpi r19, 0x21 ; 33 66: 33 34 cpi r19, 0x43 ; 67 ...
- assembly from elf using:
avr-objdump -h -SD memtest.elf
snipped after data section:
memtest.elf: file format elf32-avr Sections: Idx Name Size VMA LMA File off Algn 0 .text 00000064 00000000 00000000 00000074 2**1 CONTENTS, ALLOC, LOAD, READONLY, CODE 1 .data 00000080 00800060 00000064 000000d8 2**0 CONTENTS, ALLOC, LOAD, DATA 2 .stab 00000858 00000000 00000000 00000158 2**2 CONTENTS, READONLY, DEBUGGING 3 .stabstr 0000044e 00000000 00000000 000009b0 2**0 CONTENTS, READONLY, DEBUGGING Disassembly of section .text: 00000000 <__vectors>: 0: 12 c0 rjmp .+36 ; 0x26 <__ctors_end> 2: 2c c0 rjmp .+88 ; 0x5c <__bad_interrupt> 4: 2b c0 rjmp .+86 ; 0x5c <__bad_interrupt> 6: 2a c0 rjmp .+84 ; 0x5c <__bad_interrupt> 8: 29 c0 rjmp .+82 ; 0x5c <__bad_interrupt> a: 28 c0 rjmp .+80 ; 0x5c <__bad_interrupt> c: 27 c0 rjmp .+78 ; 0x5c <__bad_interrupt> e: 26 c0 rjmp .+76 ; 0x5c <__bad_interrupt> 10: 25 c0 rjmp .+74 ; 0x5c <__bad_interrupt> 12: 24 c0 rjmp .+72 ; 0x5c <__bad_interrupt> 14: 23 c0 rjmp .+70 ; 0x5c <__bad_interrupt> 16: 22 c0 rjmp .+68 ; 0x5c <__bad_interrupt> 18: 21 c0 rjmp .+66 ; 0x5c <__bad_interrupt> 1a: 20 c0 rjmp .+64 ; 0x5c <__bad_interrupt> 1c: 1f c0 rjmp .+62 ; 0x5c <__bad_interrupt> 1e: 1e c0 rjmp .+60 ; 0x5c <__bad_interrupt> 20: 1d c0 rjmp .+58 ; 0x5c <__bad_interrupt> 22: 1c c0 rjmp .+56 ; 0x5c <__bad_interrupt> 24: 1b c0 rjmp .+54 ; 0x5c <__bad_interrupt> 00000026 <__ctors_end>: 26: 11 24 eor r1, r1 28: 1f be out 0x3f, r1 ; 63 2a: cf e5 ldi r28, 0x5F ; 95 2c: d4 e0 ldi r29, 0x04 ; 4 2e: de bf out 0x3e, r29 ; 62 30: cd bf out 0x3d, r28 ; 61 00000032 <__do_copy_data>: 32: 10 e0 ldi r17, 0x00 ; 0 34: a0 e6 ldi r26, 0x60 ; 96 36: b0 e0 ldi r27, 0x00 ; 0 38: e4 e6 ldi r30, 0x64 ; 100 3a: f0 e0 ldi r31, 0x00 ; 0 3c: 02 c0 rjmp .+4 ; 0x42 <.do_copy_data_start> 0000003e <.do_copy_data_loop>: 3e: 05 90 lpm r0, Z+ 40: 0d 92 st X+, r0 00000042 <.do_copy_data_start>: 42: a0 3e cpi r26, 0xE0 ; 224 44: b1 07 cpc r27, r17 46: d9 f7 brne .-10 ; 0x3e <__SP_H__> 00000048 <__do_clear_bss>: 48: 10 e0 ldi r17, 0x00 ; 0 4a: a0 ee ldi r26, 0xE0 ; 224 4c: b0 e0 ldi r27, 0x00 ; 0 4e: 01 c0 rjmp .+2 ; 0x52 <.do_clear_bss_start> 00000050 <.do_clear_bss_loop>: 50: 1d 92 st X+, r1 00000052 <.do_clear_bss_start>: 52: a0 3e cpi r26, 0xE0 ; 224 54: b1 07 cpc r27, r17 56: e1 f7 brne .-8 ; 0x50 <.do_clear_bss_loop> 58: 02 d0 rcall .+4 ; 0x5e <main> 5a: 02 c0 rjmp .+4 ; 0x60 <_exit> 0000005c <__bad_interrupt>: 5c: d1 cf rjmp .-94 ; 0x0 <__heap_end> 0000005e <main>: int main(void){ /* unsigned char *x; x = malloc(1024); *x =255;*/ return; } 5e: 08 95 ret 00000060 <_exit>: 60: f8 94 cli 00000062 <__stop_program>: 62: ff cf rjmp .-2 ; 0x62 <__stop_program> Disassembly of section .data: 00800060 <__data_start>: 800060: 31 32 cpi r19, 0x21 ; 33 800062: 33 34 cpi r19, 0x43 ; 67 ...
- memtest.c
3.2.7 Code to show heap and stack pointers
and available memory
http://www.arduino.cc/playground/Code/AvailableMemory
and showing stack and heap pointers
also: http://forum.pololu.com/viewtopic.php?f=10&t=989#p4218
- using this code:
#define F_CPU 12000000 #include <avr/io.h> #include <avr/interrupt.h> #include <stdio.h> #include <avr/delay.h> #include <stdarg.h> #include <stdlib.h> #include <stdint.h> #define UART_BAUD_RATE 9600 #define UART_BAUD_CALC(UART_BAUD_RATE,F_CPU) ((F_CPU)/((UART_BAUD_RATE)*16l)-1) uint8_t * heapptr, * stackptr; void init_uart(void) { // set baud rate UBRRH = (uint8_t)(UART_BAUD_CALC(UART_BAUD_RATE,F_CPU)>>8); UBRRL = (uint8_t)UART_BAUD_CALC(UART_BAUD_RATE,F_CPU); // Enable receiver and transmitter; enable RX interrupt UCSRB = (1<<RXEN) | (1<<TXEN); //asynchronous 8N1 UCSRC = (1<<URSEL) | (3<<UCSZ0); } static int uart_putchar(char c, FILE *stream); static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE); static int uart_putchar(char c, FILE *stream) { loop_until_bit_is_set(UCSRA, UDRE); UDR = c; return 0; } int availableMemory(void) { int size = 1024; // Use 2048 with ATmega328 unsigned char *buf; while ((buf = (unsigned char *) malloc(--size)) == NULL) ; free(buf); return size; } void check_mem(void) { stackptr = (uint8_t *)malloc(4); // use stackptr temporarily heapptr = stackptr; // save value of heap pointer free(stackptr); // free up the memory again (sets stackptr to 0) stackptr = (uint8_t *)(SP); // save value of stack pointer } int main(void) { unsigned int xx; init_uart(); stdout = &mystdout; while(1) { // xx=availableMemory(); check_mem(); printf("stack %d heap %d\n\r", stackptr, heapptr); // printf("memory island %d\n\r", xx); _delay_us(100); } }
- note: we don't run check_mem and availableMemory at the same time as availableMemory seems to increase heap size despite the free() call.
- avr-size
avr-size memtest2.elf text data bss dec hex filename 3768 40 14 3822 eee memtest2.elf
- so data+bss gives 54 bytes. memory on the ATmega8 starts at 0x60 which is 96 in decimal.
- 96 + 54 = 150
- running the stack and heap code we see that the heap starts at 152 and the stack (which is working down from end of memory) at 1111
- 1111-152=959
- and running the free memory code alone we see that malloc returns maximum of 959 bytes of free memory!
3.2.8 links:
3.3 Other languages
3.3.1 SCHEME
On scrying board, ATmega128 with 512Kb external memory.
3.3.2 Forth
amforth is a forth language implementation for the Atmel AVR family of microcontrollers. http://amforth.sourceforge.net
see also: http://libarynth.org/amforth?s=amforth
3.3.3 Any others?
3.4 alternatives to the Arduino IDE
3.4.1 GNU Emacs, arduino-mode.el and ardmake/arduino-make.sh
Integrating editing code, compiling code and uploading to the Arduino/arduino-a-like.
- arduino-mode.el
- setup
from:
http://github.com/bookest/arduino-mode/blob/09fd1b81880072937881799f6a1cc3431c85002a/arduino-mode.el
Get code:
git clone git://github.com/bookest/arduino-mode.git
Make sure that arduino-mode.el is on the load path and then:
(require 'arduino-mode)
- what it offers/how to use
Loaded as soon as we edit a .pde file.
- integration with ardmake
- what is ardmake?
arduino-make.sh or ardmake is "a command-line Arduino make/build environment". From:
http://arkku.com/misc/arduino\_make.sh
- basic use
1] Install to say /usr/local/bin
2] cd into the project directory with the .pde
3] arduino_make.sh upload to compile/link/upload the sketch
- rough and ready GNU Emacs integration
(defun ard_upload() (interactive) (shell-command "/usr/local/bin/arduino_make.sh upload &" "*arduino*")) ;; C-c k to exit straight from M-x serial-term (defun ser_mon() (interactive) (make-serial-process :port "/dev/ttyUSB0" :speed 9600 :buffer "serial monitor") (switch-to-buffer "serial monitor"))
- setup
4 Code upload/the programmer
4.1 about bootloaders
4.1.1 Bootloaders
USBaspLoader: http://www.obdev.at/products/vusb/usbasploader.html
BootloadHID: http://www.obdev.at/products/vusb/bootloadhid.html
AVRUSBboot: http://www.fischl.de/avrusbboot/
Listing of: http://www.scienceprog.com/usb-bootloaders-for-avr-microcontrollers/
4.2 generic hardware
For our choices of programming hardware we make use of an ISP (in system programming) interface which accesses the to-be-programmed chip on the following pins (ATmega8 and 168):
Pin 22 : GND Pin 19: SCK Pin 18: MISO Pin 17: MOSI Pin 1: RESET
And for the ATmega128 we use PDI/PDO rather than MISO/MOSI as follows:
Pin 22 : GND Pin 11: SCK Pin 3: PDO Pin 2: PDI Pin 20: RESET
4.3 programming the AVR-HID[SMD] or Byron
Both present a standard 10 pin ISP (In System Programming) header. A programmer (see below) is simply attached to the board (in the case of usbasp with a straight 10 pin to 10 pin cable. The left-most of the top right jumpers (vertical) must be closed to allow the board to be programmed!
Pins as follows (with pin 1 as top right of the 10 pins):
1 MOSI 2 +5V 3 LED or n/c 4 GND 5 RESET 6 GND 7 SCK 8 GND 9 MISO 10 GND
4.4 programming the Arduino/arduino-alike using an external programmer
4.5 programmers
4.5.1 AvrUsb500
From Guido Socher: http://tuxgraphics.org/electronics/200510/article05101.shtml
5 pin ISP header as detailed above (for Mega8/168)
4.5.2 BSD-Programmer
See: http://www.bsdhome.com/avrdude/
Attaches to the parallel port and only works on (mostly desktop) machines.
Connect 1K resistors between the parallel port pins and all wires as follows EXCEPT the GND line of the parallel port (18-25) which is connected with straight wire to the AVR's GND pins.
Pins 18-25 (joined) : GND Pin 8: SCK (1K) Pin 10: MISO (1K) Pin 9: MOSI (1K) Pin 7: RESET (1K)
4.5.3 Byron as usbasp programmer:
The Byron in SMD format presents a standard 10 pin ISP (In System Programming) cable for programming all AVR parts (see above). The right-most of the two jumpers (vertical) must be closed to allow programming of low frequency parts (eg. straight from the factory 1MHz) as pictured here. Cable also as pictured:
Using code from: http://www.fischl.de/usbasp to program the ATmega8 on the AVR-HID board.
A new design (bringing out RESET and adding new jumpers) reflects minor changes needed to the (older) board design:
4.6 the software - avrdude
Using avrdude to upload a hex file generated by avr-gcc:
To install:
sudo apt-get install avrdude
To program:
;; attach ISP header/cable to target. ;; apply POWER to target if necessary (from USB header or battery) avrdude -c avrisp2 -p m8 -P /dev/ttyUSB0 -U flash:w:main.hex ;; to use the avrusb500 programmer (on usb serial port ttyUSB0) to ;; program main.hex on the ATmega8 part avrdude -p m8 -c bsd -U flash:w:main.hex ;; for the BSD programmer (with port described in /etc/avrdude.conf) avrdude -p m8 -c usbasp -U flash:w:main.hex ;; for our usbasp programmer
4.6.1 other softwares for programming
ponyprog: http://www.lancos.com/prog.html
4.7 fusebits
Fusebits need to be programmed to make use of external oscillators, brownout detection and other functionalities outlined in the data sheet for the relevant part.
4.7.1 How to find these out
Fuse calculator: http://www.engbedded.com/fusecalc/
Guide: http://electrons.psychogenic.com/modules/arms/art/14/AVRFusesHOWTOGuide.php
- Stock fuses:
4.7.2 How to set these using avrdude
As part of code upload:
avrdude -c usbasp -p m8 -U lfuse:w:0xFF:m -U hfuse:w:0xDF:m -U flash:w:main.hex
Non-interactively:
avrdude -c usbasp -p m8 -U lfuse:w:0xFF:m -U hfuse:w:0xDF:m
Interactively:
avrdude -p m8 -u -c usbasp -t -v -v
To invoke the interactive avrdude session with the appropriate programmer (and also in verbose mode)
w lf 0 0xff
w hf 0 0xdf
To write ff to the low fuse and df to the high fuse
5 links
http://en.wikibooks.org/wiki/Embedded\_Systems/Atmel\_AVR
http://electrons.psychogenic.com/modules/arms/art/3/AVRGCCProgrammingGuide.php
http://code.rancidbacon.com/Arduino
http://code.rancidbacon.com/LearningAboutArduinoAVRUSB
http://www.arduino.cc/en/Hacking/Programmer
http://javiervalcarce.es/wiki/Program\_Arduino\_with\_AVR-GCC
Date: 2010-11-03 12:24:27 GMT
HTML generated by org-mode 6.31trans in emacs 23