Hallo,
weiss zufällig jemand wie man das Bitbanding für _Bool Variablen nutzen
kann? Ich kann wohl ein Bit über #defines definieren aber das liegt dann
eben an einer festen Adresse.
Mit fällt auf Anhieb nur ein einen Bit Struct zu definieren:
typedef bitfeld {
_Bool flag_1:1;
_Bool flag_2:1;
_Bool flag_2:1;
...
} __attribute_packed(()) bitfeld_t;
Dabei erzeugt der Compiler aber einiges mehr an Code für den Zugriff.
Und da verliessen sie ihn auch schon.
Knifflig. Lokale Variablen werden gern in Registern aufbewahrt, damit
geht es überhaupt nicht. Theoretisch wäre es möglich, wenn sie auf dem
Stack liegen. Aber dann müsste man ihre Adresse kennen um die in die
BitBand Adresse umzurechnen. Das ist in C irgendwie nicht vorgesehen.
Bleiben globale Variablen. Dazu könnte man im Linker Script zwei
Sections anlegen, eine im RAM für die Bits und eine für den zugehörigen
Bereich in der BitBand Region. In dieser Section legt man die
Bool-Variablen als int an (sie haben 32 Bit, können aber nur die Werte 0
und 1 annehmen).
Damit kann man mit einfachen, schnellen 32-Bit-Zugriffen einzelne Bits
lesen und schreiben. Der Zugriff auf das RAM ist angeblich ein echter,
unteilbarer read-modify-write Zyklus. Stimmt das wirklich, auch bei
einem Fault während die Floating Point Register gerettet werden (oder
noch schlimmeren Sachen)?
Auf die Section im RAM sollte man wahrscheinlich nicht selbst zugreifen.
Wie würde man mit C-Mitteln die richtige Zuordnung der beiden Sections
machen?
Christian J. schrieb:> weiss zufällig jemand wie man das Bitbanding für _Bool Variablen nutzen> kann? Ich kann wohl ein Bit über #defines definieren aber das liegt dann> eben an einer festen Adresse.>> Mit fällt auf Anhieb nur ein einen Bit Struct zu definieren:>> typedef bitfeld {>> _Bool flag_1:1;> _Bool flag_2:1;> _Bool flag_2:1;> ...>> } __attribute_packed(()) bitfeld_t;
Irgendwie passt das nicht zusammen. Beim Bitbanding bekommt ja gerade
jedes Bit eines Registers ein eigenes Byte (bzw. sogar mehrere)
zugewiesen (und nicht nur ein Bit).
Auszug aus dem Handbuch des F407:
2.3.3 Bit banding
The Cortex™-M4F memory map includes two bit-band regions. These regions
map each word in an alias region of memory to a bit in a bit-band region
of memory. Writing to a word in the alias region has the same effect as
a read-modify-write operation on the targeted bit in the bit-band
region.
In the STM32F4xx devices both the peripheral registers and the SRAM are
mapped to a bitband region, so that single bit-band write and read
operations are allowed. The operations are only available for
Cortex™-M4F accesses, and not from other bus masters (e.g. DMA).
A mapping formula shows how to reference each word in the alias region
to a corresponding bit in the bit-band region. The mapping formula is:
bit_word_addr = bit_band_base + (byte_offset x 32) + (bit_number × 4)
where:
– bit_word_addr is the address of the word in the alias memory region
that maps to
the targeted bit
– bit_band_base is the starting address of the alias region
– byte_offset is the number of the byte in the bit-band region that
contains the targeted bit
– bit_number is the bit position (0-7) of the targeted bit
Example
The following example shows how to map bit 2 of the byte located at SRAM
address
0x20000300 to the alias region:
0x22006008 = 0x22000000 + (0x300*32) + (2*4)
Writing to address 0x22006008 has the same effect as a read-modify-write
operation on bit 2 of the byte at SRAM address 0x20000300.
Reading address 0x22006008 returns the value (0x01 or 0x00) of bit 2 of
the byte at SRAM address 0x20000300 (0x01: bit set; 0x00: bit reset).
Also eher ausrechen als Structs verwenden...
eagle user schrieb:> Damit kann man mit einfachen, schnellen 32-Bit-Zugriffen einzelne Bits> lesen und schreiben. Der Zugriff auf das RAM ist angeblich ein echter,> unteilbarer read-modify-write Zyklus. Stimmt das wirklich, auch bei> einem Fault während die Floating Point Register gerettet werden (oder> noch schlimmeren Sachen)?>
Es ist beim BitBanding gar keine read-modify-write mehr sondern nur noch
ein einzelner (atomarer) write. Dafür das die restlichen Bits in ruhe
gelassen werden sorgt hier die Hardware
> Auf die Section im RAM sollte man wahrscheinlich nicht selbst zugreifen.> Wie würde man mit C-Mitteln die richtige Zuordnung der beiden Sections> machen?
So ganz verstehe ich nicht was du mit deinen zwei Sectionen meinst?
An den BitBandig Adressen befindet sich kein RAM. Der ARM hat nur einen
einzigen Linearen Adressraum für alles gemeinsam auf dem immer gleich
zugegriffen werden kann ganz egal ob unter einer bestimmten Adresse
Flash, RAM, Register, I/O oder sonstwas gemappt ist.
Irgendwer schrieb:
> Es ist beim BitBanding gar keine read-modify-write mehr sondern nur noch> ein einzelner (atomarer) write. Dafür das die restlichen Bits in ruhe> gelassen werden sorgt hier die Hardware
das glaube ich nicht, tim... Das Ziel ist ein beliebiges Wort im
normalen RAM, das ist 32 Bit breit. Woher soll diese Hardware die
restlichen 31 Bit kennen, ohne sie vorher zu lesen? Auch dann, wenn die
Daten keinen Umweg durch die CPU nehmen, weil es eine Spezial-Hardware
direkt am Bus gibt.
>> Auf die Section im RAM sollte man wahrscheinlich nicht selbst zugreifen.>> Wie würde man mit C-Mitteln die richtige Zuordnung der beiden Sections>> machen?> So ganz verstehe ich nicht was du mit deinen zwei Sectionen meinst?
Die Section im RAM braucht man, damit der Linker diesen Bereich nicht
für andere Daten benutzt. Außerdem braucht man die RAM Adressen, damit
man sie in BitBanding Adressen umrechnen kann. Die BitBandig Section
braucht man nicht, auf diese Adressen kann man natürlich mit beliebigen
C-Mitteln zugreifen. Aber ich finde
eagle user schrieb:> das glaube ich nicht, tim... Das Ziel ist ein beliebiges Wort im> normalen RAM, das ist 32 Bit breit. Woher soll diese Hardware die> restlichen 31 Bit kennen, ohne sie vorher zu lesen? Auch dann, wenn die> Daten keinen Umweg durch die CPU nehmen, weil es eine Spezial-Hardware> direkt am Bus gibt.
Richtig. Es ist immer noch ein read-modify-write Zyklus, allerdings
atomar ausgeführt (was einem das Sperren der Interrupts bei
Bitmanipulationen erspart).
eagle user schrieb:> C-Mitteln zugreifen. Aber ich findeint> __attribute__((section(".bitband"))) foo; schöner als #define
Ich weiss wie das technisch funktioniert aber wie man das nun in C
umsetzt, daran hapert es. Der Bitband Bereich kann zb im Debugger nicht
angezeigt werden. Klar kann ich da Variablen reinlegen mit #definde
(volatile) (*adresse)..... aber die bügelt der Compiler ggf. über. Und
wie man das Linker File umschreibt weiss ich nicht. Es nützt natürlich
auch nichts, wenn für jedes Bit ein Riesenaufwand an Umrechnung
passieren muss. Aber ich habe derzeit ein kleines Problem 320x240 Bits
unterzubringen in einem 20kb Chip.
Die Beispiele im Netz geben immer absolute Adressen als Ziel an aber
"dynamische" zb globale Variablen, dazu findet sich nichts. Es entsteht
ja erst die Variable an Platz x, dazu muss sie noch in den Bitband
Bereich bewegt werden durch eine section und dann erfolgt der Zugriff
über die Bitband Alias Adressen.
edit: Sorry, glaube das ist Müll. Das ganze SRAM ist ja als Bitband
abgebildet, d.h. jedes Bit meiner 20kb ab 0x20000000 lässt sich in eine
32 Bit Adresse "weit oben" umrechnen. Und über die erreiche ich dann
jedes Bit. So legt man zb nur einen Array an char abc[32] und hat dann
32*8 Adressen oben zur Verfügung um auf die Bits zuzugreifen. Über
uint8_t *ptr = &abc kriegt man die Adresse des Arrays raus. Diese Alias
Adressen müssten nur gut verpackt werden, so dass zb ein Array
entstünde, der [256] Elemente hat, vom Typ Bit ist und schreibt man in
array[100] rein wird tatsächlich nur das eine Bit gesetzt.
Mal durchgrübeln... kann ja nicht so schwer sein....
https://searchcode.com/codesearch/view/17574679/
Christian J. schrieb:
> Das ganze SRAM ist ja als Bitband abgebildet, d.h. jedes Bit meiner> 20kb ab 0x20000000 lässt sich in eine 32 Bit Adresse "weit oben"> umrechnen. Und über die erreiche ich dann jedes Bit. So legt man> zb nur einen Array an char abc[32] und hat dann 32*8 Adressen oben> zur Verfügung um auf die Bits zuzugreifen.
genau so.
> Über uint8_t *ptr = &abc kriegt man die Adresse des Arrays raus.> Diese Alias Adressen müssten nur gut verpackt werden, so dass zb ein> Array entstünde, der [256] Elemente hat, vom Typ Bit ist und schreibt> man in array[100] rein wird tatsächlich nur das eine Bit gesetzt.
Naja, nach der Umrechnung von ptr auf die BitBand Adresse hast du ja
einen int Pointer auf array[0]. Damit kannst du doch alles machen.
eagle user schrieb:> Naja, nach der Umrechnung von ptr auf die BitBand Adresse hast du ja> einen int Pointer auf array[0]. Damit kannst du doch alles machen.
#define BITBAND_ALIAS_ADDRESS(addr, bit) \
((volatile uint32_t*)((((uint32_t)(addr) & 0xF0000000) + 0x02000000)
\
+((((uint32_t)(addr)&0xFFFFF)*32)\
+( (uint32_t)(bit)*4))))
Alsoooooo.... mal aus der Hüfte geschossen:
uint32_t ptr = BITBAND_ALIAS_ADDRESS(myarray, 0)
Mit * oder &, müsste ich erst kompilieren.
Mit *(ptr++) würde ich dann die Elemente als Bit vorfinden und hätte die
Pixel meines Displays, statt auf 76.kb, dann auf 320x240 Bit = 9600
Bytes. Natürlich uimgerechnet auf 2D Array mit x,y.
Cool... direkt mal ausprobieren heute abend. der GDB Debugger streikt
leider im Bitbandbereich, "cannot read memory".
Christian J. schrieb:> Mit fällt auf Anhieb nur ein einen Bit Struct zu definieren:
Das ist hier der grundfalsche Gedanke per se.
Also: manche Hersteller haben für manche µC etwas eingeführt, was man
mit Bitbanding bezeichnen kann, aber das ist erstens nur ein Schlagwort
und zweitens nicht überall implementiert, also relativ unportabel.
Hintergrund ist, daß die einzelnen Bits der allgemeinen Port-Register
nicht in einem 8, 16 oder 31 Bit Portregister angesprochen werden (was
man parallel zum Bitbanding aber trotzdem immer noch tun kann), sondern
es ist irgendwo im Adreßbereich des µC ein Hardware-Array angeordnet,
das aus einzelnen Boolean-Variablen besteht und hinter jeder derartigen
Variablen steckt ein einzelnes Port-Bein. Damit kann man einzelne
Portbeine separat als Boolean-Variablen ansprechen (0 oder 1). Ob
allerdings so eine Variable 8 oder 16 oder 32 Bit groß ist, also ob man
sie als bool oder longbool oder weiß der Geier ansprechen muß, kann nur
das RefMan klären.
Je nachdem, wie gut du beim Formulieren von #define Konstrukten bist,
kannst du dir diese Arrays von Hardwareregistern selber definieren oder
du benutzt dazu ne kleine Assemblerquelle, aus der heraus du diese
Arrays exportierst. Dann eben in deinen C-Quellen
extern longbool Port_A_Pins[32];
oder so ähnlich.
W.S.
Das Ziel muss als volatile deklariert sein, ansonsten ist nicht sicher
dass das Programm das gleich mitbekommt wenn per bitband manipuliert
wird.
Der Zugriff auf die Speicherstelle erfolgt mit der selben Breite wie der
Zugriff auf die Alias-Region. Schreibzugriffe erfolgen auch als
read-modify-write, die bits sind also nicht wirklich separat
ansprechbar.
Sinn macht das hauptsächlich um sich ein disablen von interrupts zu
sparen, eventuell wirds beim manipulieren von einzelnen bits auch etwas
schneller und oder kleiner als die herkömmliche methode.
Also,
https://searchcode.com/codesearch/view/17574679/
das hier läuft bei mir nicht :-(
volatile uint32_t foo;
volatile uint32_t *adress;
WRITE_BITBANDING(foo,0,1);
foo wird nicht 1.
adress = BITBAND_ALIAS_ADDRESS(foo,0);
Hard Fault Error.
Tja...