Als LPC-Nutzer ist man auf den Import von Dateien aus anderen Projekten
angewiesen. Dies führt in der Regel zu Fehlermeldungen, weil der Zugriff
auf Register unterschiedlich gehandhabt wird.
Beispiel CodeRed:
Zugriff über LPC17xx.h/CMSIS-Library:
1
LPC_PINCON_TypeDefLPC_PINCON;
2
// Set P1_24, P1_25, P1_28, P1_29 to 00 - GPIO
3
LPC_PINCON->PINSEL3&=(~0x0F0F0000);
4
// Set GPIO - P1_24, P1_25, P1_28, P1_29 - to be outputs
Beispiel Keil:
Zugriff erfolgt über Strukturen, die in diversen Dateinen abgelegt sind,
z.B. lpc17xx_pinsel.h,lpc17xx_gpio
1
PINSEL_CFG_TypePinCfg;
2
3
PinCfg.Funcnum=0;
4
PinCfg.OpenDrain=0;
5
PinCfg.Pinmode=0;
6
PinCfg.Portnum=3;
7
PinCfg.Pinnum=25;
8
PINSEL_ConfigPin(&PinCfg);
9
PinCfg.Pinnum=26;
10
PINSEL_ConfigPin(&PinCfg);
11
GPIO_SetDir(3,(1<<25)|(1<<26),1);
Bei Fehlermeldungen wegen Registerzugriffs müssen die Entsprechenden
Bibliotheken eingebunden oder der Code geändert werden. Ich bevorzuge
den Registerzugriff über LPC176x.h, weil die dort definierten
Registernamen den Bezeichnungen im Handbuch entsprechen. Ein Blick ins
Manual und man weiß, welche Funktion Registernamen verkörpern:
1
// Set P1_24, P1_25, P1_28, P1_29 to 00 - GPIO
2
PINSEL3&=(~0x0F0F0000);
3
// Set GPIO - P1_24, P1_25, P1_28, P1_29 - to be outputs
4
FIO1DIR|=((1<<24)|(1<<25)|(1<<28)|(1<<29))
Dass Pinsel3 für Port1 zuständig ist, liegt daran dass jeder Pin über
4Bit beschrieben wird und demzufolge für 32Pins insgesamt 4
32Bit-Register erforderlich sind. Übersichtlicher wird es mit Macros:
Damit werden die Register über
pinSEL(PortNr,PinNr,Funktionsnummer)aufgerufen, ohne dass man
rückrechnen muss, welches Pinsel-Register dem Pin zugerdnet ist.
LPC176x.h enthält Fehler. Das Register CCR ist doppelt definiert und
kann daher bei der RTC nicht funktionieren. RxFliterCtrl müsste wohl
richtig RxFilterCtrl heißen. Das führt bei Anpassung von
importiertem Code zu Fehlermeldungen.
Auf der CodeRed-Seite wird 5.2.6 angeboten. Woher hast du 6.1.4?
Meine LPC176x.h ist vom Februar 2013.
Was ich noch störend finde, ist das #define MIN /rtc, das gibt Probleme
wenn irgenwo MIN/MAX definiert ist.
Danke, ich möchte mein CodeRed noch nicht updaten, da meine jetzige
Version gut läuft. Nach UM10360/20.12.2013 gibt es immer noch zwei
Register, die gleich benannt sind:
Configuration and Control Register CCR 0xE000ED14
und
Clock Control Register CCR 0x40024008
Wie haben die denn dieses Problem in der neuen LPC176x.h gelößt?
Wäre es dir möglich, deine Frage(n) auch auf lpcware.com
unter der Sektion Forum lpc175x_6x bzw.
direkter Link
http://www.lpcware.com/forums/microprocessor-forums/lpc17xx
zu posten? Ich denke, die Frage wäre dort gut aufgehoben,
damit NXP sieht, dass es hier Probleme gibt...
Die Installation von LPCXpresso geht paralell zu CodeRed, welches im
übrigen
nicht mehr weiterentwickelt wird.
Der Name CCR existiert mehrfach. Die Nutzung des Register wird über die
jeweiligen Subsysteme und deren Strukturdefinitionen erledigt.
Bsp :
static LPC_TIM_Typedef (*const TIM) = LPC_TIM;
static LPC_RTC_Typedef (*const RTC) = LPC_RTC;
LPC_TIM->CCR ...
LPC_RTC->CCR ...
Das CCR ( Configuration und Control Rgister ) ist in core_cm3h.h
definiert und wird mit der struct SCB ( System Control Block )
angesprochen. Diese Register ist nur im priveligierten Modus nutzbar.
karl k. schrieb:> Als LPC-Nutzer ist man auf den Import von Dateien aus anderen Projekten> angewiesen.
SO?
Mir ist sowas noch nie vorgekommen. Ich benutze entweder die vom
Chip-Hersteller veröffentlichten Headerdateien oder (wenn mir die nicht
gefallen) schreibe ich mir sowas selbst - und basta. Da weiß man
wenigstens, was man tut und worauf man sich verlassen kann.
Die oftmals geübte Methode, Ports in Structs zu fassen, finde ich
grottenschlecht. Mal abgesehen davon, daß man sich damit tonnenweise
Dummy-Deklarationen (a la char undef_192[17] und so) einhandelt, ist
zumindest der Compiler beim Keil so schlau, sich auch bei völlig separat
deklarierten Registern die optimale Zugriffsvariante auszusuchen.
Ob man nun UART0->TRH = MyByte; oder nach anderer Deklaration UART0THR =
MyByte; schreibt, ist damit egal und das Verwenden von Struct's führt zu
keinerlei Vorteil. Da ist mir das separate Deklarieren mit exakt den
gleichen Namen wie im RefMan bedeutend lieber.
Ebenso ist der Eiertanz mit dem oftmals geübten Bit- und
Bitgruppen-Deklarieren ein Graus. Sowas liest sich miserabel und führt
auch nicht wirklich zu besserem Quellcode (vom MC ganz zu schweigen..).
Ich kann dir also nur raten, dich nicht mit allzeit divergierenden
Geschmacksrichtungen von Header-Dateien herumzuplagen, sondern dir sowas
im Zweifelsfall selber zu schreiben. Oftmals ist es sogar besser, auf
allgemeine Header zu verzichten und die HW-Register direkt und selbst in
der Quelle ihres zuständigen Treibers zu deklarieren. Sie werden ja auch
nur DORT und sonst nirgendwo gebraucht - wenn man's richtig macht und
den LowLevel-Treiber so schreibt, daß er die jeweilige HW vernünftig
kapselt. Und wenn man die HW wechselt, ist ohnehin ein anderer
LowLevel-Treiber erforderlich.
W.S.
@W.S.
Zum Vergleich UART0->TRH = MyByte bzw. UART0THR = MyByte
Es ist schon ganz praktisch, wenn man eine Funktion hat,
die man für jede Instanz eines UARTs benutzen kann,
etwa in der Art:
SendUartChar(UARTBASE uartbase, uint8_t MyByte)
{
uartbase->TRH = MyByte;
}
Bei einem Register ist es egal, da könnte man auch UART0THR
als Parameter übergeben, aber spätestens, wenn man mehrere Register
braucht, geht dies damit viel einfacher.
Man kann natürlich auch die Uart-Nr übergeben, dann muss man
aber mittels if oder switch immer von Uart-Nr auf UARTxTHR umrechnen.
(oder halt ein Array pro Register).
Zum selber Schreiben von Register-Dateien:
Ich hatte das früher mal gemacht, weil es für einen Controller
noch keine Datei gab. Es ist eine Riesenarbeit und fehleranfällig.
Ich bin froh, wenn ich das nicht mehr machen brauche.
Da ist mir die Zeit zu schade...