Forum: Compiler & IDEs Byte Array shiften


von JojoS (Gast)


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:
1
void
2
_rol_array(uint8_t *__data)
3
{
4
  __asm__ volatile (
5
        "ld r0,%a0" "\n\t"
6
    "sec"  "\n\t"
7
    "rol r0" "\n\t"
8
    "st  %a0+,r0" "\n\t"
9
10
        "ld r0,%a0" "\n\t"
11
    "rol r0" "\n\t"
12
    "st  %a0+,r0" "\n\t"
13
14
        "ld r0,%a0" "\n\t"
15
    "rol r0" "\n\t"
16
    "st  %a0+,r0" "\n\t"
17
18
        "ld r0,%a0" "\n\t"
19
    "rol r0" "\n\t"
20
    "st  %a0+,r0" "\n\t"
21
22
        "ld r0,%a0" "\n\t"
23
    "rol r0" "\n\t"
24
    "st  %a0+,r0" "\n\t"
25
26
        "ld r0,%a0" "\n\t"
27
    "rol r0" "\n\t"
28
    "st  %a0+,r0" "\n\t"
29
30
        "ld r0,%a0" "\n\t"
31
    "rol r0" "\n\t"
32
    "st  %a0+,r0" "\n\t"
33
34
        "ld r0,%a0" "\n\t"
35
    "rol r0" "\n\t"
36
    "st  %a0+,r0" "\n\t"
37
38
        "ld r0,%a0" "\n\t"
39
    "rol r0" "\n\t"
40
    "st  %a0+,r0" "\n\t"
41
42
        "ld r0,%a0" "\n\t"
43
    "rol r0" "\n\t"
44
    "st  %a0+,r0" "\n\t"
45
46
        "ld r0,%a0" "\n\t"
47
    "rol r0" "\n\t"
48
    "st  %a0+,r0" "\n\t"
49
50
       : /* void */
51
     : "e" (__data)
52
     : "memory"
53
       );
54
}
55
56
void
57
_ror_array(uint8_t *__data)
58
{
59
  __asm__ volatile (
60
    "adiw %0,11" "\n\t"
61
62
        "ld r0,-%a0" "\n\t"
63
    "sec"  "\n\t"
64
    "ror r0" "\n\t"
65
    "st  %a0,r0" "\n\t"
66
67
        "ld r0,-%a0" "\n\t"
68
    "ror r0" "\n\t"
69
    "st  %a0,r0" "\n\t"
70
71
        "ld r0,-%a0" "\n\t"
72
    "ror r0" "\n\t"
73
    "st  %a0,r0" "\n\t"
74
75
        "ld r0,-%a0" "\n\t"
76
    "ror r0" "\n\t"
77
    "st  %a0,r0" "\n\t"
78
79
        "ld r0,-%a0" "\n\t"
80
    "ror r0" "\n\t"
81
    "st  %a0,r0" "\n\t"
82
83
        "ld r0,-%a0" "\n\t"
84
    "ror r0" "\n\t"
85
    "st  %a0,r0" "\n\t"
86
87
        "ld r0,-%a0" "\n\t"
88
    "ror r0" "\n\t"
89
    "st  %a0,r0" "\n\t"
90
91
        "ld r0,-%a0" "\n\t"
92
    "ror r0" "\n\t"
93
    "st  %a0,r0" "\n\t"
94
95
        "ld r0,-%a0" "\n\t"
96
    "ror r0" "\n\t"
97
    "st  %a0,r0" "\n\t"
98
99
        "ld r0,-%a0" "\n\t"
100
    "ror r0" "\n\t"
101
    "st  %a0,r0" "\n\t"
102
103
        "ld r0,-%a0" "\n\t"
104
    "ror r0" "\n\t"
105
    "st  %a0,r0" "\n\t"
106
107
       : /* void */
108
     : "e" (__data)
109
     : "memory"
110
       );
111
}

(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?

von Εrnst B. (ernst)


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

von JojoS (Gast)


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).
1
uint8_t* p = &disp[0];
2
for (r=0; r<DIGITS; r++)
3
{
4
   _rol_array(p);
5
   //p+=11;
6
}

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:
1
static inline  uint8_t*
2
_rol_array(uint8_t *__data)
3
{
4
  __asm__ volatile (
5
     "sec"  "\n\t"
6
     
7
     "ld __tmp_reg__,%a0"
8
     "rol __tmp_reg__"
9
     "st  %a0+,__tmp_reg__"
10
11
     "ld __tmp_reg__,%a0"
12
     "rol __tmp_reg__"
13
     "st  %a0+,__tmp_reg__"
14
15
     :  "=e" (__data)  /* "=&e" geht auch nicht */
16
     : "e" (__data)
17
     : "memory"   );
18
19
   return __data;
20
}

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?

von JojoS (Gast)


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.
1
uint8_t* p = &disp[0];
2
for (r=0; r<DIGITS; r++)
3
{
4
     p = _rol_array(p);
5
}

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

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.