Hallo,
ist schon ein klasse Gefühl: Das Olimex Board mit dem Wiggler liegt vor
einem und zwei LEDs blinken abwechselnd :-))))) Hast zwar fast 2h
gedauert, bis ich so langsam dahinter gestiegen bin aber es läuft erst
einmal.
Aber noch eine Frage:
Man kann mit den debug_prinft und debug_scanf Befehlen aus der
Crossworks Lib eine virtuelle Console auf dem PC bedienen. Dh. printf
gibt Ergebnisse auf dieser Console aus oder speichert sie in einem File
auf der Platte, bzw liest scanf auch Zahlen ein. Habe mal ganz simpel
eine Fliesskommaaddition mit Tasteneingabe gemacht. Toll, der ARM7
rechnet richtig :-)
Die Frage ist aber nun, was passiert mit diesen debug befehlen, wenn ich
den Code mit "ARM Relaese" compiliere und standalone laufen lasse. Dann
hat das Board ja keine virtuelle Console mehr über den PC. Muss ich
diese befehle dann ausklammern oder mit define Anweisungen nur beim
Debuggen einbinden?
Zweite Frage: Hat jemand auf die Schnell Code um die Echtzeituhr mit der
Zeit und dem Datum zu füttern? Oder spielt man nur die Werte in die
register und das Ding läuft los? Ich finde so recht keine Steuerbits im
ARM7 Manual.
PS: Ist schon ein klasse Teil! Besser als die 8 Bitter, endlich richtig
mit vollem C Umfang arbeiten können jubel
Gruss,
Christian
Na dann herzlichen Glückwunsch. Wieder jemand der es geschafft
einen achso komplizierten ARM7 mit seinem nahezu unbeherrschbaren
Interrupthandling in Betrieb zu nehmen ;)
Wenn du uns jetzt auch noch mitteilst um welchen Controller es
sich handelt, könnte deine zweite Frage vielleicht beantwortet
werden. Zur ersten kann ich nichts sagen, da ich kein Crossworks
benutze. Aber ich habe hier irgendwo Code für die RTC des LPC2000.
Christian J. wrote:
> PS: Ist schon ein klasse Teil! Besser als die 8 Bitter, endlich richtig> mit vollem C Umfang arbeiten können *jubel*
???
In welchem Punkt entspricht der AVR-GCC bitte nicht dem C-Standard in
"vollem Umfang"?
Wenn Du damit meinst, daß man nun für jeden Pups erstmal 2kB RAM
alloziiert (man hats ja), dann ist das auch aufm ARM immer noch
schlechter C Programmierstil.
D.h. irgendwann fällt man damit auf die Nase, nur eben etwas später.
Peter
let wrote:
> Na dann herzlichen Glückwunsch. Wieder jemand der es geschafft> einen achso komplizierten ARM7 mit seinem nahezu unbeherrschbaren> Interrupthandling in Betrieb zu nehmen ;)
Von Interrupts hat er doch garnichts geschrieben.
Die Fallgruben komme auch dann erst, wenn man Interrupts temporär
disablen muß, mehrere Interrupts und Prioritäten verwendet (und keinen
Cortex M3 verwendet).
Peter
Soweit sind wir noch lange nicht. Jedenfalls rennt der Bursche.
Ist ein LPC2138, 512kb Flash und 32kb RAM. Stimmt,man hats ja :-) Wenn
man aus dem Hause PIC kommt schon 768 Bytes schon viel. Allerdings zieht
sich der Compiler schonmal 2kb für sich selbst rein aber das kann man
sicher noch optimieren.
Ich habe gerade mal die PLL in Betrieb genommen und festgestellt, dass
sie auch extrem übertaktet läuft, d.h. auf 100 Mhz kriegt man ihn schon,
nur wird er da mollig warm. Bin mir nicht sicher wie lange die Chips das
Tuning aushalten. Erstmal wieder runter auf 60 Mhz.
Auch die IRQ werden beherrschbar sein...... irgendwann mal.
Die Beispielprogramme dimensionieren den Stack üblicherweise
recht großzügig. Muß in vielen Fällen nicht sein.
Lass dich wegen der IRQs nicht verrückt machen. Ein berüchtigtes
Problem mit der Kombination ARM7/VIC (PL190) ist der 'spurious
interrupt'. Der Name ist schwieriger als das Problem selbst.
Der PL192 wie er im LPC23xx/24xx eingesetzt wird kennt so etwas
nicht.
Ich bin davon ausgegangen das deine LEDs über Timerinterrupts
gesteuert werden. So machen es die 'Blinky' Beispiele meist.
Den RTC Code habe ich angehängt. Ist nichts besonderes aber
es tut.
Christian J. wrote:
> Wenn> man aus dem Hause PIC kommt schon 768 Bytes schon viel.
Bei PIC kann ich nicht mitreden.
Wenn man vorher schon Z80 und 8051 kannte, dann kommt man mit den PICs
einfach nicht mehr klar.
Ich hatte mal das MPLAB installiert und das Datenblatt eines PIC12
runtergeladen, dann etwas rumprobiert und dann alles kopfschüttelnd
wieder beiseite gelegt.
Die AVRs haben ja gut zugelegt (8kB Flash/512Byte SRAM bei den
8-Pinnern, 256kB Flash/8kB SRAM bei den 64-Pinnern.
Das finde ich schon sehr bequem, um "mit vollem C Umfang" zu
programmieren.
Die 8- und 14-Pinner setze ich fast so oft ein, wie früher Logik-ICs (1
AVR statt 2..20 TTLs).
Peter
Hallo Peter,
gut, ich habe seit 1996 nur mit PIC zu tun gehabt und die Dinger sind
sehr einfach zu handhaben. Dafür aber nie einen Draht zu AVR gehabt.
PICs programmiere ich heute in kurzer Zeit, wenn sie einfache Aufgaben
machen sollen, einstecken und laufen lassen. Und mit den 18er kann man
schon sehr komplexe Aufgaben bewältigen, zudem die Compiler einen HAL
haben. I2C ist sonst ein Horror, so reduziert es sich auf wenige Befehle
und die funktionieren auch. Schön auch die komfortable Gangschaltung von
31 khz bis rauf nach 40 Mhz. Dennoch sind es eben 8 Bitter und bei Int32
rödeln die sich schon einen ab. Ich werde sie auch weiterhin als kleine
Helfer einsetzen, die Viecher mit 14 Pins sind teilweise randvoll mit
Peripherie gepackt, alles was man sich wünschen kann. Im Beruf sind sie
sehr oft in Sicherheitsschaltungen vorhanden.
Werde jetzt gleich einmal die RTC vom ARM ausprobieren, danke für den
Code auch! Und an diese Konstrukte wie (1<<5) werde ich mich wohl
gewöhnen müssen, denn bei PICs sind alle Steuerregister Bitadressierbar,
d.h. man gibt den Steuerbits Namen und besetzt sie mit Boolschen Werten,
erhält dadurch sehr übersichtlichen Code.
Womit ich beim ARM allerdings nicht klarkomme sind die Ports. Wer hat
sich das bloss mit dem IOSET und IOCLR ausgedacht? Wie soll man denn da
Datenwörter einspielen, die gleichzeitig anliegen müssen? Ich vermisse
mein PORTA = 0x46.
Gruss,
Christian
Christian J. wrote:
> gewöhnen müssen, denn bei PICs sind alle Steuerregister Bitadressierbar,
Das hat aber nicht nur mit den Prozessoren zu tun, sondern ist
hauptsächlich eine Eigenschaft der Include-Files für den Compiler. Die
gleiche Technik, Bitfelder in der Definition der I/O-Register zu
verwenden, würde auch bei anderen Architekturen funktionieren. Nicht
immer so effizient, aber auf Hochsprachenebene sähe es gleich aus.
> Womit ich beim ARM allerdings nicht klarkomme sind die Ports. Wer hat> sich das bloss mit dem IOSET und IOCLR ausgedacht?
Derjenige, der merkte, dass konventionelle I/O-Register wie bei PIC oder
AVR in einer Architektur ohne passende Bitset/clear-Befehle nicht nur
umständlich sind, sondern in Zusammenhang mit Interrupts auch noch
äusserst fehlerträchtig (1). In der ersten Generation der LPC2000 ist
allerdings vergessen worden, das simple Schreibregister ebenfalls zu mit
zu implementieren. Wurde später nachgeholt, beispielsweise im
LPC2138/01.
Andere ARM Implementierungen verwenden andere Techniken für die
I/O-Register. So ist die entsprechende ARM Primecell zu dieser Funktion
(verwendet beispielsweise in STR9 und LM3) in dieser Hinsicht eleganter
gebaut - dafür aber in an anderer Stelle problematisch. Ziemlich sauber
ist eine ähnliche Technik im Thumb2 Core definiert (LM3, STM32), aber
das ist immerhin auch die erste ARM Architektur speziell für Controller.
(1):
http://www.mikrocontroller.net/articles/Interrupt#Interruptfeste_Programmierung
let wrote:
> ^ Ist IOnPIN bei der ersten LPC Generation read-only? Ich habe hier> nur den 2136/01 bzw. 2148 und 2368.
Bei den LPC2106 und LPC2129 nebst Verwandten ja.
Dem aktuellen Manual vom LPC2138 zufolge gibt es das schreibbare IOPIN
auch schon, aber da gibt es auch den merkwürdigen Satz "Bit-level set
and clear registers allow a single instruction set or clear of any
number of bits in one port (LPC213x/01 only)", der suggeriert, dass
IOSET/IOCLR erst mit /01 existieren würden. Was ja nun falsch ist.
Andreas,
danke für Deine Ausführungen. Der Wecker tickt jetzt bei mir, noch
richtig, es ist ein externer Uhrenquarz dran.
Aber kann man diese Konstrukte
CCR = CCR & ~(1<<0); // Uhr stoppen (Bit 0)
CCR = CCR | (1<<CCR_CLKEN_BIT); // Uhr wieder starten
"Schreibe in das CCR den Wert, der sich aus dem CCR UND verknüpft mit
dem invertierten Wert einer um 0 Positionen verschobenen 1 ergibt"
nicht vereinfachen? Ich kriege da jedesmal einen Knoten im Hirn :-((
Geht das nicht wie beim PIC, so:
#bit CLKEN = CCR.0 // Deklaration
CCR.CLKEN = 1; // setzen
und man freut sich? Beim PIC sind die wirklich hardwaremässig
bitadressierbar. Der Compiler übernimmt nur die Umrechung der Adresse
und Position in eine Bitnummer, denn die ist fortlaufend über die
Register und kann somit sehr gross werden.
Das Headerfile bei Crossworks ist auch so lieblos dahingeschmiert, alles
untereinander geklatscht, keine Gruppen zusammengefasst, keine
Kommentare. Etwas mehr Mühe hätten die sich ja schon geben können
<grummel>
Christian J. wrote:
> und man freut sich? Beim PIC sind die wirklich hardwaremässig> bitadressierbar.
Nein. Die so ziemlich einzige Architektur mit echter Bitadressierung war
TI990 (70er). Alles andere adressiert Bytes (oder auch schon mal Worte).
Und setzt Bits indem gelesen, modifiziert und wieder zurückgeschrieben
wird.
Auch die PICs machen das nicht anders. Nur haben sie Befehle, die das in
einem Rutsch machen, während ARM dafür 3 braucht.
Aber niemand hindert dich daran, auf ARMs die I/O-Register als
Christian J. wrote:
> #bit CLKEN = CCR.0 // Deklaration
Wobei das kein C ist, sondern einer mehr oder weniger kranken Phantasie
eines Compilerbauers entspringt. Und zu genau dem Effekt führt, den du
hier beklagst: Du klebst an einem ganz bestimmten Compiler.
Was dir oben einen Knoten ins Hirn macht, ist das, was alle machen die
weder proprietäre Compilererweiterungen noch Bitfelder mögen. Und hat
den Vorteil, dass es überall genauso funktioniert.
Danke für den Tip!
Was bedeutet "extern" in dem Falle?
Beim CCS Compiler ist es wirklich so, dass der Code nicht portabel ist,
vor allem wegen des HAL. Aber wer damit zufrieden ist lebt damit sehr
gut. zudem das portiren auf einen anderen Prozessor sowieso schwierig
ist, wenn man Peripherie dran hat. Oder man übergibt die
Hardwarefunktion als Zeiger an die High-level Ebene zB bei der SD Karten
Verwaltung wurde das so gemacht, dass die Bitschieberei für jeden
Prozessor selbst geschrieben werden muss, nur das Management ist
allgemeingültig.
Christian J. wrote:
> Was bedeutet "extern" in dem Falle?
Sorry, aber das C Tutorial findet grad woanders statt.
PS: Hauptsächlich Faulheit meinerseits. Hatte keine Lust, hier die
übliche #define CCR (*(ccr_t *)0xAFFETOOT) Orgie konsequent
durchzuspielen.
Ok, lassen wir das..... noch ein Döschen "Faxe" aufmachen und dann in
die heia, für heute reicht es, morgen wieder an echte "Hardware" , siehe
http://www.der-scirocco.de/viewtopic.php?t=66
Hallo,
ich habe mich jetzt im GCC Manual und mit Google totgesucht aber leider
immer noch keine Lösung gefunden, wie man einen Struct auf eine feste
Adresse im Speicher abbildet.
1
structmystruct{
2
3
shortCLKEN:1;
4
shortCTCRTST:1;
5
shortCTTEST:2;
6
shortCLKSRC:1;
7
shortrest:3
8
};
Den will ich auf die Adresse
CCR -> (*(volatile unsigned long *)0xE0024008)
abbilden, so dass ich einzelne Bits mit CCR.CLKEN = 1 oder 0 setzen
kann. Nicht ganz klar ist mir auch, ob "short" da oben richtig ist.
Gruss,
Christian
Von der Performance her ist so etwas aber u. U. langsamer da solche
Zugriffe immer auf ein Read/Modify/Write hinauslaufen.
Das __attribute__((packed)) teilt dem Compiler mit das er bei
den Element der Struktur kein Word-Alignment zur Optimierung
durchführen, sondern alle Elemente Bit für Bit hintereinander
packen soll.
let wrote:
> Von der Performance her ist so etwas aber u. U. langsamer da solche> Zugriffe immer auf ein Read/Modify/Write hinauslaufen.
Muß nicht unbedingt sein.
Z.B. beim AVR wird das vom GCC korrekt in SBI/CBI umgesetzt.
Ich mag es auch lieber, wenn die Bits als Variablen definiert sind, ist
besser lesbar und weniger fehlerträchtig.
Außerdem hat man ja gerade deshalb nen ARM genommen, weil man massiv
32Bit-Berechnungen machen will und nicht viel Bitschubserei.
Bitschubsen können die 8Bitter nunmal besser, da muß man keinen ARM
vergewaltigen.
Nur weil man sich mit dem ARM beschäftigt, ist es ja nicht plötzlich
verboten, weiterhin 8Bitter einzusetzen.
Peter
>Muß nicht unbedingt sein.>Z.B. beim AVR wird das vom GCC korrekt in SBI/CBI umgesetzt.
Stümmt. Aber der ARM7 von unserem Schrauber kann das nicht.
>Bitschubsen können die 8Bitter nunmal besser, da muß man keinen ARM>vergewaltigen.
Du meinst "keinen ARM7". Der M3 dürfte die 8Bitter wieder übertreffen.
Der hat neben SBI/CLI auch Befehle für "Bit-Extraction" um auf
Bit-Bereiche (z. B. [2:5]) zuzugreifen. Aber auch der ARM7 kann mit
seinem Barrel-Shifter oft zaubern.
>ist es ja nicht plötzlich verboten, weiterhin 8Bitter einzusetzen.
Doch, doch. Sobald man sein erstes 32Bit .hex-File erstellt hat.
Und desweiteren darf man dann nicht mehr schlecht über ARM sprechen.
Bei Mac-Usern ist das ähnlich.
Sicher ist "Schrauber" korrekt :-) Bei so einem Sesselpfurzer Job wie
meinem die Erholung schlechthin.
Um die Bitschubserei kommt man leider bei den Steuerregistern nicht
drumherum und sowas wie ein "Flag" möchte man ja auch haben. Aber dafür
spendiert man beim ARM wahrscheinlich auch ein ganzes Byte.
Erstmal Danke für die Lösung! Werde das mal heute nacht ausprobieren.
Insgesamt frage ich mich wer die vielen hundert Funktionen und
Spezialausdrücke des GCC eigentlich braucht. Sachen wie "typeof" oder
eine "union" habe ich noch nie im Leben gebraucht und diese
_attribute_ Sache muss ich mir mal in Ruhe anschauen.
Gruss,
Christian
Nachtrag an "let":
Der Code funktioniert!
Nur frage ich mich grad, ob man den Ausdruck
#define REG_CCR (*((volatile struct ccr_s*)&CCR))
einfach hinnehmen soll wie er ist oder ob man den auch logisch verstehen
kann, so dass man selbst drauf kommt? Das Wörtchen "volatile" ist mir
noch heute suspekt, nach fast 20 Jahre mit C musste ich es noch nie
verwenden.
& ist "Adresse von..."
<variable>* ist "Zeigertyp auf...."
*<variable> ist "Inhalt von Adresse..."
Wäre ich doch bloss bei Pascal geblieben :-(
PS: Die Performance spielt keine Rolle, der GCC ist ohnehin ein
Bausteincompiler, der einiges mehr an Code erzeugt als es die reine
Assemblerlösung brauchen würde. Das wird aber durch die Geschwindigkeit
der ARM wieder wett gemacht.
Gruss,
Christian
Christian J. wrote:
> Das Wörtchen "volatile" ist mir> noch heute suspekt, nach fast 20 Jahre mit C musste ich es noch nie> verwenden.
Beim GCC mußt Du Dich dran gewöhnen und mußt es auch verwenden.
Der GCC ist da knallhart, wenn Du 2 Zuweisungen auf ne Variable machst,
dann wird die 1. gnadenlos wegoptimiert.
Z.B. wenn Du nen Portpin auf 0 und dann auf 1 setzt, um nen Taktimpuls
auszugeben.
Andere Compiler sagen sich, wenn der Autor 2 Zuweisungen hinschreibt,
dann wird er sich ja was dabei gedacht haben und lassen sie stehen.
Oder wenn ne Abfrage innerhalb einer Schleife erfolgt.
Den GCC muß man aber erst dazu zwingen, indem man die Variable als
volatile definiert.
Leider ist volatile kein Datentyp, zu dem man einfach casten kann.
Daher ist noch der zusätzliche Umweg über einen void Pointer nötig.
Peter
Peter,
kurze Frage: Was bewirkt volatile direkt?
Wenn a=5 und danach a=7 ist a=5 überflüssig, leuchtet ein.
In der GCC Beschreibung kommt das auch nicht eindeutig hervor.
Überdies habe ich mir mal meinen Kerninghan & Ritchie von 1989 mal
wieder hervorgekramt, Zeiger pauken. Ist doch schon ein Unterschied
vorhanden, wenn man sowas vorher nie gebraucht hat.
gruss,
Christian
Damit kann man dann über die üblich Dereferenzierung bei
Zeigern auf Strukuren arbeiten:
1
intmain()
2
{
3
REG_CCR->CLKEN=1;
4
}
'volatile' verbietet dem Compiler, wie Peter schon geschrieben hat,
Optimierungen beim Umgang mit solchen Variablen vorzunehmen.
Bei
1
PORTB.2=1;
2
PORTB.2=0;
zum Togglen der 'E' Leitung bei einem LCD würde die erste
Zuweisung wegoptimiert werden.
Ich hoffe das du bei deiner Einschätzung zu Assembler vs. C nicht
den CCS Compiler als Grundlage nimmst. Der GCC steht zwei oder drei
Stufen über dem PIC-C. Was bei den C-Compilern für die 8Bitter
noch hinzukommt ist ihr notorischer Drang zu 16Bit Berechnungen,
auch wenn 8Bit genügen würden.
Im Internet gibt es diverse Vorlesungsskripte zur Sprache C. Kannst
ja mal bei Google dein Glück versuchen. Der PIC-C ist mehr oder
weniger nur an C angelehnt.
Christian J. wrote:
> kurze Frage: Was bewirkt volatile direkt?
Man sagt dem Compiler damit, dass es in Bezug auf diese Variable Dinge
zwischen Himmel und Erde gibt, die sich seiner Kenntnis entziehen.
Hat zur Folge, dass jeder Variablenzugriff auf Quelltextebene auch exakt
einem Zugriff im erzeugten Code an entsprechender Stelle entspricht,
lesend wie schreibend.
> In der GCC Beschreibung kommt das auch nicht eindeutig hervor.
Muss auch nicht, da die GCC-Doku Kenntnis des C Standards voraussetzt.
Hallo Let,
danke für die Antwort, werde das heute abend mal umsetzen für diverse
Hardware.
Ach ja... da ich schon mal einen Fachmann hier habe :-)
Wie schafft man es unter Benutzung der IOSET und IOCLR Register eine
gescheite parallele Datenübertragung zu zu bekommnen, zB für 4 Bit
Displays?
Früher war das
1
PORTA=PORTA|(wert&0b00001111);
Aber mit den SET und CLR schauts doch irgendwie anders aus. Muss man da
mit den Bits jonglieren, zB eine Maske drüberlaufen lassen und je
nachdem ob 1 oder 0 dann IOSET oder IOCLR aufrufen?
Gruss,
Christian
Hier mal was zum Ablachen, bin heute wieder voll in die volatile-Falle
reingetappt:
Mit dem alten WINAVR liefs prima, mit dem von 2007 hat mir die
Software-UART plötzlich nur noch das letzte Byte ausgegeben, alle
anderen als 0x00.
Der Grund war, daß ich das Datenbyte nicht als volatile hatte, stört die
putchar-Routine ja auch nicht.
Bloß hat der neue GCC in seinem Inline-Wahn die mit ins puts reingezogen
und dann eben nur die letzte Zuweisung gemacht.
Man hatte ich ne Wut im Bauch.
Man muß sich bei jeder neuen GCC-Version immer auf derartige
Überaschungen gefaßt machen.
Peter
Hallo Peter,
ja, solche Sachen machen Spass, vor allem wenn man dann nach Stunden mit
dem Kopf vor die Wand rennen will.
Ich probiere grad was anderes und frage mich: Welche kranken Hirne haben
den Interrupt Controller VIC hier erfunden? <bäng> Das können nur
käsebleiche, frauenlose, picklige VHDL Junkys hinter ihren zugezogenen
Jalousien gewesen.
Mannomann, da blickt ja keiner mehr durch, so ein Drama um die paar
Interrupts <crazy-smiley>
Habe das alles mal umgestrickt. Funktioniert soweit. Was nicht mehr
funktioniert ist die Abfrage des PLOCK Bits in einer While Schleife, ob
die PLL gelockt wurde. Das bleibt immer Null. Vorher hats geklappt nach
der alten Methode.
Wenn du viel Pech hast, kriegt die Hardware mit, dass ein Bytezugriff
auf ein Wortregister erfolgt, und nimmt übel. Bei solchen
Steuerregistern ist die Bitfeld-Methode nicht anwendbar.
Bei der PLL steht darüber allerdings nichts drin. Beim VIC schon, der
mag nur Worte.
Er schreibt ja nicht, er liest. Und der Code sieht korrekt aus:
1
.L3:
2
ldrb r3, [r2, #137]
3
tst r3, #4
4
beq .L3
Schreibzugriff ist aber ebenfalls byteweise, daher meine Bedenken. Dass
unbenutzte Bits auch mal gesetzt werden ist wenig wahrscheinlich (im
Code auch nicht erkennbar).
Aber kann natürlich trotzdem sein, dass der Fehler woanders liegt.
Funktioniert es denn, wenn genau nur diese eine Abfragezeile durch die
klassische Version ersetzt wird, der Rest aber mit Bitfeldern arbeitet?
Hallo Andreas,
hier der ganze Code. Nein, sie funktioniert nicht, die anderen Bits habe
ich noch nicht getestet, ob die richtige Inhalte haben. Es klappt erst
wieder, wenn man auf die klassische Art zuzrückbaut. Die anderen
Register der PLL funktionieren aber, wenn man sie auf Bitfehler umbaut.
Es mag eine dumme Frage sein aber welche Breite haben denn die
Steuerregister? Hat der ARM unterschiedliche Längen, also mal 8 Bit, mal
32 Bit für ein Register? Es wird ja immer ein Zeiger auf 32 Bit erzeugt
durch "unsigned long..."
Wäre nett, was man das klären könnte, dann spare ich mir die Arbeit den
Registersatz auf Bitfelder umzubauen. Nachteil ist ja, dass man auch
mehr Code derzeugt, weil man keine zwei Bits gleichzeitig setzen kann,
es sei denn man definiert das Register noch mit einem neuen Namen auf
andere Art.
Das Programm läuft auch so, nur ist es blöd, wenn das Problem anderswo
wieder auftaucht. Was würde passieren, wenn man die Bitfehler auf 8 bzw.
tatsächliche Registerbreite mit Leerbits auffüllen würde?
Anmerkung: Ich war mal 1 Jahr bei NEC 1998, da wurde ARM Peripherie mit
entwickelt für die eigenen uCs, zumindest der IRQ Controller. Ich baute
seinerzeit ein FPGA Board für den internen AMBA Bus und flantschte es an
einen reinen ARM Core an, der als Softmakro vorhanden war. (Ein
Riesen-Chip mit 400 Pins). Damals war es eine Diskussion, dass man die
reserved Bits nicht beschreiben darf, weil das Verhalten undefiniert
sei.
1
/----DiePLLeinstellen
2
voidInitPLL(void)
3
{
4
5
PLLCFG->MSEL=PLL_M-1;
6
PLLCFG->PSEL=PLL_P-1;
7
PLLFEED=0xAA;//PLL Feed-Sequenz
8
PLLFEED=0x55;
9
10
PLLCON->PLLC=0;
11
PLLCON->PLLE=1;// PLL aktivieren
12
13
while(!(PLLSTAT->PLOCK));// Hier hängt er dann.
14
15
16
// Mit MAMTIM werden die Waitstates beim Flashspeicherzugriff //eingestellt
Beim letzten Mal, als ich mit gcc versucht habe die Register auf
Bitfelder zu "mappen", ging das schief. Hatte versucht, Code für
IAR-EWARM-compiler ohne Änderungen mit GCC compilieren zu können. IAR
bietet einer herstellerspezifische Erweiterung für so etwas. Andreas
Kaiser hat die Gründe angeschnitten. Der gcc hat Assembleranweisungen
für Bytezugriffe generiert, die der Core nicht akzeptiert hat, wollte
32-bit Zugriffe. (->exception, data-abort?). Grade nicht erinnerlich, ob
nur beim Schreiben oder auch beim Lesen. Experimente waren allerdings
mit einem LPC23xx, sollte aber nur eine untergeordnete Rolle spielen.
Vgl. auch: http://en.mikrocontroller.net/topic/81611#new und
http://gcc.gnu.org/bugzilla/show_bug.cgi?id=23623
Den Patch aus dem GNU bugzilla hatte ich vor einiger Zeit mal
ausprobiert. Hat nicht funktioniert. Dann den Schreiber des Patches
angeschrieben und gefragt, ob ich was falsch gemacht habe. Antwort in
der Art: ja, weiß, Patch behebt Problem nicht.
Langer Rede: selbst wenn es in irgendeiner gcc-Version mal funktionieren
sollte 32-Bit Zugriffe für bestimmte Adressen zu erzwingen, schreibt man
wenig portablen Code. Ein Satz Macros, dürfte da deutlich portabler und
dennoch halbwegs übersichtlich sein.
(Prosa: Diverser Beispielcode von Olimex ist auf die IAR-Erweiterung
angewiesen. Ist eine elende "Dummenarbeit", diesen zu portieren. Könnte
allerdings auch Absicht sein, Olimex stellt einige Eval-Boards und Code
dazu her, die IAR in "Kickstart-Bundles" verkauft bzw. IAR-EWARM als
Beispiele beilegt.)
Martin Thomas
Hallo,
hier mal die Antwort eines echten Profis, der eine Position bei einer
ARM Schmiede bekleidet:
Hallo Christian,
ich bin fast sicher, daß das an dem schönen Zauberwort "volatile" liegt.
volatile besagt, daß sich diese Variable asynchron zum Programmfluß
ändern
kann. Wenn volatile nicht angegeben ist, kann der Compiler die Variable
z.B. in ein Register legen oder anderweitig wegoptimieren. Am besten
schaust Du Dir mal den erzeugten Assemblercode an. Dann siehst Du, was
passiert.
Die Zeile "#define PLLSTAT ((volatile struct pllstat_s*) 0xE01FC088)"
definiert einen volatile Pointer auf die genannte Adresse. Damit darf
der
Zeiger asynchron geändert werden. Du willst aber sagen, daß das wo er
hinzeigt volatile ist. Daher müsste m.E. in dem struct "volatile
unsigned
int PLOCK : 1;" stehen. Außerdem ist mir nicht klar, wofür
"__attribute__((packed))" steht. Gepackte Strukturen sorgen
normalerweise
dafür, daß Integer Variablen ohne Lücken abgelegt werden. Das ist aber
nur
relevant, wenn zwischen mehreren ints ein char oder short steht. Wenn
nur
ints in den Strukturen sind, sind sie automatisch gepackt.
Spiel mal ein wenig rum und analysiere mal den Assemblercode.
Viel Spaß und schönen Gruß,
Michael
Christian J. wrote:
> Die Zeile "#define PLLSTAT ((volatile struct pllstat_s*) 0xE01FC088)"> definiert einen volatile Pointer auf die genannte Adresse.
Wenn das ein C-Profi von ARM ist, dann gute Nacht ARM.
Zeiger volatile: struct pllstat *volatile.
Ist nicht anders wie beim weit besser bekannten "const char *s". Da ist
schliesslich auch der "char" konstant, nicht der Pointer. Ein konstanter
Pointer auf variable Zeichen wäre dementsprechend "char *const s".
Wie auch immer, jedenfalls können das Compiler wie keil oder IAR auch.
Also muss der Kram irgendwie gehen und genau das werde ich heute abend
ausprobieren.
Das ist überhaupt kein Problem. Wirklich nicht. Ist ganz einfach. Du
musst nur den GCC so umschreiben, dass er auf die hier zweifelhafte
Optimierung von Bytezugriffen auf solche Bitfelder verzichtet. IAR/Keil
tut sowas nicht und deshalb geht es dort.
Hallo,
ich hab es aufgegeben, es geht einfach nicht. Jedes Bit was über der 8
Bit Grenze liegt kann nicht erreicht werden. Schade um die Arbeit.
Aber was anderes: Ich weiss, der Spruch "Besorg Dir ein C Tutorial!"
kommt bestimmt aber ausser dem K&R habe ich nichts hier bzw. finde ich
im Netz auch keine richtige. Wer wie ich nur mit einem eingeschränkten
Funktionssatz bisher gearbeitet hat, der stösst schon auf so manche
Hürde.
Ich möchte gern modularen Code schreiben, der die Hardware soweit als
möglich abstrahiert, wenn ich mit der SD Karte oder anderen Geräten
spiele, wie zB am SPI Bus angeschlossenen PIC Controllern. Daher habe
ich mich mal mit der Übergabe von Funktionen in der Parameterliste
befasst, denn das ging bei PICs mit dem CCS bisher nicht. Wollte ich
aber schon immer mal haben :-)
Durch Herumprobieren entstand das, wobei das Ergebnis passt, ich habe
einfach solange probiert, bis der Compiler durchlief und die Zahlen
stimmten.
Ist das so ok?
sollte es gehen. Es wundert mich das der Compiler die fehlende
Klammer um 'funk' nicht bemängelt.
Die Parameterliste darf nur bei einem C Compiler leer sein. Das
bedeutet dann das die Funktion eine beliebige Anzahl Argumente
übergeben werden darf (oder auch gar keine). Bei C++ bedeutet
'leer' genau das was da steht: keine Parameter.
Hallo,
danke für die C Buch Links, sind schon ausgedruckt.
Naja, ein IRQ Beispiel für Timer 0 ist schon gestern gescheitert, obwohl
der Code als beispiel beigelegt wurde und wirklich nichts anderes macht
alos ein paar VIC Register zu setzen und eine Blinke-LED Routine für
Timer 0 einzurichen. Blinkte nichts, IRQ wurde nicht angesprungen und ob
Timer 1 läuft war auch nicht sicher, dá man die Timer Register nicht im
Watch Fenster darstellen kann. Bei Crossworks vermisse ich diese
Möglichkeit die Steuerregister sehen zu können, man muss sie erst auf
Variablen zuweisen.