24 Einzelne Bits zu 3 Byte zusammen fügen in c++?

OP #5515533
Lesenswert?

Hallo,

ich benutze einen 32Bit MC und habe 24 I/O Pins die nicht in einer Reihe 
sind definiert als SIG1-SIG24 (liefern also den Pin Zustand 0/1).

Ich benötige sie aber in der richtigen Reihenfolge in einem entweder 
3Byte Array oder in einer 4Byte Long Variable jenachdem was besser geht.

Wie stelle ich das am besten an?

Gruß
Markus
Gast #5515540
Lesenswert?

1
uint32t value=0;
2
if (pin 32 is set)
3
  value|=(1<<32);
4
if (pin 31 is set)
5
  value|=(1<<31);
6
...
7
if (pin 0 is set)
8
  value|=(1<<0);

Die Ausdrücke in den Klammern kriegst du selber hin, oder?
Gast #5515582
Lesenswert?

Man könnte Markos benutzen, finde ich aber auch nicht gut:
1
#define isset(port,bit) (((port) >> (bit)) & 1)
2

3
uint32_t value =
4
  (isset(registerX,24) << 31) | 
5
  (isset(registerX,7) << 30) |
6
  (isset(registerX,0) << 29) |
7
  ...
8
  (isset(registerX,12) << 0);

Wenn da ein Tippfehler passiert, spuckt der Compiler sicher eine 
herrlich unverständliche Fehlermeldung aus.
Gast #5515585
Lesenswert?

Markus S. schrieb:
> Ne variante ohne 'IF' wird dann wohl nicht gehen oder?
>
> value|=(1<<32);    setzt ein Bit
> value|=(0<<32);    löscht aber kein Bit oder?

Nein. Entweder, Du initialisierst Deinen uint32 immer mit 0 und setzt 
dann nur die nötigen Bits (wie Stefan demonstriert hat), oder Du machst 
das mit &=~.
Gast #5515591
Lesenswert?

>> Buhaha;)

>Nach 6 Wochen weichgekochtem Hirn bei 28-36°C solltest auch du solche
>Flüchtigkeitsfehler verzeihen können.

Kein Problem. War halt lustig;)

>Egal ob du noch im Kindergarten
>spielst oder älter bist.

Das hättest du dir jetzt auch verkneifen können.

> value|=(1<<32);    setzt ein Bit
> value|=(0<<32);    löscht aber kein Bit oder?

OMG, nicht noch mehr 32. Das geht nicht! Dieses Bit fliegt raus.
Passt nicht in 32 Bit.
Beitrag #5515596 wurde von einem Moderator gelöscht.
#5515748
Lesenswert?

Ich hab das nicht so ganz verstanden:

Markus S. schrieb:
> ich benutze einen 32Bit MC und habe 24 I/O Pins die nicht in einer Reihe
> sind definiert als SIG1-SIG24 (liefern also den Pin Zustand 0/1).

Was sind SIG1-SIG24? Variablen, die einfach 0 oder 1 sind? Oder 
Bitnummern in einem Register?

Markus S. schrieb:
> Ne variante ohne 'IF' wird dann wohl nicht gehen oder?

Doch, geht schon. Dann muss man das Bit maskieren und an die richtige 
Stelle schieben.
Beispiel: Dein Bit ist bit 20 von Register X und soll in bit 15 der 
Variable:
1
variable |= (RegisterX >> 20 & 0x01) << 15;

Sofern SIG1-SIG24 einfach Variablen sind, die 0 oder 1 sind, reicht 
natürlich sowas wie:
1
variable |= SIG20 << 20;

> value|=(1<<32);    setzt ein Bit
> value|=(0<<32);    löscht aber kein Bit oder?

Nein.
Gast #5515762
Lesenswert?

Markus S. schrieb:
> uint32t value=0;
> value|=(SIG24<<23);
> value|=(SIG23<<22);
> value|=(SIG22<<21);
> ...
> value|=(SIG1<<0);

Mit den Variablen wird das doch zur Laufzeit geschoben.
Du füllst doch irgendwo die SIGn Variablen, pack da doch gleich den Wert 
rein statt Null oder Eins.

if(pinset(x) SIG12 = 4096;

value = SIG1 + SIG2 + SIG3 ...

Ein if(SIG6) ist dann immer nuch nur wahr oder falsch.
#5515779
Lesenswert?

Markus S. schrieb:
> Ich benötige sie aber in der richtigen Reihenfolge in einem entweder
> 3Byte Array oder in einer 4Byte Long Variable jenachdem was besser geht.

"Besser" in welchem kontext?

Schau dir aber einmal std::bitset an, das könnte dir bieten worauf du 
hinaus willst.

Ansonsten wäre auch ein Union von 24 bool Variabeln, oder gleich eines 
bool arrays der Grösse 24 möglich.
#5515811
Lesenswert?

Scheint wirklich heiß zu sein, da draussen. Der Index in mix gibt an, 
wo's hin soll, der Wert, wo's herkommt.
1
uint32_t shuffle(uint32_t raw)
2
{
3
    uint8_t mix[] = { 1, 12, 18, 0, 24, 11 };
4
    uint32_t ret = 0;
5

6
    for (int i = 0; i < sizeof(mix); i++)
7
        ret |= ((raw >> mix[i]) & 1) << i;
8

9
    return ret;
10
}
Persönliche Seite #5515841
Lesenswert?

Da der Thread eh schon entgleist ist, hier noch die übertriebene 
template-Variante:
1
#include <cstddef>
2
#include <iostream>
3
#include <iomanip>
4
#include <climits>
5

6
template <std::size_t iPort, std::size_t iPin>
7
struct HWPin {
8
  static constexpr std::size_t port = iPort;
9
  static constexpr std::size_t pin = iPin;
10
};
11

12
template <typename... T>
13
struct List {};
14

15
template <typename HwPort, std::size_t nHwPorts, typename LogPort, std::size_t... Ports, std::size_t... Pins, std::size_t... I>
16
void readPorts2 (LogPort& out, HwPort (&in) [nHwPorts], List<HWPin<Ports, Pins>...>, std::index_sequence<I...>) {
17
  out = 
18
    ((((in [Ports] >> Pins) & 1) << I) + ... );
19
}
20

21
template <typename HwPort, std::size_t nHwPorts, typename LogPort, std::size_t... Ports, std::size_t... Pins>
22
void readPorts (LogPort& out, HwPort (&in) [nHwPorts], List<HWPin<Ports, Pins>...> l) {
23
  readPorts2 (out, in, l, std::make_index_sequence<sizeof...(Ports)> {});
24
}
25

26

27
int main () {
28
  // Array mit Eingabe-Portdaten
29
  uint32_t inPorts [4] { GPIOA->IDR, GPIOB->IDR, GPIOC->IDR };
30
  uint32_t packed;
31
  readPorts (packed, inPorts, List<
32
    // Definition der Pins in logischer Reihenfolge
33
    HWPin<0,1> , HWPin<0,7>, HWPin<0, 3>, HWPin<1, 4>
34
  > {});
35
  std::cout << "0x" << std::hex << std::setw(CHAR_BIT * sizeof(packed) / 4) << std::setfill('0') << packed << std::endl;
36
}
#5516002
Lesenswert?

Rolf M. schrieb:
>> ich benutze einen 32Bit MC und habe 24 I/O Pins die nicht in einer Reihe
>> sind definiert als SIG1-SIG24 (liefern also den Pin Zustand 0/1).
>
> Was sind SIG1-SIG24? Variablen, die einfach 0 oder 1 sind? Oder
> Bitnummern in einem Register?

Wenn sie symbolisch für IO-Pins stehen, und sich diese Bits gebündelt 
auf wenige Ports verteilen, aber hauptsächlich die Reihenfolge nicht 
passt, dann lassen sich Bytes dieser Ports wie oben erwähnt über 
Tabellen umcodieren.
Gast #5516604
Lesenswert?

Also ehrlich, der erste Code von Stefan ist klar, sauber, sauschnell, 
lesbar und maximal flexibel. Bei einem Controller mit wenigen 100 Pins 
macht was "schlaues" wenig Sinn.

Alternativ wäre statt bitbanging noch bitfelder in gleicher Weise 
möglich, wenn man bitfelder nicht für Teufelszeug hält.

Ergänzung: statisch analysierbar, dann fallen die meisten 
Flüchtigkeitsehler auch auf
Gast #5516656
Lesenswert?

Markus S. schrieb:
> ich benutze einen 32Bit MC und habe 24 I/O Pins die nicht in einer Reihe
> sind

..aber du verrätst niemandem, welcher µC das ist. Dann mußt du dein 
Problem eben allein lösen.

Tip: bei manchen 32 Bittern aus der Cortex-Riege gibt es mehrere 
Zugriffsmöglichkeiten für die Ports. Eine davon ist ein Alias-Feld 
(offizieller Name fällt mit grad nicht ein), wo jedes Portpin als eine 
Boolean-Variable dargestellt ist. Und das wahlweise als 8, 16 oder 32 
Bit longbool.

Wo sowas vorhanden ist (z.B. LPC11E12), kannst du etwa so schreiben:
1
#define GPPB    0x50000000
2
#define W0  (*((volatile unsigned long*) (GPPB + 0x1000)))
3
#define W1  (*((volatile unsigned long*) (GPPB + 0x1004)))
4
...
5

6
MyVector =
7
  (W0  << 1) |
8
  (W27 << 2) |
9
  (W3  << 3) |
10
   ... usw.
Wo sowas nicht geht, mußt du zwangsläufig auf
((PortX >> nummer) &1) << bitpos) |
zurückgreifen.

W.S.
OP #5516808
Lesenswert?

Danke nochmal für die Rege Diskussion, welchen MC ich benutze spiel 
keine Rolle (funktioniert mit jedem) und es ging ja darum, es möglichst 
effizient zu machen.

Wie ich oben geschrieben habe liefern SIG1-SIG24 (per #define) direkt 
den Bitzustand des entsprechenden Pins am MC.
Zitat:
> ich benutze einen 32Bit MC und habe 24 I/O Pins die nicht in einer Reihe
> sind definiert als SIG1-SIG24 (liefern also den Pin Zustand 0/1).

Die wohl einfachste/schnellste/übersichtlichste Lösung ist diese:

uint32t value=0;
value|=(SIG24<<23);
value|=(SIG23<<22);
value|=(SIG22<<21);
...
value|=(SIG1<<0);

Habe sie jetzt auch fertig programmiert und sie funktioniert 
einwandfrei!

Gruß
Markus
Beitrag #5516819 wurde von einem Moderator gelöscht.
#5516858
Lesenswert?

Niklas G. schrieb:
> Da der Thread eh schon entgleist ist, hier noch die übertriebene
> template-Variante

Daran ist gar nichts übertrieben. Das ist nämlich die einzige Variante 
die Lauf- und Compilezeit Werte unterstützten könnte. Sprich ist der 
Wert für "out" bekannt bekommt man 2 Instruktionen und nicht ein paar 
hundert...

Von Reuse brauch ich gar nicht erst anfangen.
Gast #5516862
Lesenswert?

Die wohl einfachste/schnellste/übersichtlichste Lösung ist diese:
1
uint32t value=0;
2
value|=(SIG24<<23);
3
value|=(SIG23<<22);
4
value|=(SIG22<<21);
5
...
6
value|=(SIG1<<0);

einfach: ja
übersichtlich: ja
schnellste: nein

Denn so werden immer alle 32 Makros ausgeführt, dann das Bit geschoben, 
dann mit value verodert. Mein Vorschlag mit der if-kette verkürzt die 
Sache etwas bei den Bits, die 0 sind.
#5516864
Lesenswert?

Stefanus F. schrieb:
> Mein Vorschlag mit der if-kette verkürzt die
> Sache etwas bei den Bits, die 0 sind.

einverstanden,

Stefanus F. schrieb:
> uint32t value=0;
> if (pin 32 is set)
>   value|=(1<<32);
> if (pin 31 is set)
>   value|=(1<<31);
> ...
> if (pin 0 is set)
>   value|=(1<<0);

dann machen wir es doch richtig (rem 24 I/O)

uint32t value=0;
if (pin 24 is set)
  value|=(1<<23);
if (pin 23 is set)
  value|=(1<<22);
...
if (pin 1 is set)
  value|=(1<<0);

sorry aber als Letztes sollte es richtig stehen
Gast #5516869
Lesenswert?

Jetzt sollte man natürlich noch diese SIGxx Makros verkürzen, dass sie 
bei Low Pegel eine 0 liefern und bei High pegel irgendeine höhere Zahl.

Momentan hat er die Makros ja so geschrieben, dass 0 oder 1 bei raus 
kommt. Für diese if-Kette würden sie damit eine unnötige 
Schiebe-Operation enthalten.
Gast #5516870
Lesenswert?

Das wird doch eh alles wegoptimiert. Lieber das Übersichtlichste nehmen 
und schauen ob der generierte Code nicht vielleicht sogar optimal ist...
Auf >= Cortex-M3 wären das die Instruktionen UBFX und BFI, wenn die Bits 
komplett durcheinander sind.
Gast #5516873
Lesenswert?

Wobei ich die Variante mit "if" nicht so schön finde - die Ziel Variable 
wird mehrfach verändert (mutable), wodurch das ganze relativ weit weg 
von funktionaler Ausdrucksweise ist und daher m.E. unübersichtlicher. 
Sollte es tatsächlich nicht wegoptimiert werden, sind bedingte Sprünge 
je nach Prozessor auch ineffizient.
#5516877
Lesenswert?

Stefanus F. schrieb:
> Mein Vorschlag mit der if-kette verkürzt die
> Sache etwas bei den Bits, die 0 sind.

Ganz so einfach ist es nicht. Es hängt ein wenig vom Prozessor ab, 
inwieweit ein
  if (reg1 & in_bit)
     reg2 |= out_bit;
als Bit-Test und bedingtes Bit-Or übersetzt wird, z.B. beim ARM7. Mit 
Sprung spielt die Laufzeit bedingter Sprünge mit hinein, die je nach 
Core und Anbindung vom Programmspeicher hoch ausfallen kann.

Und wenn die 24 Inputs alle von einem 32-Bit Port stammen, dann ist
  out = a3[input >> 24 & 0xFF]
      | a2[input >> 16 & 0xFF]
      | a1[input >>  8 & 0xFF]
      | a0[input >>  0 & 0xFF];
deutlich schneller.
#5516878
Lesenswert?

Das ist zwar kein C, aber geht bestimmt auch damit.

Procedure ReadStatus;             // Einlesen und aufbereiten der 
C&RStatus-Variablen
  Var D1, D2 : Byte;
  Begin
    D1:= not PinB;                // --> C5 R5 C6 R6 C7 R7 C8 R8
    D2:= not PinF;                // --> R1 C1 R2 C2 R3 C3 R4 C4
    RStatus:=$00;
    RStatus:=((D1 and %00000001) shl 7) or ((D1 and %00000100) shl 4) or
             ((D1 and %00010000) shl 1) or ((D1 and %01000000) shr 2) or
             ((D2 and %00000010) shl 2) or ((D2 and %00001000) shr 1) or
             ((D2 and %00100000) shr 4) or ((D2 and %10000000) shr 7);

    CStatus:=$00;
    CStatus:=((D1 and %00000010) shl 6) or ((D1 and %00001000) shl 3) or
              (D1 and %00100000)        or ((D1 and %10000000) shr 3) or
             ((D2 and %00000001) shl 3) or  (D2 and %00000100)        or
             ((D2 and %00010000) shr 3) or ((D2 and %01000000) shr 6);
  End ReadStatus;
#5516887
Lesenswert?

Niklas Gürtler schrieb:
> Welcher 32 Bit Prozessor hat denn keinen? Und außerdem auch noch keine
> Pipeline, welche durch bedingte Sprünge ausgebremst wird?

Ein Problem gibts eher bei einem Portzugriff pro Bit, also zB
   #define SIGxx (... PORT2 ...)
   ... SIGxx << 13 ...
oder dem analogen Bitbanging, weil so ein Portzugriff ein paar Takte 
dauern kann und dank volatile nicht optimiert wird. Bei 24 davon läppert 
sich das.

Eine generische Methode, die völlig unabhängig von der Verteilung der 
Input-Pins auf Ports ist, die ist zwar elegant, aber sehr wahrscheinlich 
nicht laufzeitoptimal.
Gast #5516900
Lesenswert?

C fehlt ein Set/Unset Operetor.

Mit # als Operatorzeichen etwa so:

port # 1 # 2;

Setzt das LSB und loescht das Bit darueber.


Traditionell ginge das wohl so:

port = (port | 1) & ~2;


oder:

result = var # 1 # 2;


Bei einem:

port ## 2 oder: port #1 #

koennte der Compiler das jeweils unnoetige schonmal herausoptimieren.
Beitrag #5516903 wurde von einem Moderator gelöscht.
#5516908
Lesenswert?

Operator schrieb:
> koennte der Compiler das jeweils unnoetige schonmal herausoptimieren.

Solange der Compiler pro Bit auf einen Port zugreifen muss, hast du die 
Zugriffszeit daran an der Backe. Unabhängig von der Syntax.

Auf Register angewandt sieht das mit diesem Operator nur optisch anders 
aus, an möglicher Optimierung ändert das nichts. Jeder Compiler wird |0 
oder <<0 ohnehin streichen, wenn optimiert übersetzt.
Gast #5516910
Lesenswert?

A. K. schrieb im Beitrag #5516903:
> ... und jetzt bitte nochmal für Normalsterbliche.

Man kann in manchen Sprachen den Zugriff auf als public definierte class 
member steuern, indem man den get- und set-Operator verwendet.
Dabei wird bei einer Zuweiung der set-Operator verwendet und beim 
Auslesen der get-Operator.
Um willkürlichem Schreibzugriff entgegenzuwirken, kann man den 
set-Operator private definieren und den get als public.
Dann kann von überall lesend auf die Variable zugegriffen werden, aber 
nur innerhalb der Klasse schreibend.
Die Operatoren arbeiten wie Funktionen (get endet mit einem return, set 
hat als quasi unsichtbares Argument die Variable "value").
Innerhalb dieser Operatoren kann man auch noch Programmcode abarbeiten 
lassen.
#5516915
Lesenswert?

STK500-Besitzer schrieb:
> Man kann in manchen Sprachen den Zugriff auf als public definierte class
> member steuern, indem man den get- und set-Operator verwendet.

Yep, damit lassen sich Programme eleganter formulieren. Wenn es primär 
auf die Optik ankommt, kann das sehr nützlich sein. Wenn indes die 
Laufzeit wichtig ist, dann muss man in der hiesigen Aufgabe von der 
Abstraktion runter auf die Realität, und die konkrete Pinverteilung 
betrachten. Das ist nicht annähernd so schön, kann aber sehr viel 
schneller sein.

Wobei ich eine Weile brauchte, bis ich verstand, wer "Operator" ist. 
Dessen Hirn windet sich allerdings völlig anders als meines. ;-)
Beitrag #5516918 wurde von einem Moderator gelöscht.
Beitrag #5516920 wurde von einem Moderator gelöscht.
Gast #5516925
Lesenswert?

> Wenn SIG1..SIG24 nur den Zustand 0 und 1 haben

Leider spielt der TO nicht mit offenen karten, so daß wir alle nicht 
wissen, wie seine SIGxx Makros aussehen.

Das man kein if "braucht", habe wir längst festgestellt. Wir sind schon 
einen Schritt weiter und vergleichen die Performance diverser Varianten.

Was aber - wie nun klar ist - ohne die Makros und den µC zu kennen zu 
keiner konkreten Empfehlung führen kann.

Es wurde alles dazu gesagt, nur nicht nicht von jedem. Mal sehen, wie 
viele Leute noch die selben Vorschläge wiederholen und dann die selben 
Bedenken dazu äußern.
Gast #5516966
Lesenswert?

Operator schrieb:
> C fehlt ein Set/Unset Operetor.

Da es ja um C++ geht, steht es dir frei das selbst zu implementieren... 
# ist schon belegt. Aber so etwas könnte man sich bauen:
1
RegisterXY[7] = 0;
2
RegisterYZ.BitBlubb =1;
Mit einer cleveren Umsetzung ist das dann auch genau so effizient wie 
das direkte Hinschreiben. C(++) sind halt Hochsprachen und nicht primär 
für Treiber Entwicklung gemacht, weshalb solche Dinge nicht direkt 
kompakt unterstützt werden. Nach dem Grundsatz:
Oft benutzte Dinge einfach machen, alle Dinge möglich machen.
Gast #5517033
Lesenswert?

Vincent H. schrieb:
> Daran ist gar nichts übertrieben. Das ist nämlich die einzige Variante
> die Lauf- und Compilezeit Werte unterstützten könnte.

Es ist die einzige Variante, die geradezu blind ist für die 
zugrundeliegende Hardware. Man bedenke mal, daß das Zusammenklauben von 
wild in der Peripherie verstreuten Bits prinzipiell derart hardware- und 
projekt-nah ist, daß man mit Templates und dergleichen an dieser Stelle 
eigentlich GARNICHTS Gutes bewirken kann.

Will man einen hochästhetisch aussehenden Quellcode oder einen 
hocheffektiven Maschinencode?


Stefanus F. schrieb:
> Falls noch jemand wissen wollte, warum C Programmierer auch ein bisschen
> Assembler können sollten: Dieser Thread zeigt es.

Wenigstens ein wenig Assembler sollte JEDER µC-Programmierer können. 
Aber das reicht nicht. Man sollte auch die Peripherie des betreffenden 
µC soweit kennen, daß man sie auch benutzen kann.

Wer mit irgendwelchen Makros versucht, Portpins in eine generalisierte 
Form zu bringen, vergeigt fast immer wesentliche Möglichkeiten, die der 
betr. µC bietet.


Operator schrieb:
> Bei einem:
> port ## 2 oder: port #1 #
> koennte der Compiler das jeweils unnoetige schonmal herausoptimieren.

siehe oben. Das ist ein glatter Fehlgedanke. Der Compiler kann beim 
gestellten Thema überhaupt nichts herausoptimieren, denn es geht 
darum, 24 wild in der Prärie liegende Pinzustände in eine einzige long 
Variable zu befördern. Also müssen alle 24 Zustände irgendwie abgefragt 
werden und man kann keinen davon mal eben wegoptimieren.

Schlußendlich habe ich den Eindruck, daß hier mal wieder eine völlig 
falsche Aufgabenstellung zelebriert wird. Der TO hat genau so etwas vor 
und fragt nur nach, wie er das am besten kann, aber wie schon so oft in 
diesem Forum erweist sich wohl auch dieses als falscher - weil 
uneffektiver - Denkansatz, der bei besserer Gesamtplanung des 
zugrundeliegenden Projektes schlichtweg überflüssig wäre.

W.S.
Gast #5517067
Lesenswert?

W.S. schrieb:
> Man bedenke mal, daß das Zusammenklauben von wild in der Peripherie
> verstreuten Bits prinzipiell derart hardware- und projekt-nah ist, daß
> man mit Templates und dergleichen an dieser Stelle eigentlich GARNICHTS
> Gutes bewirken kann.

Der Code wird ggf. übersichtlicher. Die Definition der Funktion ist 
etwas kryptisch, dafür ist der Aufruf ziemlich kurz und es ist leicht 
ersichtlich, wie die Pins definiert sind.

W.S. schrieb:
> Will man einen hochästhetisch aussehenden Quellcode oder einen
> hocheffektiven Maschinencode?

Compiler sind heutzutage sehr gut im Optimieren. Der abstrakte, lesbare 
Code wird in einen anwendungsspezifischen optimalen Maschinencode 
übersetzt. Man muss ggf. noch ein bisschen mit "restrict" und 
"always_inline" nach helfen.

Siehe z.B. die im Artikel Serialisierung vorgestellte Bibliothek. 
Diese ermöglicht sehr abstrakten, übersichtlichen und wartbaren Code. 
Dieser wird aber sehr effizient übersetzt. Genau das ist der Spagat, für 
den es C++ gibt.
Gast #5517153
Lesenswert?

Niklas Gürtler schrieb:
> Compiler sind heutzutage sehr gut im Optimieren.

Du hast kein einziges Wort verstanden.

Ganz egal, ob ein Compiler den ihm vorgesetzten Code optimieren kann 
oder nicht, kann er (der Compiler!) die zugrundeliegende Hardware der 
Peripherie nicht kennen. Er weiß daher nicht, ob dessen Peripherie nicht 
nur eine einzige Art Zugriff auf die Portpins kennt, sondern ggf. auch 
noch andere Zugriffsarten, die dann eben weitaus effizienter sind für 
den gegebenen Fall.

Siehe z.B. auch das hier in diesem Forum ewige Thema "Setzen eines 
Portpins zu hi oder lo", was bei manchen Chips auf dramatisch bessere 
Weise (BSRR Register o.a.) als sonst üblich getan werden kann. So etwas 
kann kein Compile dieser Welt optimieren, denn dafür ist hardware- und 
projekt-nahes Wissen vonnöten.

W.S.
#5517163
Lesenswert?

Markus S. schrieb:
> Danke nochmal für die Rege Diskussion, welchen MC ich benutze spiel
> keine Rolle (funktioniert mit jedem) und es ging ja darum, es möglichst
> effizient zu machen.

Wenn es für alle möglichen Controller mit jeder möglichen Pinbelegung 
und jeder beliebigen Definition für deine SIGnn-Makros funktioniert, 
dann ist das Ergebnis alles andere als "möglichst effizient".

Niklas Gürtler schrieb:
>> Nur wenn der betreffende µC keinen "Barrel Shifter" hat.
>
> Welcher 32 Bit Prozessor hat denn keinen? Und außerdem auch noch keine
> Pipeline, welche durch bedingte Sprünge ausgebremst wird?

Der erzwungene Barrelshifter ist eine Spezialität von ARM, auf allen 
anderen Architekturen ist er eine Optimierung, entsprechend muss er 
nicht auf jeder MIPS- oder RISCV-Implementation vorhanden sein.

Da wir vom TO eine absolute Unkenntnis der Realität verordnet bekommen 
haben, kann es sich durchaus um einen PicoRV32 handeln: Keine Pipeline, 
optionalen Barrelshifter. Oder um eine Hochschul-Kursimplementation von 
MIPS-I.
Gast #5517165
Lesenswert?

W.S. schrieb:
> Du hast kein einziges Wort verstanden

Und du meinen Code nicht gelesen. Da ist überhaupt kein Peripherie 
Zugriff drin. Den macht der Aufrufer selbst, so wie es optimal ist. 32 
Bits auf einmal Lesen dürfte ziemlich optimal sein (besser als Bit 
Banding). Und wenn man es drauf anlegt, kann man das selbstverständlich 
auch mit Templates modellieren - wenn nur genau 1 Bit gebraucht wird und 
das an Stelle 0 stehen soll, automatisch auf die Bit Banding Region 
zugreifen. In anderen Fällen dürfte das sonst keinen Vorteil bieten. Bei 
anderen Architekturen gilt das dann analog.
Gast #5517300
Lesenswert?

Weil's so schön und etwas anders ist ;-)
1
    uint32_t value = 0;
2
    value = (value<<1) | !!SIG24;
3
    value = (value<<1) | !!SIG23;
4
    value = (value<<1) | !!SIG22;
5
    ...
6
    value = (value<<1) | !!SIG3;
7
    value = (value<<1) | !!SIG2;
8
    value = (value<<1) | !!SIG1;
9
    return value;
Beitrag #5517324 wurde von einem Moderator gelöscht.
#5517369
Lesenswert?

Niklas Gürtler schrieb:
> ... gilt natürlich auch für die Ausgabe per BSRR o.ä., aber um die ging
> es hier überhaupt nicht.

Wenn man unbedingt will, dann kann C++17 sogar die Umsetztabelle "Bits 
die ausgegeben werden sollen" in "BSSR-Patterns" als constexpr 
generieren. Zumindest für den Fall "alle Bits beliebig auf eine Port 
verstreut" und bis zu einer in der Source einstellbaren Anzahl von Bits, 
da dies ja ein uint32_t Array wird und es noch ins ROM passen muß. Für 
typische 4-Bit+RS+E-LCD-Schnittstellen braucht das 256-Byte Flash und 
ein zusätzliches Laden aus der Tabelle.
Und wenn irgend eine Bedingung (Port/Anzahl Pins/kein BSSR) nicht 
eingehalten wird, dann wird per constexpr if eine andere Variante 
benutzt. Der Anwedungs-Code ändert sich nicht, die Templates muß 
zuallererst mal der Compiler verstehen. STL ist auch nichts leicht 
lesbares, aber sehr zuverlässig.

(ist als Ergänzung zu Niklas zu verstehen)
#5517373
Lesenswert?

W.S. schrieb:
>
> Siehe z.B. auch das hier in diesem Forum ewige Thema "Setzen eines
> Portpins zu hi oder lo", was bei manchen Chips auf dramatisch bessere
> Weise (BSRR Register o.a.) als sonst üblich getan werden kann. So etwas
> kann kein Compile dieser Welt optimieren, denn dafür ist hardware- und
> projekt-nahes Wissen vonnöten.
>

Das kann der Compiler auch nicht wissen, das bekommt er vom 
Template-Programmierer gesagt. So der das kann.

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