Forum: Mikrocontroller und Digitale Elektronik dma schreibt nicht ins Datenregister


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Sebastian Kaulitz (Gast)


Bewertung
-1 lesenswert
nicht 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

von Sebastian Kaulitz (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
hat wohl nicht funktioniert.
hier nochmals der Link:

https://www.file-upload.net/download-13230132/test.rar.html

von S. R. (svenska)


Bewertung
3 lesenswert
nicht lesenswert
Hänge deinen Quelltext (Minimalbeispiel) hier an. Von dubiosen Service 
lade ich nichts runter, und viele andere hier sicherlich auch nicht.

von Sebastian Kaulitz (Gast)


Angehängte Dateien:

Bewertung
-1 lesenswert
nicht lesenswert
Ok, ist im Anhang.

von Sebastian Kaulitz (Gast)


Bewertung
-1 lesenswert
nicht lesenswert
Sebastian Kaulitz schrieb:
> Ok, ist im Anhang.

Hat denn keiner eine Idee?
Ich stecke irgendwie fest und komme nicht weiter.

von Max M. (jens2001)


Bewertung
2 lesenswert
nicht lesenswert
Sebastian Kaulitz schrieb:
> Ok, ist im Anhang.

Welche Program erzeugt Sourcecode mit der Endung .rar????

(How low can it go)

von Thomas E. (picalic)


Bewertung
0 lesenswert
nicht 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.

von Winfried J. (Firma: Nisch-Aufzüge) (winne) Benutzerseite


Bewertung
0 lesenswert
nicht 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

: Bearbeitet durch User
von Thomas E. (picalic)


Bewertung
0 lesenswert
nicht 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.

von Sebastian Kaulitz (Gast)


Bewertung
0 lesenswert
nicht 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.

von S. R. (svenska)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Sebastian Kaulitz (Gast)


Bewertung
0 lesenswert
nicht 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
}

von S. R. (svenska)


Bewertung
0 lesenswert
nicht 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)?

von Christopher J. (christopher_j23)


Bewertung
0 lesenswert
nicht 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.

von Sebastian Kaulitz (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.

von Sebastian Kaulitz (Gast)


Bewertung
0 lesenswert
nicht lesenswert
SPI_DR mit 0x40013000 SPI_BASE und DR Offset 0x0C stimmt auch --> 
0x4001300C

von Carl D. (jcw2)


Bewertung
0 lesenswert
nicht 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.

von Sebastian Kaulitz (Gast)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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? :)

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht 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.

von Sebastian Kaulitz (Gast)


Bewertung
0 lesenswert
nicht 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?

von Christopher J. (christopher_j23)


Bewertung
0 lesenswert
nicht 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?

von Harry L. (mysth)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Sebastian Kaulitz (Gast)


Bewertung
0 lesenswert
nicht 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.. :(

von S. R. (svenska)


Bewertung
0 lesenswert
nicht 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

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

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.