PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : [ERLEDIGT] BIT BANDING auf GPIO's beim LPC17xx



Siro
10.02.2014, 16:20
Hallo zusammen. Ich beschäftige mich grade mit dem Bit-Banding beim LPC1768
Sinn und Zweck ist die Ausführung von "atomaren" code für Bitmanipulationen auf den GPIO's

Alle Versuche auf die GPIO's mittels Bit-Banding zuzugreifen landen aber bei mir im HardFault_Handler
zumindest mit den überall veröffentlichen Macros bzw. include Files.
Auf andere Register funktioniert es, die haben aber auch einen völlig anderen Adressbereich.

Die GPIO's haben die physikalischen Adressen 0x2009 C0xx
Dazu zählen die Register FIO SET CLR PIN MASK DIR

Laut Datenblatt befinden sich die "peripheral bit band alias adressen" ab 0x4200 0000
die sind aber NICHT für die GPIO's gedacht.

Das Register WDT phsikalisch 0x4000.0000 liegt Bittechnisch an den Adressen 0x4200.0000 bis 0x420.001F
Ich habe es auch ausprobiert und dort Bits gesetzt. Funktioniert einwandfrei.

Welche Bit-Banding Adresse hat aber z.B. das FIO0SET Register ?
geht das Bitbanding überhaupt auf den GPIO's

Laut Datenblatt ja:
UM10360 Page 6 of 841
All GPIOs are located on an AHB bus for fast access, and support Cortex-M3 bit-banding.

auf Seite 13 ist der AHB Bus in einem anderem Bereich als die GPIO's
UM10360 page 13 of 841
GPIO 0x2009 C000 - 0x2009 FFFF
APB 0x4000 0000 - 0x4007 FFFF
AHB 0x5000 0000 - 0x501 FFFF

Ich bin jetzt der Meinung es geht nicht :( aber ich HOFFE Ihr könnt mich eines Besseren belehren ;)

Erwartungsvoll
Siro


perSetBit(LPC_FIO0PIN,0); /* setzte Bit 0 am Port 0 , führt zum HardFault_Handler */




#ifndef BitBanding_Included
#define Bitbanding_Included

#define RAM_BASE 0x20000000UL /* normal RAM Base address */
#define RAM_BB_BASE 0x22000000UL /* Bit Banding Base address for RAM */

#define PER_BASE 0x40000000UL /* normal periperal Base address */
#define PER_BB_BASE 0x42000000UL /* Bit Banding peripheral Base address for RAM */

/* macros for bit manipulation in RAM */
#define _varClrBit(VarAddr, BitNumber) \
(*(U32 *) (RAM_BB_BASE | ((VarAddr - RAM_BASE) << 5) | ((BitNumber) << 2)) = 0)

#define _varSetBit(VarAddr, BitNumber) \
(*(U32 *) (RAM_BB_BASE | ((VarAddr - RAM_BASE) << 5) | ((BitNumber) << 2)) = 1)

#define _varGetBit(VarAddr, BitNumber) \
(*(U32 *) (RAM_BB_BASE | ((VarAddr - RAM_BASE) << 5) | ((BitNumber) << 2)))


/* macros for bit manipulation in peripheral registers */
#define _perClrBit(PerAddr, BitNumber) \
(*(U32 *) (PER_BB_BASE | ((PerAddr - PER_BASE) << 5) | ((BitNumber) << 2)) = 0)

#define _perSetBit(PerAddr, BitNumber) \
(*(U32 *) (PER_BB_BASE | ((PerAddr - PER_BASE) << 5) | ((BitNumber) << 2)) = 1)

#define _perGetBit(PerAddr, BitNumber) \
(*(U32 *) (PER_BB_BASE | ((PerAddr - PER_BASE) << 5) | ((BitNumber) << 2)))


/* with these macros we can easily work with bits in atomic code */
#define varClrBit(var,bit) (_varClrBit((U32)&var,bit))
#define varSetBit(var,bit) (_varSetBit((U32)&var,bit))
#define varGetBit(var,bit) (_varGetBit((U32)&var,bit))

#define perClrBit(var,bit) (_perClrBit((U32)&var,bit))
#define perSetBit(var,bit) (_perSetBit((U32)&var,bit))
#define perGetBit(var,bit) (_perGetBit((U32)&var,bit))

#endif

Siro
11.02.2014, 11:11
Das Problem ist gelöst:

Die GPIO's befinden sich NICHT im Peripherie Bereich, sondern im SRAM Bereich
und so muss ich die anderen Macros benutzen.

also NICHT perSetBit(LPC_FIO0PIN,0); sondern varSetBit(LPC_FIO0PIN,0);

Die Firma NXP hat mir auch zurück geschrieben mit einem zusätzlichen Hinweis:


Bit-banding is possible, since the GPIO's are in the Cortex-M3 "SRAM" area.

Example for GPIO1.28:
#define BITBAND_SRAM(a,b) ((volatile uint32_t *)((0x22000000 + ((uint32_t)(a)-0x20000000)*32)))[b]
#define LED BITBAND_SRAM(&GPIO1->FIOPIN, 28)

This only makes sense for the FIOPIN or FIODIR registers, not for FIOSET and FIOCLR. Note that bit-banding performs a read-modify-write operation on the peripheral register when writing by bit-banding!

Also note that writing to FIOPIN by bit-banding requires a __DSB() instruction afterwards. This is due to the structure of the GPIO block.

Example:
LED = 1;
__DSB();


Im IAR-COMPILER kann das __DSB(); wie folgt geschrieben werden:

__asm("DSB"); /* ein doppelter Unterstrich */

Die Funktion ansich ist auch ohne das DSB (Data Synchronisation Barrier) gegeben. Aber das DSB stellt sicher, daß die intgerne Verarbeitung auch fertig geworden ist.
"The DSB instruction completes when all explicit memory accesses before it complete."

Siro
26.02.2014, 14:59
Thread Sicheres Bit Setzen und Löschen auf den GPIO's (der Vollständigkeit halber)

Nun funktioniert es endlich :)


#define BITBAND_SRAM(a,b) ((volatile U32 *)((0x22000000 + ((U32)(a)-0x20000000)*32)))[b]
#define BIT_SET_GPIO(port,bit) BITBAND_SRAM(&port,bit) = 1; __asm("DSB")
#define BIT_CLR_GPIO(port,bit) BITBAND_SRAM(&port,bit) = 0; __asm("DSB")



Nun kann mit folgendem Code ein einzelnes Bit verändert werden OHNE dass ein Interrupt
oder anderer Task während der Sequenz auch das Bit verändert. Wir haben einen atomaren Code, der auch einigermaßen übersichtlich ist.

Beispiele:

BIT_SET_GPIO(LPC_FIO1PIN,31); /* setze Bit 31 vom Port P1 */
BIT_CLR_GPIO(LPC_FIO1PIN,31); /* lösche Bit 31 vom Port P1 */

BIT_SET_GPIO(LPC_FIO0PIN,12); /* setze Bit 12 vom Port P0 */
BIT_CLR_GPIO(LPC_FIO0PIN,12); /* lösche Bit 12 vom Port P0 */