Forum: Mikrocontroller und Digitale Elektronik asm in C einbinden


von Marco G. (arccra)


Lesenswert?

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
extern void servoinit(void);
4
extern void pulsinit(void);
5
6
7
int main(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

von Wilhelm F. (Gast)


Lesenswert?

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.

von Hmm (Gast)


Lesenswert?

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.

von Karol B. (johnpatcher)


Lesenswert?

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

von Markus M. (adrock)


Lesenswert?

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

von Hmm (Gast)


Lesenswert?

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.

von Markus M. (adrock)


Lesenswert?

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

von amateur (Gast)


Lesenswert?

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.

von Ralf G. (ralg)


Lesenswert?

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'... :-)

von Marco G. (arccra)


Lesenswert?

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

von Marco G. (arccra)


Lesenswert?

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
volatile uint8_t servodata[64];
4
extern void servoinit(void);
5
6
7
int main(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

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.