dma schreibt nicht ins Datenregister

Gast #5486822
Lesenswert?

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
#5487457
Lesenswert?

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.
(Firma: Nisch-Aufzüge) Persönliche Seite #5487463
Lesenswert?

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
#5487488
Lesenswert?

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.
Gast #5487689
Lesenswert?

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.
Gast #5487768
Lesenswert?

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.

1
/* SPI1 init function */
2
static void MX_SPI1_Init(void)
3
{
4
  
5
  __HAL_RCC_SPI1_CLK_ENABLE();
6

7
  hspi1.Instance = SPI1;
8
  hspi1.Init.Mode = SPI_MODE_MASTER;
9
  hspi1.Init.Direction = SPI_DIRECTION_2LINES;
10
  hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
11
  hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
12
  hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
13
  hspi1.Init.NSS = SPI_NSS_SOFT;
14
  hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_4;
15
  hspi1.Init.FirstBit = SPI_FIRSTBIT_LSB;
16
  hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
17
  hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
18
  hspi1.Init.CRCPolynomial = 7;
19
  hspi1.Init.CRCLength = SPI_CRC_LENGTH_DATASIZE;
20
  hspi1.Init.NSSPMode = SPI_NSS_PULSE_DISABLE;
21
  if (HAL_SPI_Init(&hspi1) != HAL_OK)
22
  {
23
    _Error_Handler(__FILE__, __LINE__);
24
  }
25

26
}
#5487784
Lesenswert?

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)?
#5487944
Lesenswert?

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.
Gast #5487965
Lesenswert?

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.
Angehängte Dateien:
#5487978
Lesenswert?

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.
Gast #5487991
Lesenswert?

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:
1
   HAL_SPI_Transmit(&hspi1, flameBits , sizeof(flameBits)/sizeof(flameBits[U8FLAMELED1ST.position]), TIMEOUT);
2

3
  HAL_SPI_Transmit_DMA(&hspi1, digitNumbers, 1);
4
  put2STR();

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? :)
Angehängte Dateien:
#5487994
Lesenswert?

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.
Gast #5487997
Lesenswert?

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?
#5488086
Lesenswert?

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?
Gast #5488224
Lesenswert?

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.. :(
#5488613
Lesenswert?

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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren