www.mikrocontroller.net

Forum: Compiler & IDEs Byte Array shiften


Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich baue gerade ein LED Display mit einer Matrix von 80 x 10 LEDs. Die 
Zeilen werden über 10 Schieberegister per Hardware SPI angesteuert, das 
funktioniert auch schon. Für einen laufenden Text muss ich jetzt die 
Zeilendaten von 80Bit um eine Stelle schieben. Das habe ich auch mit 
inline Assembler hinbekommen:
void
_rol_array(uint8_t *__data)
{
  __asm__ volatile (
        "ld r0,%a0" "\n\t"
    "sec"  "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

        "ld r0,%a0" "\n\t"
    "rol r0" "\n\t"
    "st  %a0+,r0" "\n\t"

       : /* void */
     : "e" (__data)
     : "memory"
       );
}

void
_ror_array(uint8_t *__data)
{
  __asm__ volatile (
    "adiw %0,11" "\n\t"

        "ld r0,-%a0" "\n\t"
    "sec"  "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

        "ld r0,-%a0" "\n\t"
    "ror r0" "\n\t"
    "st  %a0,r0" "\n\t"

       : /* void */
     : "e" (__data)
     : "memory"
       );
}

(Bei Syntaxfehlern stürzt das AVRStudio hier übrigens gerne ab wenn es 
keinen Output vom GCC bekommt.)
Jetzt habe ich noch überlegt das ich eigentlich garnicht soviel schieben 
muß weil ich ja schon ein HW Schieberegister habe. Das SPI kann immer 
nur 8 Bit am Stück ausgeben (ATMega32), oder gibt es einen Trick 1..7 
Bits auszugeben? Wenn nicht mit dem HW-SPI, kann ich dann die 1..7 Bits 
vom letzten Byte 'von Hand' hinterherschieben? Ich meine funkt mir das 
Hardware SPI nicht dazwischen wenn ich den SPI Port manuell setze?

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hrm. Einfach per Software-SPI 1..7 bits rausshiften, und danach erst das 
Hardware-SPI Einschalten und mit ganzen Bytes füttern?

Bzw, für ne Schieberegisterreihe ists warscheinlich andersrum besser:
Per HW-SPI die ganzen Bytes schicken, dann die fehlenden Bits per 
Software-SPI hinterher, danach RCK pulsen.

/Ernst

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
danke, endlich mal jemand der es gelesen hat.
Ich bin erstmal beim Hardware SPI geblieben und schiebe die Daten im 
Inline asm. Da stolpere ich gerade über die kryptische inline Syntax 
(eigentlich ein Grund das doch nicht zu verwenden).
uint8_t* p = &disp[0];
for (r=0; r<DIGITS; r++)
{
   _rol_array(p);
   //p+=11;
}

das funktioniert mit auskommentierter Zeile wenn gcc Optimierung -Os 
ein, wenn Optimierung aus muss der Pointer inkrementiert werden.
Ich habe auch probiert die funktion _rol_array() mit Returnwert zu 
versorgen, aber das klappt auch nicht so recht:
static inline  uint8_t*
_rol_array(uint8_t *__data)
{
  __asm__ volatile (
     "sec"  "\n\t"
     
     "ld __tmp_reg__,%a0"
     "rol __tmp_reg__"
     "st  %a0+,__tmp_reg__"

     "ld __tmp_reg__,%a0"
     "rol __tmp_reg__"
     "st  %a0+,__tmp_reg__"

     :  "=e" (__data)  /* "=&e" geht auch nicht */
     : "e" (__data)
     : "memory"   );

   return __data;
}

der Pointer __data wird in der Funktion durch 'st %a+, r0' manipuliert, 
daher wohl der Unterschiedliche Effekt bei mit/ohne Optimierung. Aber 
auch wenn ich den return Wert verwende wie er hier rauskommt ist der 
nicht richtig. Kann man auf einen Blick sagen das ist def. falsch oder 
ist das eher ein Randbereich des gcc?

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich nehme alles zurück, die letzte Version funktioniert jetzt doch mit 
-Os und -O0, der Aufruf war nach dem vielen probieren nur falsch.
uint8_t* p = &disp[0];
for (r=0; r<DIGITS; r++)
{
     p = _rol_array(p);
}

jetzt weiss der Compiler endlich was er machen soll :-)

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.