Hallo zusammen,
ich habe ein paar Fragen in Bezug auf die Einbindung von Assembler in
ein c Programm. Ich benutze das Atmel Studio 6 und programmiere einen
ATMega32U4. Hier die, zum besserem Verständnis, gekürzen Programme:
c-Programm:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
externvoidservoinit(void);
4
externvoidpulsinit(void);
5
6
7
intmain(void)
8
{
9
10
servoinit();
11
12
{
13
14
}
15
}
16
17
18
ISR(TIMER0_OVF_vect)
19
{
20
pulsinit();
21
}
asm-Programm:
1
#define _SFR_ASM_COMPAT1
2
#define __SFR_OFFSET 0
3
#include <avr/io.h>
4
5
6
.data
7
servodata: .BYTE 64
8
9
.text
10
11
.global servoinit, pulsinit
12
13
14
servoinit:
15
16
// asm code
17
18
ret
19
20
21
pulsinit:
22
23
// asm code
24
25
ret
Nun meine Fragen dazu:
1. Da ich bis jetzt hauptsächlich asm programmiert habe, bin ich es
gewohnt den Stackpointer einzurichten. Brauche ich dies nun nicht mehr
zu machen? Bzw. wie kann ich diesen einrichten?
2. pulsinit: wird durch einen timer Interrupt aufgerufen. Kann ich dies
irgendwie direkt tun oder muss ich hier wirklich den Umweg über eine
Funktion machen?
3. Stimmt bei pulsinit: der Rücksprung Befeht ret oder müsste ich hier
reti hinschreiben? Beides funktioniert bei meinem Programm.
4. Ich adressiere den Anfang von 64 Bytes im SRAM, wie kann ich sicher
gehen dass, wenn ich z.B. weiteren c Code einfüge, diese nicht
überschrieben werden?
5. Wie kann ich eines der 64 SRAM Daten direkt aus c beschreiben (z.B.
Byte 30)? Oder muss ich hier den umweg über eine asm Funktion gehen?
Das sind viele Fragen aber ich hoffe einige können gelöst werde können.
Leider habe ich dazu nicht sehr viel im Internet gefunden oder einfach
falsch gesucht. Über Lektüre über dieses Thema würde ich mich freuen.
Grüße, Marco
Du mußt genau das Manual zum Compiler lesen, da steht es drin, wie man
ASM einbindet, und auch die Übergabemodalitäten.
Zugegeben, es ist manchmal schräg und umständlich beschrieben, und man
findet und versteht nicht alles sofort.
So geht es mir manchmal, z.B. beim SDCC.
Du solltest vielleicht erstmal ein wenig von Deinem Erfahrungsstand
berichten.
So als Anhaltswert:
Alles weniger als ein zwei Jahre C und zwei Jahre Assembler deutet auf
einen Konzeptionsfehler.
Lange Assembler und wenig C Erfahrung bedeutet notwendige Skepsis bei
Vorhaben die mit "in Assembler geht das besser" begründet sind.
Guck Dir mal C-Compiler Dokumentationen (am besten wohl GNUC) an wie die
Funktionen und Aufrufe in Assembler umsetzen.
Hmm schrieb:> Alles weniger als ein zwei Jahre C und zwei Jahre Assembler deutet auf> einen Konzeptionsfehler.
Naja, das ist schon eine sehr monotone Betrachtung.
Marco G. schrieb:> Leider habe ich dazu nicht sehr viel im Internet gefunden oder einfach> falsch gesucht. Über Lektüre über dieses Thema würde ich mich freuen.
Den Wiki-Artikel ([1]) sowie die dortigen Referenzen kennst du bzw. hast
du schon gelesen?
[1]:
https://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Assembler_und_Inline-Assembler
Hi,
wenn Du danach googelst findest Du die Informationen inkl. Beispiele.
Die ersten 4 Treffer sollten Dir alles an Infos geben:
https://www.google.de/search?q=avr+mixing+c+assembler
Die ISR würde ich direkt auf das Assemblerporgamm zeigen lassen, ohne
den Umweg über C. Gerade in ISRs kann sich das lohnen.
Die Parameter werden in den Register R24 abwärts übergeben, die Rückgabe
der Funktion wird in R24 erwartet. R1 ist immer 0x00. R0 ist scratch.
R18-R27 und R30/R31 musst Du in Deinem Assemblerporgamm sichern sofern
Du sie veränderst. Das gilt natürlich nicht für die ISR die direkt
angesprungen wird, dort musst Du das Statusregister und ALLE Register
sichern die Du veränderst.
Um den Stack musst Du Dich nicht kümmern.
Im Studio 6 legst Du das ganze als AVR C Projekt an. Die Assembler-Files
bekommen dann ein .s als Endung und somit weiss Studio dann das es dort
den Assembler aufrufen muss.
Grüße
Markus
Karol Babioch schrieb:> Hmm schrieb:>> Alles weniger als ein zwei Jahre C und zwei Jahre Assembler deutet auf>> einen Konzeptionsfehler.>> Naja, das ist schon eine sehr monotone Betrachtung.
Durchaus nicht. Nimmt man etwa die Prämisse hinzu das der TO schon die
genannt Erfahrung hat, dann bleibt die Folgerung nicht bestehen, das es
sich um einen Konzeptionsfehler handelt. Es handelt sich als nicht um
eine monotone Folgerung resp. Betrachtung.
Siehe Wikipedia: http://de.wikipedia.org/wiki/Monotonie_%28Logik%29
Andere Deutungen von "Monotonie" kommen hier sicher nicht in Betracht.
Aber Dein Link ist durchaus wertvoll.
Achso:
3: RETI ist richtig
4: Der Linker sortiert das schon alles richtig, das nichts überschrieben
wird
5: Du müsstest das servodata m.E. ebenfalls als global definieren und
dann in C ein "extern uint8_t servodata[];" definieren, dann solltest Du
darauf zurgeifen können.
Grüße
Markus
Im Studio 4 brauchtest Du nur die Hilfe anklicken und in der
Bibliotheksbeschreibung zum C-Compiler blättern.
Da wurde sogar ein Beispiel mitgeliefert und in den FAQ die Standards,
die beim Verwenden der Register (rübber und nübber) gelten, beschrieben.
Keine Ahnung wo Du das jetzt findest, aber ich glaube nicht, dass das
Ersatzlos gestrichen wurde.
Markus M. schrieb:> Die ISR würde ich direkt auf das Assemblerporgamm zeigen lassen, ohne> den Umweg über C. Gerade in ISRs kann sich das lohnen.
Ich kann mir nicht vorstellen, dass es einen Fall gibt, wo man das
nicht so machen sollte: Da die C-ISR die verwendeten Register nicht
kennt, wird alles gesichert/ wieder hergestellt, was (nach den Regeln)
in Unterprogrammen geändert werden könnte. Dafür die ISR als 'nackig' zu
deklarieren, finde ich nicht so gut. Da hat man zwei Baustellen. Und
außerdem: Warum Assembler? Damit's schnell und kurz ist? Also dann ohne
'c-Ummantelung'... :-)
Hallo zusammen,
vielen Dank für eure Hilfe, bis auf die direkte Beschreibung des SRAMs
habe ich alles hin bekommen. Danke an Markus M. für den Tipp mit der
globalen Variable. Da werde ich mich mal weiter schlau machen.
Was mir besonders aufgefallen ist, war der extreme
Geschwindigkeitsanstieg durch das direkte aufrufen des timer Interrupts.
Die im Interrupt benutzen Register werden natürlich vorab gesichert:
push r16
push r17
push XL
push XH
push ZL
push ZH
in tmp, SREG
push tmp
...und dem entsprechend am Ende auch wieder hergestellt.
Der timer Interrupt ist dazu da, bei einem Hexapod die Servos über 4
Schieberegister zu steuern. Der Code hierzu ist nicht kurz und deswegen
wollte ich kein inline Assembler benutzen.
Grüße, Arcanix
Hallo zusammen,
auch die letzte Hürde ist geschafft. Es sieht nun so aus und
funktioniert perfekt:
1
#include<avr/io.h>
2
#include<avr/interrupt.h>
3
volatileuint8_tservodata[64];
4
externvoidservoinit(void);
5
6
7
intmain(void)
8
{
9
10
servoinit();
11
12
{
13
servodata[30]=20;
14
}
15
}
1
#define _SFR_ASM_COMPAT1
2
#define __SFR_OFFSET 0
3
#include <avr/io.h>
4
5
6
.extern servodata
7
8
.text
9
10
.global servoinit, TIMER0_OVF_vect
11
12
13
servoinit:
14
15
// asm code
16
17
ret
18
19
20
TIMER0_OVF_vect:
21
22
// asm code
23
24
reti
Nicht zu vergessen dass dies nur ein Ausschnitt des Programmes ist und
hier z.B. noch das Einrichten des Interrupts und einiges mehr fehlt.
Vielen Dank nochmals.
Grüße, Marco