www.mikrocontroller.net

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


Autor: Loo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
  asm volatile(
        "in r16, PINC"
  );

aber das klappt nicht.

Kann mir jemand helfen?

Gruß
Loo

: Verschoben durch Moderator
Autor: Loo (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, das hat sich schon erledigt, hab das grad mit dem Zugriff auf SFRs 
gelesen
hab jetzt folgenden Code
volatile unsigned char DatenBits[3];
volatile unsigned char maskierbyte=0b00100000; //Daten kommen am PC5
volatile unsigned char ausblenden;


void datenLesen(){
    asm volatile (
      "in %[register0], %[PortC]"  "\n\t"
      "in %[register1], %[PortC]"  "\n\t"
      "in %[register2], %[PortC]"  "\n\t"


      ::[PortC] "M" (_SFR_IO_ADDR (PINC)), [register0] "r" (DatenBits[0]), [register1] "r" (DatenBits[1]), [register2] "r" (DatenBits[2])
    );  


}


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

Autor: Ben (Gast)
Datum:

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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Loo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Loo (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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:
#include <avr/io.h>

int
readit(uint8_t *data)
{
        uint8_t a, b, c;

        a = PINC;
        b = PINC;
        c = PINC;

        data[0] = a;
        data[1] = b;
        data[2] = c;
}

compiliert zu:
readit:
/* prologue: function */
/* frame size = 0 */
        movw r30,r24
        in r24,51-32
        in r25,51-32
        in r18,51-32
        st Z,r24
        std Z+1,r25
        std Z+2,r18
/* epilogue start */
        ret

Für eine Variable Anzahl von Bytes wirst du es in Assembler kaum
schneller bekommen als der Compiler:
#include <avr/io.h>

int
readit(uint8_t *data, uint8_t count)
{
        do {
                *data++ = PINC;
        } while (--count != 0);
}

ergibt:
.global readit
        .type   readit, @function
readit:
/* prologue: function */
/* frame size = 0 */
        movw r30,r24
.L2:
        in r24,51-32
        st Z+,r24
        subi r22,lo8(-(-1))
        brne .L2
/* epilogue start */
        ret

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

Autor: yamamoto (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
for(int i=0;i<=2)
{
     ausblenden=maskierbyte&DatenBits[i];

     SetDisplayCursorTo(i);

     if(ausblenden=0b00100000){
          WriteCharToDisplay('1');
     }else{
          WriteCharToDisplay('0');
     }

     i++;
}

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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn's unbedingt inline asm sein soll, dann geht das hier:
#include <avr/io.h>

void
readit(uint8_t *result)
{
        uint8_t data0, data1, data2, data3,
                data4, data5, data6, data7;

        asm volatile("in %[r0], %[pinc]\n"
                "in %[r1], %[pinc]\n"
                "in %[r3], %[pinc]\n"
                "in %[r4], %[pinc]\n"
                "in %[r5], %[pinc]\n"
                "in %[r6], %[pinc]\n"
                "in %[r7], %[pinc]"
                : [r0] "=r" (data0),
                [r1] "=r" (data1),
                [r2] "=r" (data2),
                [r3] "=r" (data3),
                [r4] "=r" (data4),
                [r5] "=r" (data5),
                [r6] "=r" (data6),
                [r7] "=r" (data7)
                : [pinc] "M" (_SFR_IO_ADDR (PINC)));
        result[0] = data0;
        result[1] = data1;
        result[2] = data2;
        result[3] = data3;
        result[4] = data4;
        result[5] = data5;
        result[6] = data6;
        result[7] = data7;
}

Ergibt:
readit:
/* prologue: function */
/* frame size = 0 */
        movw r30,r24
/* #APP */
 ;  9 "foo.c" 1
        in r24, 19
in r25, 19
in r19, 19
in r20, 19
in r21, 19
in r22, 19
in r23, 19
 ;  0 "" 2
/* #NOAPP */
        st Z,r24
        std Z+1,r25
        std Z+2,r18
        std Z+3,r19
        std Z+4,r20
        std Z+5,r21
        std Z+6,r22
        std Z+7,r23
/* epilogue start */
        ret

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

Autor: yamamoto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, SPI suche ich nicht.

und eigentlich hab ich in der if das stehen:
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!!!!

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
yamamoto schrieb:

>
> if(ausblenden==32){
> 

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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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. ;-)

Autor: yamamoto (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: yamamoto (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das ist der Sendercode:
while(JUMPER3){
  asm volatile (
    "out %[addrPORTD], %[txen_h_txd_h]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_l]"  "\n\t"
    "out %[addrPORTD], %[txen_l_txd_h]"  "\n\t"
    "out %[addrPORTD], %[txen_h_txd_h]"
    :: [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))
  );
}

Autor: Rolf Magnus (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: yamamoto (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: yamamoto (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.