Forum: Mikrocontroller und Digitale Elektronik [STM32 SAI] Warum läuft DMA in Schleife?


von Solocan Z. (solocan)


Lesenswert?

Ich stehe vor einem seltsamen Verhalten, das ich mir nicht erklären 
kann:

Ich will (beispielhaft) ein einziges 32-bit Word über DMA ins 
Datenregister von SAI schreiben. Also ich will, dass das erwünschte 
Datenblock ins FIFO geht, wenn es vollständig übertragen ist, ein 
Callback auslöst und aufhört. Im normalen (Blocking) Modus funktioniert 
das, wenn ich es mit DMA mache, läuft die DMA die ganze Zeit im 
Hintergrund.

Aber das geschriebene Wort wird von einem Mechanismus dauerhaft ins FIFO 
gefüllt und in Schleife ausgegeben. D.h. ich kriege kein Transfer 
complete callback etc. Wodurch wird die DMA die ganze Zeit getriggert?

Das folgende vereinfachte Programm gibt das Wort "buf" in Schleife 
wieder, siehe Bild.  https://ibb.co/1K5tn7G (Gerade lassen sich keine 
Bilder hier hochladen?)

1
//Programmcode
2
uint32_t buf=0b10101010101010101100110011001100;
3
HAL_SAI_Transmit_DMA2(&hsai_BlockA1, (uint8_t*)&buf, 1);
4
5
//DMA Transmit Funktion
6
7
HAL_StatusTypeDef HAL_SAI_Transmit_DMA2(SAI_HandleTypeDef *hsai, uint8_t *pData, uint16_t Size){
8
9
    HAL_DMA_Start(hsai->hdmatx, (uint32_t)pData, (uint32_t)&hsai->Instance->DR, Size);
10
11
    // Enable SAI
12
    __HAL_SAI_ENABLE(hsai);
13
14
    /* Enable SAI Tx DMA Request */
15
    hsai->Instance->CR1 |= SAI_xCR1_DMAEN;
16
17
    return HAL_OK;
18
19
}
20
21
//Konfiguration SAI
22
23
  hsai_BlockA1.Instance = SAI1_Block_A;
24
  hsai_BlockA1.Init.AudioMode = SAI_MODEMASTER_TX;
25
  hsai_BlockA1.Init.Synchro = SAI_ASYNCHRONOUS;
26
  hsai_BlockA1.Init.OutputDrive = SAI_OUTPUTDRIVE_DISABLE;
27
  hsai_BlockA1.Init.NoDivider = SAI_MASTERDIVIDER_ENABLE;
28
  hsai_BlockA1.Init.FIFOThreshold = SAI_FIFOTHRESHOLD_HF;
29
  hsai_BlockA1.Init.AudioFrequency = SAI_AUDIO_FREQUENCY_8K;
30
  hsai_BlockA1.Init.SynchroExt = SAI_SYNCEXT_DISABLE;
31
  hsai_BlockA1.Init.MonoStereoMode = SAI_STEREOMODE;
32
  hsai_BlockA1.Init.CompandingMode = SAI_NOCOMPANDING;
33
  hsai_BlockA1.Init.TriState = SAI_OUTPUT_NOTRELEASED;
34
  HAL_SAI_InitProtocol(&hsai_BlockA1, SAI_I2S_MSBJUSTIFIED, SAI_PROTOCOL_DATASIZE_32BIT, 2);
35
36
//Konfiguration DMA
37
38
__HAL_RCC_DMA2_CLK_ENABLE();
39
40
 hdma_sai1_a.Instance=DMA2_Stream1;
41
 hdma_sai1_a.Init.Channel = DMA_CHANNEL_0;// Channel 0, Stream 0
42
 hdma_sai1_a.Init.Direction=DMA_PERIPH_TO_MEMORY;
43
 hdma_sai1_a.Init.PeriphInc=DMA_PINC_DISABLE;
44
 hdma_sai1_a.Init.MemInc=DMA_MINC_DISABLE;
45
 hdma_sai1_a.Init.PeriphDataAlignment=DMA_PDATAALIGN_HALFWORD;
46
 hdma_sai1_a.Init.MemDataAlignment=DMA_MDATAALIGN_HALFWORD;
47
 hdma_sai1_a.Init.Mode=DMA_NORMAL;
48
 hdma_sai1_a.Init.Priority=DMA_PRIORITY_HIGH;
49
 hdma_sai1_a.Init.FIFOMode=DMA_FIFOMODE_DISABLE;
50
 hdma_sai1_a.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_HALFFULL;
51
 hdma_sai1_a.Init.MemBurst=DMA_MBURST_SINGLE;
52
 hdma_sai1_a.Init.PeriphBurst=DMA_PBURST_SINGLE;
53
 hdma_sai1_a.XferCpltCallback  = HAL_DMA_XFER_HALFCPLT_CB_ID;
54
55
//Initialize DMA
56
HAL_DMA_Init(&hdma_sai1_a);

von Martin B. (ratazong)


Lesenswert?

Blick Dein Programm nicht ganz, aber was mir auffällt:

hdma_sai1_a.Init.MemInc=DMA_MINC_DISABLE;

müsste da nicht enable stehen? Die Adressen im memorry sollten doch 
incrementiert werden.


hdma_sai1_a.XferCpltCallback  = HAL_DMA_XFER_HALFCPLT_CB_ID;

Wieso HALFCPLT ?

von Solocan Z. (solocan)


Lesenswert?

Martin B. schrieb:
> Blick Dein Programm nicht ganz, aber was mir auffällt:
>
> hdma_sai1_a.Init.MemInc=DMA_MINC_DISABLE;
>
> müsste da nicht enable stehen? Die Adressen im memorry sollten doch
> incrementiert werden.
>
>
> hdma_sai1_a.XferCpltCallback  = HAL_DMA_XFER_HALFCPLT_CB_ID;
>
> Wieso HALFCPLT ?

Nein, meine Quell- und Zieladresse sind fest. Die Daten kommen auch 
richtig an. Nur es hört nach einem Transfer nicht auf...(Das mit dem 
Enablen habe ich auch probiert, bringt nichts.)

Das Problem ist, als wäre der Circular mode aktiv, obwohl ich es 
deaktiviert habe (Normal mode aktiv)

HALFCPLT ist auskommentiert. Einfach ignorieren.

: Bearbeitet durch User
von Martin B. (ratazong)


Lesenswert?

Willst Du immer nur ein byte übertragen?

Was macht das Programm denn, wenn Du DMA_MINC_ENABLE da rein schreibst?
Würde mich mal interessieren.
Grüße

von Solocan Z. (solocan)


Lesenswert?

Martin B. schrieb:
> Willst Du immer nur ein byte übertragen?

Nein, ich möchte um die 48 Word große Datenblöcke übertragen, aber nicht 
in Schleife. Das Verhalten ist aber dasselbe, ich habe nur den 
Programmcode vereinfacht, um es zu zeigen.

Martin B. schrieb:
> Was macht das Programm denn, wenn Du DMA_MINC_ENABLE da rein schreibst?

Genau dasselbe. Es ändert sich nichts. Weiterhin in Schleife

von Martin B. (ratazong)


Lesenswert?

da fällt mir nicht mehr viel ein.

willst Du DMA_MEMORY_TO_PERIPH oder DMA_PERIPH_TO_MEMORY ?

aber Du sagst ja es funktioniert. Merkwürdig.

von Solocan Z. (solocan)


Lesenswert?

Martin B. schrieb:
> Merkwürdig

Was auch sehr merkwürdig ist, dass jemand alle meiner Beiträge pauschal 
negativ bewertet. Das ist sehr merkwürdig. Na ja.

Ich habe gerade festgestellt, dass SAI Initialisierung die DMA 
Einstellungen überschreibt. HAL eben...Jetzt versuche ich 
herauszufinden, wie und wo und warum sie das tut.

von Solocan Z. (solocan)


Lesenswert?

Fehler gefunden:

Die DMA wird in "HAL_SAI_MspInit()" in der Datei "stm32f7xx_hal_msp.c" 
intialisiert. Da ich das nicht sah, hatte ich eine andere Instanz in 
meiner "main.c" definiert. Meine Instanz samt Einstellungen wurde 
natürlich überschrieben.

Also konkret lag's wie vermutet an DMA mode. "DMA_NORMAL" läuft einmal 
und "DMA_CIRCULAR" läuft in Schleife.

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.