Hallo zusammen! Bislang habe ich eigentlich nur uCs á la 328p
programmiert... und taste mich gerade vorsichtig an einen ARM M3 heran.
Ich habe mir ein Board und einen Programmer zugelegt (siehe Anhang).
Nachdem ich mit CooCox diverse Probleme hatte und noch immer habe, bin
ich auf EmBitz umgestiegen. Hier funktioniert soweit scheinbar alles
einwandfrei. Zum flashen nutze ich CoFlash von ST (funktioniert wohl
auch einwandfrei). Nun wollte ich einfach mal eine LED zum blinken
bringen... doch nun verhält sich der Code recht seltsam und ich weiß
nicht wieso?!
#include "stm32f10x.h"
int main(void)
{
unsigned long c = 0;
SystemInit();
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
while(1)
{
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_SET);
for(c=0;c<100000;c++);
GPIO_WriteBit(GPIOC, GPIO_Pin_13, Bit_RESET);
for(c=0;c<100000;c++);
}
}
Wenn man die for-Schleifen wie oben gezeigt bis 100000 zählen läßt, ist
die LED aus! Zählen sie nur bis 1000, leuchtet die LED minimal. Bei 100
mit etwa 50% Intensität. Bei 10 und 1 hell!
Wieso? Sollte sie nicht immer langsamer blinken, desto größer die Grenze
gewählt wird? Und noch mal... es blinkt NICHTS! Es verhält sich ehr wir
ein DAC... ???
Welche Optimierungsstufe hast du eingestellt?
Ein halbwegs schlauer Compiler optimiert dir die Schleifen einfach raus,
weil sie am Programmverlauf an sich nichts, sondern nur die
Programmdauer ändern. Und das primäre Ziel ist eine möglichst kurze
Programmausführungszeit bei geringem Speicherbedarf.
GG schrieb:> Bullseye!!! :D
Naja, blind geworfen... ;-)
> Die Optimierung Stand auf Stufe 2. Bei -O0 läuft alles wie gewünscht!
Es ist übrigens eine gute Idee, hin- und wieder mal die
Optimierungsstrategie umzuschalten und zu schauen, ob das Design noch
"läuft". Sonst erlebt man evtl. beim nächsten Update mit einer neuen
Compilerversion eine unliebsame Überraschung.
Ok, wird gemacht. Dennoch verstehe ich nicht, was da "optimiert" wurde.
Selbst wenn dem Compiler die for-Schleifen unsinnig erscheinen und er
diese einfach entfernt hat, hätte die LED unabhängig vom eingestellten
Wert immer gleich "leuchten" müssen... ???
2cents schrieb:> dann sollte es mit voller Optimierung auch wieder laufen.
Dann sollte man zumindest das c vorher noch zur globalen Variablen
machen. Denn c ist innerhalb der main-Routine definiert, deshalb
kann es sich gar nicht (z.B. durch einen Interrupt) von ausserhalb
ändern. Das weiß der Compiler auch.
GG schrieb:> Ok, wird gemacht. Dennoch verstehe ich nicht, was da "optimiert" wurde.
Ich sehe mir da immmer das erzeugte Compilat an. Man lernst mit solchen
Dreizeilern seinen Compiler ganz gut kennen...
2cents schrieb:> ersetze> unsigned long c = 0;> durch> volatile unsigned long c = 0;>> dann sollte es mit voller Optimierung auch wieder laufen.
ja, das funktioniert! :)
Quatschkopf schrieb:> Als Delay-Funktion empfehle ich:
Leider hat die AFAIK je nach Compiler Optimierungsstufe
unterschiedliches Delay.
Für konstantes Delay muss man Hardware Timer oder Assembler bemühen.
Delay über Dummy-Operationen war schon vor 30 Jahren Unsinn.
Damals(tm) hatten DOS-Rechner tatsächlich einen Turbo-Knopf, mit dem man
von 8MHz auf höhere Taktung gehen konnte, für Anwendungen. Weil viele
Spieleprogrammierer genau diese Methode für die Warteroutinen genutzt
haben.
Nop schrieb:> Delay über Dummy-Operationen war schon vor 30 Jahren Unsinn.>> Damals(tm) hatten DOS-Rechner tatsächlich einen Turbo-Knopf, mit dem man> von 8MHz auf höhere Taktung gehen konnte, für Anwendungen. Weil viele> Spieleprogrammierer genau diese Methode für die Warteroutinen genutzt> haben.Jim M. schrieb:>> Für konstantes Delay muss man Hardware Timer oder Assembler bemühen.
was genau meinst Du mit "Hardware Timern"? Externe RTCs? Jeder
Prozessortimer leitet sich von der Taktfrequenz ab, also ist Alles, was
im Controller passiert, bei Änderung der Taktung beeinträchtigt. Das
passiert aber zumindestens bei Embedded relativ selten, und wenn,
funktioniert so ziemlich nichts mehr wie erwartet.
WENN schon ein busy waiting, kann man das beim Cortex M über den DWT
cycle counter machen, dessen Stand abhängig vom Takt immer einen
verlässlichen Wert liefert. Da die Taktfrequenz i.d. Regel aus dem RCC
ausgelesen werden kann, ist sogar die Mathematik relativ einfach, das
erforderliche Delta an Taktzyklen zu einem Delay auch bei sich ändernden
Taktfrequenzen für ein "absolutes delay" dynamisch zu berechnen, aber
wie gesagt sind dynamisch variable Taktungen ein eher akademisches
Problem.
Was Alles natürlich nichts daran ändert, dass busy waiting nur in
seltenen Fällen eine Berechtigung hat.
Nico W. schrieb:> Hat der Cortex M1 überhaupt nen DWT? Ist doch afaik erst in nem M3?!?
guter Punkt, aber wie kommst Du darauf, dass der 32F103xx auf einem M1
basiert? lt. ST Dokument RM0008 ist das ein M3?
Ruediger A. schrieb:> lt. ST Dokument RM0008 ist das ein M3?
Ja, da hast du auch wieder recht :)
Ich nutze bei meinem Projekt Assembler für ein kurzes Delay.
Ich nutze den DWT gerne dazu mein Projekt genauer zu betrachten wie
lange die Funktionen brauchen.