mein Board zeigt über die Core Clock Variable SystemFrequency=72Mhz an. Wenn ich die tatsächliche Taktzahl mit i++ messe, ergeben sich nur 3.789.608 Zyklen. Wer kann mir die Differenz zwischen System-CPU und tatsächlicher Taktzahl erklären? Wie kann man die tatsächliche Taktzahl anheben? Die Funktion zur Messung der Taktzahl beruht auf dem rtc interrupt und ist augenscheinlich in Ordnung: void cpuspeed(void){ uint64_t zlfcpu=0; zlrtc=0; led2_off; while(zlrtc<3); led2_on; while(zlrtc<13)zlfcpu++; led2_off; F_CPU=zlfcpu/10; lwi(15,5,"F_CPU:"); lgi(16,5,F_CPU); lcd_write("xx"); lgi(17,5,SystemFrequency); } Ich bin für jeden Hinweis dankbar
Das Problem ist hier schon einmal behandelt worden. Wenn man die Schleife teilweise auflößt - 100 x i++;i++;... - steigt die angzeigte Taktrate auf etwas über 7,1 Mhz. Braucht der ARM wirklich 10 Takte um die Operation i++ auszuführen? Jedenfalls scheint ein Prozessortakt eines ARM deutlich uneffektiver zu sein, als eines RISC-AVRs.
Hier kommt es nun drauf an, mit welchen Compilereinstellungen du das Programm übersetzen lassen hast. Dazu können auch immernoch Interrupts wärend des Zählens auftreten, die dein Ergebnis verfälschen würden.
Davon ab vergisst du, dass du mit jedem Schleifendurchlauf eine Variable vergleichst, die wohl noch volatile ist, da sie vom Interrupt erhöht wird. Der Vergleich kostet Zeit. Dazu rechnest du mit 64bit Variabel auf einen 32bit Prozessor. Hier muss der Code auch immer einen Vergleich durchführen um die Inkrementierung zu überprüfen, ob es keinen Überlauf einer 32bit Variabel gibt. Dieser Code auf einem AVR ausgeführt, würde dir ebenso ein "merkwürdiges" Ergebnis präsentieren wie auf einem ARM.
> Wenn ich die tatsächliche Taktzahl mit i++ messe, Das wird auch nicht über eine Variable gemessen. Und auch nicht über das Toggeln einer LED in einer Funktion -> man weiss nie, was der Compiler draus macht und man weiss nie, was der Compiler nach dem nächsten Update desselben draus macht. Die tatsächliche "Taktzahl" wird immer durch Hardware gemessen, alles andere ist ein Zufallsgenerator. - Kann der LPC den Systemtakt durch Hardware (also einen Pin entsprechend konfigurieren, den Rest macht die Hardware automatisch) auf einem Pin ausgeben? Wenn ja, nimm das und messe die Frequenz - Wenn nicht, dann gibt's Timer-, PWM- und weitere Ausgänge. Wenn du hierfür eine bestimmte Frequenz annimmst und diese als Berechnungsgrundlage für die Einstellungen der o.g. Peripherie verwendest sollte an den Pins dann auch eine entsprechende Frequenz rauskommen (bspw. 10ms für einen Timer-Ausgang oder eine PWM-Frequenz von 1kHz oder oder oder). Ralf
Vielen dank für die Tipps. Durch Austausch von 64bit gegen 32 bit steigt die "Tatktzahl" auf rund 14Mhz. Das gibt ein Verhältnis von 1:6 zur systemFrequency. Es geht mir um das Verständnis des PLLO-Systems. ich möchte im Prinzip sehen, wie sich die Änderung der Systemfrequenz auswirkt. Praktisches Problem ist, dass ich für die Übernahme von AVR-Funktionen -z.B. DS1820- eine delay-funktion brauche. Etwas vergleichbares zu _delay_ms habe ich nicht gefunden. Um eine brauchbare delay-Funktion hinzubekommen, ist es schon sinnvoll zu wissen, wievil takte der Vorgang i++ braucht. Wahrscheinlich gibt es für delay bereits eine standardisierte Lösung, ich habe sie aber nicht gefunden.
Wenn man nicht von Compiler-Einstellungen und -Versionen abhängig sein möchte, dann muss Assembler her. Ich verwende folgendes als Delay, braucht ca. 3 Cycles pro Iteration:
1 | # Assember for Delay |
2 | |
3 | # --------------------------------------------- |
4 | # mode of asembly |
5 | # --------------------------------------------- |
6 | .syntax unified |
7 | .thumb |
8 | .arch armv7m |
9 | |
10 | # --------------------------------------------- |
11 | # allocation |
12 | # --------------------------------------------- |
13 | .text |
14 | |
15 | # DelayLoop |
16 | |
17 | .global DelayLoopAsm |
18 | .thumb_func |
19 | DelayLoopAsm: |
20 | CBZ R0, DelayLoopAsmEnd |
21 | DelayLoopAsmLoop: |
22 | SUBS r0, 1 |
23 | BNE DelayLoopAsmLoop |
24 | DelayLoopAsmEnd: |
25 | BX LR |
26 | |
27 | |
28 | .end |
Für C sieht das so aus:
1 | void DelayLoopAsm(unsigned int delay); |
> Praktisches Problem ist, dass ich für die Übernahme von AVR-Funktionen > -z.B. DS1820- eine delay-funktion brauche. Och nöööööö, bitte nicht. Tut's dafür nicht ein ordentlich implementierter Timer? Ralf
Ziel ist eine delay-funktion, die wie beim AVR immer ohne weiteres Nachdenken problemlos funktioniert. Ob mit timer oder ohne timer ist mir egal. Man müsste dies aus systemFrequency ableiten können. So funktioniert es aber auch: void cpuspeed(void){ uint32_t i=0; zlrtc=0; led2_off; while(zlrtc<1); led2_on; while(zlrtc<3)i++; led2_off; F_CPU=i/1836; } _delay_ms(uint32_t ms){//genau auf 100sec uint32_t i,j=F_CPU*ms; for(i=0;i<j;i++); }
karl k. schrieb: > Ziel ist eine delay-funktion, die wie beim AVR immer ohne weiteres > Nachdenken problemlos funktioniert. Die funktioniert dort auch nicht immer problemlos :-) > So funktioniert es aber auch: Nun ja. Bei der nächsten Compiler-Version, andere Optimierungsstufe, anderer Frequenz etc. auch noch? Die leere Schleife bietet sich zum Wegoptimieren jederzeit an. Schon mal mit -Os probiert? Mach es einfach so, wie es Ralf vorgeschlagen hat. Das ist exakt. Früher oder später wirst Du Dich eh mit den Timern befassen, es sind genug da. Anregungen finden sich hier: Beitrag "STM32 Systicktimer wert in ms"
Da kann man aber auch gewaltig reinfallen. Bei den Cortexen ist es nicht wie beim AVR, dass jede Instruction sofort und immer gleich ausgeführt wird. Da der Flash in der Regel langsamer ist als die 120MHz die beim LPC1769 einstellbar sind, kann es passieren, dass da Wartezustände der CPU dazukommen, die nicht calkulierbar sind. Insbesondere das Allignment, also ob der Code der innersten Schleife auf Wortgrenzen liegt oder nicht kann da mal leicht 50% Unterschied erzeugen. Das hat mich schon mal zur Weißglut gebracht obwohl ich diese Funktionen auch nur sehr selten benutze. Ich stelle mal meine um das richtige Alignment erweiterte Funktion hier rein. Leider kenne ich die Ursprungsquelle nicht mehr.
1 | void DelayuS(uint32_t uS) |
2 | {
|
3 | uint32_t CyclestoLoops; |
4 | |
5 | CyclestoLoops = SystemCoreClock; |
6 | if (CyclestoLoops >= 2000000) |
7 | {
|
8 | CyclestoLoops /= 1000000; |
9 | CyclestoLoops *= uS; |
10 | }
|
11 | else
|
12 | {
|
13 | CyclestoLoops *= uS; |
14 | CyclestoLoops /= 1000000; |
15 | }
|
16 | |
17 | if (CyclestoLoops <= 100) |
18 | return; |
19 | |
20 | CyclestoLoops -= 100; // cycle count for entry/exit 100? should be measured |
21 | CyclestoLoops /= 4; // cycle count per iteration- should be 4 on Cortex M0/M3 |
22 | |
23 | if (!CyclestoLoops) |
24 | return; |
25 | |
26 | // Delay loop for Cortex M3 thumb2
|
27 | asm volatile |
28 | (
|
29 | // Load loop count to register
|
30 | " mov r3, %[loops]\n" |
31 | " .align 4\n" |
32 | // loop start- subtract 1 from r3
|
33 | "loop: subs r3, #1\n" |
34 | " nop \n" |
35 | // test for zero, loop if not
|
36 | " bne loop\n\n" |
37 | |
38 | : // No output registers |
39 | : [loops] "r" (CyclestoLoops) // Input registers |
40 | : "r3" // clobbered registers |
41 | );
|
42 | }
|
Beim OneWire sollte aber eine komplett andere Technik zum Einsatz kommen. Code dazu habe ich schon mal hier eingestellt: Beitrag "DS18x20 unter FreeRTOS und LPCXpresso 1769"
Vielen Dank für die Hinweise Der Link auf den systicktimer endet mit Das ganze hat noch 2 Probleme: - Ein Überlauf des Systick timers wird nicht beachtet, falls (mtime + end) > 2^32 ist hört die Funktion sofort auf - Die Funktion ist nur auf 1mS genau. Ein delay(2) kann zwischen 1ms und 2ms dauern. Das hilft zumindest für _delay_us nicht wirklich weiter. Die funktion mit CyclestoLoops -= 100; // cycle count for entry/exit 100? should be measured hat - wenn ich das richtig verstanden habe - den Vorteil dass so eine Art Multitasking mit mehreren Anwendungen gleichzeitig unterstützt wird, muss aber anscheinend auch kalibriert werden. Ich habe mein lpc-board seit weihnachten. Es war für mich äußerst Schwierig, überhaupt einen Zugang zu finden. (programmieren bootlader ging nicht, altera-clone ging nicht, erst die anschaffung des lpcxpresso-boards mit anschließendem Zersägen hat zum Zugang zum board geführt). Ich bin also erst dabei, meine avr-amwendungen auf arm zu transferieren, d.h. das lpc-board läuft (noch) nicht im multitasking. Aufgabenstellung für das delay ist damit nur die kalibrierte Verzögerung im us und ms- Bereich. das Board hält während des delays an und macht nichts anderes. Interrupts, die zu berücksichtigen wären gibt es nicht. Die kalibrierung über die rtc ist dann wohl naheliegend, da die rtc-clock nach meinem verständnis die einzige taktquelle von gleichbleibender berechenbarer größe ist. Die von mir vorgestellte Funktion ist offensichtlich geeignet, die Messung einer Anzahl von Takten während einer Secunde durchzuführen. Es wird aus dem Code auch nichts wegoptimiert. Das Blinken der Led und die Anzeige auf dem Lcd zeigen ausreichend an, dass es funktioniert. Zumindest beim Single Task ist eine einfache Schleife auch ausreichend geeignet, eine Zeitmessung vorzunehmen. Es geht nur um die Kalibrierung der Anzahl der Schleifendurchläufe. Interessant ist das 1wire-projekt. gibt es dazu noch neuere versionen? Ich habe eine Heizungssteuerung mit ca. 15 Sensoren, die ich von avr auf arm umstellen möchte. was mir noch vorschwebt, ist ein mp3 player mit einem vs1053. was ich bislang habe, ist eine startdatei für gpio, rtc und lcd. Nächste Schritte sind USB-Stick und sd-karte, dann rj45.
karl k. schrieb: > - Ein Überlauf des Systick timers wird nicht beachtet, falls (mtime + > end) > 2^32 ist hört die Funktion sofort auf Sorry, aber an dem zusätzlichen Vergleich wird es hoffentlich nicht scheitern. Du kannst auch einfach den Zähler vorher auf Null setzen. > - Die Funktion ist nur auf 1mS genau. Ein delay(2) kann zwischen 1ms und > 2ms dauern. > > Das hilft zumindest für _delay_us nicht wirklich weiter. Doch, das geht. Absolut zuverlässig in Produktion. karl k. schrieb: > Das Blinken der Led und die > Anzeige auf dem Lcd zeigen ausreichend an, dass es funktioniert. Das ist Zufall. Es ist so, wie es temp sehr schön dargestellt hat: Dort findest Du das "alignment" und ein (hoffentliche gezieltes) "nop". Und ich bin mir zu 99% sicher, dass die "static inline" Timer Variante feiner auflösen kann, weil sie weniger Instruktionen benötigt. Denn dort wird im Prinzip das gleiche wie in temp's ASM-Variante gemacht, nur halt mit dem Timer.
Vielen Dank für die Hinweise. Ich werde bei Gelegenheit die Delay-Funktion auf einen eigenen timer umstellen, der dann über die rtc kalibriert wird.
leluno schrieb: > der dann über die rtc kalibriert wird. Du kommst von einem Extrem ins andere :-) Zuerst eine ziemlich unsichere, und jetzt ultra-korrekt :-) Also wenn vorher die Variante mit "ohne Timer" funktioniert hat, dann wird die "mit Timer" auch ohne Kalibrierung funktionieren.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.