Blackpool Computer Club is sponsored by: ThisHosting.Rocks

User Tools

Site Tools


arduino_command_line_assembler

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

arduino_command_line_assembler [2018/08/09 11:15] (current)
admin created
Line 1: Line 1:
 +
 +I wanted a simple assembler example to use with the Uno LED.
 +Here it is, a few lines of code to turn on the LED. No huge makefile, no obscure include files, no magic incantations,​ just a few lines of code. In fact there are more comments than actual code.
 +
 +====Using with avra====
 +
 +AVRA is an assembler for Atmel AVR microcontrollers,​ and it is almost compatible with Atmel’s own assembler AVRASM32. The programming principles and conceptions are based on the ANSI programming language "​C"​.
 +
 +[[http://​avra.sourceforge.net/​README.html]] ​
 +
 +<file asm ledon.S>
 +;;;;   ​assemble with:​- ​   avra ledon.S
 +;;;;   get disassembly with:- avr-objdump -s -m avr5 ledon.S.hex ​
 +;;;;   the output file produced is ledon.S.hex
 +;;;;   ​upload this file to the arduino using avrdude:-
 +;;;;   ​avrdude -p m328p -c Arduino -P /​dev/​ttyACM0 -b 115200 ​ -Uflash:​w:​ledon.S.hex:​i -v -v
 +
 +; Load the binary pattern 11111111 into Register 16               ​
 +LDI    R16,  0b11111111 ​
 +
 +; send all the 1s to the Data direction register at address 0x04
 +; to configures all lines on Portb  as an Outputs ​     ​
 +OUT    0x04, R16              ​
 +
 +
 +; not really needed, already loaded wits 1s.
 +;but later if we put all zeros here the LED would go off 
 +LDI    R16,  0b11111111
 +
 +
 +; Send all the 1s to all lines on port B at address 0x05. 
 +;A 1 takes the line up to 5 volts and lights the LED
 +;A 0 takes the line down to 0 volts and the LED goes off.     
 +OUT    0x05, R16             
 +
 +; If we had an LED connected to each line of port b, they would all light up.
 + 
 +             
 +stop:
 +rjmp stop                    ;don't run on past end of program ​
 +                ​
 +</​file> ​
 +
 +[[Using avr-gcc]]
 +
 +
 +====Intel hex file====
 +
 +Below is the intel hex file [[http://​en.wikipedia.org/​wiki/​Intel_HEX#​Record_types]] ledon.hex produced by typing:- avr-objcopy -O ihex ledon.o ledon.hex
 +ledon.hex is NOT what is sent to the arduino. Avrdude reads this file and extracts the hex bytes (opcodes/​data)to be sent to the arduino.
 +
 +<file asm ledon.hex>​
 +:​0C0000000FEF04B900E005B9000000C0DB
 +:00000001FF
 +</​file>​
 +
 +The colon signals the start of a record.
 +The first 2 digits indicate the number of data bytes, (0C hex) 12 decimal.
 +The next four digits is the address (0000).
 +The next 2 digits is the record type (00) this means it is a data record.
 +The next 24 digits (12 bytes)is the actual data sent to the arduino.
 +The last two digits is a checksum.
 +  ​
 +Data sent to arduino =  0FEF04B900E005B9000000C0
 +
 +====Code does not assemble====
 +
 +It important to note that many code listing for the AVR you are likely to find on the web are often unsuitable for use with avr-gcc and the avr assembler avr-as. Though the avr instruction set is uniform throughout the AVR family, the specific assembly directives used (for instance to include header files and defined constants) in the source available on the web may vary from those used by the binutils AVR assembler, avr-as. To use such source code with avr-as, you'll need to make a number of changes such as:
 +
 +Adding an architecture definition, such as ".arch atmega8"​
 +Changing ".def a=b" and ".equ a=b" lines to "#​define a b"
 +Replacing any .include directives by equivalent #includes
 +And likely more changes we are unaware of...
 +
 +Syntax varies between assemblers, and some '​include'​ files provided by one environment may not be available when using a different environment. All these differences means that there are a lot of assembler examples that will not assemble. ​
 +
 +The first important thing to note is that the syntax and the assembler need to match.
 +In this case, the first comment in the file points out that the assembler in use is avra
 +[[http://​avra.sourceforge.net/​README.html]] avra assembler
 +
 +The next point to notice about the example, is that there are no '​include' ​ (.h) files included.
 +The assembly will fail if the assembler cannot find any .h files referenced in the code, so none are used.
 +
 +The code above is so simple, that you could even get by without the assembler with a bit of patience. ​ Below is what is sent to the programmer, avrdude.
 +This is NOT what is sent to the arduino. This is intel hex format, and the programmer, avrdude, uses the information in this file to determine what to send to the arduino.
 +The 10 bytes between the square brackets on the middle line is what is sent to the arduino. The square brackets are not in the actual file, I have inserted them to highlight the 10 bytes.
 +
 +<file c ledon.s.hex>​
 +:​020000020000FC
 +:​0A000000[0FEF04B90FEF05B9FFCF]B1
 +:00000001FF
 +</​file>​
 +
 +
 +[:][Byte Count][Address][Record Type][Data][Checksum]
 +
 +So, the following line of the hex file can be split like this:
 +
 +[:][0A] [0000] [00] [0FEF04B90FEF05B9FFCF] [B1]
 +
 +Instructions are 16-bits, or 4 hex digits.
 +The RJMP opcode is described in the ATMEGA datasheet as : 1100 kkkk kkkk kkkk
 +0b'​1100 = 0xC
 +So, an instruction that has 0xC as the first digit, implies that it is an RJMP instruction:​
 +
 +The data from the .hex file can be parsed into the following instructions:​
 +0C94
 +4F00
 +0C94
 +4F00
 +1124
 +1FBE
 +CFEF  <--- This is the RJMP 0xFEF instruction. ​ (0xFEF = decimal 4079)
 +D4E0
 +
 +
 +According to the addresses specified in the .hex file, the actual program is only 0x00F8 bytes long.  I'm unsure why we're jumping 4079 bytes, when our program does not exist there.
 +---------------------
 +$ avr-gcc -c file.S
 +$ objcopy -O binary file.o binfile
 +You can make sure it's correct with objdump:
 +
 +$ avr-objdump -d file.o ​
 +file.o: ​    file format pe-i386
 +
 +
 +Disassembly of section .text:
 +
 +00000000 <_f>:
 +   ​0: ​  ​55 ​                     push   %ebp
 +   ​1: ​  89 e5                   ​mov ​   %esp,%ebp
 +   ​3: ​  83 ec 04                sub    $0x4,%esp
 +   ​6: ​  8b 45 08                mov    0x8(%ebp),​%eax
 +   ​9: ​  0f af 45 08             ​imul ​  ​0x8(%ebp),​%eax
 +   ​d: ​  89 45 fc                mov    %eax,​-0x4(%ebp)
 +  10:   8b 45 fc                mov    -0x4(%ebp),​%eax
 +  13:   83 c0 02                add    $0x2,%eax
 +  16:   ​c9 ​                     leave  ​
 +  17:   ​c3 ​                     ret
 +And compare to the binary file:
 +
 +$ avr-hexdump -C binfile ​
 +00000000 ​ 55 89 e5 83 ec 04 8b 45  08 0f af 45 08 89 45 fc  |U......E...E..E.|
 +00000010 ​ 8b 45 fc 83 c0 02 c9 c3                           ​|.E......|
 +00000018
 +
 +--------------------------
 +
 +The point to take away from this example is that makefiles, header files and magic incantations are all designed to make life easier, but if you want to, you can do without them once you understand what is going on.
 + 
 +Ultimately, how you work probably depend on why you are using assembly in the first place. A lot of comments on forums indicate that assembly language programming is pointless, but I believe assembler is a very useful method for understanding the Uno hardware, and what makes the it '​tick'​.
 +
 + 
 +
 +
 +[[http://​www.webring.org/​l/​rd?​ring=avr;​id=76;​url=http%3A%2F%2Felectrons%2Epsychogenic%2Ecom%2Fmodules%2Farms%2Fart%2F3%2FAVRGCCProgrammingGuide%2Ephp]]
 +
 +
 +
 +==Binary==
 +A micro-controller accepts instructions in Binary (base 2) format, zeros or ones is all it will accept. The instructions are presented to the micro-controller as low or high voltages. With low voltage representing zero and high voltage representing one.Binary is ideal as a machine language, but it is very error prone when we try to work with it. Long strings of ones and zeros are hard to comprehend, so hexadecimal (base 16) was introduced.
 +
 +==Instruction set==
 +When a micro-controller is designed, it is given an instruction set, these are the only instructions it will accept. These instructions are just  numbers, and they must be provided to the micro-controller in binary form as previously stated.The micro-controller will work through each instruction,​ carrying out one instruction at a time. If the micro-controller is turned off or reset, it will always restart at the '​beginning'​. The location of the '​beginning'​ is defined by the manufacturer.
 +The manufacturer of a micro-controller will provide a user manual which explains how to use the chosen device. The manual will contain the instruction set.
 +
 + 
 +
 +==Example Instructions in binary and hex==
 +Here is a small sample of instructions in binary and hex which apply to the Atmel atmega328 (Arduino uno) micro-controller. ​
 +
 +
 +send CPU to sleep:
 +Binary=1001.0101.1000.1000 hex=9588
 +
 +Add register R1 to register R0: 
 +Binary=0000.1100.0000.0001 hex=0C01
 +
 +Subtract register R1 from register R0: 
 +Binary=0001.1000.0000.0001 hex=1801
 + 
 +As can be seen from the above, hex is easier to comprehend than binary, ​ but even hex is a bit obscure. If we wanted to give instructions to the micro-controller,​ we would need to look up the hex code for each instruction. It is possible to do this, but to make things a bit easier to remember, mnemonics are used. 
 +
 +Example Instruction mnemonic  ​
 +The add instruction from earlier, ​ hex=0C01 becomes
 +
 +ADD Rt,Rs 
 +much easier to understand.
 + 
 +
 +==The assembler==
 +Finally, the assembler.
 +Remember that the instructions must be given to the micro-controller in binary. ​
 +Now we are writing mnemonics, we need something to turn the mnemonics back into binary, and this is one of the things the assembler does for us. 
 +
 +See this forum post where a new user is struggling with assembler blink code, and is told to insert a magic incantation with no explanation of what it does or why it works.
 +
 +[[http://​www.avrfreaks.net/​forum/​looking-avr-gcc-asm-example-or-tutorial-linux]]
 +
 +
 +
 +In this same thread, one responder suggests that the gnu compiler collection GCC probably isn't the best choice for avr assembly.
 +
 + "​I suggest the asm that goes with GCC (avr-gcc). Then you can link C and asm files, in time. You can also do asm files only and link them together like you can if working with C-files only and the toolchain will link the asm files together and you don't have to bang your head keeping track of address labels using .org statements. Using AvrASM, you can only write 1 big asm file."
 +
 +"This (the belief that gnu-as is designed for machine code generation) has been mentioned, several times, quite recently."​ Or only use it if you are a machine!
 +
 +
 +
 +Using Linux and the avr assembler (avr-as) the code is assembled by typing the following command ​
 + 
 +avr-as blinky.S compiles and uploads, but doesn'​t work as expected
 + 
 +blinky.S being the name of the source file being assembled. I have not specified an output file name, so the default output file is called:
 +a.out  (the a.out file format is elf32-avr)
 + 
 +Assembly source code -  blinky.S
 +
 +click on the blinky.S tab to download the code to your computer, ready to compile and upload. ​
 +
 +<file c blinky.S>​
 +;;;;​blinky.S, ​  ​assemble with    avr-as blinky.S to get a.out
 +
 +.set DDRB,  0x04
 +.set PORTB, ​ 0x05
 +
 +.org 0x0000
 +    rjmp RESET
 +
 +RESET:
 +    ldi R16,0x20
 +    out DDRB,R16
 +
 +    ldi R18,0x00
 +    ldi R17,0x00
 +    ldi R20,0x20
 +Loop:
 +
 +    ldi R19,0xE8
 +aloop:
 +    inc R17
 +    cpi R17,0x00
 +    brne aloop
 +
 +    inc R18
 +    cpi R18,0x00
 +    brne aloop
 +
 +    inc R19
 +    cpi R19,0x00
 +    brne aloop
 +
 +    eor R16,R20
 +    out PORTB, R16
 +    rjmp Loop
 +    ​
 + </​file>​
 +
 +Code Disassembly ​
 +
 +use: avr-objdump -h -S a.out > blinky.dis
 +
 +to get the disassembly into a file called blinky.dis. ​
 +You can open blinky.dis. in a text editor and see the machine code the assembler has produced.
 +this is what it looks like:-
 +
 +a.out: ​    file format elf32-avr  ​
 + 
 +Sections:
 +Idx Name          Size      VMA       ​LMA ​      File off  Algn
 +  0 .text         ​00000026 ​ 00000000 ​ 00000000 ​ 00000034 ​ 2**0
 +                  CONTENTS, ALLOC, LOAD, RELOC, READONLY, CODE
 +  1 .data         ​00000000 ​ 00000000 ​ 00000000 ​ 0000005a ​ 2**0
 +                  CONTENTS, ALLOC, LOAD, DATA
 +  2 .bss          00000000 ​ 00000000 ​ 00000000 ​ 0000005a ​ 2**0
 +                  ALLOC
 +
 +Disassembly of section .text:
 +
 +00000000 <​RESET-0x2>:​
 +   ​0: ​   00 c0           ​rjmp ​   .+0          ; 0x2 <​RESET>​
 +
 +00000002 <​RESET>:​
 +   ​2: ​   00 e2           ​ldi ​   r16, 0x20    ; 32
 +   ​4: ​   04 b9           ​out ​   0x04, r16    ; 4
 +   ​6: ​   20 e0           ​ldi ​   r18, 0x00    ; 0
 +   ​8: ​   10 e0           ​ldi ​   r17, 0x00    ; 0
 +   ​a: ​   40 e2           ​ldi ​   r20, 0x20    ; 32
 +
 +0000000c <​Loop>:​
 +   ​c: ​   38 ee           ​ldi ​   r19, 0xE8    ; 232
 +
 +0000000e <​aloop>:​
 +   ​e: ​   13 95           ​inc ​   r17
 +  10:    10 30           ​cpi ​   r17, 0x00    ; 0
 +  12:    01 f4           ​brne ​   .+0          ; 0x14 <​aloop+0x6>​
 +  14:    23 95           ​inc ​   r18
 +  16:    20 30           ​cpi ​   r18, 0x00    ; 0
 +  18:    01 f4           ​brne ​   .+0          ; 0x1a <​aloop+0xc>​
 +  1a:    33 95           ​inc ​   r19
 +  1c:    30 30           ​cpi ​   r19, 0x00    ; 0
 +  1e:    01 f4           ​brne ​   .+0          ; 0x20 <​aloop+0x12>​
 +  20:    04 27           ​eor ​   r16, r20
 +  22:    05 b9           ​out ​   0x05, r16    ; 5
 +  24:    00 c0           ​rjmp ​   .+0          ; 0x26 <​aloop+0x18>​
 +
 +==Produce Intel hex file==
 +
 +
 +use: avr-objcopy -O ihex a.out aout.hex
 +to produce the intel hex file (aout.hex) that the avrdude programmer will  send to the arduino using:-
 +
 +avrdude -p m328p -c avrisp -P /​dev/​ttyACM0 -b 115200 -D -Uflash:​w:​aout.hex -v -v
 +
 +Check that your arduino com port is correct, ie. /​dev/​ttyACM0 (Linux)
 +
 +on windows, it will look more like this, but check that the arduino is attached to com5 if not insert the correct com port:
 + 
 +avrdude -p m328p -c avrisp -P com5 -b 115200 -D -Uflash:​w:​aout.hex
 +
 +[[http://​www.ladyada.net/​learn/​avr/​avrdude.html]] AVRDUDE options
 +
 +Although 'Yikes invalid device signature'​ is displayed, the upload works and the LED starts blinking.
 +
 +{{:​pasted:​20140921-094532.png}}
 +
 +
 +more about  avr-objcopy
 +
 +Excellent assembler guides found here:-
 +
 +[[https://​sites.google.com/​site/​boisemicromouse/​resources/​using-avrdude-from-the-cmd-line]]
 +[[http://​www.atmel.com/​webdoc/​AVRLibcReferenceManual/​group__demo__project_1demo_ihex.html]]
 +[[http://​www.avr-asm-tutorial.net/​avr_en/​AVR_TUT.html]]
 +[[http://​www.avr-asm-tutorial.net/​avr_en/​beginner/​REGISTER.html]]
 +http://​www.avr-asm-download.de/​beginner_en.pdf
 +
 +assembly code not working check port addresses/​addressing
 +this c code works
 +[[http://​balau82.wordpress.com/​2011/​03/​29/​programming-arduino-uno-in-pure-c/​]]
 +
 +
 +
  
arduino_command_line_assembler.txt · Last modified: 2018/08/09 11:15 by admin