Inline-Assambler PINC in register speichern

Gast #1467895
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
Gast #1468050
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
Moderator Persönliche Seite #1468065
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.
Moderator Persönliche Seite #1468152
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.
Gast #1468289
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.
Moderator Persönliche Seite #1468332
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.
Gast #1468333
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!!!!
Moderator Persönliche Seite #1468493
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.
Gast #1469701
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.
Gast #1469707
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
}
Gast #1470286
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?
Gast #1472225
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?
Gast #1473425
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren