Forum: Mikrocontroller und Digitale Elektronik Bits spiegeln in Hardware oder in Software?


von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Hallo zusammen,

folgendes Problem: ich designe grad ein kleines Platinchen, welches 
(u.a.) einen ATmega328 und ein Display haben soll. Fürs Display brauch 
ich ein komplettes Byte (8 bits, D0..D7) da bietet sich Port D an. Die 8 
bits liegen sowohl am Display als auch am AVR recht nett nebeneinander. 
Da ich aber das Display aus Platzgründen auf der Lötseite montieren 
will, sind die bits genau verdreht (gespiegelt) also PD0->D7, PD1->D6 
usw.

Nun hab ich zwei Möglichkeiten: Layout einfach halten, und die Bits in 
Software spiegeln, oder Schaltplan und Software "sauber" halten, dafür 
ein kleiner Alptraum beim layouten (wird einseitig).

Da es ein grafisches Display ist, wird da das Spiegeln eh nicht so 
tragisch, da sowieso eine Menge Bit-Schubserei damit verbunden ist. Mehr 
Sorgen machen mir diverse Kommando-Sequenzen, hier muss auf jeden Fall 
gespiegelt werden. Allerdings sind das wieder z.T. hart codierte 
Kommandos, da könnte ich das Spiegeln ja dem Präprozessor umhängen.

Frage 1: welche Variante würdet ihr empfehlen?

Frage 2: wie spiegelt man effizient am AVR (in C!)

Frage 3: wie spiegelt man im Präprozessor?


Danke, Michi

von spess53 (Gast)


Lesenswert?

Hi

>Frage 2: wie spiegelt man effizient am AVR (in C!)

Beitrag "Re: LCD Datenleitungen invertieren"

MfG Spess

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

spess53 schrieb:
> Hi
>
>>Frage 2: wie spiegelt man effizient am AVR (in C!)
>
> Beitrag "Re: LCD Datenleitungen invertieren"
>
> MfG Spess

S U P E R ! Danke! (nach "invertieren" hab ich natürlich nicht 
gesucht...)

von Peter S. (psavr)


Lesenswert?

>dafür ein kleiner Alptraum beim layouten (wird einseitig).
Wenn Dir das schon Albträme bereitet, dann solltest Du Deinen 
Beruf/Hobby wechseln!

Das einzige Richtige: Schliesse das Teil richtig an!

-Display oder uC auf die andere LPL-Seite?
-Anderen uC Port benutzen mit passender Pin folge?
-Signale von "innen" bzw. von der anderen Seite auf das Display führen?
-Drähte (schlimmstenfalls)

von Volker (Gast)


Lesenswert?

> Das einzige Richtige: Schliesse das Teil richtig an!

Was für ein Blech Du da redest...

Schon mal was von Effizienz gehört? Meinst Du, das Display ginge kaputt, 
wenn man die Datenleitungen anders anschliesst? Du bist wahrscheinlich 
auch jemand, der ein RAM "richtig" anschliesst: d0-d7 an d0-d7 und 
a0-a... an a...

Wahrscheinlich müsste seine Platine größer werden, um das einseitige(!) 
Layout fassen zu können. Aber Hauptsache, das Display ist richtig 
angeschlossen... Kopfschüttel

Volker

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Eine Frage noch zur mirror() Funktion vom Peter:
1
unsigned char mirror( unsigned char n )
2
{
3
  n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa); 
4
  n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc); 
5
  n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0); 
6
  return n;
7
}

gibts einen Trick die Funktion in ein Preprozessor-Makro zu wandlen, 
damit der Preprozessor bei Aufruf mit konstanten Werten gleich das 
Ergebnis errechnet?

von oszi40 (Gast)


Lesenswert?

Michael Reinelt schrieb:
> konstanten Werten

Tabelle?
Nebenbei wäre noch das zeitliche Verhalten zu beleuchten.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Michael Reinelt schrieb:

> gibts einen Trick die Funktion in ein Preprozessor-Makro zu wandlen,
> damit der Preprozessor bei Aufruf mit konstanten Werten gleich das
> Ergebnis errechnet?
1
#define mirror(bits) __builtin_avr_insert_bits (0x01234567, bits, 0)

http://gcc.gnu.org/onlinedocs/gcc-4.7.2/gcc/AVR-Built_002din-Functions.html#AVR-Built_002din-Functions

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Johann L. schrieb:

>
1
#define mirror(bits) __builtin_avr_insert_bits (0x01234567, bits,
2
> 0)

ich bin sprachlos....

da musste ich doch sofort mal ein testprogramm mit drei varianten 
machen:

V1:
1
uint8_t mirror1( uint8_t n )
2
{
3
  n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa); 
4
  n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc); 
5
  n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0); 
6
  return n;
7
}
wird zu
1
  mov r18,r24
2
  ldi r19,0
3
  lsl r18
4
  rol r19
5
  andi r18,170
6
  lsr r24
7
  andi r24,lo8(85)
8
  or r24,r18
9
  mov r18,r24
10
  ldi r19,0
11
  lsl r18
12
  rol r19
13
  lsl r18
14
  rol r19
15
  andi r18,204
16
  lsr r24
17
  lsr r24
18
  andi r24,lo8(51)
19
  or r24,r18
20
  swap r24
21
  ret

V2:
1
uint8_t mirror2( uint8_t n )
2
{
3
    return __builtin_avr_insert_bits (0x01234567, n, 0);
4
}
wird zu
1
  lsl r24
2
  adc r24,__zero_reg__
3
  mov __tmp_reg__,r24
4
  bst r0,1
5
  bld r24,7
6
  bst r0,2
7
  bld r24,6
8
  bst r0,3
9
  bld r24,5
10
  bst r0,5
11
  bld r24,3
12
  bst r0,6
13
  bld r24,2
14
  bst r0,7
15
  bld r24,1
16
  ret

Und der test mit konstantem Wert:
1
uint8_t mirror3 (void)
2
{
3
    return __builtin_avr_insert_bits (0x01234567, 0x12, 0);
4
}
wird zu
1
  ldi r24,lo8(72)
2
  ret

Sieht doch gut aus, oder?

von Peter S. (psavr)


Lesenswert?

@Volker
>Was für ein Blech Du da redest...
>Wahrscheinlich müsste seine Platine größer werden, um das einseitige(!)
Ich denke wenn man etwas Hirnschmalz investiert, würde die Platine weder 
teurer noch grösser!

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Frage 1: welche Variante würdet ihr empfehlen?

Die Standardvariante, keinen Spiegel. Lohnt sich nicht bei 8 Leitungen. 
Du kannst keine Standard Lib benutzen und das umdrehen eines Bytes 
braucht 8x so viele Takte wie das einfache senden.

Das noch bei einem Grafik Display wo große Datenmengen geschubst werden.

Da blickt man auch nicht mehr durch irgendwann (schätze so ca. nach 3 
Tagen). 8 bedrahtete null Ohm Widerstände lösen das Problem besser.

von ... (Gast)


Lesenswert?

Meine Meinung:

- bei doppelseitiger Platine mit Durchkontaktierungen: richtig 
anschließen und enstprechend routen

- bei einseitiger Platine: einfach in Software die Bits vertauschen, bei 
der LCD Ansteuerung ist doch die Geschwindigkeit egal

von Peter D. (peda)


Lesenswert?

Alle Konstanten, also auch Zeichensatztabellen kann man schon zur 
Compilezeit durch das Macro jagen.
Da kostet das Spiegeln also keine zusätzliche Laufzeit.

Peter

von Der Rächer der Transistormorde (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Alle Konstanten, also auch Zeichensatztabellen kann man schon zur
> Compilezeit durch das Macro jagen.
> Da kostet das Spiegeln also keine zusätzliche Laufzeit.

Ich werd mal ein bisschen akademisch (die Frage lässt sich ja durch "7 
Brücken" lösen) jetzt weiß ich auch wo der Song herkommt ;-).

Wie viele Konstanten gibt es denn so bei GLCD Ansteuerung? Fonts und 
Steuerkommandos Ok, aber alle anderen Elemente werden doch errechnet.

von oszi40 (Gast)


Lesenswert?

Egal ob Bitrotation oder Tabelle, in 3 Tagen habt Ihr vergessen was Ihr 
da tolles rumprogrammiert habt. Ein paar Durchkontaktierungen sind auch 
in 20 Jahren noch deutlich zu erkennen.

von fonsana (Gast)


Lesenswert?

oszi40 schrieb:
> Egal ob Bitrotation oder Tabelle, in 3 Tagen habt Ihr vergessen was Ihr
> da tolles rumprogrammiert habt.

Dafuer wurden doch Kommentare erfunden oder taeusche ich mich da?

fonsana

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Peter Dannegger schrieb:
> Alle Konstanten, also auch Zeichensatztabellen kann man schon zur
> Compilezeit durch das Macro jagen.
> Da kostet das Spiegeln also keine zusätzliche Laufzeit.

Da hatte ich meine Zweifel, da deine Funktion ja streng genommen kein 
Makro ist, und sich auch schwer in ein solches umwandlen lässt (weil n 
mehrmals zugewiesen/verwendet wird).

Allerdings steigt meine Hochachtung vor dem gcc:
1
uint8_t mirror1( uint8_t n )
2
{
3
  n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa); 
4
  n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc); 
5
  n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0); 
6
  return n;
7
}
8
9
uint8_t test4 (void)
10
{
11
    return mirror1(0x12);
12
}

er macht tatsächlich folgendes aus test4:
1
  ldi r24,lo8(72)
2
  ret

von Bronco (Gast)


Lesenswert?

Meine Meinung:

Programmiere Deine Display-Module so, wie Du sie für einen normalen Port 
machen würdest. Mache Dir eine Hardware-Kapsel, wo Du an einer einzigen 
zentralen Stelle spiegelst und auf den Port schreibst.
Hat den Nachteil, daß es mehr Ressourcen frißt als eine perfekte 
Durchoptimierung, aber den Vorteil, daß Du Deine Display-Module 
unabhängig von der Hardware sind, und logisch und einfach 
nachzuvollziehen bleiben.
Hardware-Abhängigkeit sollte man immer in einer "HAL" kapseln und nicht 
quer durch ein Projekt durchziehen.

von Fabian O. (xfr)


Lesenswert?

Michael Reinelt schrieb:
> Da hatte ich meine Zweifel, da deine Funktion ja streng genommen kein
> Makro ist, und sich auch schwer in ein solches umwandlen lässt (weil n
> mehrmals zugewiesen/verwendet wird).

Daher macht man sowas auch eher mit einer Inline-Funktion. Wenn man ganz 
sicher gehen will, dass der Compiler sie inlint, kann man es auch 
erzwingen:
1
static inline __attribute__((__always_inline__)) uint8_t mirror1( uint8_t n )
2
{
3
  n = ((n >> 1) & 0x55) | ((n << 1) & 0xaa); 
4
  n = ((n >> 2) & 0x33) | ((n << 2) & 0xcc); 
5
  n = ((n >> 4) & 0x0f) | ((n << 4) & 0xf0); 
6
  return n;
7
}

Man kann die Entscheidung aber auch dem Compiler überlassen und ihm nur 
mit dem Wörtchen "inline" einen Tipp geben. Bei nicht-konstanten Werten 
kostet der Funktionsaufruf ja im Vergleich zur Codegröße nicht viel 
zusätzliche Zeit, aber ggf. recht viel Programmspeicher, wenn man ihn 
oft kopiert.

Wichtig ist auch noch, dass die Funktion in der gleichen 
Compilierungseinheit (C-Datei) definiert ist, um die Optimierung zu 
ermöglichen. Daher würde ich sie als "static inline"-Funktion in eine 
Headerdatei packen.

von Fabian O. (xfr)


Lesenswert?

Bronco schrieb:
> Hat den Nachteil, daß es mehr Ressourcen frißt als eine perfekte
> Durchoptimierung, aber den Vorteil, daß Du Deine Display-Module
> unabhängig von der Hardware sind, und logisch und einfach
> nachzuvollziehen bleiben.

Wenn man die Hardwareabstraktion ebenfalls in einer Header-Datei mit 
Inline-Funktionen macht, kostet das praktisch keine Ressourcen. :-)

von Michael R. (Firma: Brainit GmbH) (fisa)


Lesenswert?

Fabian O. schrieb:
> Daher macht man sowas auch eher mit einer Inline-Funktion. Wenn man ganz
> sicher gehen will, dass der Compiler sie inlint, kann man es auch
> erzwingen:

Streng genommen hat das gar nichts mit inlining zu tun, sondern mit 
"constant folding". Und das hat mich überrascht, wie gut dieses constant 
folding funktioniert.

von Rolf Magnus (Gast)


Lesenswert?

Michael Reinelt schrieb:
> Fabian O. schrieb:
>> Daher macht man sowas auch eher mit einer Inline-Funktion. Wenn man ganz
>> sicher gehen will, dass der Compiler sie inlint, kann man es auch
>> erzwingen:
>
> Streng genommen hat das gar nichts mit inlining zu tun, sondern mit
> "constant folding".

Ja, aber das klappt bei Funktionsparametern natürlich nur, wenn die 
Funktion auch inline aufgelöst wird.

Fabian O. schrieb:
> Man kann die Entscheidung aber auch dem Compiler überlassen und ihm nur
> mit dem Wörtchen "inline" einen Tipp geben. Bei nicht-konstanten Werten
> kostet der Funktionsaufruf ja im Vergleich zur Codegröße nicht viel
> zusätzliche Zeit, aber ggf. recht viel Programmspeicher, wenn man ihn
> oft kopiert.

Zur Not kann man auch verzweigen, abhängig davon, ob der Wert eine 
Konstante ist oder nicht. Dazu gibt's bei gcc __builtin_constant_p().

von Achim M. (minifloat)


Lesenswert?

Wenn man 256 Byte Flash übrig hat, könnte es auch eine Lookuptable tun. 
Die Wird bei der Ausführung mit dynamischen Argumenten keine 8 Takte 
brauchen...
mfg mf

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.