Forum: Compiler & IDEs Inline-Assambler PINC in register speichern


von Loo (Gast)


Lesenswert?

Hallo,
ich würde gernen in meinem C-Code ein ein Stück Assamblercode einfügen.

Ich will die Bits, die am PINC anliegen in ein Register speichern.
dazu hab ich mir folgendes überlegt:
1
  asm volatile(
2
        "in r16, PINC"
3
  );

aber das klappt nicht.

Kann mir jemand helfen?

Gruß
Loo

: Verschoben durch Moderator
von Loo (Gast)


Lesenswert?

Ok, das hat sich schon erledigt, hab das grad mit dem Zugriff auf SFRs 
gelesen
hab jetzt folgenden Code
1
volatile unsigned char DatenBits[3];
2
volatile unsigned char maskierbyte=0b00100000; //Daten kommen am PC5
3
volatile unsigned char ausblenden;
4
5
6
void datenLesen(){
7
    asm volatile (
8
      "in %[register0], %[PortC]"  "\n\t"
9
      "in %[register1], %[PortC]"  "\n\t"
10
      "in %[register2], %[PortC]"  "\n\t"
11
12
13
      ::[PortC] "M" (_SFR_IO_ADDR (PINC)), [register0] "r" (DatenBits[0]), [register1] "r" (DatenBits[1]), [register2] "r" (DatenBits[2])
14
    );  
15
16
17
}


Aber das kunktioniert nicht...

Ich brauche von PINC nur das Bit 5 also PC5. Daher hab ich oben noch ein 
maskierbyte.

Wenn ich das array DatenBits  auslese, dann stehen da nur Nullen drin, 
obwohl an PC5 Daten ankommen.

Bitte um Hilfe
Gruß
Loo

von Ben (Gast)


Lesenswert?

was ist das für ein controller? atmega? jtag interface abgeschaltet? den 
entsprechenden pin als eingang initialisiert?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Loo schrieb:

> ich würde gernen in meinem C-Code ein ein Stück
> Assamblercode einfügen.

Ist das eine Übung, oder soll das irgendeinen praktischen Nährwert
haben?

Der inline-Assembler vom GCC ist relativ komplex und alles andere
als etwas, was man sich als Anfänger auf die Tagesordnung setzen
sollte.  Er ist insbesondere ein nettes Werkzeug für Bibliotheks-
entwickler, die damit plattformspezifische Funktionalität prima
(und vor allem ohne Einbußen bei der restlichen Optimierungsarbeit
des Compilers) integrieren können, aber er lebt natürlich in der
Ebene, in der der Compiler auch optimiert.  Von daher muss man ein
wenig verstanden haben, wie der Compiler arbeitet, damit man ihn
auch sinnvoll einsetzen kann.

Für deine Aufgabe sehe ich erst einmal nicht, was dich davon abhält,
das alles in C zu schreiben.

von Loo (Gast)


Lesenswert?

das ist ein atmega8.
DDRC ist für PC5 auf Eingang gesetzt, also 0.
was jtag interface bedeutet weiss ich nicht, aber ist vermutlich 
abgeschaltet.

Ist denn der Code soweit OK?


Gruß
Loo

von Loo (Gast)


Lesenswert?

Also ich muss so schnell wie möglich die Daten am PC5 des uC einlesen. 
Am besten mit jedem Takt.

Die Daten kommen von einem Flexray-Chip.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Loo schrieb:
> Also ich muss so schnell wie möglich die Daten am PC5 des uC einlesen.

OK.

> Am besten mit jedem Takt.

Geht nur für eine begrenzte Anzahl, denn in einem Takt lässt sich
nur etwas in ein CPU-Register lesen, mehr nicht.  Für eine
begrenzte Anzahl macht auch der Compiler schon das Richtige:
1
#include <avr/io.h>
2
3
int
4
readit(uint8_t *data)
5
{
6
        uint8_t a, b, c;
7
8
        a = PINC;
9
        b = PINC;
10
        c = PINC;
11
12
        data[0] = a;
13
        data[1] = b;
14
        data[2] = c;
15
}

compiliert zu:
1
readit:
2
/* prologue: function */
3
/* frame size = 0 */
4
        movw r30,r24
5
        in r24,51-32
6
        in r25,51-32
7
        in r18,51-32
8
        st Z,r24
9
        std Z+1,r25
10
        std Z+2,r18
11
/* epilogue start */
12
        ret

Für eine Variable Anzahl von Bytes wirst du es in Assembler kaum
schneller bekommen als der Compiler:
1
#include <avr/io.h>
2
3
int
4
readit(uint8_t *data, uint8_t count)
5
{
6
        do {
7
                *data++ = PINC;
8
        } while (--count != 0);
9
}

ergibt:
1
.global readit
2
        .type   readit, @function
3
readit:
4
/* prologue: function */
5
/* frame size = 0 */
6
        movw r30,r24
7
.L2:
8
        in r24,51-32
9
        st Z+,r24
10
        subi r22,lo8(-(-1))
11
        brne .L2
12
/* epilogue start */
13
        ret

Und was soll das mit der Maske?  Die hast du ja dort noch nicht
benutzt.

von yamamoto (Gast)


Lesenswert?

Die Maske hab ich nicht benutzt. Die barauche ich, um dann die Bitfolge 
die an PC5 reinkommt auf einem Display auszugeben.

das sieht dann so aus:
1
for(int i=0;i<=2)
2
{
3
     ausblenden=maskierbyte&DatenBits[i];
4
5
     SetDisplayCursorTo(i);
6
7
     if(ausblenden=0b00100000){
8
          WriteCharToDisplay('1');
9
     }else{
10
          WriteCharToDisplay('0');
11
     }
12
13
     i++;
14
}

Aber eigentlich Muss ich insgesamt 8 Bit oder 16 Bit direkt hinter 
einander einlesen.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

yamamoto schrieb:

>      if(ausblenden=0b00100000){

Das macht vermutlich nicht das, was du willst, das es tut.

> Aber eigentlich Muss ich insgesamt 8 Bit oder 16 Bit direkt hinter
> einander einlesen.

Aber du suchst nicht etwa ein SPI-Interface?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Wenn's unbedingt inline asm sein soll, dann geht das hier:
1
#include <avr/io.h>
2
3
void
4
readit(uint8_t *result)
5
{
6
        uint8_t data0, data1, data2, data3,
7
                data4, data5, data6, data7;
8
9
        asm volatile("in %[r0], %[pinc]\n"
10
                "in %[r1], %[pinc]\n"
11
                "in %[r3], %[pinc]\n"
12
                "in %[r4], %[pinc]\n"
13
                "in %[r5], %[pinc]\n"
14
                "in %[r6], %[pinc]\n"
15
                "in %[r7], %[pinc]"
16
                : [r0] "=r" (data0),
17
                [r1] "=r" (data1),
18
                [r2] "=r" (data2),
19
                [r3] "=r" (data3),
20
                [r4] "=r" (data4),
21
                [r5] "=r" (data5),
22
                [r6] "=r" (data6),
23
                [r7] "=r" (data7)
24
                : [pinc] "M" (_SFR_IO_ADDR (PINC)));
25
        result[0] = data0;
26
        result[1] = data1;
27
        result[2] = data2;
28
        result[3] = data3;
29
        result[4] = data4;
30
        result[5] = data5;
31
        result[6] = data6;
32
        result[7] = data7;
33
}

Ergibt:
1
readit:
2
/* prologue: function */
3
/* frame size = 0 */
4
        movw r30,r24
5
/* #APP */
6
 ;  9 "foo.c" 1
7
        in r24, 19
8
in r25, 19
9
in r19, 19
10
in r20, 19
11
in r21, 19
12
in r22, 19
13
in r23, 19
14
 ;  0 "" 2
15
/* #NOAPP */
16
        st Z,r24
17
        std Z+1,r25
18
        std Z+2,r18
19
        std Z+3,r19
20
        std Z+4,r20
21
        std Z+5,r21
22
        std Z+6,r22
23
        std Z+7,r23
24
/* epilogue start */
25
        ret

Der Weg über ein lokales Array ist zwar weniger Schreibarbeit, wird
aber vom Compiler nicht wegoptimiert, sodass dann doppelt kopiert
wird.

von yamamoto (Gast)


Lesenswert?

Nein, SPI suche ich nicht.

und eigentlich hab ich in der if das stehen:
1
if(ausblenden==32){
Eigentlich müsste das doch so richtig sein.

Ich sende mit einem anderen Flexray-Chip andauernd Nullen und Einsen auf 
den Bus.
Aber im Display der Empängers stehen nur Nullen.

Jörg, dein Code kann ich leider im moment nicht ausprobieren. Aber mit 
meinem Assamblercode müsste das doch auch klappen?!?

Danke übrigens für die Hilfe!!!!

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

yamamoto schrieb:

>
1
> if(ausblenden==32){
2
>

Du solltest dich mal entscheiden, wann du 0b00100000 und wann 32
schreibst.  Am besten machst du ein #define dafür.

> Eigentlich müsste das doch so richtig sein.

Ich blicke immer noch nicht ganz durch, was denn da ausgeblendet
werden soll, aber das doppelte Gleichheitszeichen ist natürlich
erst einmal richtig.

> Ich sende mit einem anderen Flexray-Chip andauernd Nullen und Einsen auf
> den Bus.

Hat der denn den gleichen Takt wie der AVR, oder wie soll das
funktionieren?

> Aber mit
> meinem Assamblercode müsste das doch auch klappen?!?

Nein, da gibt's einen subtilen Unterschied...

Bei der Benutzung des inline-Assemblers ist es wirklich ratsam, dass
man am Ende nochmal den generierten Assemblercode verifiziert.  Ich
mache das immer, indem ich statt mit -c mit -S compiliere: dann legt
der Compiler eine Datei ${dateiname}.s an, die den Assemblercode
enthält.  All die Disassembler-Listings finde ich nur halb so
übersichtlich.

von Karl H. (kbuchegg)


Lesenswert?

Ich wette, dass die Lösung nicht im Inline Assembler liegt, sondern dass 
das Problem ein ganz banaler C-Fehler ist.
Topp die Wette gilt

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Karl heinz Buchegger schrieb:

> Topp die Wette gilt

Kann sein, dass da auch noch was falsch war, aber ansonsten hast du
die Wette verloren. ;-)

von yamamoto (Gast)


Lesenswert?

>Ich blicke immer noch nicht ganz durch, was denn da ausgeblendet
>werden soll

Ich speichere den ganzen PINC, also alle 8 Bit die da rauskommen. Aber 
ich brauche nur das Bit-Nr.5...
Daher habe ich erstmal das maskierbyte wo alles Nullen sind außer 
Bit-Nr.5.
Dann mache ich eine und-Verknüpfung mit DatenBits. Als Ergebnis lifert 
mir diese Operation alle Bits als Nullen weil eben egal ist ob in 
"DatenBits" ne 1 oder eine 0 steht, denn die & operation liefert dann 
null.
Ausser an der 5.Stelle. Da kommt es darauf an. Wenn da eine eins steht 
ist im "ausblenden=0b00100000=32". Sonst ist da eine Null.


>Hat der denn den gleichen Takt wie der AVR, oder wie soll das
>funktionieren?

Der Sender-Flexray-Chip wird ebenfalls von einem atmega8 gesteuert.
Der arbeitet mit dem Gleichen takt, also 10Mhz.

In dem Sendercode hab ich ebenfalls ein inline-assamblercode eingebaut, 
damit er mit jedem Takt ein Bit auf den Bus sendet.

Es geht mir erstmal darum irgendwie mit jedem Takt daten reinzuholen.

von yamamoto (Gast)


Lesenswert?

Das ist der Sendercode:
1
while(JUMPER3){
2
  asm volatile (
3
    "out %[addrPORTD], %[txen_h_txd_h]"  "\n\t"
4
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
5
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
6
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
7
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
8
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
9
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
10
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
11
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
12
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
13
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
14
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
15
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
16
    "out %[addrPORTD], %[txen_h_txd_h]"
17
    :: [txen_l_txd_h] "r" (txen_l_txd_h), [txen_l_txd_l] "r" (txen_l_txd_l),[txen_h_txd_h] "r" (txen_h_txd_h), [txen_h_txd_l] "r" (txen_h_txd_l), [addrPORTD] "I" (_SFR_IO_ADDR (PORTD))
18
  );
19
}

von Rolf Magnus (Gast)


Lesenswert?

> Der Sender-Flexray-Chip wird ebenfalls von einem atmega8 gesteuert.
> Der arbeitet mit dem Gleichen takt, also 10Mhz.

Hm, wie stellst du eigentlich sicher, daß dein AVR erst dann den Eingang 
sampelt, wenn der Ausgang der Gegenseite einen stabilen Wert angenommen 
hat?

von yamamoto (Gast)


Lesenswert?

>Hm, wie stellst du eigentlich sicher, daß dein AVR erst dann den Eingang
>sampelt, wenn der Ausgang der Gegenseite einen stabilen Wert angenommen
>hat?

Das stell ich gar nicht sicher. Mir geht es erstmal darum überhaupt was 
zu samplen, egal ob das richtig abgetastet wird oder nicht.

Später will ich dann versuchen langsamer zu senden, um zu gucken, ab 
welcher Geschwindigkeit fehler auftreten....

Hat jemand eine Idee wie man das besser machen könnte?

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

yamamoto schrieb:

> Hat jemand eine Idee wie man das besser machen könnte?

. schnellerer Prozessor
. CPLD zum Sampeln benutzen und dann parallel zum AVR ausgeben

von yamamoto (Gast)


Lesenswert?

Ne, geht leider nicht.
Das ist genau der Knackpunkt dieser Aufgabe. Ich muss es irgendwie 
schaffen mit dieser Hardware eine Abtastung vorzunehmen.

Es muss halt nicht mit maximaler Datenrate sein. Ich wollte erstmal mit 
dem obigen Programm grundsätzlich versuchen...

Habt ihr Vorschläge, wie man das im Code realisieren könnte?

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.