<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=80.130.44.129</id>
	<title>Mikrocontroller.net - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://www.mikrocontroller.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=80.130.44.129"/>
	<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/articles/Spezial:Beitr%C3%A4ge/80.130.44.129"/>
	<updated>2026-04-10T23:38:39Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.7</generator>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=ARM_Bitbanding&amp;diff=95894</id>
		<title>ARM Bitbanding</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=ARM_Bitbanding&amp;diff=95894"/>
		<updated>2017-04-10T06:53:51Z</updated>

		<summary type="html">&lt;p&gt;80.130.44.129: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hintergrund =&lt;br /&gt;
&lt;br /&gt;
Eine RISC Architektur wie die der ARM Prozessoren besitzt oft keine&lt;br /&gt;
Befehle, um einzelne Bits im Speicher zu manipulieren. Um ein&lt;br /&gt;
einzelnes Bit in einem Peripherieregister zu setzen ist daher eine Folge&lt;br /&gt;
mehrerer Befehle erforderlich, wie beispielsweise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
ldr     r0, =0x40012C0C&lt;br /&gt;
ldrh    r1, [r0]&lt;br /&gt;
orr     r1, #1&amp;lt;&amp;lt;9&lt;br /&gt;
strh    r1, [r0]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
oder in C formuliert&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
uint16_t temp = TIM1.DIER;&lt;br /&gt;
temp |= 1&amp;lt;&amp;lt;9;&lt;br /&gt;
TIM1.DIER = temp;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine solche Befehlssequenz im Hauptprogramm steht und in einem&lt;br /&gt;
Interrupt Handler ein anderes Bit des gleichen Peripherieregisters verändert&lt;br /&gt;
wird, dann kann es vorkommen, dass der Handler zwischen dem Load- und&lt;br /&gt;
dem Store-Befehl dieser Sequenz ausgeführt wird. In diesem Fall geht&lt;br /&gt;
die Änderung im Handler mit dem Store-Befehl verloren, der seinen Wert&lt;br /&gt;
aus dem Zustand vor dem Aufruf des Handlers ableitet.&lt;br /&gt;
&lt;br /&gt;
Nun kann man natürlich die Befehlssequenz dagegen absichern, indem man&lt;br /&gt;
sie mit abgeschalteten Interrupts ausführt. Das ist aber recht&lt;br /&gt;
umständlich und verlängert zudem die Reaktionszeit von Interrupts.&lt;br /&gt;
&lt;br /&gt;
ARM Controller mit den Cores Cortex-M3 und -M4 sowie auch manche&lt;br /&gt;
Cortex M0+ besitzen jedoch die Fähigkeit, einzelne Bits im RAM und im&lt;br /&gt;
Peripheriebereich direkt adressieren zu können. Dazu existiert für den&lt;br /&gt;
Peripheriebereich 0x40000000-0x400FFFFF ein weiterer Adressbereich&lt;br /&gt;
0x42000000-0x43FFFFFF und für den RAM-Bereich 0x20000000-0x200FFFFF&lt;br /&gt;
der Bereich 0x22000000-0x23FFFFFF. Das sogenannte &#039;&#039;&#039;Bitbanding&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Arbeitsweise =&lt;br /&gt;
&lt;br /&gt;
In der Bitbanding-Region wird aus den Adressbits 5..24 die Byteadresse&lt;br /&gt;
abgeleitet, indem diese Bits um 5 Bits nach rechts verschoben zur&lt;br /&gt;
Basisadresse der normalen Region addiert werden. Die Adressbits 2..4&lt;br /&gt;
geben die Bitnummer im Byte an. Die Adressbits 0..1 besitzen keine&lt;br /&gt;
Funktion und sollten 0 enthalten.&lt;br /&gt;
&lt;br /&gt;
Ladebefehle in einer Bitbanding-Region laden den Wert 1, wenn das&lt;br /&gt;
adressierte Bit gesetzt ist, sonst 0. Speicherbefehle speichern Bit 0&lt;br /&gt;
des Wertes ins adressierte Bit.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Bitbanding1.png|Adressierung]]&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die obige Sequenz nun zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
ldr     r0, =0x422581A4&lt;br /&gt;
mov     r1, #1&lt;br /&gt;
strh    r1, [r0]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
oder in C&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
*(volatile uint16_t *)0x422581A4 = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das skizzierte Problem mit Interrupt-Handlern kann hier nicht mehr&lt;br /&gt;
auftreten, da die Bitmodifikation als ununterbrechbarer Teil des&lt;br /&gt;
Store-Befehls ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
= Zu beachten =&lt;br /&gt;
&lt;br /&gt;
== Interner Ablauf ==&lt;br /&gt;
&lt;br /&gt;
Es handelt sich bei einer Bitmodifikation weiterhin um eine Abfolge von drei getrennten Operationen:&lt;br /&gt;
* Wert aus dem RAM/Peripherieregister laden,&lt;br /&gt;
* Bit setzen,&lt;br /&gt;
* Wert wieder speichern.&lt;br /&gt;
Nur wird diese Sequenz vom Core im Store-Befehl ausgeführt.&lt;br /&gt;
Die Bitbanding-Operation ist also nicht exakt äquivalent zu speziellen&lt;br /&gt;
Peripherieregistern mit Setzen/Löschen Funktion, wie sie insbesondere&lt;br /&gt;
bei GPIO Ports nicht selten zu finden sind. Diese speziellen Register&lt;br /&gt;
führen wirklich nur eine Bitoperation durch, während es sich beim&lt;br /&gt;
Bitbanding technisch um Operationen auf das gesamte Register handelt.&lt;br /&gt;
&lt;br /&gt;
Siehe: [http://www.mikrocontroller.net/topic/267654 Wo Bitbanding nicht funktioniert]&lt;br /&gt;
&lt;br /&gt;
== Wortbreite ==&lt;br /&gt;
&lt;br /&gt;
Der Core verwendet bei den Bitbanding-Operationen intern die&lt;br /&gt;
Zugriffsbreite genau so, wie sie im Befehl angegeben wird. Ports die&lt;br /&gt;
nur wortweise angesprochen werden dürfen, müssen also auch beim&lt;br /&gt;
Bitbanding wortweise angesprochen werden. Halbwort- oder Bytebefehle&lt;br /&gt;
sind dann nicht zulässig.&lt;br /&gt;
&lt;br /&gt;
== Aliasing ==&lt;br /&gt;
&lt;br /&gt;
Der C Compiler weiss nicht, dass es sich bei den verschiedenen&lt;br /&gt;
Adressen für die normalen Daten und deren Bitbanding-Adressen in&lt;br /&gt;
Wirklichkeit um die gleiche Speicherstelle handelt. Es kann also&lt;br /&gt;
sogenanntes Aliasing auftreten.&lt;br /&gt;
&lt;br /&gt;
Damit der Optimizer des Compilers keinen Strich durch die Rechnung&lt;br /&gt;
macht, sollten alle Daten, die per Bitbanding angesprochen werden, als&lt;br /&gt;
&amp;quot;volatile&amp;quot; deklariert werden. Das gilt sowohl für die Daten selbst,&lt;br /&gt;
als auch für deren Spiegelbereich in der Bitbanding-Region.&lt;br /&gt;
&lt;br /&gt;
Dies betrifft in der Praxis hauptsächlich Bitbanding im RAM-Bereich, da&lt;br /&gt;
die Peripherieregister ohnehin als &amp;quot;volatile&amp;quot; deklariert sind.&lt;br /&gt;
&lt;br /&gt;
= Makros =&lt;br /&gt;
&lt;br /&gt;
Um die Adressrechnung vom Bitbanding zu vereinfachen, wird man&lt;br /&gt;
sinnvollerweise Makros einsetzen. Wer C++ verwendet, kann natürlich&lt;br /&gt;
auch Templates nutzen.&lt;br /&gt;
&lt;br /&gt;
==GCC==&lt;br /&gt;
&lt;br /&gt;
Beim GNU Compiler kann man für den Peripheriebereich beispielsweise diese Makros verwenden, die auf den Definitionen und der Konvention von ARM CMSIS aufsetzen und Besonderheiten des GNU Compilers nutzen:&lt;br /&gt;
&lt;br /&gt;
===Direkte Adressierung===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Access bitbanded peripheral register by direct address.&lt;br /&gt;
#define BBPeriphBit(perReg, bit)   (*(__typeof__(perReg)*) ((PERIPH_BB_BASE + (((unsigned)&amp;amp;(perReg) - PERIPH_BASE) &amp;lt;&amp;lt; 5) + ((bit) &amp;lt;&amp;lt; 2))))&lt;br /&gt;
#define BBPeriphMask(perReg, mask) BBPeriphBit(perReg, BBitOfMask(mask))&lt;br /&gt;
#define BBitOfMask(mask)           (31 - __builtin_clz(mask))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit lassen sich direkt adressierte Peripherieregister ansprechen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
BBPeriphBit(TIM1-&amp;gt;DIER, 9) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro BBPeriphMask erwartet keine Bitnummer, sondern eine&lt;br /&gt;
Bitmaske, da die Definitionen in den Include-Files der Hersteller die&lt;br /&gt;
Bits u.U. nur als Maske zur Verfügung stellen. Die Umrechnung einer konstanten&lt;br /&gt;
Maske in eine Bitnummer erfolgt durch den Compiler.&lt;br /&gt;
&lt;br /&gt;
Die Adressrechnung erfolgt bei konstanten Adressen durch den Compiler. Über einen Pointer adressierte Register sollten so nicht verwendet werden, jedenfalls nicht wenn man über diesen Pointer mehrere Zugriffe in der Funktion durchführt, da dann die Adressrechnung zur Laufzeit erfolgt und man sehr von der Intelligenz des Optimierers abhängt.&lt;br /&gt;
&lt;br /&gt;
===Indirekte Adressierung===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Convert regular base address of a peripheral to bitbanded base address.&lt;br /&gt;
// perPtr: base address of peripheral, typed as pointer to peripheral_TypeDef &lt;br /&gt;
#define BBaseOfPeriph(perPtr)		((__typeof__(*(perPtr))*) (PERIPH_BB_BASE + (((unsigned)(perPtr) - PERIPH_BASE) &amp;lt;&amp;lt; 5)))&lt;br /&gt;
&lt;br /&gt;
// Access bitbanded peripheral register by bitbanded base address and register offset.&lt;br /&gt;
// perBB: bitbanded base address of peripheral, typed as pointer to peripheral_TypeDef &lt;br /&gt;
// member: member name of peripheral_TypeDef&lt;br /&gt;
#define BBOffset(perBB, member)         (__builtin_offsetof(__typeof__(*(perBB)), member) &amp;lt;&amp;lt; 5)&lt;br /&gt;
#define BBasedBit(perBB, member, bit)   (*(__typeof__((perBB)-&amp;gt;member)*) (((unsigned)(perBB) + BBOffset(perBB, member) + ((bit) &amp;lt;&amp;lt; 2))))&lt;br /&gt;
#define BBasedMask(perBB, member, mask) BBasedBit(perBB, member, BBitOfMask(mask))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
extern TIM_TypeDef *timer;&lt;br /&gt;
TIM_TypeDef *timer_bbptr = BBaseOfPeriph(timer);&lt;br /&gt;
BBasedMask(timer_bbptr, DIER, TIM_DIER_CC1DE) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressrechnung erfolgt hier zur Laufzeit in BBaseOfPeriph(). Bei konstanter Bitnummer erfolgt die Berechnung des Offsets relativ zum Pointer durch den Compiler, beim Zugriff entsteht dann also kein Zusatzaufwand. Der Bitbanding-Pointer timer_bbptr lässt sich für alle Register des Timers verwenden.&lt;br /&gt;
&lt;br /&gt;
===Portierung auf andere Compiler===&lt;br /&gt;
&lt;br /&gt;
Es wird der Maschinenbefehl CLZ (Count Leading Zeroes) verwendet, um eine Bitmaske in eine Bitnummer zu übersetzen. Alternativ kann dies auch per ?: Kaskade realisiert werden, nur übersetzt sich dies bei nicht-konstanter Maske in hässlich viel Code. GCC berechnet bei konstanter Maske die CLZ Operation bereits selbst.&lt;br /&gt;
&lt;br /&gt;
Mit __typeof__ wird erreicht, dass die Zugriffe automatisch mit der richtigen Breite durchgeführt werden. Ein in Halbwortbreite deklariertes Register wird auch mit Halbwortbefehlen angesprochen.&lt;br /&gt;
&lt;br /&gt;
Das Konstrukt __builtin_offsetof existiert auch als offsetof.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:ARM]]&lt;/div&gt;</summary>
		<author><name>80.130.44.129</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=ARM_Bitbanding&amp;diff=95893</id>
		<title>ARM Bitbanding</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=ARM_Bitbanding&amp;diff=95893"/>
		<updated>2017-04-10T06:53:29Z</updated>

		<summary type="html">&lt;p&gt;80.130.44.129: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hintergrund =&lt;br /&gt;
&lt;br /&gt;
Eine RISC Architektur wie die der ARM Prozessoren besitzt oft keine&lt;br /&gt;
Befehle, um einzelne Bits im Speicher zu manipulieren. Um ein&lt;br /&gt;
einzelnes Bit in einem Peripherieregister zu setzen ist daher eine Folge&lt;br /&gt;
mehrerer Befehle erforderlich, wie beispielsweise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
ldr     r0, =0x40012C0C&lt;br /&gt;
ldrh    r1, [r0]&lt;br /&gt;
orr     r1, #1&amp;lt;&amp;lt;9&lt;br /&gt;
strh    r1, [r0]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
oder in C formuliert&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
uint16_t temp = TIM1.DIER;&lt;br /&gt;
temp |= 1&amp;lt;&amp;lt;9;&lt;br /&gt;
TIM1.DIER = temp;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine solche Befehlssequenz im Hauptprogramm steht und in einem&lt;br /&gt;
Interrupt Handler ein anderes Bit des gleichen Peripherieregisters verändert&lt;br /&gt;
wird, dann kann es vorkommen, dass der Handler zwischen dem Load- und&lt;br /&gt;
dem Store-Befehl dieser Sequenz ausgeführt wird. In diesem Fall geht&lt;br /&gt;
die Änderung im Handler mit dem Store-Befehl verloren, der seinen Wert&lt;br /&gt;
aus dem Zustand vor dem Aufruf des Handlers ableitet.&lt;br /&gt;
&lt;br /&gt;
Nun kann man natürlich die Befehlssequenz dagegen absichern, indem man&lt;br /&gt;
sie mit abgeschalteten Interrupts ausführt. Das ist aber recht&lt;br /&gt;
umständlich und verlängert zudem die Reaktionszeit von Interrupts.&lt;br /&gt;
&lt;br /&gt;
ARM Controller mit den Cores Cortex-M3 und -M4 sowie auch manche&lt;br /&gt;
Cortex M0+ besitzen jedoch die Fähigkeit, einzelne Bits im RAM und im&lt;br /&gt;
Peripheriebereich direkt adressieren zu können. Dazu existiert für den&lt;br /&gt;
Peripheriebereich 0x40000000-0x400FFFFF ein weiterer Adressbereich&lt;br /&gt;
0x42000000-0x43FFFFFF und für den RAM-Bereich 0x20000000-0x200FFFFF&lt;br /&gt;
der Bereich 0x22000000-0x23FFFFFF. Das sogenannte &#039;&#039;&#039;Bitbanding&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Arbeitsweise =&lt;br /&gt;
&lt;br /&gt;
In der Bitbanding-Region wird aus den Adressbits 5..24 die Byteadresse&lt;br /&gt;
abgeleitet, indem diese Bits um 5 Bits nach rechts verschoben zur&lt;br /&gt;
Basisadresse der normalen Region addiert werden. Die Adressbits 2..4&lt;br /&gt;
geben die Bitnummer im Byte an. Die Adressbits 0..1 besitzen keine&lt;br /&gt;
Funktion und sollten 0 enthalten.&lt;br /&gt;
&lt;br /&gt;
Ladebefehle in einer Bitbanding-Region laden den Wert 1, wenn das&lt;br /&gt;
adressierte Bit gesetzt ist, sonst 0. Speicherbefehle speichern Bit 0&lt;br /&gt;
des Wertes ins adressierte Bit.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Bitbanding1.png|Adressierung]]&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die obige Sequenz nun zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
ldr     r0, =0x422581A4&lt;br /&gt;
mov     r1, #1&lt;br /&gt;
strh    r1, [r0]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
oder in C&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
*(volatile uint16_t *)0x422581A4 = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das skizzierte Problem mit Interrupt-Handlern kann hier nicht mehr&lt;br /&gt;
auftreten, da die Bitmodifikation als ununterbrechbarer Teil des&lt;br /&gt;
Store-Befehls ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
= Zu beachten =&lt;br /&gt;
&lt;br /&gt;
== Interner Ablauf ==&lt;br /&gt;
&lt;br /&gt;
Es handelt sich bei einer Bitmodifikation weiterhin um eine Abfolge von drei getrennten Operationen:&lt;br /&gt;
* Wert aus dem RAM/Peripherieregister laden,&lt;br /&gt;
* Bit setzen,&lt;br /&gt;
* Wert wieder speichern.&lt;br /&gt;
Nur wird diese Sequenz vom Core im Store-Befehl ausgeführt.&lt;br /&gt;
Die Bitbanding-Operation ist also nicht exakt äquivalent zu speziellen&lt;br /&gt;
Peripherieregistern mit Setzen/Löschen Funktion, wie sie insbesondere&lt;br /&gt;
bei GPIO Ports nicht selten zu finden sind. Diese speziellen Register&lt;br /&gt;
führen wirklich nur eine Bitoperation durch, während es sich beim&lt;br /&gt;
Bitbanding technisch um Operationen auf das gesamte Register handelt.&lt;br /&gt;
&lt;br /&gt;
Siehe: [http://www.mikrocontroller.net/topic/267654 Wo Bitbanding nicht funktioniert]&lt;br /&gt;
&lt;br /&gt;
== Wortbreite ==&lt;br /&gt;
&lt;br /&gt;
Der Core verwendet bei den Bitbanding-Operationen intern die&lt;br /&gt;
Zugriffsbreite genau so, wie sie im Befehl angegeben wird. Ports die&lt;br /&gt;
nur wortweise angesprochen werden dürfen, müssen also auch beim&lt;br /&gt;
Bitbanding wortweise angesprochen werden. Halbwort- oder Bytebefehle&lt;br /&gt;
sind dann nicht zulässig.&lt;br /&gt;
&lt;br /&gt;
== Aliasing ==&lt;br /&gt;
&lt;br /&gt;
Der C Compiler weiss nicht, dass es sich bei den verschiedenen&lt;br /&gt;
Adressen für die normalen Daten und deren Bitbanding-Adressen in&lt;br /&gt;
Wirklichkeit um die gleiche Speicherstelle handelt. Es kann also&lt;br /&gt;
sogenanntes Aliasing auftreten.&lt;br /&gt;
&lt;br /&gt;
Damit der Optimizer des Compilers keinen Strich durch die Rechnung&lt;br /&gt;
macht, sollten alle Daten, die per Bitbanding angesprochen werden, als&lt;br /&gt;
&amp;quot;volatile&amp;quot; deklariert werden. Das gilt sowohl für die Daten selbst,&lt;br /&gt;
als auch für deren Spiegelbereich in der Bitbanding-Region.&lt;br /&gt;
&lt;br /&gt;
Dies betrifft in der Praxis hauptsächlich Bitbanding im RAM-Bereich, da&lt;br /&gt;
die Peripherieregister ohnehin als &amp;quot;volatile&amp;quot; deklariert sind.&lt;br /&gt;
&lt;br /&gt;
= Makros =&lt;br /&gt;
&lt;br /&gt;
Um die Adressrechnung vom Bitbanding zu vereinfachen, wird man&lt;br /&gt;
sinnvollerweise Makros einsetzen. Wer C++ verwendet kann natürlich&lt;br /&gt;
auch Templates nutzen.&lt;br /&gt;
&lt;br /&gt;
==GCC==&lt;br /&gt;
&lt;br /&gt;
Beim GNU Compiler kann man für den Peripheriebereich beispielsweise diese Makros verwenden, die auf den Definitionen und der Konvention von ARM CMSIS aufsetzen und Besonderheiten des GNU Compilers nutzen:&lt;br /&gt;
&lt;br /&gt;
===Direkte Adressierung===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Access bitbanded peripheral register by direct address.&lt;br /&gt;
#define BBPeriphBit(perReg, bit)   (*(__typeof__(perReg)*) ((PERIPH_BB_BASE + (((unsigned)&amp;amp;(perReg) - PERIPH_BASE) &amp;lt;&amp;lt; 5) + ((bit) &amp;lt;&amp;lt; 2))))&lt;br /&gt;
#define BBPeriphMask(perReg, mask) BBPeriphBit(perReg, BBitOfMask(mask))&lt;br /&gt;
#define BBitOfMask(mask)           (31 - __builtin_clz(mask))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit lassen sich direkt adressierte Peripherieregister ansprechen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
BBPeriphBit(TIM1-&amp;gt;DIER, 9) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro BBPeriphMask erwartet keine Bitnummer, sondern eine&lt;br /&gt;
Bitmaske, da die Definitionen in den Include-Files der Hersteller die&lt;br /&gt;
Bits u.U. nur als Maske zur Verfügung stellen. Die Umrechnung einer konstanten&lt;br /&gt;
Maske in eine Bitnummer erfolgt durch den Compiler.&lt;br /&gt;
&lt;br /&gt;
Die Adressrechnung erfolgt bei konstanten Adressen durch den Compiler. Über einen Pointer adressierte Register sollten so nicht verwendet werden, jedenfalls nicht wenn man über diesen Pointer mehrere Zugriffe in der Funktion durchführt, da dann die Adressrechnung zur Laufzeit erfolgt und man sehr von der Intelligenz des Optimierers abhängt.&lt;br /&gt;
&lt;br /&gt;
===Indirekte Adressierung===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Convert regular base address of a peripheral to bitbanded base address.&lt;br /&gt;
// perPtr: base address of peripheral, typed as pointer to peripheral_TypeDef &lt;br /&gt;
#define BBaseOfPeriph(perPtr)		((__typeof__(*(perPtr))*) (PERIPH_BB_BASE + (((unsigned)(perPtr) - PERIPH_BASE) &amp;lt;&amp;lt; 5)))&lt;br /&gt;
&lt;br /&gt;
// Access bitbanded peripheral register by bitbanded base address and register offset.&lt;br /&gt;
// perBB: bitbanded base address of peripheral, typed as pointer to peripheral_TypeDef &lt;br /&gt;
// member: member name of peripheral_TypeDef&lt;br /&gt;
#define BBOffset(perBB, member)         (__builtin_offsetof(__typeof__(*(perBB)), member) &amp;lt;&amp;lt; 5)&lt;br /&gt;
#define BBasedBit(perBB, member, bit)   (*(__typeof__((perBB)-&amp;gt;member)*) (((unsigned)(perBB) + BBOffset(perBB, member) + ((bit) &amp;lt;&amp;lt; 2))))&lt;br /&gt;
#define BBasedMask(perBB, member, mask) BBasedBit(perBB, member, BBitOfMask(mask))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
extern TIM_TypeDef *timer;&lt;br /&gt;
TIM_TypeDef *timer_bbptr = BBaseOfPeriph(timer);&lt;br /&gt;
BBasedMask(timer_bbptr, DIER, TIM_DIER_CC1DE) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressrechnung erfolgt hier zur Laufzeit in BBaseOfPeriph(). Bei konstanter Bitnummer erfolgt die Berechnung des Offsets relativ zum Pointer durch den Compiler, beim Zugriff entsteht dann also kein Zusatzaufwand. Der Bitbanding-Pointer timer_bbptr lässt sich für alle Register des Timers verwenden.&lt;br /&gt;
&lt;br /&gt;
===Portierung auf andere Compiler===&lt;br /&gt;
&lt;br /&gt;
Es wird der Maschinenbefehl CLZ (Count Leading Zeroes) verwendet, um eine Bitmaske in eine Bitnummer zu übersetzen. Alternativ kann dies auch per ?: Kaskade realisiert werden, nur übersetzt sich dies bei nicht-konstanter Maske in hässlich viel Code. GCC berechnet bei konstanter Maske die CLZ Operation bereits selbst.&lt;br /&gt;
&lt;br /&gt;
Mit __typeof__ wird erreicht, dass die Zugriffe automatisch mit der richtigen Breite durchgeführt werden. Ein in Halbwortbreite deklariertes Register wird auch mit Halbwortbefehlen angesprochen.&lt;br /&gt;
&lt;br /&gt;
Das Konstrukt __builtin_offsetof existiert auch als offsetof.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:ARM]]&lt;/div&gt;</summary>
		<author><name>80.130.44.129</name></author>
	</entry>
	<entry>
		<id>https://www.mikrocontroller.net/index.php?title=ARM_Bitbanding&amp;diff=95892</id>
		<title>ARM Bitbanding</title>
		<link rel="alternate" type="text/html" href="https://www.mikrocontroller.net/index.php?title=ARM_Bitbanding&amp;diff=95892"/>
		<updated>2017-04-10T06:52:40Z</updated>

		<summary type="html">&lt;p&gt;80.130.44.129: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;= Hintergrund =&lt;br /&gt;
&lt;br /&gt;
Eine RISC Architektur wie die der ARM Prozessoren besitzt oft keine&lt;br /&gt;
Befehle, um einzelne Bits im Speicher zu manipulieren. Um ein&lt;br /&gt;
einzelnes Bit in einem Peripherieregister zu setzen ist daher eine Folge&lt;br /&gt;
mehrerer Befehle erforderlich, wie beispielsweise&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
ldr     r0, =0x40012C0C&lt;br /&gt;
ldrh    r1, [r0]&lt;br /&gt;
orr     r1, #1&amp;lt;&amp;lt;9&lt;br /&gt;
strh    r1, [r0]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
oder in C formuliert&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
uint16_t temp = TIM1.DIER;&lt;br /&gt;
temp |= 1&amp;lt;&amp;lt;9;&lt;br /&gt;
TIM1.DIER = temp;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Wenn eine solche Befehlssequenz im Hauptprogramm steht und in einem&lt;br /&gt;
Interrupt Handler ein anderes Bit des gleichen Peripherieregisters verändert&lt;br /&gt;
wird, dann kann es vorkommen, dass der Handler zwischen dem Load- und&lt;br /&gt;
dem Store-Befehl dieser Sequenz ausgeführt wird. In diesem Fall geht&lt;br /&gt;
die Änderung im Handler mit dem Store-Befehl verloren, der seinen Wert&lt;br /&gt;
aus dem Zustand vor dem Aufruf des Handlers ableitet.&lt;br /&gt;
&lt;br /&gt;
Nun kann man natürlich die Befehlssequenz dagegen absichern, indem man&lt;br /&gt;
sie mit abgeschalteten Interrupts ausführt. Das ist aber recht&lt;br /&gt;
umständlich und verlängert zudem die Reaktionszeit von Interrupts.&lt;br /&gt;
&lt;br /&gt;
ARM Controller mit den Cores Cortex-M3 und -M4 sowie auch manche&lt;br /&gt;
Cortex M0+ besitzen jedoch die Fähigkeit, einzelne Bits im RAM und im&lt;br /&gt;
Peripheriebereich direkt adressieren zu können. Dazu existiert für den&lt;br /&gt;
Peripheriebereich 0x40000000-0x400FFFFF ein weiterer Adressbereich&lt;br /&gt;
0x42000000-0x43FFFFFF und für den RAM-Bereich 0x20000000-0x200FFFFF&lt;br /&gt;
der Bereich 0x22000000-0x23FFFFFF. Das sogenannte &#039;&#039;&#039;Bitbanding&#039;&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
= Arbeitsweise =&lt;br /&gt;
&lt;br /&gt;
In der Bitbanding-Region wird aus den Adressbits 5..24 die Byteadresse&lt;br /&gt;
abgeleitet, indem diese Bits um 5 Bits nach rechts verschoben zur&lt;br /&gt;
Basisadresse der normalen Region addiert werden. Die Adressbits 2..4&lt;br /&gt;
geben die Bitnummer im Byte an. Die Adressbits 0..1 besitzen keine&lt;br /&gt;
Funktion und sollten 0 enthalten.&lt;br /&gt;
&lt;br /&gt;
Ladebefehle in einer Bitbanding-Region laden den Wert 1, wenn das&lt;br /&gt;
adressierte Bit gesetzt ist, sonst 0. Speicherbefehle speichern Bit 0&lt;br /&gt;
des Wertes ins adressierte Bit.&lt;br /&gt;
&lt;br /&gt;
[[Datei:Bitbanding1.png|Adressierung]]&lt;br /&gt;
&lt;br /&gt;
Dadurch wird die obige Sequenz nun zu:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;avrasm&amp;quot;&amp;gt; &lt;br /&gt;
ldr     r0, =0x422581A4&lt;br /&gt;
mov     r1, #1&lt;br /&gt;
strh    r1, [r0]&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
oder in C&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
*(volatile uint16_t *)0x422581A4 = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das skizzierte Problem mit Interrupt-Handlern kann hier nicht mehr&lt;br /&gt;
auftreten, da die Bitmodifikation als ununterbrechbarer Teil des&lt;br /&gt;
Store-Befehls ausgeführt wird.&lt;br /&gt;
&lt;br /&gt;
= Zu beachten =&lt;br /&gt;
&lt;br /&gt;
== Interner Ablauf ==&lt;br /&gt;
&lt;br /&gt;
Es handelt sich bei einer Bitmodifikation weiterhin um eine Abfolge von drei getrennten Operationen:&lt;br /&gt;
* Wert aus dem RAM/Peripherieregister laden,&lt;br /&gt;
* Bit setzen,&lt;br /&gt;
* Wert wieder speichern.&lt;br /&gt;
Nur wird diese Sequenz vom Core im Store-Befehl ausgeführt.&lt;br /&gt;
Die Bitbanding-Operation ist also nicht exakt äquivalent zu speziellen&lt;br /&gt;
Peripherieregistern mit Setzen/Löschen Funktion, wie sie insbesondere&lt;br /&gt;
bei GPIO Ports nicht selten zu finden sind. Diese speziellen Register&lt;br /&gt;
führen wirklich nur eine Bitoperation durch, während es sich beim&lt;br /&gt;
Bitbanding technisch um Operationen auf das gesamte Register handelt.&lt;br /&gt;
&lt;br /&gt;
Siehe: [http://www.mikrocontroller.net/topic/267654 Wo Bitbanding nicht funktioniert]&lt;br /&gt;
&lt;br /&gt;
== Wortbreite ==&lt;br /&gt;
&lt;br /&gt;
Der Core verwendet bei den Bitbanding-Operationen intern die&lt;br /&gt;
Zugriffsbreite genau so, wie sie im Befehl angegeben wird. Ports die&lt;br /&gt;
nur wortweise angesprochen werden dürfen, müssen also auch beim&lt;br /&gt;
Bitbanding wortweise angesprochen werden. Halbwort- oder Bytebefehle&lt;br /&gt;
sind dann nicht zulässig.&lt;br /&gt;
&lt;br /&gt;
== Aliasing ==&lt;br /&gt;
&lt;br /&gt;
Der C Compiler weiss nicht, dass es sich bei den verschiedenen&lt;br /&gt;
Adressen für die normalen Daten und deren Bitbanding-Adressen in&lt;br /&gt;
Wirklichkeit um die gleiche Speicherstelle handelt. Es kann also&lt;br /&gt;
sogenanntes Aliasing auftreten.&lt;br /&gt;
&lt;br /&gt;
Damit der Optimizer des Compilers keinen Strich durch die Rechnung&lt;br /&gt;
macht, sollten alle Daten, die per Bitbanding angesprochen werden, als&lt;br /&gt;
&amp;quot;volatile&amp;quot; deklariert werden. Das gilt sowohl für die Daten selbst,&lt;br /&gt;
als auch für deren Spiegelbereich in der Bitbanding-Region.&lt;br /&gt;
&lt;br /&gt;
Dies betrifft in der Praxis hauptsächlich Bitbanding im RAM-Bereich, da&lt;br /&gt;
die Peripherieregister ohnehin als &amp;quot;volatile&amp;quot; deklariert sind.&lt;br /&gt;
&lt;br /&gt;
= Makros =&lt;br /&gt;
&lt;br /&gt;
Um die Adressrechnung vom Bitbanding zu vereinfachen wird man&lt;br /&gt;
sinnvollerweise Makros einsetzen. Wer C++ verwendet kann natürlich&lt;br /&gt;
auch Templates nutzen.&lt;br /&gt;
&lt;br /&gt;
==GCC==&lt;br /&gt;
&lt;br /&gt;
Beim GNU Compiler kann man für den Peripheriebereich beispielsweise diese Makros verwenden, die auf den Definitionen und der Konvention von ARM CMSIS aufsetzen und Besonderheiten des GNU Compilers nutzen:&lt;br /&gt;
&lt;br /&gt;
===Direkte Adressierung===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Access bitbanded peripheral register by direct address.&lt;br /&gt;
#define BBPeriphBit(perReg, bit)   (*(__typeof__(perReg)*) ((PERIPH_BB_BASE + (((unsigned)&amp;amp;(perReg) - PERIPH_BASE) &amp;lt;&amp;lt; 5) + ((bit) &amp;lt;&amp;lt; 2))))&lt;br /&gt;
#define BBPeriphMask(perReg, mask) BBPeriphBit(perReg, BBitOfMask(mask))&lt;br /&gt;
#define BBitOfMask(mask)           (31 - __builtin_clz(mask))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Damit lassen sich direkt adressierte Peripherieregister ansprechen:&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
BBPeriphBit(TIM1-&amp;gt;DIER, 9) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Das Makro BBPeriphMask erwartet keine Bitnummer, sondern eine&lt;br /&gt;
Bitmaske, da die Definitionen in den Include-Files der Hersteller die&lt;br /&gt;
Bits u.U. nur als Maske zur Verfügung stellen. Die Umrechnung einer konstanten&lt;br /&gt;
Maske in eine Bitnummer erfolgt durch den Compiler.&lt;br /&gt;
&lt;br /&gt;
Die Adressrechnung erfolgt bei konstanten Adressen durch den Compiler. Über einen Pointer adressierte Register sollten so nicht verwendet werden, jedenfalls nicht wenn man über diesen Pointer mehrere Zugriffe in der Funktion durchführt, da dann die Adressrechnung zur Laufzeit erfolgt und man sehr von der Intelligenz des Optimierers abhängt.&lt;br /&gt;
&lt;br /&gt;
===Indirekte Adressierung===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
// Convert regular base address of a peripheral to bitbanded base address.&lt;br /&gt;
// perPtr: base address of peripheral, typed as pointer to peripheral_TypeDef &lt;br /&gt;
#define BBaseOfPeriph(perPtr)		((__typeof__(*(perPtr))*) (PERIPH_BB_BASE + (((unsigned)(perPtr) - PERIPH_BASE) &amp;lt;&amp;lt; 5)))&lt;br /&gt;
&lt;br /&gt;
// Access bitbanded peripheral register by bitbanded base address and register offset.&lt;br /&gt;
// perBB: bitbanded base address of peripheral, typed as pointer to peripheral_TypeDef &lt;br /&gt;
// member: member name of peripheral_TypeDef&lt;br /&gt;
#define BBOffset(perBB, member)         (__builtin_offsetof(__typeof__(*(perBB)), member) &amp;lt;&amp;lt; 5)&lt;br /&gt;
#define BBasedBit(perBB, member, bit)   (*(__typeof__((perBB)-&amp;gt;member)*) (((unsigned)(perBB) + BBOffset(perBB, member) + ((bit) &amp;lt;&amp;lt; 2))))&lt;br /&gt;
#define BBasedMask(perBB, member, mask) BBasedBit(perBB, member, BBitOfMask(mask))&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beispiel:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c&amp;quot;&amp;gt;&lt;br /&gt;
extern TIM_TypeDef *timer;&lt;br /&gt;
TIM_TypeDef *timer_bbptr = BBaseOfPeriph(timer);&lt;br /&gt;
BBasedMask(timer_bbptr, DIER, TIM_DIER_CC1DE) = 1;&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Die Adressrechnung erfolgt hier zur Laufzeit in BBaseOfPeriph(). Bei konstanter Bitnummer erfolgt die Berechnung des Offsets relativ zum Pointer durch den Compiler, beim Zugriff entsteht dann also kein Zusatzaufwand. Der Bitbanding-Pointer timer_bbptr lässt sich für alle Register des Timers verwenden.&lt;br /&gt;
&lt;br /&gt;
===Portierung auf andere Compiler===&lt;br /&gt;
&lt;br /&gt;
Es wird der Maschinenbefehl CLZ (Count Leading Zeroes) verwendet, um eine Bitmaske in eine Bitnummer zu übersetzen. Alternativ kann dies auch per ?: Kaskade realisiert werden, nur übersetzt sich dies bei nicht-konstanter Maske in hässlich viel Code. GCC berechnet bei konstanter Maske die CLZ Operation bereits selbst.&lt;br /&gt;
&lt;br /&gt;
Mit __typeof__ wird erreicht, dass die Zugriffe automatisch mit der richtigen Breite durchgeführt werden. Ein in Halbwortbreite deklariertes Register wird auch mit Halbwortbefehlen angesprochen.&lt;br /&gt;
&lt;br /&gt;
Das Konstrukt __builtin_offsetof existiert auch als offsetof.&lt;br /&gt;
&lt;br /&gt;
[[Kategorie:ARM]]&lt;/div&gt;</summary>
		<author><name>80.130.44.129</name></author>
	</entry>
</feed>