Ich frage mich ob es eine gute Idee war mit den HAL-Bibliotheken
anzufangen ...
Mikrocontroller: STM32F205VCT6
Compiler: arm-none-eabi-gcc, gcc version 7.3.1 20180622 (release)
[ARM/embedded-7-branch revision 261907] (15:7-2018-q2-4)
Die HAL-Bibliotheken wurden mittels STM32CubeMX, Version 4.27.0
erstellt.
Aktivierte Peripherie:
SPI3 (Transmit Only Master), SPI3 global interrupt enabled
GPIOA.9 als output
Es soll (nicht blockierend) ein Byte gesendet werden:
Weiterer Code wurde von mir zu dem von STM32CubeMX erzeugten Code nicht
hinzugefügt.
Folgendes Problem:
Wird mittels HAL_SPI_Transmit_IT() nur ein Byte übergeben, so blockiert
die Funktion bis das Byte gesendet wurde (siehe SCR203.PNG). Werden
hingegen mehrere Bytes übergeben, so funktioniert die Funktion korrekt
(siehe SCR204.PNG). Ich konnte aus dem HAL-Quellcode die Ursache dafür
nicht finden.
Ein Bug? Oder eine fehlerhafte Konfiguration?
Gruß Marc
Er macht genau was er soll.
Du ziehst den CS auf low startest den Transfer und dann geht der CS auf
high.
Was du aber willst ist folgendes:
Möglichkeit A: Aktives Warten - müsste mit folgendem gehen:
1
HAL_SPI_Transmit(&hspi3,buffer,1);
Möglichkeit B: Du setzt den Befehl ab und nimmst deine Interruptfunktion
"HAL_SPI_Transmit_IT" und im Interrupt Callback den CS wieder hoch. Da
müsste ein Funktionsrumpf da sein.
Das bei einem Byte ein Blockierender Aufruf folgt kann sein, da müsste
man aber genauer schauen. Da kann viel reinspielen.
Blockierender Aufruf würde ich mit der Funktion ohne IT machen.
Nachdem die beiden Befehlszeilen ausgeführt wurden, sollte das Signal
GPIO_PIN_9 unmittelbar auf HIGH gehen, nicht erst nachdem der
SPI-Transfer beendet ist. Sonst würde der Interrupt-Betrieb keinen Sinn
machen. Er sollte nicht-blockierend sein.
> Du ziehst den CS auf low startest den Transfer und dann geht der CS auf> high.
In der aktuellen Konfiguration gibt es kein CS. CS wird zum Senden nicht
benötigt.
> Das bei einem Byte ein Blockierender Aufruf folgt kann sein, da müsste> man aber genauer schauen. Da kann viel reinspielen.
Ja genau. Und genau deswegen schrieb ich diesen Post.
Gruß Marc
Wenn du die *_IT-Funktionen nutzt, musst du auch den/die zugehörigen
Callback(s) implementieren, sonst macht das alles wenig Sinn.
In deinem Fall ist das mindestens:
Harry L. schrieb:> Wenn du die *_IT-Funktionen nutzt, musst du auch den/die zugehörigen> Callback(s) implementieren, sonst macht das alles wenig Sinn.> In deinem Fall ist das mindestens:>
Marc L. schrieb:> Harry L. schrieb:>> Wenn du die *_IT-Funktionen nutzt, musst du auch den/die zugehörigen>> Callback(s) implementieren, sonst macht das alles wenig Sinn.>> In deinem Fall ist das mindestens:>>
Harry L. schrieb:> Ja, weil CS viel zu früh inaktiv wird.
Es gibt in meiner Konfiguration kein CS!
> W.g.: ohne die Callbacks wird das nix mit den *_IT-Varianten.
Ich geb's auf.
Meine Vermutung ist, daß es nur so aussieht, als ob es nicht
funktioniert.
Wenn Du nur ein Byte sendest, wird ja sofort die DMA Transfer Complete
ISR aufgerufen, d.h. bereits vor dem Befehl zum Setzen des Ports auf
High, und möglicherweise wird dort blockierend auf den Abschluss der
Übertragung des letzten Bytes gewartet. Normalerweise dürfte das
notwendig sein, damit die (bei Dir nicht vorhandene) Callback-Funktion
tatsächlich erst NACH dem Abschluss des kompletten Sendevorgangs
aufgerufen wird und nicht schon, wenn das letzte Byte per DMA gerade
erst aus dem Speicher gelesen wurde.
Ist aber bloß eine Theorie - von dem HAL-Zeugs halte ich mich lieber
fern. Es reicht mir schon, die Bugs in meinem eigenen Code zu finden, da
muss ich nicht auch noch den Code von ST debuggen... ;)
Marc L. schrieb:> Harry L. schrieb:>>> Ja, weil CS viel zu früh inaktiv wird.>> Es gibt in meiner Konfiguration kein CS!
Welche Funktion hat denn GPIO A9 in deinem Programm?
Lutz schrieb:> Welche Funktion hat denn GPIO A9 in deinem Programm?
GPIOA.9 dient dazu den Startzeitpunkt und den Endzeitpunkt der Funktion
HAL_SPI_Transmit_IT() am Oszilloskop darzustellen.
Marc L. schrieb:> Ich frage mich ob es eine gute Idee war mit den HAL-Bibliotheken> anzufangen ...
Natürlich nicht. Wüsstest Du aber, wenn Du öfters hier im Forum mal
mitgelesen hättest... Habe gerade mal in den Code geschaut. Der ist ja
sowas von aufgeblasen. Dabei sind das nur ein paar Bits und ein paar
Zeilen Code - selbst wenn man DMA nutzt - wenn man das in richtig macht.
Thomas E. schrieb:> Meine Vermutung ist, daß es nur so aussieht, als ob es nicht> funktioniert.> Wenn Du nur ein Byte sendest, wird ja sofort die DMA Transfer Complete> ISR aufgerufen, d.h. bereits vor dem Befehl zum Setzen des Ports auf> High, und möglicherweise wird dort blockierend auf den Abschluss der> Übertragung des letzten Bytes gewartet. Normalerweise dürfte das> notwendig sein, damit die (bei Dir nicht vorhandene) Callback-Funktion> tatsächlich erst NACH dem Abschluss des kompletten Sendevorgangs> aufgerufen wird und nicht schon, wenn das letzte Byte per DMA gerade> erst aus dem Speicher gelesen wurde.
Klar, dazu reicht ein Blick in dieses üble Framework:
Erst:
Marc L. schrieb:> GPIOA.9 dient dazu den Startzeitpunkt und den Endzeitpunkt der Funktion> HAL_SPI_Transmit_IT() am Oszilloskop darzustellen.
Du könntest den Pin nach Aufruf der Tx-Funktion in einer Endlosschleife
togglen, dann könnte man sehen, ob da am Ende der Übertragung irgendwas
blockiert und wie lange.
Thomas E. schrieb:> Du könntest den Pin nach Aufruf der Tx-Funktion in einer Endlosschleife> togglen, dann könnte man sehen, ob da am Ende der Übertragung irgendwas> blockiert und wie lange.
Gute Idee!
Dann senden wir mal 3 Bytes:
Siehe Scope -> grauenhaft!
Doctor Snuggles schrieb:> Mein Vorschlag: Mach das selber. Ist wirklich trivial.
Ich denke Du hast recht. Die Fehlersuche, Code-Analyse der
HAL-Bibliotheken und daraus folgenden Workarounds haben mich schon
soviel Zeit gekostet ...
Inzwischen konnte ich die Ursache des Problems finden.
Das Problem ist, dass das Ende einer SPI-Übertragung nicht durch einen
TX-Interrupt signalisiert wird. Die HAL-Bibliotheken behelfen sich damit
über eine while-Schleife das Busy-Flag abzufragen. Dadurch entsteht die
Blockade. Leider löst das Busy-Flag keinen Interrupt aus.
ST hat mir vorgeschlagen das Ende einer Übertragung über den
RX-Interrupt signalisieren zu lassen. Das funktioniert sehr gut.
Allerdings verwende ich inzwischen meinen eigenen Code.
Falls es jemanden interessiert, hier der Link zum
Kommunikationsaustausch mit ST:
https://community.st.com/s/question/0D50X00009sW5LdSAK/halspitransmitit-blocks