Forum: Mikrocontroller und Digitale Elektronik STM32 - Low Level Library Dokumentation


von Low-Level-Programmierer (Gast)


Lesenswert?

Mahlzeit allerseits

Ich hätte da mal eine Frage:
Gibt es irgendwo so etwas wie eine Dokumentation zur LL? Das, was sich 
im CubeMX Firmwarepackage unter Documentation verbirgt kommt mir eher 
wie ein schlechter Witz vor.

Es ist ja eigentlich nett und idiotensicher von ST gelöst, die 
Registerzugriffe hinter Funktionen zu verstecken. Wenn die Funktionen 
vernünftig benannt sind, kommt da gut lesbarer Code raus, finde ich. Das 
gefällt mir, auch besser als direkte Registerzugriffe mit logischen 
Verknüpfungen.

Aber wie finde ich z.B. die Funktion, mit der ich einen Timer loslaufen 
lassen oder wieder anhalten kann? Sich im Eclipseverschnitt durch die 
Autocodevervollständigung durchzuhangeln finde ich jetzt weniger gut, 
allzumal das teilweise etwas uneindeutig ist.

Und sich ein Beispielprojekt zu suchen in der Hoffnung, daß dieses die 
Hardware verwendet die man auch benutzen will...das ist eine nette 
Demonstration, aber keine Doku.

Und duckduckgo findet leider auch nichts außer Werbeflyer.

Ich suche eigentlich so etwas wie eine Funktionsübersicht oder so. Gibt 
es da irgendetwas hilfreiches?

Vielen Dank.

von Ben S. (bensch123)


Lesenswert?

Die wollen halt, dass du HAL benutzt. Lerne einfach den Mikrocontroller 
ohne irgendeine LIB über Registerebene zu verwenden.

von Harry L. (mysth)


Lesenswert?

Als Beispiel für die STM32F1xx findest du die Beschreibung hier:
https://www.st.com/resource/en/user_manual/dm00154093-description-of-stm32f1-hal-and-lowlayer-drivers-stmicroelectronics.pdf
Darin enthalten ist sowohl die Beschreibung für HAL wie auch für die 
LL-Treiber.

Das gibts auch für die übrigen Familien.

von errdzg (Gast)


Lesenswert?

die einzelnen files sind nicht so riesig. Ich bin bisher immer damit 
zurechtgekommen, einfach mal durch zu lesen, was es da so gibt. Da neben 
das ref manual, damit man versteht, was die Register tun.
Machmal ist es auch hilfreich, mit dem STM32CubeMX ein Projekt 
aufzusetzen und in den generierten Code zu schauen, wie z.B. die 
Initialisierung aussieht.
Und aus der Erfahrung raus: Es ist sehr viel angenehmer, die 
LL-funktionen zu verwenden, als selbst in den Registern rum zu stochern.

Viele Grüße,
Hermann

von georg (Gast)


Lesenswert?

Die einzige gute Doku von ST sind die in CubeMX mitgelieferten 
Beispielprojekte. Ansonsten hilft der griff zur Reference Manual, da die 
LL-Treiber in der Regel eh nur einzelne Registerzugriffe abstrahieren.

von Low-Level-Programmierer (Gast)


Lesenswert?

Ja, das Reference Manual kenne ich.

Danke für den Link...sowas hab ich gesucht (und danach für den F3 jetzt 
auch gefunden).

von W.S. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Es ist ja eigentlich nett und idiotensicher von ST gelöst, die
> Registerzugriffe hinter Funktionen zu verstecken. Wenn die Funktionen
> vernünftig benannt sind, kommt da gut lesbarer Code raus, finde ich. Das
> gefällt mir, auch besser als direkte Registerzugriffe mit logischen
> Verknüpfungen.
>
> Aber wie finde ich z.B. die Funktion, mit der ich einen Timer loslaufen
> lassen oder wieder anhalten kann?

Also was hast du eigentlich davon, wenn du für jeden HW-Registerzugriff 
anstelle des eigentlichen Zugriffs eine Funktion aufrufst? Willst du 
bloß Taktzyklen verbraten?

Ich glaube auch nicht, daß da ein guter Code herauskommt. Daß so etwas 
schön lesbar sein kann, glaube ich dir sofort - aber ist so etwas auch 
gut verstehbar? Oder kommt da gar ein guter Algorithmus bei heraus? 
Nein, eben nicht.

Lowlevel-treiber sollten die Dinge abstrahieren, also nicht so:

void SetzePin(int port, int bit, bool hi_lo);

sondern so:

void SchalteLampeEin(void);

Ich denke, du merkst den Unterschied: Das SetzePin abstrahiert überhaupt 
nichts, sondern verallgemeinert bloß. Noch mehr verallgemeinert wäre 
das:

void SetzeBit(int variable, int bit, bool hi_lo);

Aber wer braucht so etwas denn?

Zweck der Abstrahierung ist, daß man sich in den höheren 
Programmschichten eben NICHT mehr um die niederen Details zu kümmern 
braucht. Also nicht darum, wie denn nun die Lampe eingeschaltet wird. 
Aber so etwas bietet ST eben nicht an, sondern alles bleibt immerzu sehr 
ST-spezifisch.

Kann man verstehen, muß man aber nicht gut heißen.

Für dein Beispiel zum starten und stoppen des Timers würde auch gehören, 
ihn aufzusetzen, also Taktquelle, Flanke, intern/extern, Vorteiler und 
so weiter. Und das alles mit separaten Funktionen, wo doch viele 
Einstellungen im selben Einstell-Register vorzunehmen sind? Nein, hier 
ist der direkte HW-Zugriff gefragt - und dieser möglichst in einem 
separaten Lowlevel-Treiber, der ein hardwareunabhängiges Interface hat. 
Etwa sowas:
long MissZeitdifferenz(long TakteBisTimeout);

W.S.

von errdzg (Gast)


Lesenswert?

W.S. schrieb:
> Also was hast du eigentlich davon, wenn du für jeden HW-Registerzugriff
> anstelle des eigentlichen Zugriffs eine Funktion aufrufst? Willst du
> bloß Taktzyklen verbraten?

nachdem viele der ST-Funktionen inline definiert sind, hält sich der 
Overhead vermutlich in Grenzen. Und selbst wenn: Optimierung sollte 
immer der letzte Schritt sein, wenn die Software an sich funktioniert. 
Und das meiste holt man sicherlich nicht bei einer handgestrickten 
Initialisierung der Peripherie raus...

> Ich glaube auch nicht, daß da ein guter Code herauskommt. Daß so etwas
> schön lesbar sein kann, glaube ich dir sofort - aber ist so etwas auch
> gut verstehbar? Oder kommt da gar ein guter Algorithmus bei heraus?
> Nein, eben nicht.

Abstraktion hat erstmal nichts mit der Funktionalität an sich zu tun, 
eher etwas mit Wiederverwendbarkeit und Portabilität.

> Lowlevel-treiber sollten die Dinge abstrahieren, also nicht so:
>
> void SetzePin(int port, int bit, bool hi_lo);
>
> sondern so:
>
> void SchalteLampeEin(void);

Sinnvolle Abstraktion besteht aus mehreren Schichten. Sonst schreibt man 
die Software für jedes Projekt neu. In Deinem Beispiel also eher nicht:
void SchalteLampeEin(void);
sondern:
void SetzePin(LampenPin);
wenn das für die Applikation sinnvoll ist, kann man darüber ja noch was 
spezifischeres setzen:
dann habe ich ein Lampenmodul, das z.B. nicht nur anbietet:
Lampe_einschalten(Lampe1) sonder auch z.B. 
Lampe_aktiviereBlinken(Lampe1), oder Lampe_einschaltenMitTimeout(timeout 
in ms)

Auch ST bietet ja zwei Schichten an:
einmal die LL, die die Registerzugriffe abstrahiert und verständlicher 
macht. Um die selbst sinnvoll zu nutzen, sollte man durchaus wissen, wie 
die Register aussehen und die jeweilige Einheit aufgebaut ist.

die nächste Schicht bei ST ist dann die HAL, die die HW weiter 
abstrahiert und erweiterte Features wie Ringpuffer für den Usart, usw 
anbietet.

Die finde ich persönlich allerdings auch etwas überladen, weshalb wir 
uns auf Basis der LL eine eigene HAL gebaut haben.
Die Verwendung der LL hat dabei den Vorteil, das wir ohne größere 
Umbaumaßnahmen innerhalb einer Controllerfamile (STM32G0, STM32F1, 
STM32L0, usw) wechseln können.
Die darüberliegende Schicht ermöglich dann z.B. die "gleiche" 
Applikation auf einem STM32 oder auf einem STM8 o.ä. laufen zu lassen. 
Ein bisschen Anpassung ist im Zweifel schon nötig, aber kein Vergleich 
als wenn man alles mit direkten Registerzugriffen geschrieben hätte.

Viele Grüße,
Hermann

von W.S. (Gast)


Lesenswert?

errdzg schrieb:
> In Deinem Beispiel also eher nicht:
> void SchalteLampeEin(void);
> sondern:
> void SetzePin(LampenPin);

Nein, dein Beispiel ist schlecht, denn es setzt ja voraus, daß man die 
Lampe über ein Pin einschaltet. Das definiert man dann in einer .h und 
hat das dann in den Algorithmus eingeschleust, wo es nicht hin gehört.

Denn verschiedene Plattformen haben auch verschiedene Port-Definitionen 
und verschiedene Ansteuerung für Portpins und damit hat man dann den 
ganzen Kruscht mitten in den Programmteilen, wo eigentlich nur der 
Algorithmus hingehört, aber nicht die Einzelheiten der aktuellen 
Peripherie.

Das SchalteLampeEin() hingegen ist genau richtig, denn da kann die Lampe 
auch per I2C-Expander oder sonstiger Peripherie oder zum Beispiel auch 
per LAN bei den Antipoden angeordnet sein, OHNE daß es den Algorithmus 
betrifft, der die Lampe benutzen muß. Der Einzige, der wissen muß, wie 
die Lampe angeht, ist der Lowlevel-Treiber. Aber der ist sehr 
überschaubar, denn er hat ja nur diese eine Aufgabe.

So soll es sein: daß der Algorithmus so plattformunabhängig wie möglich 
sein soll. Die Umsetzung auf irgend eine spezielle Plattform macht dann 
ein recht einfach gehaltener Lowlevel-Treiber, der dann das EInzige ist, 
was man ändern muß, wenn man das Ganze woanders hin portieren will.

Du hast hingegen unbewußt eine unnötige Einschränkung vorgenommen. 
Extrapoliert man das, dann landet man unweigerlich wieder bei den 
plattform- und herstellerabhängigen Libs.

W.S.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

W.S. schrieb:
> Lowlevel-treiber sollten die Dinge abstrahieren, also nicht so:
>
> void SetzePin(int port, int bit, bool hi_lo);
>
> sondern so:
>
> void SchalteLampeEin(void);

Mal wieder W.S. geblubber.
Beide sind nicht das gelbe vom Ei.
Erstens steht hier STM32 im Titel, daher hat son Pin noch mehr config:
Pullupdown, speed, alternate function, usw.
Das packt man alles schön in const struct und übergibt den Pointer davon 
einer SetzeIrgendwas(const struct *pin);

Diese Funktion "SchalteLampeEin(void)" hat was von deinem Lernbetty 
Kopierpastencode ala:
Uart1_Init();
Uart2_Init();
Uart3_Init();
Also Code sinnfrei duplizieren wo eine Hauptfunktion reicht mit einem 
Pointer zu nem Pin.
Sei es init, set, clear oder sonstwas.
Diese Pointer kann man dann als Config struct einem Treiber reinwerfen 
statt auf hardcalls setzen zu müssen.

W.S. schrieb:
> Also was hast du eigentlich davon, wenn du für jeden HW-Registerzugriff
> anstelle des eigentlichen Zugriffs eine Funktion aufrufst? Willst du
> bloß Taktzyklen verbraten?

Mal wieder keine Ahnung von nichts!
Die LL Funktionen sind inline, da wird im Gegensatz zum HAL wirklich 
nichts verbraten.
Fang doch bitte erst an was zu tippen wenn du mal reingesehen hast, so 
machst du dich nur noch lächerlicher als du schon bist.

von Low-Level-Programmierer (Gast)


Lesenswert?

W.S. schrieb:
> Also was hast du eigentlich davon, wenn du für jeden HW-Registerzugriff
> anstelle des eigentlichen Zugriffs eine Funktion aufrufst? Willst du
> bloß Taktzyklen verbraten?

Was ich davon (Gebrauch von CubeMX) habe? Eine Kontrolle darüber, daß 
keine Parameter miteinander kollidieren, Hardwareressourcen doppelt 
belegt werden, ich muß mich um die Initialisierung nicht mehr kümmern, 
graphische Übersicht über die Takteinstellungen, ...

Auch wenn ich mit STM32 relativ unerfahren bin:
Zunächst einmal würde ich mich nicht darauf verlassen, daß der Compiler 
aus einem Funktionsaufruf in C auch tatsächlich einen Sprung im 
Maschinencode macht. Im Gegenteil, wenn in der Funktion nur eine 
einzelne Anweisung steht würde ich von einem halbwegs anständigen 
Compiler erwarten, den Aufruf wegzuoptimieren. Und andere schrieben ja 
schon 'Inline'.

Überhaupt halte ich es für reichlich sinnlos, in Hochsprachen (da zähle 
ich C dazu, auch wenn ich die Beschreibung von C als "Assembler mit 
syntaktischem Zucker" durchaus treffend finde) sehr viel Wert auf 
Performance zu legen. Sperrige Konstrukte wie überflüssige 
Arrayiterationen mal aussen vor gelassen.

Irgendwo geisterte hier mal ein Thread über so eine Fragestellung herum. 
Ich glaube, es war die Frage, wie man in einer for-Schleife die 
Abbruchbedingung am effizientesten prüft. Nachdem die Helden bestimmt 
über 50 Beiträge lang gestritten haben was denn nun besser ist, hat mal 
jemand das Compilat der zwei konkurrierenden Abbruchvarianten 
hochgeladen: Aus beiden Codestücken hat der Compiler denselben ASM-Code 
gestrickt.

Und Code, der besser lesbar ist, ist auch definitiv besser verstehbar.

von Stefan F. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Eine Kontrolle darüber, daß
> keine Parameter miteinander kollidieren, Hardwareressourcen doppelt
> belegt werden, ich muß mich um die Initialisierung nicht mehr kümmern,
> graphische Übersicht über die Takteinstellungen, ...

Ich habe CubeMx dreimal versucht, und jedes mal ist genau das passiert. 
Es beschützt dich eben nicht vor solchen Fehler, es sieht nur so aus. 
Das Programm ist voller Bugs, die mich ohne Erfahrung mit dem Framework 
total überfordert haben.

Die Programmierung anhand des Referenzhandbuchs macht mir hingegen keine 
Sorgen.

von Low-Level-Programmierer (Gast)


Lesenswert?

Dann danke ich für die Wahrnung...mal sehen, ob es dann klappt.

von Alex (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Das Programm ist voller Bugs

Welche Bugs?

Gruß,

von W.S. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Überhaupt halte ich es für reichlich sinnlos, in Hochsprachen ... sehr
> viel Wert auf  Performance zu legen.

Hmm.. da hast du eine eigentümliche Einstellung.

Aber ich schätze, du hast mich durchweg nicht verstanden. Was ist zum 
Beispiel, wenn du dein Programm mal von einem STM32 auf einen PIC32 
portieren willst? Oder (um es einfacher zu machen) auf einen LPC oder 
einen NUC120? Wenn du in deinen Algorithmen keine plattformspezifischen 
Dinge machst, dann kannst du die ohne Probleme woanders auch benutzen. 
Wenn du hingegen dort jede Menge Zeugs wie von Cube usw. drin hast, dann 
ist es mit dem Portieren weitaus miserabler.

W.S.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Alex schrieb:
> Welche Bugs?

79596 [MX-RCC] Wrong exported RCC configuration with LL drivers.
78859 [MX-G0][I2C] No SDA signal.
73371 [MX-MP][USART] Hardware flow control (RS485) not available.
70790 [MX-Code Generation] Incorrect OPAMP number assigned.
66665 [MX-MP][PINOUT] Pinout changes not updated.
52366 STM32F412 FSMC PB7 functionality: STM32CubeMX vs. datasheet 
discrepancy.
68063 [MX-L4][TIM2-GPIO] Line missed in code generation.
69542 [MX-USB]: USB pins set wrongly as alternate functions.
70459 [MX-F4][ADC] Cannot enable “DMA Continuous Requests”.
70965 [MX-L4][CLOCK] Wrong minimum frequency for ADC.
65919 [MX-F7][USB]: Speed setting for USB_OTG_HS Device missed.
66183 [MX-F7][QSPI]: Add disabled mode to dual-Flash parameter.
66502 [MX-L4+][SYSTICK] [LL]: SysTick is disabled after calling 
SystemClock_Config().
66652 [MX-F3][ADC-LL]: Wrong code gen in the configuration for ADC LL.
57986 Bug in STM32CubeMX / STM32F0 LL Library internal ADC channel.
62446 [MX-F7][SAI] Internal synchronization does not work.
63768 [MX-SPI] Cannot configure CRC poly.

Brauchste noch mehr?
Das sind nur die gefixten von v5.2 nach v5.6 und dann nur eine Auswahl 
meinerseits.

Bei sowas biste dann erstmal am suchen in der HAL.
Daher die LL direkt nutzen (wies der TE vorhat) oder nach Refman selber 
coden,

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

W.S. schrieb:
> Hmm.. da hast du eine eigentümliche Einstellung.

Wie oft willste eigentlich immer über dich reden?

W.S. schrieb:
> Aber ich schätze, du hast mich durchweg nicht verstanden.

Dein Geschwurbel ist auch unverständlich und voller "dont dos" ;)

von Alex (Gast)


Lesenswert?

Mw E. schrieb:
> Brauchste noch mehr?

Ne, vielen dank für die Aufführung.

Ich wurde nur einmal mehr darin bestätigt, HAL nicht zu nutzen.

Gruß,

von Stefan F. (Gast)


Lesenswert?

Alex schrieb:
>> Das Programm ist voller Bugs
> Welche Bugs?

Hatten wir auf mikrocontroller.net diskutiert. Ich will das nicht erneut 
aufkochen.

von Low-Level-Programmierer (Gast)


Lesenswert?

W.S. schrieb:
> Aber ich schätze, du hast mich durchweg nicht verstanden. Was ist zum
> Beispiel, wenn du dein Programm mal von einem STM32 auf einen PIC32
> portieren willst? Oder (um es einfacher zu machen) auf einen LPC oder
> einen NUC120?

Hätten mir direkte Registerzugriffe denn in diesem Fall was gebracht? 
Hat der PIC32 einen High Resolution Timer? Ist die Taktkonfiguration 
hinreichend bei beiden Controllern hinreichend identisch?


W.S. schrieb:
> Wenn du in deinen Algorithmen keine plattformspezifischen
> Dinge machst, dann kannst du die ohne Probleme woanders auch benutzen.

Eben, dafür gibt es Hochsprachen wie C. Dann lagert man 
plattformUNspezifische Dinge halt in eine Funktion aus, und übergibt 
alle notwendigen Daten in plattformUNspezifischen Datentypen. Oder liege 
ich da so falsch?

Wie gesagt, ich habe von STM32 leider nur wenig Ahnung (ändert sich 
demnächst hoffentlich), aber mit AVR-Assembler und mit C allgemein kann 
ich durchaus umgehen. Auch wenn ich den mit großem Abstand meisten Code 
bisher in Java geschrieben habe. Und eigentlich kein Programmierer bin.


Eine Frage hätte ich mal noch an Mw E:
Wo hast du die Fehlerliste ausgegraben? Ich glaube ich seh da schon 
etwas, das mir auf die Füße fallen könnte...

von Low-Level-Programmierer (Gast)


Lesenswert?

Ich hätte mal noch eine Frage:
Es gibt ja von ST allerhand Debug- und Profilerkram für 
Motorsteuerungen.

Gibt es auch ein Debug-Werkzeug, das z.B. ADC-Werte mitloggt und 
anzeigt?

von Johannes S. (Gast)


Lesenswert?

Kann ich nicht direkt beantworten, aber ST hat viel Doku und Application 
Notes, da sollte sich was finden lassen. Und wenn über eine 
Schnittstelle Momentanwerte abgefragt werden können, dann können die 
auch geloggt werden.

von Low-Level-Programmierer (Gast)


Lesenswert?

Ich hätte mal noch eine Frage zum ADC des F334:

Ich will jetzt zwei Kanäle auf einem ADC benutzen. Sehe ich das richtig, 
daß ich anhand der Flags nur sehen kann, daß:
1. ein neuer Wert konvertiert wurde und
2. ob der ADC mit einer Sequenz fertig ist?

Oder habe ich da noch etwas übersehen? Ein Register, welcher Kanal 
gerade selektiert war/ist, gibt es nicht?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Low-Level-Programmierer schrieb:
> Eine Frage hätte ich mal noch an Mw E:
> Wo hast du die Fehlerliste ausgegraben? Ich glaube ich seh da schon
> etwas, das mir auf die Füße fallen könnte...

Man suche nach "cubemx changelog pdf".
Dann kommt sowas:
https://www.st.com/content/ccc/resource/technical/document/release_note/b2/02/4b/e3/81/32/49/c4/DM00107607.pdf/files/DM00107607.pdf/jcr:content/translations/en.DM00107607.pdf
Da einfach mal durchstöbern.

Low-Level-Programmierer schrieb:
> Ich hätte mal noch eine Frage:
> Es gibt ja von ST allerhand Debug- und Profilerkram für
> Motorsteuerungen.
>
> Gibt es auch ein Debug-Werkzeug, das z.B. ADC-Werte mitloggt und
> anzeigt?

Mit dem ST-Link fällt mir da jetzt kein Weg ein.
Aber mit meinem J-Link Edu und J-Scope geht das.
https://www.segger.com/products/debug-probes/j-link/tools/j-scope/
Einen originalen ST-Link von ST kann man auf einen J-Link mini 
umflashen:
https://www.segger.com/products/debug-probes/j-link/models/other-j-links/st-link-on-board/
Ob dann J-Scope damit funzt kann ich dir leider nicht sagen, da musste 
experimentieren.

Low-Level-Programmierer schrieb:
> Ich hätte mal noch eine Frage zum ADC des F334:
>
> Ich will jetzt zwei Kanäle auf einem ADC benutzen. Sehe ich das richtig,
> daß ich anhand der Flags nur sehen kann, daß:
> 1. ein neuer Wert konvertiert wurde und
> 2. ob der ADC mit einer Sequenz fertig ist?
>
> Oder habe ich da noch etwas übersehen? Ein Register, welcher Kanal
> gerade selektiert war/ist, gibt es nicht?

Ich hab mal kurz ins F334 Refman gesehen, der ADC sieht ziemlich gleich 
aus mit dem vom F2/F4/L4, daher sage ich:
Nein, gibt es nicht.
Aber dafür gibts den DMA!
Du stellst den DMA auf Ringbuffer ein mit so vielen Elementen wie du ADC 
Kanäle samplen willst.
Dann hast du in einem Array immer den neusten ADC Wert.
Der ADC kann eh so schnell samplen, dass ein IRQ manchmal zu langsam 
abgehandelt wird.

Wenn dir das erstmal zu kompliziert ist:
Der F334 hat 2 ADC Instanzen und du willst erstmal nur 2 Kanäle.
Dann nimm doch einen ADC pro Kanal, so weiste immer was du ließt.

---

Ansonsten empfehle ich dir dich nicht weiter mit W.S. 
auseinanderzusetzen.
Er hat hier schon mehrmals im Forum gezeigt, dass er keine Ahnung hat.
Sein Magic Number Code der Lernbetty (ein Projekt, dass niemanden hier 
im Forum interessiert), bietet er auch bei jeder Gelegenheit als besten 
Code der Welt an.
Sein lustigster Klogriff letztens ist die Verteufelung von memcpy.
Da weis man echt nicht mehr was man dazu sagen soll ;)
Ansonsten evrteufelt er noch Debugger, denn Leute die sowas nutzen könne 
ja nicht programmieren! (schreibt er).
DMA mag er auch nicht, weil er nicht versteht was das ist und faselt 
dann imemr was von "das nimmt der CPU keine Rechenleistung ab" = keine 
AHnung was DMA ist aber gegen hetzen.
Außerdem siehst du ja, dass er nur mit Allgemeinplätzchen kommt, bei mir 
wirds konkret.

: Bearbeitet durch User
von Mitleser (Gast)


Lesenswert?

Mw E. schrieb:
> Er hat hier schon mehrmals im Forum gezeigt, dass er keine Ahnung hat.

Und du zeigst hier immer wieder, dass du kein Benehmen hast. Deine 
permanente Stänkerei gegen W.S. nervt.
Wir waren zwar auch mal jung, haben uns aber nicht im Ton vergriffen. 
Halt einfach mal den Mund!

von Low-Level-Programmierer (Gast)


Lesenswert?

Keine Sorge Leute, den W.S. kenn ich doch. Ich bin ja öfter hier, 
allerdings verirre ich mich selten in diesen Teil des µC-Boards. :)

Den DMA wollte ich erstmal vermeiden aber wie es aussieht ist es wohl 
doch sinnvoller, sich auch gleich damit zu befassen.

Vielen Dank bis hierher. :)

von Johannes S. (Gast)


Lesenswert?


von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Low-Level-Programmierer schrieb:
> Den DMA wollte ich erstmal vermeiden aber wie es aussieht ist es wohl
> doch sinnvoller, sich auch gleich damit zu befassen.

Ich klickma auf Thread beobachten mit ich die Fragen nicht verpasse.

So schwer ist der DMA nu aber auch wieder nicht, stells dir wie ein 
memcopy in Hardware vor.

von Paul G. (paul_g210) Benutzerseite


Lesenswert?

Wenn ich in der LL etwas nicht finde habe ich eigentlich nur im 
Referenzmanual nachgeschaut um welchen Register es sich hauptsächlich 
dreht. Zum Beispiel um zu prüfen welcher PIN den Interrupt getriggert 
hat suche ich nach dem EXTI_PR Register einfach in der entsprechenden 
smt32fxxx_ll_exti.h nach dem Register und finde dann meist schnell die 
passende Funktion. Zur Not schaue ich auch tatsächlich mal in die HAL 
Funktionen was für Schritte dort passieren...

von Low-Level-Programmierer (Gast)


Lesenswert?

Mw E. schrieb:
> Low-Level-Programmierer schrieb:
>> Ich hätte mal noch eine Frage:
>> Es gibt ja von ST allerhand Debug- und Profilerkram für
>> Motorsteuerungen.
>>
>> Gibt es auch ein Debug-Werkzeug, das z.B. ADC-Werte mitloggt und
>> anzeigt?
>
> Mit dem ST-Link fällt mir da jetzt kein Weg ein.
> Aber mit meinem J-Link Edu und J-Scope geht das.
> https://www.segger.com/products/debug-probes/j-link/tools/j-scope/
> Einen originalen ST-Link von ST kann man auf einen J-Link mini
> umflashen:
> 
https://www.segger.com/products/debug-probes/j-link/models/other-j-links/st-link-on-board/
> Ob dann J-Scope damit funzt kann ich dir leider nicht sagen, da musste
> experimentieren.

Ich hab da was gefunden von ST...CubeMonitor.
https://www.st.com/en/development-tools/stm32cubemonitor.html

Wenn es genauso "gut" funktoniert wie es immer von CubeMX gesagt wird, 
naja...aber wenn es gut funktioniert wäre das richtig große Klasse. Dann 
muß man den DAC nicht mehr als Debugschnittstelle mißbrauchen.

Testen werde ich es auf jeden Fall einmal. (Und natürlich berichten.)

von Low-Level-Programmierer (Gast)


Lesenswert?

So liebe Leute, ich hätte mal wieder eine Frage:

Ich habe jetzt hier für das Wochenende ein Discovery Board mit dem F3 
und will damit etwas spielen.

Jetzt frag ich mich: Wie lege ich in CubeIDE eine neue Bibliothek für 
das Projekt an?

Ich hab im Ordner Projektpfad\Core\libraries\ledcircle zwei Ordner: 
einer heißt "inc", dieser beinhaltet eine Datei "ledcircle.h" und der 
andere "src", dieser beinhaltet eine Datei "ledcircle.c".

Rechtsklick auf Projekt > Properties > C/C++Build > Settings > Tab 
Toolsettings > MCU GCC Compiler > Include paths und dort habe ich 
(aktuell) für [All configurations] den Pfad 
"${ProjDirPath}Core/libraries/ledcircle/inc/" hinzugefügt.

Jetzt meckert der Linker aber andauernd, das er keine Datei ledcircle.h 
finden kann.

Kann mir mal jemand erklären, ob ich da einen offensichtlichen Fehler 
gemacht habe? Oder kann erklären, wie das funktoniert?

von Stefan F. (Gast)


Lesenswert?

Ich lege die *.h Dateien immer in das gleiche Verzeichnis, wie die 
zugehörigen *.c Dateien. Ist einfacher so.

Zu einer eigentlichen Frage: Unterhalb von "MCU GCC Compiler" gibt es 
noch einen Abschnitt für den Linker, da musst du den Pfad auch 
einstellen.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Sicher, dass der Linker meckert?
Dem sind .h eigentlich eher egal oder haste da inline Code drinne?

Ansonsten fehlen eher Include Pfade im Makefile.
Die erkennt man durch "-I<Pfad>"

von c-hater (Gast)


Lesenswert?

errdzg schrieb:

> Abstraktion hat erstmal nichts mit der Funktionalität an sich zu tun,
> eher etwas mit Wiederverwendbarkeit und Portabilität.

So SOLLTE es sein.

Tatsächlich ist es aber eher so, dass diese ganzen unnützen 
HAL-Abstraktionen so geschreiben sind, dass sie vor allem genau eins 
tuen: deren Verwender möglichst weitgehend auf genau den einen 
Hersteller festzunageln.

Das gilt natürlich herstellerübergreifend für alle gleichermaßen.

Wer das nicht kapiert, ist ein Vollidiot. Ende der Ansage.

von Stefan F. (Gast)


Lesenswert?

Mw E. schrieb:
> Ansonsten fehlen eher Include Pfade im Makefile.
> Die erkennt man durch "-I<Pfad>"

Diese IDE arbeitet standardmäßig ohne Makefile.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Stefan ⛄ F. schrieb:
> Diese IDE arbeitet standardmäßig ohne Makefile.

Dann muss man den passenden Tab für die Includepfade suchen.
Wo die bei der CubeIDE sind kann ich aber nicht sagen.

von Stefan F. (Gast)


Lesenswert?

Mw E. schrieb:
> Dann muss man den passenden Tab für die Includepfade suchen.
> Wo die bei der CubeIDE sind kann ich aber nicht sagen.

Habe ich doch schon erklärt.

von W.S. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Eben, dafür gibt es Hochsprachen wie C. Dann lagert man
> plattformUNspezifische Dinge halt in eine Funktion aus, und übergibt
> alle notwendigen Daten in plattformUNspezifischen Datentypen. Oder liege
> ich da so falsch?

Da liegst du falsch. Man lagert die plattformspezifischen Dinge in 
Lowlevel-Treiber aus. Und nicht umgekehrt.

Ich gebe dir mal ein Beispiel:
Da hatte vor Zeiten mal einer einen Treiber für irgend ein Display 
geschrieben, was per I2C anzusteuern war. Er hatte also all die 
Spezifika des I2C-Anschlusses seines µC in diesen Treiber gepackt und 
damit war sein Treiber überhaupt nicht portabel, sondern NUR auf eben 
dieser HW zu benutzen.

Ist uneffektiv, weil schon beim nächsten Projekt alles wieder von vorn 
neu geschreiben werden muß.

Ich hab sowas ja auch schon gemacht, aber gänzlich anders:
- zuerst ein LL-Treiber für den I2C, der nach oben hin völlig 
plattformunabhängig ist. Im Prinzip braucht man dazu ja nur 5 
Funktionen:
 I2C_Init(void);
 I2C_Start(byte adresse, bool rw);
 I2C_Write(byte was);
 byte I2C_Read(void);
 I2C_Stop (void);
Das reicht, und was im Inneren des Treibers abgeht, interessiert die 
Welt oberhalb überhaupt nicht. Dieses Interface ist plattformunabhängig.

So, und dann den Treiber für das Display oben drauf. Er greift natürlich 
NICHT auf irgend eine Hardware zu, sondern benutzt den I2C-Treiber. 
Damit ist er ebenfalls plattformunabhängig.

Um also so ein Display auf irgend einem anderen µC zu benutzen, muß man 
lediglich den I2C-Treiber anpassen, nicht jedoch den Treiber des 
Displays.

Du siehst, daß das alles nicht durch C oder plattformunabhängige 
Datentypen  zu machen ist, sondern nur durch Zerteilen des 
Gesamtproblems in sinnvolle Schichten.

Und wenn man es gut gemacht hat, dann ist auch das Interface des 
Displaytreibers so gehalten, daß man mit dem gleichen Interface auch den 
Treiber für ein anderes Display schreiben kann. Dann braucht sich die 
darüberliegende Schicht, also das GDI, nicht um die niederen Dinge der 
Displayansteuerung zu kümmern, sondern braucht nur die Dinge der 
GDI-Schicht zu erledigen, also Linien zeichnen, Blöcke füllen, 
Schriftzeichen in verschiedenen Fonts an die Stelle X,Y zeichnen und so 
weiter.

Natürlich ist auch das GDI nicht zum Selbstzweck da, sondern es dient 
der darüberliegenden Schicht, die dir z.B. anzeigen will, welchen Sender 
du am Radio gerade eingestellt hast oder wieviel Benzin du grad getankt 
hast und wieviel das kostet.

Ich habe nicht umsonst ein so simples Beispiel wie
"void SchalteLampeEin(void);"
gewählt. Dieses Beispiel mag dir auf den ersten Blick primitiv vorkommen 
(und ist es ja auch), aber es steht für all die Lowlevel-Treiber, die 
das Bindeglied zwischen der Hardware ganz unten und den Algorithmen ganz 
oben darstellen. Und eine jede Schicht soll das Darunterliegende 
abstrahieren. Wer den I2C benutzen will, muß sich mit dem I2C auskennen 
- aber ihn interessiert eigentlich nicht, wie das im Detail bei dem 
gerade gewählten µC gelöst ist. Viel mehr interessiert ihn, daß seine 
Quelle, die auf den I2C zugreift, auch auf anderer HW so funktioniert 
wie sie soll. Und wenn man seine Kringel auf einem 12864 malen will, 
möchte man sich auch nicht an die Details des einen oder anderen 
Produkts festnageln, sondern das soll mit allen 12864 und auf allen µC 
funktionieren.

So, ist das jetzt etwas klarer?

W.S.

von Stefan F. (Gast)


Lesenswert?

W.S. schrieb:
> I2C_Init(void);
>  I2C_Start(byte adresse, bool rw);
>  I2C_Write(byte was);
>  byte I2C_Read(void);
>  I2C_Stop (void);
> Das reicht, und was im Inneren des Treibers abgeht, interessiert die
> Welt oberhalb überhaupt nicht. Dieses Interface ist plattformunabhängig.

Ich verstehe woraus du hinaus willst und stimme grundsätzlich zu.

Dein Beispiel ist allerdings unglücklich, weil es schon auf einem 
STM32F1 unmöglich funktionieren kann. Da muss man nämlich die beiden 
letzten empfangenen Bytes anders behandeln. Da bräuchtest du drei 
verschiedene read-Funktionen oder zusätzliche Parameter.

von W.S. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Wie gesagt, ich habe von STM32 leider nur wenig Ahnung (ändert sich
> demnächst hoffentlich), aber mit AVR-Assembler und mit C allgemein kann
> ich durchaus umgehen. Auch wenn ich den mit großem Abstand meisten Code
> bisher in Java geschrieben habe. Und eigentlich kein Programmierer bin.

Nun gut, wenn du ansonsten hauptsächlich Java geschrieben hast, dann 
liegen deine Schwerpunkte eben ganz woanders. Geht mir zwar ähnlich, 
dennoch waren und sind bei mir NEC 78K4, Fujitsu FR, ARM klassisch (NXP 
und Atmel), ARM Cortex (NXP, Nuvoton, ST), MicroChip PIC16 in Mode. Und 
das sind alles z.T. recht unterschiedliche Architekturen. FR ist z.B. 
bigendian - und das schlägt sich auf die Gestaltung von einigen Quellen 
nieder, vor allem Fonts.

Noch ein Rat meineseits: Klebe nicht zu fest an ST. Benutze wenigstens 
auch die LPC's von NXP - einfach um nicht Scheuklappen zu kriegen. ST 
ist da ziemlich scharf drauf, dir welche zu verpassen.

W.S.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Stefan ⛄ F. schrieb:
> Habe ich doch schon erklärt.

Es kommt mir eben noch etwas komisch vor, dass der Linker bei einer 
Headerdatei meckert.
Daher noch die Nachfrage ob wirklich der Linker meckert.
Wenns wirklich der Linker ist, dann hast du schon die Lösung gepostet.
Wenn nicht, dann müssen wir nochmal ran.

W.S. schrieb:
> I2C_Init(void);
>  I2C_Start(byte adresse, bool rw);
>  I2C_Write(byte was);
>  byte I2C_Read(void);
>  I2C_Stop (void);

Das ist nicht portabel.
Ein STM32L431 hat zb einen I2C mit Autostart und Autostop.
Der muss vorher die Byteanzahl wissen und möchte die nicht kleckerweise 
haben.

Außerdem fehlt dort eine übergabe ob I2C 1, 2 oder 3 oder mehr.
Also mal wieder setzen 6 an W.S. !

Außerdem machen deine Funktionen genau das was Low-Level-Programmierer 
geschrrieben hat, du hast nur mal wieder kein Leseverständnis.

von Stefan F. (Gast)


Lesenswert?

Hier ein blockorientiertes Beipiel für I²C, dass nicht nur auf AVR 
sondern auch auf STM32 und Lego Mindstorms umgesetzt wurde:
1
/**
2
 * Perform an I²C transaction, which sends 0 or more data bytes, followed by receiving 0 or more data bytes.
3
 *
4
 * @param slave_addr 7bit slave_addr (will be shifted within this function)
5
 * @param send_buffer Points to the buffer that contains the data bytes that shall be sent (may be 0 if not used)
6
 * @param send_size Number of bytes to send
7
 * @param receive_buffer Points to the buffer that will be filled with the received bytes (may be 0 if not used)
8
 * @param receive_size Number of bytes to receive
9
 * @return Number of received data bytes, or -1 if sending failed
10
 */
11
int i2c_communicate(uint8_t slave_addr, void* send_buffer, int send_size, void* receive_buffer, int receive_size);

von W.S. (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Dein Beispiel ist allerdings unglücklich,

1. Diese Kalamität bei diesen STM kenne ich.
2. Nicht das Beispiel ist unglücklich, sondern die Oberschlauheit von ST 
ist unglücklich. So herum. Ärgerlich ist es dennoch.
3. I2C war und ist bei sehr vielen µC einfach beschissen gemacht. Die 
einzigen, wo es recht gut gelöst war, ist NEC 78K4 gewesen. Aber NEC ist 
tot.

W.S.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

W.S. schrieb:
> 2. Nicht das Beispiel ist unglücklich, sondern die Oberschlauheit von ST
> ist unglücklich. So herum. Ärgerlich ist es dennoch.

Achsoo W.S. macht sich die Welt mal wieder wie sie ihm gefällt!
Du kennst nur die alten I2C ohne automatismem und willst nichts anderes 
wissen.
Bei den ATSAM gibts auch nette I2C mit schönen Extras.

von Low-Level-Programmierer (Gast)


Lesenswert?

Also: Ich habe dem Linker noch den Pfad mitgeteilt, jetzt sind es schon 
ein paar Fehlermeldungen weniger. Prima. :)

Welche Datei muß ich eigentlich einbinden, damit er die 
Low-Level-Funktionen wie LL_GPIO_SetPin() findet? Shift+Klick dirigiert 
mich zu einer Datei namens stm32f3xx_ll_gpio.h, aber diese einzubinden 
behebt den Fehler nicht.


@W.S.:

W.S. schrieb:
> Low-Level-Programmierer schrieb:
>> [..] plattformUNspezifische Dinge [..]
>
> Da liegst du falsch. Man lagert die plattformspezifischen Dinge in
> Lowlevel-Treiber aus. Und nicht umgekehrt.

...ich hab es doch extra groß geschrieben... :)

von Low-Level-Programmierer (Gast)


Lesenswert?

W.S. schrieb:
> Noch ein Rat meineseits: Klebe nicht zu fest an ST. Benutze wenigstens
> auch die LPC's von NXP - einfach um nicht Scheuklappen zu kriegen. ST
> ist da ziemlich scharf drauf, dir welche zu verpassen.

Ja, da hast du sicher recht. Welcher Chiphersteller wäre das nicht? :)

von Johannes S. (Gast)


Lesenswert?

oder man nimmt ein OS das NXP, STM, Nuvoton, Nordic, Freescale 
unterstützt und ein spi.write() funktioniert einfach ungeachtet der 
Hardware Kalamitäten.

von Stefan F. (Gast)


Lesenswert?

Bei Lego Mindstorms (sowohl mit der originalen Firmware als auch mit 
Lejos (Java)) kannst du mit I²C auch keine einzelnen Bytes senden und 
empfangen.

von c-hater (Gast)


Lesenswert?

Mw E. schrieb:

> Du kennst nur die alten I2C ohne automatismem

Nur eine Art von Automatismen ist akzeptabel: diejenigen, die eine 
"switch off"-Option haben...

Denn nix ist schlimmer als ein Automatismus, der bekanntermaßen unter 
bestimmten Umständen Scheiße baut, aber nicht abschaltbar ist, selbst 
wenn man schon weiss, dass genau diese Umstände eingetreten sind (bzw. 
eintreten werden)...

von Johannes S. (Gast)


Lesenswert?

W.S. schrieb:
> Aber NEC ist
> tot.

weil sie so viel besser waren als ST?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

c-hater schrieb:
> Nur eine Art von Automatismen ist akzeptabel: diejenigen, die eine
> "switch off"-Option haben...
>
> Denn nix ist schlimmer als ein Automatismus, der bekanntermaßen unter
> bestimmten Umständen Scheiße baut, aber nicht abschaltbar ist, selbst
> wenn man schon weiss, dass genau diese Umstände eingetreten sind (bzw.
> eintreten werden)...

Bei I2C ist es durchaus mal eine erfrischende Ausnahme.
Register setzen, DMA scharfstellen, go!
Die I2C Frames der ganzen Slaves sind ja ziemlich fest, das geht nach 
Schema X.
(Exoten bestätigen die Ausnahme)

von Johannes S. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Welche Datei muß ich eigentlich einbinden, damit er die
> Low-Level-Funktionen wie LL_GPIO_SetPin() findet?

hast du das define USE_FULL_LL_DRIVER gesetzt? Da in der Nähe wo auch 
die Includepfade sind, da sollten die defines rein. Dann berücksichtigt 
der Indexer die auch und zeigt den Quelltext aktiv/inaktiv an.

von Low-Level-Programmierer (Gast)


Lesenswert?

Gute Frage...ich finde keinen solchen Haken, den ich setzen könnte. :(

von Johannes S. (Gast)


Lesenswert?

das ist kein Haken, das ist in dem Dialog wo auch der Includepfad 
gesetzt wird, Symbols müsste es heissen. Schon lange kein Eclipse mehr 
benutzt.
oder Preprocessor.

von Low-Level-Programmierer (Gast)


Lesenswert?

Ah...ja, ich hab was gefunden, du meintest das hier? Preprozessor?

https://community.st.com/s/question/0D50X0000BsQvhYSQS/cubemx-ll-build-failure

Hab Ich drin, aber er meckert immer noch über ein "unresolved inclusion" 
bei besagter Datei stm32f3xx_ll_rcc.h.
In der main ist sie auch eingebunden, und da meckert er genauso.

von Johannes S. (Gast)


Lesenswert?

Puh. Nimm Mbed und eine LED blinkt in 10 Minuten.
Aber dann musst du deinen Nick ändern:)

von Low-Level-Programmierer (Gast)


Lesenswert?

Grmpf...

Er kommt jetzt nur noch mit einem einzigen Fehler raus:
1
make: *** [makefile:45: SandkastenF3.elf] Error 1
2
"make -j4 all" terminated with exit code 2. Build might be incomplete.

Kann mir jemand sagen was das heißen soll? Er markiert jedenfalls keine 
Datei mehr rot oder so.

von Johannes S. (Gast)


Lesenswert?

Könnte sagt er, wurde das .elf oder .bin was er bauen sollte vielleicht 
trotzdem erzeugt? Mit dem Parallelen kompilieren hatte Eclipse auch 
seine Probleme.

von Jedzia D. (Firma: Rast und Ruh) (jedzia)


Lesenswert?

Johannes S. schrieb:
> Puh. Nimm Mbed und eine LED blinkt in 10 Minuten.
> Aber dann musst du deinen Nick ändern:)

Mbed hat natürlich auch den Vorteil, dass sich die Kompilierzeit auf 
eine Minute verlängert und der Binärcode sich auf das 100-fache 
aufbläht.
Also zur Vollständigkeit halber: Das hat auch Konsequenzen und nicht nur 
Vorteile so ein "Komplett"-OS zu benutzen.
Oder war das als Scherz gemeint?:)

: Bearbeitet durch User
von Johannes S. (Gast)


Lesenswert?

Jedzia D. schrieb:
> Also zur Vollständigkeit halber: Das hat auch Konsequenzen und nicht nur
> Vorteile so ein "Komplett"-OS zu benutzen.

Gähn. Wurde hier schon x-mal diskutiert. Vor 15 Jahren wäre das ein 
Thema, wo 32 kB Flash noch viel war und 64 kB gar gigantisch. Vom RAM 
ganz zu schweigen.
Wer die die Zwänge hat damit auskommen zu müssen, mein Beileid.
Wer Angst hat das ein Blinky damit nicht mehr in einen F3 passt, der 
sollte auch die Finger davon lassen. Wenn das in einer Minute bei build 
all kompiliert, dann hast du einen superschnellen Rechner, da bin ich 
neidisch.
Aber ehrlich, das juckt mich nicht wenn ich die ganzen Probleme hier 
lese wie man ein SPI oder I2C ans Laufen bekommt. Ich will das Rad nicht 
mehr erfinden.
Grafikdisplays die nicht in TTY Geschwindigkeit Klötzchengrafik 
aktualisieren (mal touchGFX oder lvgl gesehen?), Ethernet nutzen, einen 
schnellen HTTP Server zu haben, eine aktuelle Stdlib nutzen zu können, 
ein C++ API mit dem Basiskram in Klassen vorliegen zu haben, Filesysteme 
zu nutzen auf Basis von SPIF, QSPIF, internem Flash, SD karten, das ist 
der Level den ich haben möchte ohne erstmal einen Codegenerator 
anstossen zu wollen. Da will ich hin bzw. habe es in weiten Teilen 
erreicht.
Scheiss auf 1 Minute kompilieren und 100 fachen Code für eine blinkende 
LED, das ist eben nicht nur Luft.
Und mit Eclipse rumärgern, nein da will ich jetzt gar nicht mehr mit 
anfangen. Schonmal versucht zu ergründen wie das automagische make 
arbeitet und versucht es zu beeinflussen?

von Jedzia D. (Firma: Rast und Ruh) (jedzia)


Lesenswert?

Eine gar nicht so schlechte Übersicht/Dokumentation lässt sich übrigens 
mit doxygen erstellen.

eine default config (-g) mit z.B.:
1
INPUT                  = Drivers/STM32F3xx_HAL_Driver
2
...
3
FILE_PATTERNS          = *_ll_*.c \
4
...
5
                         *_ll_*.h \
um nur die ll files mit einzubeziehen.

Johannes: Ich hatte nicht erwartet deine persönliche Leidensgeschichte 
zu hören. Ich meinte was ich schrieb nicht anekdotenhaft. Eine 
ordentlich auf die Problemstellung angepasste Lösung ist meist schlanker 
und performanter als eine auf höherer Abstraktionsebene und Generische. 
Das wird natürlich mit Zeit zum einarbeiten oder zur Softwarepflege 
bezahlt. Trotz das wir uns in einem Beitrag mit "Low Level" darin 
tummeln war mein Kommentar nicht als Seitenhieb gemeint. Es gibt halt 
auch Menschen, die zeitlich kurze Kompilate schätzen;)

von Johannes S. (Gast)


Lesenswert?

Jedzia D. schrieb:
> Es gibt halt auch Menschen, die zeitlich kurze Kompilate schätzen;)

Und das ist der Hauptgrund einen F3 zu benutzen?

von Low-Level-Programmierer (Gast)


Lesenswert?

Johannes S. schrieb:
> Könnte sagt er, wurde das .elf oder .bin was er bauen sollte vielleicht
> trotzdem erzeugt? Mit dem Parallelen kompilieren hatte Eclipse auch
> seine Probleme.

Also, eine .elf- oder .bin-Datei habe ich nicht gefunden.

Wenn es ein Problem mit parallelem Kompilieren gibt: kann man das nicht 
auf seriell umstellen? (Und wenn ja: wie?)

Wegen etwas Kompilierzeit mache ich mir jetzt nicht ins Hemd, das wäre 
für mich aktuell ein Luxusproblem.

von Jedzia D. (Firma: Rast und Ruh) (jedzia)


Lesenswert?

Johannes S. schrieb:
> Jedzia D. schrieb:
>> Es gibt halt auch Menschen, die zeitlich kurze Kompilate schätzen;)
>
> Und das ist der Hauptgrund einen F3 zu benutzen?

Falls sich das auf mich bezieht, was ich wegen des Zitats annehme: 
"Drivers/STM32F3xx_HAL_Driver" ist Beispielhaft gemeint und doxygen 
weiss nichts von irgendwelcher Hardware. Das ist komplett aus dem 
Kontext gerissen, wie auch andere deiner Annahmen über mich und 
Makefiles, etc. ... falls sich das auf mich beziehen sollte. Auf diese 
Idee würde ich allerdings nur im Traum kommen, da ich mich nicht 
angesprochen fühle, bzw. deinen merkwürdigen anekdotischen 
Gedankengängen nicht folgen kann.

von Johannes S. (Gast)


Angehängte Dateien:

Lesenswert?

worum ging es nochmal?

Low-Level-Programmierer schrieb:
> Also, eine .elf- oder .bin-Datei habe ich nicht gefunden.

Die parallel Option ist in dem Project properties Dialog versteckt, am 
Besten über die Suche links oben finden. Das ist aber nur ein kleiner 
Strohhalm, ich kenne das bisher nur als kosmetisches Problem das nur die 
Ausgaben durcheinandergewürfelt sind. Habe Eclipse aber auch schon 
länger nicht mehr benutzt.
Der Screenshot ist aus MCUXpresso, aber an der Stelle sollten die 
Eclipse Varianten gleich sein, trotzdem ohne Gewähr.


Hat das den vor den LL Änderungen schon funktioniert oder von Anfang an 
nicht? Hast du CubeMX zum Start benutzt?
Letzteres wäre der einfache Weg. Starten, mit 'Start my Project from 
STBoard' anfangen. Dann das vorhandene Board auswählen, damit werden die 
HW Voreinstellungen wie Clock und belegte Pins ausgewählt. Weitere Pins 
und Middleware nach belieben hinzufügen, Projekt speichern und dann 
'generate Code' drücken. Die CubeIDE auswählen und links auf die 
Advanced Options.
Da ist dann versteckt rechts oben die Auswahl ob HAL oder LL.

von Low-Level-Programmierer (Gast)


Lesenswert?

Hi

Also, die Parallel Jobs Settings hab ich auch, aber das hat nichts 
gebracht. Mist.

Ansonsten: Ich habe das Projekt in CubeIDE aufgezogen, und gleich als LL 
angelegt. Über die CubeMX-View, allerdings war ganz am Anfang noch etwas 
HAL
-Zeug drin weil ich USB nicht deaktiviert habe.
Und ich habe das Projekt anfangs über den Boardselektor zum passenden 
Discoveryboard ausgewählt, also im Prinzip alles so wie du geschrieben 
hast.

Aber mal sehen, vielleicht werd ich es mal als richtiges HAL-Projekt 
bauen, mal sehen obs dann wird.

von Low-Level-Programmierer (Gast)


Lesenswert?

Umstellung auf HAL hat nix gebracht, außer 168 Fehler (in generiertem 
Code). Und ich habe definitiv keine Lust, die alle zu beheben.

Dafür hatte ich danach den Spaß, alle include-Pfade wieder einzubauen, 
Eclipse hat die zwischendurch gelöscht. Nach einigen Ratespielchen (wars 
jetzt "${ProjDirPath}/Core/libraries/ledcircle/" oder doch 
"${ProjDirPath}Core/libraries/ledcircle/" bin ich zumindest wieder an 
der Ausgangssituation mit dem Fehler, daß er nicht bauen will.

Ach, ist das frustrierend...

von Low-Level-Programmierer (Gast)


Angehängte Dateien:

Lesenswert?

Ok..ich hab es jetzt. Im Supportforum wurde mir geraten, die Option -L 
einzuschalten (was immer die auch tut, ich hab keine Ahnung) und dabei 
fiel mir auf, daß "External Builder" aktiviert war. Nach Umstellung auf 
"Internal Builder" baut er jetzt brav das Projekt.

Falls irgendwer bei seiner verzweifelten Googlesuche auf diesen Thread 
stößt, im Anhang steht was ich umgestellt habe.

Mal sehen wie ich es jetzt aus der IDE auf den F3 bekomme...

von Johannes S. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Nach Umstellung auf
> "Internal Builder" baut er jetzt brav das Projekt.

ja, das ist das automagische make das ich schon erwähnte von dem man 
nicht genau weiss was es macht. Eclipse kann schon eine Menge, man muss 
es nur finden und wissen was die vielen Knöppe bewirken...

Low-Level-Programmierer schrieb:
> Mal sehen wie ich es jetzt aus der IDE auf den F3 bekomme...

oben sollten Launch oder Debug Buttons sein, den STLink wird ST schon 
vorkonfiguriert haben. Wenn das Board einen aktuellen STLink drauf hat 
(evtl. Update mit STLink Utility durchführen), dann kann man auch das 
.bin in das USB MSD vom Nucleo kopieren.

Zu der IDE müsste es auch ein mitgeliefertes Tutorial geben. oder das:
https://www.digikey.com/en/maker/projects/getting-started-with-stm32-introduction-to-stm32cubeide/6a6c60a670c447abb90fd0fd78008697

von Low-Level-Programmierer (Gast)


Lesenswert?

Den STLink auf dem Board hab ich schon auf die neuste Version 
aktualisiert (V2J34S0), und Verbinden mit dem STLink-Utillity ist auch 
kein Problem.

In der IDE macht er aber nix wenn ich auf Debug (F11) klicke. Eigentlich 
sollte da eine zweite Leiste mit den Debugger-Knöpfen aufgehen, macht er 
aber nicht. Das Projekt kompiliert er lediglich neu.

von Low-Level-Programmierer (Gast)


Lesenswert?

Übrigens ein sehr schöner Terminus: automagisch...ich glaub den merk ich 
mir. :)

von Johannes S. (Gast)


Lesenswert?

aus dem verlinkten getting started:
click Run > Debug As > STM32 MCU C/C++ Application.
Man muss eine Launch config erstellen, das macht ein STM Plugin.

von Stefan F. (Gast)


Lesenswert?

Johannes S. schrieb:
> click Run > Debug As > STM32 MCU C/C++ Application.

Wenn du mehrere Projekte offen hast, kommt er dabei oft durcheinander.

Ich klicke mit der rechten Maustaste auf den Projektnamen und dann auf 
Debug. Dann verwendet er immer die richtige Konfiguration.

von Low-Level-Programmierer (Gast)


Lesenswert?

Johooo...es scheint endlich geklappt zu haben. Ich mußte einen Suchpfad 
wieder entfernen (auch wenn in der Konsole "Build finished" steht, so 
versteckte sich da noch eine Meldung daß er eine Bibliothek nicht 
gefunden hat), CubeIDE wollte den ST-Link nochmal updaten, und noch 
allerlei anderes Zeug...jetzt gehts.

Bzw. heißt das: Jetzt geht gerade gar nix mehr, das Standardprogramm ist 
jedenfalls weg und vermutlich habe ich in meinem eigenen Programm 
vergessen, den Timer anzuwerfen.

Weiß vielleicht noch jemand, wie der Funktionsaufruf dazu heißt? Ich 
hätte so etwas wie LL_TIM_Enable() erwartet, aber so etwas gibts nicht. 
Nur ein Haufen Funktionen, die div. Features enablen.

von Stefan F. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> das Standardprogramm ist
> jedenfalls weg und vermutlich habe ich in meinem eigenen Programm
> vergessen, den Timer anzuwerfen.

Ich empfehle Dir, ein Source Repository wie Mercurial oder GIT zu 
verwenden und dann Zwischenstände von deinem Programm zu sichern. Damit 
kannst du später alle Änderungen nachvollziehen. Also GUI dazu dann 
TortoiseHG oder TortoiseGit.

von Low-Level-Programmierer (Gast)


Lesenswert?

Naja, das was ich jetzt hier habe ist ja nur ne Spielerei, um mit der 
Technik etwas warm zu werden. Und den Quellcode von dem Programm, mit 
dem das Discovery ausgeliefert wird, hab ich nicht. :)

Für ernsthafte Sachen verwende ich SVN oder GIT.

von Johannes S. (Gast)


Lesenswert?

egal was das Programm macht, mit einem Breakpoint im main sollte das da 
auch anhalten. Bei Cube gab es noch die Falle das man SWD da in der 
Pinconfig auch auswählen muss.

Git Unterstützung ist in doch im Eclipse schon länger mit drin? Früher 
musste man dafür ein Plugin installieren.

von Low-Level-Programmierer (Gast)


Lesenswert?

Eclipse wird ganz sicher GIT von sich aus unterstützen. Ich hab mir aber 
abgewöhnt, die internen Versionskontrollsystem zu benutzen, ich mach das 
lieber mit etwas externem.

von Low-Level-Programmierer (Gast)


Lesenswert?

So, doch noch ein paar Fragen.

So siehts in der main gerade aus:
1
int main(void)
2
{
3
  /* MCU Configuration--------------------------------------------------------*/
4
5
  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
6
  
7
8
  LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_SYSCFG);
9
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_PWR);
10
11
  NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_0);
12
13
  /* System interrupt init*/
14
15
  /* USER CODE BEGIN Init */
16
17
  /* USER CODE END Init */
18
19
  /* Configure the system clock */
20
  SystemClock_Config();
21
22
  /* USER CODE BEGIN SysInit */
23
24
  /* USER CODE END SysInit */
25
26
  /* Initialize all configured peripherals */
27
  MX_GPIO_Init();
28
  MX_TIM6_Init();
29
30
  /* Initialize interrupts */
31
  MX_NVIC_Init();
32
  /* USER CODE BEGIN 2 */
33
  LL_TIM_EnableCounter(TIM6);        //<--Breakpoint
34
  LL_TIM_GenerateEvent_UPDATE(TIM6); //<--Breakpoint
35
  /* USER CODE END 2 */
36
37
  /* Infinite loop */
38
  /* USER CODE BEGIN WHILE */
39
  while (1) {
40
    /* USER CODE END WHILE */
41
42
    /* USER CODE BEGIN 3 */
43
  }
44
  /* USER CODE END 3 */
45
}

Ich habe da mal zwei Haltepunkte reingesetzt, ein dritter Haltepunkt ist 
in der Timer-IRH-Funktion:
1
void TIM6_DAC_IRQHandler(void)
2
{
3
  /* USER CODE BEGIN TIM6_DAC_IRQn 0 */
4
  nextLedInCircle();               //<--Breakpoint
5
  /* USER CODE END TIM6_DAC_IRQn 0 */
6
  
7
  /* USER CODE BEGIN TIM6_DAC_IRQn 1 */
8
9
  /* USER CODE END TIM6_DAC_IRQn 1 */
10
}

Initialisierungen:
1
void MX_TIM6_Init(void)
2
{
3
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
4
5
  /* Peripheral clock enable */
6
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
7
8
  TIM_InitStruct.Prescaler = 72;
9
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
10
  TIM_InitStruct.Autoreload = 0;
11
  LL_TIM_Init(TIM6, &TIM_InitStruct);
12
  LL_TIM_DisableARRPreload(TIM6);
13
  LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_RESET);
14
  LL_TIM_DisableMasterSlaveMode(TIM6);
15
16
}
17
18
static void MX_NVIC_Init(void)
19
{
20
  /* TIM6_DAC_IRQn interrupt configuration */
21
  NVIC_SetPriority(TIM6_DAC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
22
  NVIC_EnableIRQ(TIM6_DAC_IRQn);
23
}

Sieht jemand, was da schiefläuft und warum mein Interrupt nicht 
aufgerufen wird?

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Mit dem ARR Register auf 0 läuft der Timer nicht los.

edit:
wenn LL_TIM_DisableARRPreload das ARR deaktiviert, dann ist es das 
nicht.
Aber im Timer gibts noch Maskierungsbits damit der IRQ den Timer auch 
verlässt und das wurd da nicht gesetzt.
Ein Event ist kein IRQ.
Mit einem Event kannste IRQ los einen ADC sample anstoßen zb.

: Bearbeitet durch User
von Fragesteller (Gast)


Angehängte Dateien:

Lesenswert?

Low-Level-Programmierer schrieb:
> So, doch noch ein paar Fragen.

Ich hätte auch eine: warum beachtest du nicht die Regeln beim
Posten von Beiträgen? Gelten die für dich nicht oder sind sie
unleserlich oder unverständlich geschrieben?

von Wühlhase (Gast)


Lesenswert?

Oh man...stimmt, ohne AutoReload funktioniert das nicht.
Ich habe da jetzt mal den Wert 1000 eingetragen, da sollte ich jetzt 
(mit Vorteiler 72, der Takt läuft mit 72MHz mit) alle ms einen Interrupt 
bekommen.

Wie gesagt: sollte. Ist aber leider nicht.
1
void MX_TIM6_Init(void)
2
{
3
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
4
5
  /* Peripheral clock enable */
6
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
7
8
  TIM_InitStruct.Prescaler = 72;
9
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
10
  TIM_InitStruct.Autoreload = 1000;
11
  LL_TIM_Init(TIM6, &TIM_InitStruct);
12
  LL_TIM_DisableARRPreload(TIM6);
13
  LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_RESET);
14
  LL_TIM_DisableMasterSlaveMode(TIM6);
15
16
}

Aber er bleibt in der while-Schleife in der main-Funktion.
Codebeispiele haben mich da auch noch nicht weitergebracht.
Hast du vielleicht noch eine Idee?

von Low-Level-Programmierer (Gast)


Lesenswert?

Ja...es läuft. :)

Update aktivieren vergessen...

von Fragesteller (Gast)


Lesenswert?

Ist jetzt <Low-Level-Programmierer> plötzlich <Wühlhase>?

Wie auch immer, <Wühlhase> darf sich auch an die vorher erwähnten
und immer lesbaren Regeln halten.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Und direkt in die Falle getappt zu nur ein Name pro Thread ;)

Ich hatte doch noch geschrieben, dass ein IRQ Mask Bit im Timer nicht 
gesetzt ist.
Willste denn nen IRQ beim Overflow oder wenn das Timerregister ein 
Compareregisterwert gleichkommt?
Du hast nämlich nur Events eingeschaltet und das sind keine IRQs.

von Low-Level-Programmierer (Gast)


Lesenswert?

Fragesteller schrieb:
> Ist jetzt <Low-Level-Programmierer> plötzlich <Wühlhase>?
>
> Wie auch immer, <Wühlhase> darf sich auch an die vorher erwähnten
> und immer lesbaren Regeln halten.

Jap...passiert mal, ich hoffe es nimmt mir niemand übel. Wenn man sich 
darauf verläßt daß normalerweise der Standardnick schon vom Browser im 
Feld eingetragen ist und dann schreibt man mal eben im Platinenforum 
oder so...
Mea culpa.

Aber ich denke, Low-Level-Programmierer passt, zumindest was STM32 
angeht, auch in mehrfacher Hinsicht besser. Daher bleib ich mal dabei. 
:)


Mw E. schrieb:
> Ich hatte doch noch geschrieben, dass ein IRQ Mask Bit im Timer nicht
> gesetzt ist.

Ja, das hast du. Ich hab allerdings nicht kapiert was du damit meintest 
und zu allem Überfluß auch noch vergessen, danach zu fragen. Gefunden 
habe ich den Funktionsaufruf dann doch noch im Beispielcode von ST.
Wenn es interessiert: mit der Low-Level-Library muß das so aussehen:
1
void MX_TIM6_Init(void)
2
{
3
  LL_TIM_InitTypeDef TIM_InitStruct = {0};
4
5
  /* Peripheral clock enable */
6
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM6);
7
8
  TIM_InitStruct.Prescaler = 72;
9
  TIM_InitStruct.CounterMode = LL_TIM_COUNTERMODE_UP;
10
  TIM_InitStruct.Autoreload = 1000;
11
  LL_TIM_EnableIT_UPDATE(TIM6);     //<- Diesen Aufruf vergessen
12
  LL_TIM_Init(TIM6, &TIM_InitStruct);
13
  LL_TIM_DisableARRPreload(TIM6);
14
  LL_TIM_SetTriggerOutput(TIM6, LL_TIM_TRGO_RESET);
15
  LL_TIM_DisableMasterSlaveMode(TIM6);
16
17
}

Ich hätte erwartet das CubeMX diese eine Zeile mit einbaut (ich hab das 
jetzt händisch eingefügt), werde jetzt aber mal noch etwas 
herumexperimentieren ob ich da auch was falsch eingestellt habe.


Jedenfalls vielen Dank für eure Hilfe bisher. Vielleicht komme ich heute 
abend noch dazu, CubeMonitor auszuprobieren.

PS:
@Mw E.:
Einen netten Basteltisch hast du da. Gefällt mir.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Low-Level-Programmierer schrieb:
> Einen netten Basteltisch hast du da. Gefällt mir.
Danke ;)

Low-Level-Programmierer schrieb:
> Ich hätte erwartet das CubeMX diese eine Zeile mit einbaut
IRQs muss man da noch extra Asuwählen,
Aber ich nutze den MX eh nur zum Pinbelegung auswürfeln.

von Fragesteller (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Jedenfalls vielen Dank für eure Hilfe bisher. Vielleicht komme ich heute
> abend noch dazu, CubeMonitor auszuprobieren.

Nicht links, nicht rechts schauen, und immer schön die Scheuklappen
anbehalten!

Fragesteller schrieb:
> Ich hätte auch eine: warum beachtest du nicht die Regeln beim
> Posten von Beiträgen? Gelten die für dich nicht oder sind sie
> unleserlich oder unverständlich geschrieben?

von Jedzia D. (Firma: Rast und Ruh) (jedzia)


Lesenswert?

Low-Level-Programmierer schrieb:
> Den STLink auf dem Board hab ich schon auf die neuste Version
> aktualisiert (V2J34S0), und Verbinden mit dem STLink-Utillity ist auch
> kein Problem.

Obwohl bestimmt die Welt davon nicht untergeht, aber V2J37S7 ist aktuell 
und deine Version ist aus dem März 2019!

... "Contains the application in its "historical" form: executable 
dedicated to Windows + dll. With all most recent firmwares (V1J13S3 for 
ST-Link/V1 boards, V2J37S7 for ST-Link/V2 boards, V2J37M26 for 
ST-Link/V2-1 boards, V3J7M2 for STLINK-V3 boards)

ST-LINK, ST-LINK/V2, ST-LINK/V2-1, STLINK-V3 boards firmware upgrade:
https://www.st.com/en/development-tools/stsw-link007.html
" ...

P.S: An GNU-make ist nichts selbst-magisch. Es ist vollkommen 
deterministisch, nachvollziehbar -> 
http://git.savannah.gnu.org/cgit/make.git und dabei ein großartiges Tool 
auf das man sich verlassen kann 
(https://savannah.gnu.org/bugs/?group=make).

von Johannes S. (Gast)


Lesenswert?

Jedzia D. schrieb:
> An GNU-make ist nichts selbst-magisch

Hat auch keiner behauptet.

von Low-Level-Programmierer (Gast)


Lesenswert?

Jedzia D. schrieb:
> Low-Level-Programmierer schrieb:
>> Den STLink auf dem Board hab ich schon auf die neuste Version
>> aktualisiert (V2J34S0), und Verbinden mit dem STLink-Utillity ist auch
>> kein Problem.
>
> Obwohl bestimmt die Welt davon nicht untergeht, aber V2J37S7 ist aktuell
> und deine Version ist aus dem März 2019!

In der Tat hast du da Recht. Ich habe erst ein Update mit 
STLink-Utillity gefahren, das hat mir diese Version als neuste 
vorgeschlagen. Und danach hab ich meinen Post verfasst.

Irgendwann hat CubeIDE aber auch noch einmal vorgeschlagen, den STLink 
zu aktualisieren und kam dann mit einer höheren Versionsnummer (welche 
weiß ich nicht mehr, wahrscheinlich die die du genannt hast).

Keine Ahnung warum das so ist...

Übrigens:
Ich habe gerade CubeMonitor erfolgreich zum Laufen gebracht und tracke 
damit jetzt eine Countervariable, mit der ich jeweils eine LED im Kreis 
leuchten lasse.

Wer es mal ausprobiern will: hier ist ein Video wie es benutzt wird:
https://www.youtube.com/watch?v=sTVds5rxM3w

Möglicherweise wird mir das Tool demnächst einiges einfacher machen. :)

von Stefan F. (Gast)


Lesenswert?

Ich finde lästig, dass ich immer wieder meine ST-Links updaten soll. 
Irgendwann geht das mal schief, und dann habe ich einen toten ST-Link.

Normalerweise update ich Firmware nur, wenn ich einen guten Grund dazu 
haben, das Update also für irgend etwas bestimmtes brauche. Aber die 
neue Cube Software lässt mir diese Wahl nicht mehr. Die verlangt immer 
nach nach einer sehr aktuellen Version.

von Jedzia D. (Firma: Rast und Ruh) (jedzia)


Lesenswert?

Ja, Stefan. Wir haben gerne alles unter Kontrolle und den Überblick:)

Ich hatte bei meiner Anmerkung auf den Softwarestand 
Low-Level-Programmierer's Absicht den "Cube-Monitor" auszuprobieren im 
Auge. Da diese Software neu heruntergeladen wurde kann es schon etwas 
ausmachen welche Versionen hier zusammenspielen und ich dachte, das 
erspart ihm Kopfschmerzen. Genau sagen kann ich das allerdings nicht. 
Hier ist die Einsicht wegen fehlender Quellen, bzw. der Komplexität der 
ganzen Infrastruktur natürlich sehr hoch. Der Wunsch nach Durchblick ist 
(bei mir) schon vorhanden, aber die Zeit, die man da investieren müsste 
überschreitet meine Hemmschwelle. Da muss ich eben mein Vertrauen 
entgegen bringen. Das ist genau so wie mit allen anderen komplexen 
Systemen, wie OpenSSL oder Firefox, etc. Da kann ich alleine nicht nach 
dem Rechten sehen und das Überschaubar halten.

Soll keine Kritik an deinen Einwänden sein, ich hab die auch, aber 
vielleicht solltest du deine Einstellung gegenüber Update-Prozessen 
dahingehend ändern, dass der Grundwert auf "Positive Sache" eingepegelt 
ist und nur Dinge, die wir sehr suspekt finden oder Erfahrung damit 
haben in einer (berechtigten?) "Update-Faulheit" münden. Es gibt Tage an 
denen funktioniert nach einem Update nichts mehr, aber auch das 
Gegenteil: Stundenlanges debuggen... Danach stellt sich die Krux als 
Nebenkriegsschauplatz dar und man fragt sich warum man so blöd war nicht 
upzudaten und all die Zeit verschwendet hat.

Entschuldigung, das ist ein weites und kontroverses Thema für sich 
allein genommen und hinterher ist frau immer schlauer! :)))

von Stefan F. (Gast)


Lesenswert?

Jedzia D. schrieb:
> und man fragt sich warum man so blöd war nicht
> upzudaten und all die Zeit verschwendet hat.

Glaube mir, natürlich habe ich schon hunderte Male Sachen auf gut Glück 
oder Neugier aktualisiert. Geholfen hat es aber noch nie bei irgendeinem 
akuten Problem.

Die wenigen male, wo Updates geholfen haben, passiert das ganz gezielt. 
Vorgestern z.B. konnte eine Kollegin eine Datenbank-Anwendung nicht mehr 
re-starten. Das Programm behauptete steif und fest, dass einige Tabellen 
nicht existieren würden - sie waren aber da und hatten passende 
Zugriffsrechte. Auslöser war, dass Cheffe vor zwei Wochen bei einigen 
Konfigurationstabellen "Versioning" aktivierte (ist ein neues Feature 
bei MariaDB). Danach habe ich dann gegoogelt, einen Bug Report gefunden 
und die Erkenntnis, dass ein neuer neuen MariaDB Connector das Problem 
behebt.

Wenn ich schon auf gut Glück jedes Updates herunter laden soll, dass mir 
angeboten wird, dann doch bitte wenigstens mit aussagekräftigen Release 
Notes. Aber nein, die muss ich mir mühsam selber suchen. Und da finde 
ich dann aktuell als einzige Erklärung diese:

"Improvements including the support of drag-and-drop programming of .hex 
files for ST-LINK/V2-1 and STLINK-V3 boards"

Auch so, und inwiefern soll das jetzt für die IDE relevant sein?

Das meine ich mit unnötigen Updates! Jedes Firmwareupgrade bringt das 
Risiko mit sich, das Gerät für immer unbrauchbar zu machen. Ich will 
dieses Risiko nicht für solche Pillepalle Änderungen an Features 
eingehen, die ich nicht einmal nutze.

Ärgerlich finde ich auch, dass ich die Release Notes zu älteren 
Versionen nicht finden konnte.

von Low-Level-Programmierer (Gast)


Lesenswert?

Hallo allerseits, da bin ich wieder.

Ich habe bis jetzt halbwegs erfolgreich mit Timerinterrupts 
herumgespielt, letztes Wochenede mit ADC/DMA angefangen, und stehe jetzt 
vor einem Problem:

Wenn ich ein neues Programm in den F3 übertragen will, kommt die Meldung 
"Error in final launch sequence: Failed to start GDB server."

Hat jemand eine Idee, was da das Problem sein könnte?

von Low-Level-Programmierer (Gast)


Lesenswert?

Noch etwas, was ich gefunden habe:
Im Debuggertab links, wo auch der Projektexplorer ist (öffnet man mit 
Klick auf die Wanze ganz rechts oben) steht eine Baumstruktur, die da 
sagt:

<terminated>SandkastenF3 (so heißt mein Projekt)
  -<terminated, exit value: 0> C:/sehr/langer/Dateipfad
  -<terminated, exit value: -1> ST-LINK (ST-LINK Gdb Server)


Außerdem gibt es noch einen Debuggertab unten, in dem steht außer 
Lizenzhinweisen aber nichts, was hilfreich aussieht.

Hat jemand eine Idee, wie ich das reparieren kann? Die IDE hab ich 
zwischenzeitlich schon neu installiert.

von Stefan F. (Gast)


Lesenswert?

Teste mal mit dem STM32 Cube Programner oder ST-Link Tool ob die 
Hardware noch heile ist.

von Low-Level-Programmierer (Gast)


Lesenswert?

Hm, also ein Target Connect mit dem ST-Link Utility ist erfolgreich.

von Stefan F. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Hm, also ein Target Connect mit dem ST-Link Utility ist erfolgreich.

Und Speicher auslesen geht auch?

Wenn ja, hast du wohl ein Problem mit GDB oder mit dessen Konfiguration. 
Die IDE legt für jede Debug-Konfiguration eine Datei im Hauptverzeichnis 
des Projektes an. Lösche die mal, und klicke dann mit der rechten 
Maustaste auf den Projektnamen und dann "Debug As...", dann auf "STM32 
Cortex-M C/C++ Application". Die IDE legt dann eine neue 
Konfigurationsdatei an.

von Low-Level-Programmierer (Gast)


Lesenswert?

Hm, du meinst die .cfg-Datei?
Die hab ich gelöscht, aber das Problem besteht weiterhin. Und CubeIDE 
hat die Datei auch nicht wiederhergestellt.

von Stefan F. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Hm, du meinst die .cfg-Datei?

Ja, die meinte ich

> Die hab ich gelöscht, aber das Problem besteht weiterhin.
> Und CubeIDE hat die Datei auch nicht wiederhergestellt.

Dann würde ich mal suchen, wo die IDE entsprechende Logfiles hin 
schreibt oder wie man das Logging einschaltet.

von Low-Level-Programmierer (Gast)


Lesenswert?

Ich habe hier mal den Inhalt des Logfiles, falls das weiterhilft:

Ganz unten steht zwar, daß er externen Speicher nicht initialisieren 
kann, aber mit dem Auslesen hatte ST-Link Utility zumindest bis gerade 
eben kein Problem.
Das ist jetzt seit gerade eben merkwürdigerweise anders. Vorher hat 
ST-Link Utility den Speicherinhalt beim Verbinden angezeigt, jetzt zeigt 
es nichts mehr an.
1
[0.000] initConfigParams():  Configuration flags start
2
[0.000] initConfigParams():  +external-init                  true
3
[0.000] initConfigParams():   pend-halt-timeout              (null)
4
[0.000] initConfigParams():   halt                           false
5
[0.000] initConfigParams():   config-file                    ""
6
[0.000] initConfigParams():   persistent                     false
7
[0.000] initConfigParams():  +log-file                       "C:\Users\Projektpfad\SandkastenF3\Debug\st-link_gdbserver_log.txt"
8
[0.000] initConfigParams():  +log-level                      31
9
[0.000] initConfigParams():  +port-number                    61234
10
[0.000] initConfigParams():  +verbose                        true
11
[0.000] initConfigParams():   refresh-delay                  15
12
[0.000] initConfigParams():  +verify                         true
13
[0.000] initConfigParams():  +swd                            true
14
[0.000] initConfigParams():   swo-port                       61234
15
[0.000] initConfigParams():   cpu-clock                      8000000
16
[0.000] initConfigParams():   swo-clock-div                  128
17
[0.000] initConfigParams():  +initialize-reset               true
18
[0.000] initConfigParams():   debuggers                      false
19
[0.000] initConfigParams():   serial-number                  ""
20
[0.000] initConfigParams():  +apid                           0
21
[0.000] initConfigParams():   attach                         false
22
[0.000] initConfigParams():  +shared                         true
23
[0.000] initConfigParams():   erase-all                      false
24
[0.000] initConfigParams():   memory-map                     ""
25
[0.003] initConfigParams():   ext-memory-loaders             false
26
[0.004] initConfigParams():  +extload                        "512W3A_STM3210E-EVAL.stldr"
27
[0.004] initConfigParams():  +stm32cubeprogrammer-path       "C:\Program Files\STMicroelectronics\STM32CubeIDE_1.3.0\STM32CubeIDE\plugins\com.st.stm32cube.ide.mcu.externaltools.cubeprogrammer.win32_1.3.0.202002181050\tools\bin"
28
[0.004] initConfigParams():   temp-path                      ""
29
[0.004] initConfigParams():   preserve-temps                 false
30
[0.004] initConfigParams():   frequency                      -1
31
[0.004] initConfigParams():   licenses                       false
32
[0.004] initConfigParams():   ignore-rest                    false
33
[0.004] initConfigParams():   version                        false
34
[0.004] initConfigParams():   help                           false
35
[0.004] initConfigParams():  Configuration flags end
36
[0.029] init():  STMicroelectronics ST-LINK GDB server. Version 5.5.0
37
Copyright (c) 2019, STMicroelectronics. All rights reserved.
38
[0.604] Device_Initialise():  Target connection mode: Under reset
39
[0.693] reset_hw_wtchpt_module():  Hardware watchpoint supported by the target 
40
[0.746] Device_Initialise():  COM frequency = 4000 kHz
41
[0.750] Device_Initialise():  ST-LINK Firmware version : V2J36S0
42
[0.750] Device_Initialise():  Device ID: 0x422
43
[0.751] Device_Initialise():  PC: 0x8001b50
44
[0.755] Device_GetStatus():  ST-LINK device status: HALT_MODE
45
[0.757] Device_Initialise():  ST-LINK detects target voltage = 2.91 V
46
[0.773] Device_Initialise():  ST-LINK device status: HALT_MODE
47
[0.774] initExternalMemory():  Found external memory initializer at 0x2000162d
48
[0.774] initExternalMemory():  Writing external memory initializer seg at 0x20000004 (0 byte)
49
[0.884] initExternalMemory():  lastAddr = 0x20002424
50
[0.884] initExternalMemory():  Writing external memory initializer seg at 0x20002424 (0 byte)
51
[0.890] initExternalMemory():  lastAddr = 0x200024ec
52
[0.898] initExternalMemory():  PC: 0x2000162d
53
[0.899] initExternalMemory():  MSP: 0x200028e0
54
[0.901] initExternalMemory():  LR: 0x200024ec
55
[0.901] initExternalMemory():  Run external memory initializer
56
[0.907] Device_GetStatus():  ST-LINK device status: RUN_MODE
57
[0.912] initExternalMemory():  PC: 0x80018e8; ret: 0
58
[1.017] initExternalMemory():  PC: 0x80018e8; ret: 0
59
[1.134] initExternalMemory():  PC: 0x80018e8; ret: 0
60
[1.254] initExternalMemory():  PC: 0x80018e8; ret: 0
61
[1.374] initExternalMemory():  PC: 0x80018e8; ret: 0
62
[1.484] initExternalMemory():  PC: 0x80018e8; ret: 0
63
[1.603] initExternalMemory():  PC: 0x80018e8; ret: 0
64
[1.729] initExternalMemory():  PC: 0x80018e8; ret: 0
65
[1.834] initExternalMemory():  PC: 0x80018e8; ret: 0
66
[1.951] initExternalMemory():  PC: 0x80018e8; ret: 0
67
[2.060] initExternalMemory():  PC: 0x80018e8; ret: 0
68
[2.164] initExternalMemory():  PC: 0x80018e8; ret: 0
69
[2.289] initExternalMemory():  PC: 0x80018e8; ret: 0
70
[2.409] initExternalMemory():  PC: 0x80018e8; ret: 0
71
[2.524] initExternalMemory():  PC: 0x80018e8; ret: 0
72
[2.624] initExternalMemory():  PC: 0x80018e8; ret: 0
73
[2.727] initExternalMemory():  PC: 0x80018e8; ret: 0
74
[2.844] initExternalMemory():  PC: 0x80018e8; ret: 0
75
[2.944] initExternalMemory():  PC: 0x80018e8; ret: 0
76
[3.044] initExternalMemory():  PC: 0x80018e8; ret: 0
77
[3.164] initExternalMemory():  PC: 0x80018e8; ret: 0
78
[3.284] initExternalMemory():  PC: 0x80018e8; ret: 0
79
[3.404] initExternalMemory():  PC: 0x80018e8; ret: 0
80
[3.524] initExternalMemory():  PC: 0x80018e8; ret: 0
81
[3.644] initExternalMemory():  PC: 0x80018e8; ret: 0
82
[3.750] initExternalMemory():  PC: 0x80018e8; ret: 0
83
[3.854] initExternalMemory():  PC: 0x80018e8; ret: 0
84
[3.954] initExternalMemory():  PC: 0x80018e8; ret: 0
85
[4.074] initExternalMemory():  PC: 0x80018e8; ret: 0
86
[4.194] initExternalMemory():  PC: 0x80018e8; ret: 0
87
[4.314] initExternalMemory():  PC: 0x80018e8; ret: 0
88
[4.434] initExternalMemory():  PC: 0x80018e8; ret: 0
89
[4.554] initExternalMemory():  PC: 0x80018e8; ret: 0
90
[4.663] initExternalMemory():  PC: 0x80018e8; ret: 0
91
[4.769] initExternalMemory():  PC: 0x80018e8; ret: 0
92
[4.878] initExternalMemory():  PC: 0x80018e8; ret: 0
93
[4.984] initExternalMemory():  PC: 0x80018e8; ret: 0
94
[5.104] initExternalMemory():  PC: 0x80018e8; ret: 0
95
[5.224] initExternalMemory():  PC: 0x80018e8; ret: 0
96
[5.334] initExternalMemory():  PC: 0x80018e8; ret: 0
97
[5.434] initExternalMemory():  PC: 0x80018e8; ret: 0
98
[5.554] initExternalMemory():  PC: 0x80018e8; ret: 0
99
[5.674] initExternalMemory():  PC: 0x80018e8; ret: 0
100
[5.778] initExternalMemory():  PC: 0x80018e8; ret: 0
101
[5.883] initExternalMemory():  PC: 0x80018e8; ret: 0
102
[5.994] initExternalMemory():  PC: 0x80018e8; ret: 0
103
[6.094] initExternalMemory():  PC: 0x80018e8; ret: 0
104
[6.214] initExternalMemory():  PC: 0x80018e8; ret: 0
105
[6.334] initExternalMemory():  PC: 0x80018e8; ret: 0
106
[6.434] initExternalMemory():  PC: 0x80018e8; ret: 0
107
[6.554] initExternalMemory():  PC: 0x80018e8; ret: 0
108
[6.674] initExternalMemory():  PC: 0x80018e8; ret: 0
109
[6.779] initExternalMemory():  PC: 0x80018e8; ret: 0
110
[6.884] initExternalMemory():  PC: 0x80018e8; ret: 0
111
[7.004] initExternalMemory():  PC: 0x80018e8; ret: 0
112
[7.124] initExternalMemory():  PC: 0x80018e8; ret: 0
113
[7.224] initExternalMemory():  PC: 0x80018e8; ret: 0
114
[7.344] initExternalMemory():  PC: 0x80018e8; ret: 0
115
[7.444] initExternalMemory():  PC: 0x80018e8; ret: 0
116
[7.544] initExternalMemory():  PC: 0x80018e8; ret: 0
117
[7.664] initExternalMemory():  PC: 0x80018e8; ret: 0
118
[7.767] initExternalMemory():  PC: 0x80018e8; ret: 0
119
[7.871] initExternalMemory():  PC: 0x80018e8; ret: 0
120
[7.975] initExternalMemory():  PC: 0x80018e8; ret: 0
121
[8.095] initExternalMemory():  PC: 0x80018e8; ret: 0
122
[8.214] initExternalMemory():  PC: 0x80018e8; ret: 0
123
[8.334] initExternalMemory():  PC: 0x80018e8; ret: 0
124
[8.454] initExternalMemory():  PC: 0x80018e8; ret: 0
125
[8.574] initExternalMemory():  PC: 0x80018e8; ret: 0
126
[8.695] initExternalMemory():  PC: 0x80018e8; ret: 0
127
[8.799] initExternalMemory():  PC: 0x80018e8; ret: 0
128
[8.906] initExternalMemory():  PC: 0x80018e8; ret: 0
129
[9.013] initExternalMemory():  PC: 0x80018e8; ret: 0
130
[9.124] initExternalMemory():  PC: 0x80018e8; ret: 0
131
[9.224] initExternalMemory():  PC: 0x80018e8; ret: 0
132
[9.344] initExternalMemory():  PC: 0x80018e8; ret: 0
133
[9.464] initExternalMemory():  PC: 0x80018e8; ret: 0
134
[9.564] initExternalMemory():  PC: 0x80018e8; ret: 0
135
[9.684] initExternalMemory():  PC: 0x80018e8; ret: 0
136
[9.800] initExternalMemory():  PC: 0x80018e8; ret: 0
137
[9.924] initExternalMemory():  PC: 0x80018e8; ret: 0
138
[10.043] initExternalMemory():  PC: 0x80018e8; ret: 0
139
[10.144] initExternalMemory():  PC: 0x80018e8; ret: 0
140
[10.264] initExternalMemory():  PC: 0x80018e8; ret: 0
141
[10.384] initExternalMemory():  PC: 0x80018e8; ret: 0
142
[10.504] initExternalMemory():  PC: 0x80018e8; ret: 0
143
[10.624] initExternalMemory():  PC: 0x80018e8; ret: 0
144
[10.733] initExternalMemory():  PC: 0x80018e8; ret: 0
145
[10.854] initExternalMemory():  PC: 0x80018e8; ret: 0
146
[10.974] initExternalMemory():  PC: 0x80018e8; ret: 0
147
[11.094] initExternalMemory():  PC: 0x80018e8; ret: 0
148
[11.214] initExternalMemory():  PC: 0x80018e8; ret: 0
149
[11.334] initExternalMemory():  PC: 0x80018e8; ret: 0
150
[11.454] initExternalMemory():  PC: 0x80018e8; ret: 0
151
[11.574] initExternalMemory():  PC: 0x80018e8; ret: 0
152
[11.694] initExternalMemory():  PC: 0x80018e8; ret: 0
153
[11.799] initExternalMemory():  PC: 0x80018e8; ret: 0
154
[11.907] initExternalMemory():  PC: 0x80018e8; ret: 0
155
[12.024] initExternalMemory():  PC: 0x80018e8; ret: 0
156
[12.144] initExternalMemory():  PC: 0x80018e8; ret: 0
157
[12.264] initExternalMemory():  Restore after external memory initializer
158
[12.264] initExternalMemory():  Init() failed returned 0x200028ac @ 0x80018e8
159
[12.274] initExternalMemory():  r0           0x200028ac
160
[12.274] initExternalMemory():  r1           0x2004a
161
[12.274] initExternalMemory():  r2           0x10200
162
[12.274] initExternalMemory():  r3           0x10200
163
[12.274] initExternalMemory():  r4           0xa0000068
164
[12.274] initExternalMemory():  r5           0x0
165
[12.274] initExternalMemory():  r6           0x0
166
[12.274] initExternalMemory():  r7           0x2000286c
167
[12.274] initExternalMemory():  r8           0x0
168
[12.274] initExternalMemory():  r9           0x0
169
[12.274] initExternalMemory():  r10          0x0
170
[12.274] initExternalMemory():  r11          0x0
171
[12.274] initExternalMemory():  r12          0x40
172
[12.274] initExternalMemory():  sp           0x2000286c
173
[12.274] initExternalMemory():  lr           0xfffffff9
174
[12.274] initExternalMemory():  pc           0x80018e8
175
[12.274] initExternalMemory():  xpsr         0x61000003
176
[12.274] initExternalMemory():  PRIMASK      0x0
177
[12.274] initExternalMemory():  BASEPRI      0x0
178
[12.274] initExternalMemory():  FAULTMASK    0x0
179
[12.274] initExternalMemory():  CONTROL      0x0
180
[12.274] initExternalMemory():  MSP          0x2000286c
181
[12.274] initExternalMemory():  PSP          0x0
182
[12.274] initExternalMemory():  Stack 0x2000286c <sp+0>:  0x0
183
[12.274] initExternalMemory():  Stack 0x20002870 <sp+4>:  0x200028ac
184
[12.274] initExternalMemory():  Stack 0x20002874 <sp+8>:  0x2004a
185
[12.274] initExternalMemory():  Stack 0x20002878 <sp+12>: 0x10200
186
[12.284] initExternalMemory():  Stack 0x2000287c <sp+16>: 0x10200
187
[12.284] initExternalMemory():  Stack 0x20002880 <sp+20>: 0x40
188
[12.284] initExternalMemory():  Stack 0x20002884 <sp+24>: 0x200000ab
189
[12.284] initExternalMemory():  Stack 0x20002888 <sp+28>: 0x20000f90
190
[12.284] initExternalMemory():  Stack 0x2000288c <sp+32>: 0x61000000
191
[12.284] initExternalMemory():  Stack 0x20002890 <sp+36>: 0x0
192
[12.294] initExternalMemory():  Stack 0x20002894 <sp+40>: 0x0
193
[12.294] initExternalMemory():  Stack 0x20002898 <sp+44>: 0x48030040
194
[12.294] Device_Initialise():  Failed to initialize external memory!
195
[12.294] initServerContext():  
196
Error in initializing ST-LINK device.
197
Reason: [12.294] initServerContext():  Unknown. Please check power and cabling to target.

von Stefan F. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> Please check power and cabling to target.

Genau das hätte ich jetzt auch ohne diese Meldung empfohlen.

Hast du Dupont Kabel oder Steckbretter im Aufbau? Die haben oft 
Wackelkontakte bzw. unsichtbare Kabelbrüche.

von Low-Level-Programmierer (Gast)


Lesenswert?

Nein, kein Steckbrett. Nur das DiscoveryF3, das mit dem Kompaß.

von Stefan F. (Gast)


Lesenswert?

Probiere mal ein anderes USB Kabel, ein möglichst dickes kurzes.

Dazu fällt mir gerade noch ein dass die USB Port beliebten Polyfuses 
dazu neigen, nach der ersten Auslösung (z.B. durch Kurzschluss) deutlich 
hochohmiger zu werden, als in neuem Zustand. Danach Funktionen an 
solchen Ports oft keine Festplatten mehr, Mäuse und Tastaturen gehen 
aber.

von Low-Level-Programmierer (Gast)


Lesenswert?

Hm...das ist merkwürdig.

Ich habe mit dem ST-Link Utility auf eine ältere Version "geupdated".
Frag mich nicht warum, aber das ST-Link Utility kennt keine neuere.

Jetzt hat CubeIDE nach einem erneuten Update verlangt (auf die alte, 
höhere Version) und nun geht es wieder.

von Low-Level-Programmierer (Gast)


Lesenswert?

So...jetzt, wo es wieder läuft, hätte ich mal wieder eine Frage. Ich 
will den ADC in Verbindung mit dem DMA nutzen.

Ich will den ADC im Continious Mode betreiben. Jetzt habe ich alles 
konfiguriert, teils mit CubeMX, teils hab ich mir die Beispielprojekte 
von ST angesehen/abkopiert, selbstverständlich auch das Reference Manual 
dabei.

Ich würde jetzt erwarten das die DMA-IRQHandler-Funktion angesprungen 
wird. Aber das passiert nicht. Sieht jemand vielleicht, was ich nicht 
sehe?

ADC-Konfiguration:
1
void MX_ADC1_Init(void)
2
{
3
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
4
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
5
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
6
7
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};
8
9
  /* Peripheral clock enable */
10
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
11
  
12
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_GPIOA);
13
  /**ADC1 GPIO Configuration  
14
  PA1   ------> ADC1_IN2 
15
  */
16
  GPIO_InitStruct.Pin = LL_GPIO_PIN_1;
17
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ANALOG;
18
  GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;
19
  LL_GPIO_Init(GPIOA, &GPIO_InitStruct);
20
21
  /* ADC1 DMA Init */
22
  
23
  /* ADC1 Init */
24
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
25
26
  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);
27
28
  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);
29
30
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
31
32
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_INCREMENT);
33
34
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
35
36
  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
37
38
  /** Common config 
39
  */
40
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
41
  ADC_InitStruct.DataAlignment = LL_ADC_DATA_ALIGN_RIGHT;
42
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
43
  LL_ADC_Init(ADC1, &ADC_InitStruct);
44
  ADC_REG_InitStruct.TriggerSource = LL_ADC_REG_TRIG_EXT_EXTI_LINE11_ADC12;
45
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
46
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;
47
  ADC_REG_InitStruct.ContinuousMode = LL_ADC_REG_CONV_CONTINUOUS;
48
  ADC_REG_InitStruct.DMATransfer = LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
49
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
50
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
51
  LL_ADC_DisableIT_EOC(ADC1);
52
  LL_ADC_DisableIT_EOS(ADC1);
53
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_SYNC_PCLK_DIV4;
54
  ADC_CommonInitStruct.Multimode = LL_ADC_MULTI_INDEPENDENT;
55
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);
56
  LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
57
  /** Configure Regular Channel 
58
  */
59
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_2);
60
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SAMPLINGTIME_1CYCLE_5);
61
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_2, LL_ADC_SINGLE_ENDED);
62
63
}
64
65
66
void Activate_ADC() {
67
  __IO uint32_t wait_loop_index = 0;
68
#if (USE_TIMEOUT == 1)
69
  uint32_t Timeout = 0; /* Variable used for timeout management */
70
  #endif /* USE_TIMEOUT */
71
72
  /*## Operation on ADC hierarchical scope: ADC instance #####################*/
73
74
  /* Note: Hardware constraint (refer to description of the functions         */
75
  /*       below):                                                            */
76
  /*       On this STM32 serie, setting of these features is conditioned to   */
77
  /*       ADC state:                                                         */
78
  /*       ADC must be disabled.                                              */
79
  /* Note: In this example, all these checks are not necessary but are        */
80
  /*       implemented anyway to show the best practice usages                */
81
  /*       corresponding to reference manual procedure.                       */
82
  /*       Software can be optimized by removing some of these checks, if     */
83
  /*       they are not relevant considering previous settings and actions    */
84
  /*       in user application.                                               */
85
  if (LL_ADC_IsEnabled(ADC1) == 0) {
86
    /* Enable ADC internal voltage regulator */
87
    LL_ADC_EnableInternalRegulator(ADC1);
88
89
    /* Delay for ADC internal voltage regulator stabilization.                */
90
    /* Compute number of CPU cycles to wait for, from delay in us.            */
91
    /* Note: Variable divided by 2 to compensate partially                    */
92
    /*       CPU processing cycles (depends on compilation optimization).     */
93
    /* Note: If system core clock frequency is below 200kHz, wait time        */
94
    /*       is only a few CPU processing cycles.                             */
95
    wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US
96
        * (SystemCoreClock / (100000 * 2))) / 10);
97
    while (wait_loop_index != 0) {
98
      wait_loop_index--;
99
    }
100
101
    /* Run ADC self calibration */
102
    LL_ADC_StartCalibration(ADC1, LL_ADC_SINGLE_ENDED);
103
104
    /* Poll for ADC effectively calibrated */
105
#if (USE_TIMEOUT == 1)
106
    Timeout = ADC_CALIBRATION_TIMEOUT_MS;
107
    #endif /* USE_TIMEOUT */
108
109
    while (LL_ADC_IsCalibrationOnGoing(ADC2) != 0) {
110
#if (USE_TIMEOUT == 1)
111
      /* Check Systick counter flag to decrement the time-out value */
112
      if (LL_SYSTICK_IsActiveCounterFlag())
113
      {
114
        if(Timeout-- == 0)
115
        {
116
        /* Time-out occurred. Set LED to blinking mode */
117
        LED_Blinking(LED_BLINK_ERROR);
118
        }
119
      }
120
    #endif /* USE_TIMEOUT */
121
    }
122
123
    /* Delay between ADC end of calibration and ADC enable.                   */
124
    /* Note: Variable divided by 2 to compensate partially                    */
125
    /*       CPU processing cycles (depends on compilation optimization).     */
126
    wait_loop_index = (ADC_DELAY_CALIB_ENABLE_CPU_CYCLES >> 1);
127
    while (wait_loop_index != 0) {
128
      wait_loop_index--;
129
    }
130
131
    /* Enable ADC */
132
    LL_ADC_Enable(ADC1);
133
134
    /* Poll for ADC ready to convert */
135
#if (USE_TIMEOUT == 1)
136
    Timeout = ADC_ENABLE_TIMEOUT_MS;
137
    #endif /* USE_TIMEOUT */
138
139
    while (LL_ADC_IsActiveFlag_ADRDY(ADC1) == 0) {
140
#if (USE_TIMEOUT == 1)
141
      /* Check Systick counter flag to decrement the time-out value */
142
      if (LL_SYSTICK_IsActiveCounterFlag())
143
      {
144
        if(Timeout-- == 0)
145
        {
146
        /* Time-out occurred. Set LED to blinking mode */
147
        LED_Blinking(LED_BLINK_ERROR);
148
        }
149
      }
150
    #endif /* USE_TIMEOUT */
151
    }
152
153
    /* Note: ADC flag ADRDY is not cleared here to be able to check ADC       */
154
    /*       status afterwards.                                               */
155
    /*       This flag should be cleared at ADC Deactivation, before a new    */
156
    /*       ADC activation, using function "LL_ADC_ClearFlag_ADRDY()".       */
157
  }
158
159
  /*## Operation on ADC hierarchical scope: ADC group regular ################*/
160
  /* Note: No operation on ADC group regular performed here.                  */
161
  /*       ADC group regular conversions to be performed after this function  */
162
  /*       using function:                                                    */
163
  /*       "LL_ADC_REG_StartConversion();"                                    */
164
165
  /*## Operation on ADC hierarchical scope: ADC group injected ###############*/
166
  /* Note: No operation on ADC group injected performed here.                 */
167
  /*       ADC group injected conversions to be performed after this function */
168
  /*       using function:                                                    */
169
  /*       "LL_ADC_INJ_StartConversion();"                                    */
170
171
}

DMA-Konfiguration:
1
void DMA_Config(){
2
  LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
3
4
  LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_1, LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
5
  LL_DMA_SetChannelPriorityLevel(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PRIORITY_HIGH);
6
  LL_DMA_SetMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MODE_CIRCULAR);
7
  LL_DMA_SetPeriphIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PERIPH_NOINCREMENT);
8
  LL_DMA_SetMemoryIncMode(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MEMORY_NOINCREMENT);
9
  LL_DMA_SetPeriphSize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_PDATAALIGN_HALFWORD);
10
  LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_1, LL_DMA_MDATAALIGN_HALFWORD);
11
12
  LL_DMA_ConfigTransfer(
13
      DMA1,
14
      LL_DMA_CHANNEL_1,
15
      LL_DMA_DIRECTION_PERIPH_TO_MEMORY |
16
      LL_DMA_MODE_CIRCULAR |
17
      LL_DMA_PERIPH_NOINCREMENT |
18
      LL_DMA_MEMORY_NOINCREMENT |
19
      LL_DMA_PDATAALIGN_HALFWORD |
20
      LL_DMA_MDATAALIGN_HALFWORD |
21
      LL_DMA_PRIORITY_HIGH);
22
23
  LL_DMA_ConfigAddresses(
24
      DMA1,
25
      LL_DMA_CHANNEL_1,
26
      LL_ADC_DMA_GetRegAddr(ADC1, LL_ADC_DMA_REG_REGULAR_DATA),
27
      &lastAdcValue,
28
      LL_DMA_DIRECTION_PERIPH_TO_MEMORY);
29
30
  LL_DMA_SetDataLength(
31
      DMA1,
32
      LL_DMA_CHANNEL_1,
33
      (uint32_t) 1);
34
35
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_CHANNEL_1);
36
  LL_DMA_EnableIT_HT(DMA1, LL_DMA_CHANNEL_1);
37
38
  //NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
39
  //NVIC_EnableIRQ(DMA1_Channel1_IRQn);
40
41
  LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_1);
42
}

Interuptvektorcontroller:
1
static void MX_NVIC_Init(void)
2
{
3
  /* TIM6_DAC_IRQn interrupt configuration */
4
  NVIC_SetPriority(TIM6_DAC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
5
  NVIC_EnableIRQ(TIM6_DAC_IRQn);
6
  /* DMA1_Channel1_IRQn interrupt configuration */
7
  NVIC_SetPriority(DMA1_Channel1_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
8
  NVIC_EnableIRQ(DMA1_Channel1_IRQn);
9
  /* EXTI0_IRQn interrupt configuration */
10
  NVIC_SetPriority(EXTI0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
11
  NVIC_EnableIRQ(EXTI0_IRQn);
12
  /* ADC1_2_IRQn interrupt configuration */
13
  NVIC_SetPriority(ADC1_2_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
14
  NVIC_EnableIRQ(ADC1_2_IRQn);
15
}


Und so wird das Ganze in der main aufgerufen:
1
MX_GPIO_Init();
2
  MX_DMA_Init();
3
  MX_TIM6_Init();
4
  MX_ADC1_Init();
5
6
  /* Initialize interrupts */
7
  MX_NVIC_Init();
8
  /* USER CODE BEGIN 2 */
9
  LL_TIM_EnableIT_UPDATE(TIM6);
10
  LL_TIM_EnableCounter(TIM6);
11
  LL_TIM_GenerateEvent_UPDATE(TIM6);
12
13
  DMA_Config();
14
  //LL_ADC_INJ_ReadConversionData12(ADC1, 1);
15
  Activate_ADC();
16
  /* USER CODE END 2 */
17
18
  /* Infinite loop */
19
  /* USER CODE BEGIN WHILE */
20
  while (1) {
21
    /* USER CODE END WHILE */
22
23
    /* USER CODE BEGIN 3 */
24
25
  }

von Low-Level-Programmierer (Gast)


Lesenswert?

Mahlzeit allerseits

Das mit dem ADC und dem DMA ist erledigt - ich habs hinbekommen.


Jetzt wartet hier das nächste auf mich: Ein Nucleoboard mit einem F446 
mit MEMS Erweiterungsboard. Zunächst will ich diesen IC darauf über I²C 
ansprechen und die Temperatur auslesen:
https://www.st.com/resource/en/datasheet/hts221.pdf

ST stellt zwar ein Softwarepackage bereit, aber ich will mich da auch 
nicht zu sehr auf ST-Produkte festnageln lassen, und etwas lernen will 
ich ja auch.

Ich meine zwar verstanden zu haben wie I²C funktioniert, aber es hapert 
noch etwas an der Umsetzung. Entweder hänge ich in meinen Warteschleifen 
fest, oder ich lese lediglich das aus was ich als letztes gesendet habe.

Ich weiß das, wenn man den HTS221 ernsthaft nutzen will, erst noch die 
Kalibrierbits ausgewertet werden müssen, aber bevor ich die 
versehentlich überschreibe will ich zur Sicherheit lieber erstmal etwas 
auslesen, was ich nicht versehentlich überschreiben kann.
1
const uint8_t HTS221ADDR = 0xBF;
2
const uint8_t HTSS221ADDW = 0xBE;
3
4
//...
5
6
  //Wait until bus is free
7
  while(!LL_I2C_IsActiveFlag_BUSY(I2C1)){};
8
9
  //Start
10
  LL_I2C_GenerateStartCondition(I2C1);
11
  //Send SAD+W
12
  LL_I2C_TransmitData8(I2C1, HTSS221ADDW);
13
  while(!LL_I2C_IsActiveFlag_TXE(I2C1)){};
14
15
  //Send SUB (0x0F -> WHO_AM_I register
16
  LL_I2C_TransmitData8(I2C1, 0x27);
17
  while(!LL_I2C_IsActiveFlag_TXE(I2C1)){};
18
  LL_I2C_GenerateStartCondition(I2C1);
19
20
  //Send SAD+R
21
  while(!LL_I2C_IsActiveFlag_TXE(I2C1)){};
22
  LL_I2C_TransmitData8(I2C1, HTS221ADDR);
23
24
  //Read answer from slave
25
  while(LL_I2C_IsActiveFlag_RXNE(I2C1));
26
  uint8_t data = LL_I2C_ReceiveData8(I2C1);
27
  LL_I2C_GenerateStopCondition(I2C1);
28
  LL_USART_TransmitData8(USART2, data);

von Stefan F. (Gast)


Lesenswert?

Low-Level-Programmierer schrieb:
> ST stellt zwar ein Softwarepackage bereit, aber ich will mich da auch
> nicht zu sehr auf ST-Produkte festnageln lassen

Warum benutzt du dann trotzdem die Bibliothek von ST? Das passt doch 
nicht zusammen. Ich meine: Ich will sie dir jetzt nicht unbedingt 
ausreden, aber entweder stehst du dazu, oder nicht.

von Low-Level-Programmierer (Gast)


Lesenswert?

Naja, die Bibliotheken sind halt nicht nur auf die Mikrocontroller von 
ST, sondern auch auf die Sensoren abgestimmt - jedenfalls, soweit wie 
ich das verstanden habe.
Und das ist für mich schon ein Unterschied.

Und wie gesagt - es geht mir auch um das selber machen. Einfach nur eine 
Funktion getTemperature() aufrufen...damit ist man schnell fertig, hat 
hinterher aber nicht mehr Ahnung als vorher.

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Du darfst auch nicht sofort ins DR schreiben nach dem Set Startbit.
Du musst warten bis die Periph auch das Startbit gesendet hat:
"Setting the START bit causes the interface to generate a Start 
condition and to switch toMaster mode (MSL bit set) when the BUSY bit is 
cleared.
Then the master waits for a read of the SR1 register followed by a write 
in the DR register with the Slave address"
Wer weis was die Hardware macht wenn man sofort ins DR reinbrüllt.

Hast du eigentlich nen Oszi um zu gucken was am I2C rauskommt?
Sonst ist das ne Suche im Nebel.

Warum du nach dem Stop noch was schreibst erschließt sich mir jetzt auch 
nicht.
Im Refman stehen schöne Schritt für Schritt Anleitungen an den man sich 
langhangelt.

Ansonsten noch Kleinigkeiten:
Erst den I2C aktivieren, dann die Pins einstellen.
Das kann sonst Glitches auf dme IO geben und das mögen die I2C SLaves 
eher nicht.
Ansonsten müssen die I2C Oins auf ALternate Function Open Drain gestellt 
werden.

Die COnfig kannste also auch mal hier reinhängen.

Low-Level-Programmierer schrieb:
> Naja, die Bibliotheken sind halt nicht nur auf die Mikrocontroller von
> ST, sondern auch auf die Sensoren abgestimmt - jedenfalls, soweit wie
> ich das verstanden habe.

Wer mir neu, dass da was abgestimmt wäre.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ich weiß jetzt nicht, wie verbuggt die I²C Schnittstelle beim F4 ist, 
aber beim F1 bekommt man sie ohne die zahlreichen Hinweise vom Errata 
Dokument kaum ans Laufen.

von Low-Level-Programmierer (Gast)


Lesenswert?

@Mw E.:
Nach dem Stopp schiebe ich das, was ich gelesen habe, über die USART am 
ST-Link raus und schau mir das mit hterm an.

Dann werd ich mal nochmal das Errata Sheet ansehen, und die 
Konfiguration ändern...

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Lesenswert?

Low-Level-Programmierer schrieb:
> Nach dem Stopp schiebe ich das, was ich gelesen habe, über die USART am
> ST-Link raus und schau mir das mit hterm an.

Hmm, freudscher verleser?
Das USART hab ich gekonnt überlsen, da ich nur I2C Funktionen erwartet 
habe :>

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
Noch kein Account? Hier anmelden.