Hallo
Ich habe mir nun ein paar Tutorials angesehen und Einiges gelesen. Ich
habe auch diverse Dinge probiert.
Nun habe ich den Code etwas abgespeckt und mit CubeMx mal den SPI und
den DMA initialisiert.
Der Beispielcode ist hier via Link verfügbar.
Ich bekomme das einfach nicht hin, obwohl ich die fertige Funktion
SPI_Transmit_DMA benutze.
Es lädt mir die Daten einfach nicht in das SPI Datenregister.
Was mache ich nur falsch? Ich würde es nun wirklich gerne mal wissen.
Ich wäre euch für kurze Hilfe sehr dankbar.
https://www.file-upload.net/download-13230132/test.rar.html]test.rar
Sebastian Kaulitz schrieb:> Hat denn keiner eine Idee?
Evtl. der ARM-Klassiker "Peripherie-Clock nicht aktiviert"?
Wenn man Deine main.c Datei mal überfliegt (gründlicher habe ich es mir
nicht angeschaut, da ich mit dem HAL-Zeugs nix am Hut hab), fällt auf,
daß in MX_GPIO_Init() und MX_DMA_Init() jeweils mit
HAL_RCC_xxx_CLK_ENABLE() Clock aktiviert wird, in MX_SPI1_Init() jedoch
nicht.
Er hat das gesamte Projekt"Test" mit nem dutzend z.t. hier nicht
benötigtigter Ordner gepackt exportiert.
Als wüste er was folgte wen er irgend eine nicht im SC deqularierte
Funtion im QT aufruft. Schlau aber nicht schlau genug gnörgeld wird
trotzdem.
Um es kurz zumachen ich kenne Keinen Prozessor bei dem der DMA HW
Register direkt verändert. Das obliegt imho besser der Init des
abgelegten Codes.
DMA dient dem schnellen Austausch von Daten mit der Perepherie ohne
Prozessorlast zu erzeugen und Register zu verändern.
Namaste
Winfried J. schrieb:> Um es kurz zumachen ich kenne Keinen Prozessor bei dem der DMA HW> Register direkt verändert.
Doch, der DMA schreibt direkt ins SPI-Tx Register (zumindest, wenn alles
richtig läuft).
Winfried J. schrieb:> Das obliegt imho besser der Init des> abgelegten Codes.
Da vermute ich bei völliger Ahnungslosigkeit (s.o.), daß
HAL_SPI_Transmit_DMA() wohl die entsprechenden Register von DMA und SPI
geeignet initialisiert. Wenn die SPI-Peripherie aber nicht getaktet ist
(meine Vermutung), geht natürlich nichts.
Thomas E. schrieb:> Sebastian Kaulitz schrieb:>> Hat denn keiner eine Idee?>> Evtl. der ARM-Klassiker "Peripherie-Clock nicht aktiviert"?> Wenn man Deine main.c Datei mal überfliegt (gründlicher habe ich es mir> nicht angeschaut, da ich mit dem HAL-Zeugs nix am Hut hab), fällt auf,> daß in MX_GPIO_Init() und MX_DMA_Init() jeweils mit> HAL_RCC_xxx_CLK_ENABLE() Clock aktiviert wird, in MX_SPI1_Init() jedoch> nicht.
Ich weiss zwar nicht warum das so gemacht wird, aber die CLK für SPI
wird im HAL_SPI_MspInit(SPI_HandleTypeDef* hspi) in der Datei ...msp.c
aktiviert gemacht. Ansonsten könnte man ja beim Debuggen nicht sehen,
dass die Werte initialisiert werden.
Sebastian Kaulitz schrieb:> Ansonsten könnte man ja beim Debuggen nicht sehen,> dass die Werte initialisiert werden.
Auch ohne Takt kann man manchmal in bestimmte Register schreiben und
deren Inhalt lesen (hängt vom Controller ab). Dynamische Prozesse
funktionieren dann trotzdem nicht.
S. R. schrieb:> Sebastian Kaulitz schrieb:>> Ansonsten könnte man ja beim Debuggen nicht sehen,>> dass die Werte initialisiert werden.>> Auch ohne Takt kann man manchmal in bestimmte Register schreiben und> deren Inhalt lesen (hängt vom Controller ab). Dynamische Prozesse> funktionieren dann trotzdem nicht.
Ich habe das jetzt mal in den SPI Init übernommen. Siehe unten. Es
funktioniert trotzdem nicht. Das DMA CNDTR Register (Anzahl Daten zur
Übertragung) ist anfangs auf 10, sprich A.
Sobald über die HAL_SPI_Transmit_DMA das DMAEN Bit 1 gesetzt wird, wird
CNDTR 0 ohne, dass das SPI_DR Register beschrieben wird. Irgendwas tut
da nicht richtig.
Sebastian Kaulitz schrieb:> Sobald über die HAL_SPI_Transmit_DMA das DMAEN Bit 1 gesetzt wird,> wird CNDTR 0 ohne, dass das SPI_DR Register beschrieben wird.
Wie prüfst du das?
Oft sind solche Register nicht lesbar, oder Lesezugriffe (auch solche
durch den Debugger!) haben Nebeneffekte. Insbesondere Registerzugriffe
durch die DMA-Engine könnten für den Debugger nicht direkt sichtbar
sein.
Kannst du manuell Werte in SPI_DR schreiben und siehst sie dann aus MOSI
rauströpfeln?
Bist du dir sicher, dass die DMA-Engine die auch an die richtige Adresse
schreibt? Lass die Daten mal nacheinander (stride = 1) ins RAM schreiben
und schaue, ob die da ankommen. Mit stride = 0 sollte nur der letzte
Wert ankommen.
Weißt du, wie die DMA-Engine feststellt, dass das zuletzt geschriebene
Byte fertig gesendet wurde (und bist du sicher, dass das funktioniert)?
S. R. schrieb:> Wie prüfst du das?>> Oft sind solche Register nicht lesbar, oder Lesezugriffe (auch solche> durch den Debugger!) haben Nebeneffekte.
Genau so sieht es nämlich aus, Heisenberg lässt grüßen. Abgesehen davon
kann man grundsätzlich nicht in das SPI DR etwas hineinschreiben und es
dann aus dem Register wieder lesen. Schreibzugriffe gehen in den
TX-Buffer und Lesezugriffe geben im Idealfall das wieder, was man auf
dem Bus empfangen hat. Logischerweise muss man nicht grundsätzlich das
empfangen was man gesendet hat. All das und noch viel mehr kann man
erfahren wenn man sich mal das Kapitel zu SPI im Handbuch durchließt.
S. R. schrieb:> Sebastian Kaulitz schrieb:> Wie prüfst du das?
Ich debugge
> Kannst du manuell Werte in SPI_DR schreiben und siehst sie dann aus MOSI> rauströpfeln?
mit direktem Schreiben mittels hspi.Instance->DR = 0x1111; geht das
Schreiben auch nicht
> Bist du dir sicher, dass die DMA-Engine die auch an die richtige Adresse> schreibt?
Ja siehe Bild
>Lass die Daten mal nacheinander (stride = 1) ins RAM schreiben> und schaue, ob die da ankommen. Mit stride = 0 sollte nur der letzte> Wert ankommen.
Ich verstehe nicht genau, was du genau meinst.
Was auch immer der Debugger anzeigt, was in das DR geschrieben wurde,
läßt sich nicht auslesen, bestenfalls weiß er noch, was er gerade
reingeschrieben hat. Schreiben per DMA ist komplett unsichtbar, es sei
denn, man schaut sich an, was auf der Sendeleitung der SPI-Schnittstelle
raus kommt. Aber da muß man sehr schnell schauen. Mit LA oder zumindest
Oszi, das auf eine Flanke triggert. Dann flackert es zumindest, wenn die
DMA heimlich Daten verschickt.
Ok, verstanden.
Christopher J. schrieb:> S. R. schrieb:
All das und noch viel mehr kann man
> erfahren wenn man sich mal das Kapitel zu SPI im Handbuch durchließt.
Das habe ich schon gelesen, dachte aber, dass man das trotzdem sehen
müsste. Das steht doch nirgends, dass man das im Debugger nicht sieht.
Wenn es stimmt, dass man das im Debugger nicht sieht, kann ich das ja
auch nicht explizit prüfen, oder doch?
Ich habe nun folgendes drin:
Grundsätzlich müsste doch jetzt, wenn ich die fertige Funktion verwende,
auf der Segment-Anzeige eine 0 sichtbar sein.
Das Signal kommt aber nicht durch.. Ich werde das denke ich mal mit dem
Oszi morgen mittels Decoder analysieren müssen..
Komischerweise komme ich nun aber - um das morgen ausführen zu können -
irgendwie nach der Zeile beim Debuggen in den Hardfault Handler?? Warum
das nun? Auch wieder Heisenberg? :)
Sebastian Kaulitz schrieb:> Ich habe nun folgendes drin: HAL_SPI_Transmit(&hspi1, flameBits ,> sizeof(flameBits)/sizeof(flameBits[U8FLAMELED1ST.position]), TIMEOUT);>> HAL_SPI_Transmit_DMA(&hspi1, digitNumbers, 1);> put2STR();
Ja,was denn jetzt?
Mit oder ohne DMA?
Du solltest dich mal entscheiden!
Doppelt bringt gar nix.
Ohne den Code genau angeschaut zu haben, sieht deine Grössenberechnung:
Sebastian Kaulitz schrieb:> sizeof(flameBits)/sizeof(flameBits[U8FLAMELED1ST.position])
auch ziemlich "strange" aus.
Harry L. schrieb:> Sebastian Kaulitz schrieb:>> Ich habe nun folgendes drin: HAL_SPI_Transmit(&hspi1, flameBits ,>> sizeof(flameBits)/sizeof(flameBits[U8FLAMELED1ST.position]), TIMEOUT);>>>> HAL_SPI_Transmit_DMA(&hspi1, digitNumbers, 1);>> put2STR();>> Ja,was denn jetzt?>> Mit oder ohne DMA?> Du solltest dich mal entscheiden!> Doppelt bringt gar nix.> Ohne den Code genau angeschaut zu haben, sieht deine Grössenberechnung:>> Sebastian Kaulitz schrieb:>> sizeof(flameBits)/sizeof(flameBits[U8FLAMELED1ST.position])>> auch ziemlich "strange" aus.
Sorry, falsch kopiert.
1
HAL_SPI_Transmit_DMA(&hspi1,flameBits,2);
2
HAL_SPI_Transmit_DMA(&hspi1,digitNumbers,1);
3
put2STR();
Warum denn strange?
1. sizeof(flameBits) = 2x uint8_t Datenlänge
2. sizeof(flameBits[U8FLAMELED1ST.position]) = uint8_t (Grösse des 1.
Elements)
1./2. gibt Länge 2
Wo ist das Problem?
Sebastian Kaulitz schrieb:> Das habe ich schon gelesen, dachte aber, dass man das trotzdem sehen> müsste.
Du willst auf die SPI-Schnittstelle sowohl schreiben, als auch lesen,
hast aber nur ein Register, nämlich DR. Wenn du jetzt beim lesen von DR
das zurück bekämst, was du zuletzt geschrieben hast, wie genau soll man
dann das lesen was der Controller von der Schnittstelle empfangen hat?
Sebastian Kaulitz schrieb:> Sorry, falsch kopiert.HAL_SPI_Transmit_DMA(&hspi1, flameBits, 2);> HAL_SPI_Transmit_DMA(&hspi1, digitNumbers, 1);
Trotzdem Quatsch!
Nach dem 1. Transmit ist der DMA noch beschäftigt, und du versuchst
direkt einen 2. hinterher zu schieben.
Harry L. schrieb:> Sebastian Kaulitz schrieb:>> Sorry, falsch kopiert.HAL_SPI_Transmit_DMA(&hspi1, flameBits, 2);>> HAL_SPI_Transmit_DMA(&hspi1, digitNumbers, 1);>> Trotzdem Quatsch!> Nach dem 1. Transmit ist der DMA noch beschäftigt, und du versuchst> direkt einen 2. hinterher zu schieben.
Darum kümmere ich mich später, wie die Kommunikation stattfinden soll
(Abwarten der Flags etc.). Ich habe die 2. Transmit Funktion nun
trotzdem mal ausgeblendet. Trotzdem komme ich aber in den Hardfault
Handler.. :(
Sebastian Kaulitz schrieb:>> Wie prüfst du das?> Ich debugge
Da siehst du vermutlich garnix.
Weder den geschriebenen Wert, noch die DMA-Engine in Aktion.
>> Kannst du manuell Werte in SPI_DR schreiben und siehst sie dann aus MOSI>> rauströpfeln?> mit direktem Schreiben mittels hspi.Instance->DR = 0x1111;> geht das Schreiben auch nicht
Wie prüfst du das?
Halte mal ein Oszilloskop, einen Logikanalysator oder meinetwegen eine
LED mit Vorwiderstand an den MOSI-Pin. Wenn du da keine Übertragung
siehst, dann kann die DMA-Engine auch keine Übertragung auslösen.
>> Bist du dir sicher, dass die DMA-Engine die auch>> an die richtige Adresse schreibt?> Ja siehe Bild
Kann ich nicht interpretieren, glaube dir aber einfach mal unbesehen.
;-)
>> Lass die Daten mal nacheinander (stride = 1) ins RAM schreiben>> und schaue, ob die da ankommen. Mit stride = 0 sollte nur der letzte>> Wert ankommen.> Ich verstehe nicht genau, was du genau meinst.
Wenn du ein 10 Byte-Array von A nach B kopierst, dann siehst du die 10
Bytes an den Adressen (B, B+1, B+2, ...) auftauchen. Das
SPI-Datenregister hat aber nur eine Adresse, also müssen die 10 Bytes
nacheinander an die gleiche Adresse geschrieben werden.
Beides kannst du testen, indem du in den RAM schreiben lässt.
Sebastian Kaulitz schrieb:
> sizeof(flameBits)/sizeof(flameBits[U8FLAMELED1ST.position])>> Wo ist das Problem?
Üblicherweise nimmt man sizeof(array)/sizeof(array[0]), wenn man die
Größe eines Arrays in Bytes möchte. Per Definition sind nämlich alle
Einträge gleich groß, da braucht man dem Compiler (und dem Leser) keine
zusätzliche Dereferenzierung aufbürden. :-)
Sebastian Kaulitz schrieb:> Trotzdem komme ich aber in den Hardfault Handler.. :(
Davon schriebst du bisher nichts. Lese die entsprechenden Register im
Handler aus und lasse dich beleuchten, warum der HardFault feuerte.
Könnte ein Alignment-Problem sein.
Du hast, soweit ich das einschätzen kann, zwei Probleme:
a) SPI funktioniert nicht
b) DMA funktioniert nicht.
Sorge erstmal dafür, dass SPI funktioniert. Notfalls teste mit einer
Software-SPI am gleichen Pin, dass deine angeschlossene Hardware auch
funktioniert. Fange erst danach an, mit DMA zu spielen.
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang