Assembler pur, mit der Arduino IDE
Es gibt mehre Möglichkeiten Assembler in unsere Arduino Programme einzuflechten.
Hier möchte ich eine reine Assembler Lösung präsentieren.
So als Beispiel, wie weit man es mit der Arduino IDE auch in die Assembler Richtung treiben kann
Damit die IDE überhaupt kompiliert, muss mindestens eine *.ino her.
In diesem Fall bleibt sie quasi leer:
/*
* voll leer
*/
In einem zweiten Tab legt man eine *.S Datei.
Ich habe sie hier mal main.S genannt:
#include <avr/io.h>
// die Arduino typische LED an PB5
// UNO, Nano und ProMini (alle ATMega328P)
// bei 16MHz Takt wird mit ca 0,5Hz an PB5 gewackelt
outpin = PB5 // LED_BUILTIN
#define worker r24 // Arbeitsregister
.section .text,"ax",%progbits // https://www.nongnu.org/avr-libc/user-manual/mem_sections.html
.global main // dem Linker bekannt geben
.global TIMER1_OVF_vect // dem Linker bekannt geben
main:
sbi _SFR_IO_ADDR(DDRB), outpin // Set to Output
// timer1 initialisieren
ldi worker, 0 // Normal Mode
sts TCCR1A, worker
ldi worker, (1 << CS12) // Clock/256
sts TCCR1B, worker
ldi worker, (1 << TOIE1) // overflow interrupt enable
sts TIMSK1, worker
sei // global interrupt enable
mainloop: rjmp mainloop // empty main loop
TIMER1_OVF_vect:
sbi _SFR_IO_ADDR(PINB), outpin // toggle
reti
Fertig! Das wars schon.
Auf einen UNO o.ä. gespielt, blinkt es vor sich hin.
Es ist nur einen rudimentäres Beispiel:
-Ein Pin wird zum Output gemacht
-Timer 1 initialisiert
-Es wird in eine Endlosschleife gestürzt
Der Timer1 overflow Interrupt toggelt den Pin.
Der Speicherverbrauch: (damit man auch mal den Erfolg der Show sieht)
:---------------------------------:----------:--------:
| [b]Verfahren[/b] | [b]Flash[/b] | [b]RAM[/b] |
:---------------------------------:----------:--------:
| Diese Assembler Version | 160 Byte | 0 Byte |
| Beispiele/01.Basics/Blink | 976 Byte | 9 Byte |
| Beispiele/01.Basics/BareMinimum | 440 Byte | 9 Byte |
| *.ino nur mit "int main()" | 134 Byte | 0 Byte |
:---------------------------------:----------:--------:
Zum Schluss noch der generierte Code, durch den Disassembler genudelt.
Ein großer Teil besteht aus den Interrupt Vektoren und der C üblichen Stackvorbereitung
c:\temp\arduino_build_499643/AssemblerSchlank.ino.elf: file format elf32-avr
Disassembly of section .text:
00000000 <__vectors>:
0: 0c 94 34 00 jmp 0x68 ; 0x68 <__ctors_end>
4: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
8: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
10: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
14: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
18: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
1c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
20: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
24: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
28: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
2c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
30: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
34: 0c 94 4c 00 jmp 0x98 ; 0x98 <__vector_13>
38: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
3c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
40: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
44: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
48: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
4c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
50: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
54: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
58: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
5c: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
60: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
64: 0c 94 3e 00 jmp 0x7c ; 0x7c <__bad_interrupt>
00000068 <__ctors_end>:
68: 11 24 eor r1, r1
6a: 1f be out 0x3f, r1 ; 63
6c: cf ef ldi r28, 0xFF ; 255
6e: d8 e0 ldi r29, 0x08 ; 8
70: de bf out 0x3e, r29 ; 62
72: cd bf out 0x3d, r28 ; 61
74: 0e 94 40 00 call 0x80 ; 0x80 <main>
78: 0c 94 4e 00 jmp 0x9c ; 0x9c <_exit>
0000007c <__bad_interrupt>:
7c: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>
00000080 <main>:
.global main // dem Linker bekannt geben
.global TIMER1_OVF_vect // dem Linker bekannt geben
main:
sbi _SFR_IO_ADDR(DDRB), outpin // Set to Output
80: 25 9a sbi 0x04, 5 ; 4
// timer1 initialisieren
ldi worker, 0 // Normal Mode
82: 80 e0 ldi r24, 0x00 ; 0
sts TCCR1A, worker
84: 80 93 80 00 sts 0x0080, r24 ; 0x800080 <__TEXT_REGION_LENGTH__+0x7e0080>
ldi worker, (1 << CS12) // Clock/256
88: 84 e0 ldi r24, 0x04 ; 4
sts TCCR1B, worker
8a: 80 93 81 00 sts 0x0081, r24 ; 0x800081 <__TEXT_REGION_LENGTH__+0x7e0081>
ldi worker, (1 << TOIE1) // overflow interrupt enable
8e: 81 e0 ldi r24, 0x01 ; 1
sts TIMSK1, worker
90: 80 93 6f 00 sts 0x006F, r24 ; 0x80006f <__TEXT_REGION_LENGTH__+0x7e006f>
sei // global interrupt enable
94: 78 94 sei
00000096 <mainloop>:
mainloop: rjmp mainloop // empty main loop
96: ff cf rjmp .-2 ; 0x96 <mainloop>
00000098 <__vector_13>:
TIMER1_OVF_vect:
sbi _SFR_IO_ADDR(PINB), outpin // toggle
98: 1d 9a sbi 0x03, 5 ; 3
reti
9a: 18 95 reti
0000009c <_exit>:
9c: f8 94 cli
0000009e <__stop_program>:
9e: ff cf rjmp .-2 ; 0x9e <__stop_program>