Hallo,
bei der Spielerei mit dem AD Wandler des LPC2138 fiel mir was
Sonderbares auf: Das 32 Bit Register AD0DR0 (=Kanal von Pin AD0.0)
enthält ganz oben 11 und muss daher maskiert werden und weiterhin spuckt
er 16 Bit Wert raus! Dabei ist die Auflösung doch nur 10 Bit, also bis
1023.
Was weiterhin auffiel ist, dass die Taktfrequenz von 4,5 Mhz bei 11
Cycles Sampling viel zu hoch ist, die Werte stimmen nicht. Erst wenn ich
wesentlich weiter runter gehe, also den APB Takt / 5 teile (~ 2,7 Mhz)
stimmen die Zahle und vor allem "flattern" sie nicht mehr. Dreht man
höher hat man immer wieder Ausreisser und der maximale Wert wird nicht
erreicht.
Hat da schonmal jemand Erfahrungen gesammelt?
Hier die Configuration:
1
unsignedintADC_Init(unsignedintchannel_mask)
2
{
3
// Pin konfigurieren
4
PINSEL0|=(0x01<<22);
5
PINSEL1|=(0x01<<22);
6
7
// Kanal 0 v AD0, CLKDIV = 1:5; Burst Mode, CLKS = 11, PDN = ON
das habe ich natürlich vorher studiert, BEVOR ich diese Frage hier
stellte. Und da steht nichts drin, da stehen auch keine Sample Zeiten
drin, da steht eigentlich nichts drin was da rein gehört, denn ein AD
Wandler ist etwas komplizierter, der braucht Sample & Hold Zeiten. Das
Datenblatt des ARM7 von Phlips ist wirklich "arm".
Und wenn man den GCC verwendet, dann wundert man sich auch, warum eine
1
for(i=0;i<10000000;i++)
Schleife als Zeitsteuerung plötzlich rasend schnell durchlaufen wird,
egal welcher Wert, wenn man den Optimization Level auf 3 setzt. Ein
Blick in den Assembercode: Die Schleife ist weg, existiert nicht mehr.
Der optimiert dann nämlich einfach die ganze Schleife weg und setzt i
nur noch auf den grössten Wert, was ich schlichtweg krank finde.
Gruss,
Christian
Hallo,
was erwartest Du?
Du sagst dem Compiler, er soll optimieren auf minimale Laufzeit oder
Codegröße, er macht genau das und Du maulst...
Ein solche Schleife macht nichts, außer Platz im Code kosten und unnütz
Rechenzeit zu verbraten, das Ergebnis ist eindeutig absehbar, also setzt
er es gleich.
Solche Busy-Loops waren schon zu meinen Z80 oder 6502-ASm-Zeiten sehr
unbeliebt, weil in dieser Zeit nichts anderes gemacht werden konnte und
vor allem keine User-Aktionen beachtet werden konnten.
Du kannst natürlich auch dort Deinen Willen durchsetzen und den Compiler
austricksen, das wird mindestens 1x die Woche hier erklärt.
Gruß aus Berlin
Michael
Hallo,
Nachtrag:
Ich hab mal interessehalber in das User-Manual geschaut,
logisch da evtl. Bits gesetzt, Bit31 DONE, Bit30 OVERRUN, 26:24 CHN
können/müssen natürlich gesetzt sein.
Außerdem sind bei mir Bit15:6 sehr wohl 10 Bit und keine 16 für das
Ergebnis V/Vref.
Den Rest habe ich mir nicht angeschaut, wird aber wohl auch
drinstehen...
Gruß aus Berlin
Michael
Christian J. wrote:
> Und wenn man den GCC verwendet, dann wundert man sich auch, warum eine>>
1
for(i=0;i<10000000;i++)
>> Schleife als Zeitsteuerung plötzlich rasend schnell durchlaufen wird,> egal welcher Wert, wenn man den Optimization Level auf 3 setzt.
Vollkommen klar, da es ein nutzloses Konstrukt ist wenn der
Schleifenkoerper leer ist.
Hallo,
der User oben hat das falsch verstanden, er meint das AD0GDR Register,
wo unter 15:6 das RESULT steht. Das Ergebnis einer Operation wird in
zwei Registern abgelegt, in jenem ist es zwischen anderen Bits
eingemauert.
Es gibt aber noch die ADxRx Register, die sind übrigens nicht im LPC
Headerfile mit drin (warum weiss ich nicht). Dort stehen die Ergebnisse
jedes ADC einzeln drin. Im Manual von Philips ist das auf der Seite 212,
ADDR0 bis ADDR7, jeweils für beide Wandler.
Den ADC einstellen reduziert sich auf das Bitweise Setzen des ADCFG
Registers im Burst Mode, dann rennt das Viech los und scannt fortlaufend
in einer Schleife alle gesetzten Pins, die im PINSEL als AD deklariert
wurden. Man muss nur noch aus den besagten Registern auslesen und
braucht sich um nichts weiter zu kümmern. Der Burst Mode kostet ca 2mA
mehr an Strom, die die Platine zieht.
Hier der Code für einen Pin am AD0.0
1
// Das AD Poti an AD0.0 auslesen
2
voidAD0_0_Init(void)
3
{
4
unsignedintapb,teiler;
5
6
// Pin AD0.0 konfigurieren
7
PINSEL0|=(0x01<<22);
8
PINSEL1|=(0x01<<22);
9
10
// richtige APB Frequenz ermitteln < als 4.5 Mhz
11
apb=PLL_GetAPBClock();
12
teiler=1;
13
while((apb/teiler>4500000)&&(teiler<10))
14
teiler++;
15
16
// Kanal 0 v AD0, CLKDIV = 4; Burst Mode, CLKS = 11, PDN = ON
Dort, im AD0DR0 (32 Bit) stehen 16 Bit Werte drin (obere 2 Bits sind
auch gesetzt). Nachdem ich damit etwas gespielt habe, habe ich bemerkt,
dass die letzten 4 Bit für die Tonne sind, die floaten nur herum.
Maximal 12 Bit aber auch nur so eben. Das Floaten wird weniger, wenn man
den uC ohne PLL laufen lässt und die APB Taktrate weit runter dreht,
klar, EMV lässt grüssen, 3.3V / 4096 sind nur noch 800uV.
Zum GCC Compiler: Plötzlich läuft mein "Flash Release", vorher kamen
immer seltsame Fehlermeldungen des Assemblers, die undeutbar waren. Und
mit Optimization Level 3 reduziert sich der Code von 3400 Bytes auf 1600
Bytes runter. Das Wörtchen volatile vorsichtshalber mal etwas öfter
verwendet und die Funktionen auf static gesetzt.
Insgesamt muss ich eines sagen: Der ARM mit Crossworks hat einen
gewissen Suchtfaktor entwickelt :-) Mit dem bunten Editor macht es
einfach Spass sauberen Code zu schreiben.
Gruss,
Christian
Nun, ich habe gerade kein aktuelles Datenblatt für den 2138.
Beim 2368 stehen die Daten an Position 15:6 in den Datenregistern.
Die separaten Register von die ADC Kanäle sind soweit ich weiß
erst mit dem 2138/01 eingeführt worden. Wenn du also so einen
hast, kannst du auch die FIO-Register der GPIO benutzen.
(F)IOPIN kann dann auch beschrieben werden.
Ich nehme an das du ein Headerfile vom 2138 verwendest. Die
zusätzlichen ADC- und FIO-Register fehlen dort.
FIO muß vor Verwendung aber aktiviert werden. Beim 2368 geht das
mit 'SCS |= GPIOM;'
>Mit dem bunten Editor macht es>einfach Spass sauberen Code zu schreiben.
Du kennst also Eclipse noch nicht? Dann aber ran ;)
Hmm....
Was seltsam ist, dass ich einen Fehler "Warning: Writeback of base
register ist UNPREDICTABLE" bekomme, wenn ich die LED Funktion aus dem
Timer IRQ heraus aufrufe... komisch. Muss man das was beachten, wenn man
aus einem ISR eine andere Routine aufruft? Anm: Die LED Routine wird
nirgendwo sonst aufgerufen, damit es keine Rekursion gibt.
Ein paar Worte zum ADC.
Natuerlich ist es ein 10-bit Wandler und man kann den verschieden
"anlehnen", also das LSB auf die Stelle "0" oder das MSB auf die
hoechste Stelle des 16-bit (halb)Wortes.
Es sollen ja auch noch 12-bit Wandler nachkommen, da laesst sich
Kompatibilitaet nur erreichen mit MSB aligned. Deshalb wurde das so
gemacht wie es ist. Natuerlich kannst Du die WErte auch als 16-bit Werte
verwenden, allerdings werden sich die 6 LSB nie veraendern.
Zum Thema Geschwindigket des ADC, das haengt natuerlich auch von der
Impedanz Deiner Quelle ab. Bei einer niederohmigen Quelle laesst sich
der ADC sehr wohl bei der angegebenen Geschwindigkeit betrieben.
Robert
Hallo,
nur als Info: Es ändern sich alle 16 Bits aber die letzten sind nicht
brauchbar.
Nochmal die Frage: Muss man etwas beachten wenn man aus einer ISR eine
andere Routine aufruft? Ich krieg da nämlich eine Fehlermeldung, erst
wenn ich die Inhalte der aufgerufenen Routine in die ISR kopiere klappt
es.
Wüßte nicht das es da etwas zu beachten gäbe. Aber der GCC hat
ein Problem mit der Codeerzeugung für ISR-Routinen. Zumindest im
Thumb-Mode funktioniert das nicht und Dateien die einen
ISR-Handler enthalten müssen im ARM-Mode übersetzt werden.
Es gibt zwei Alternativen dazu:
1. Man deklariert die Funktion als 'naked' und kümmert sich
selbst per ISR_BEGIN/ISR_END Makros (inline-ASM) um die Register
und Rücksprungadressen (Holzhammer-Methode).
2. Man baut einen ISR-Handler in den Startup-Code ein der den
Handler in C als normale Funktion aufruft. So machen es einige
Beispiele in der Sammlung von Martin Thomas (die ich übernommen
habe).
Soweit ich weiß hat Rowley auch Makros für ISR-Handler.
Hallo,
also die Holzhammer Methode vergessen wir mal lieber :-) Bei einem PIC
ja aber nicht bei einer derart komplexen CPU. Ich habe mal gesucht nach
dem Umsschalter für ARM und THUMB Code aber leider nichts gefunden.
Weiss nicht ob das ein #pragma ist oder sowas.
Vielleicht wäre eine Seite mit Codebeispielen ganz gut, bisher wurde ich
da nicht fündig. Nicht die grossen Projekte sonder die kleinen, die
bestimmte Funktionen demonstrieren.
Was sicherlich noch interessant sein dürfte wären Möglichkeiten Daten im
Flash abzulegen, etwa Messwerte. libmem bietet sich hier an. Aber ich
verlasse das Thema des Threads. Die Wissensneugier ist gross aber es
fehlen einfach die Beispiele und die Doku kann man insgesamt vergessen.
Ach ja... ein gutes Beispiel, wie man eine Library erzeugt wäre noch
toll, damit ich meine mühsam Universalfunktionen später einmal mit
einbinden kann, so wie unter Visual Basic fertige .dll eingebunden
werden können, wenn man deren Funktionssatz kennt. Bisher habe im im
Linker von Rowley dazu noch keine Möglichkeit gefunden den Object Code
einzubinden.
Gruss,
Christian