Hallo, für das Problem brauche ich einen Cortex Experten, da ich hier selber mal nicht weiter komme. Nach dem ich es mit HAL Treibern nur geschafft habe einen Sinus array abzuspielen bin ich für den DAC Trasfer eines WAV Files via DMA Unit auf Low Laytreiber umgeschwenkt. Nach 3 Monaten lesen und durchforsten von ST Dokumenten, welche sich leider nur auf SPL Bibliotheken beziehen, hatte ich jetzt gedacht die richtige Lösung gefunden zu haben. Soll Ablauf: Der Timer6 triggert die DMA Unit, welche dann den DAC Transfer ausführt. Bei halb Trasfer Flag und voll trasfer Flag werden je 256 byte aus dem WAV File nachgeladen. Ist das File am Ende wird der Timer6 gestoppt und die DMA Unit nicht mehr getriggert. So viel zu Theorie. Mein Problem ist jetzt, dass entweder die DMA Unit nicht getriggert wird, der Timer nicht richtig läuft (zu schnell für ein 48kHz WAVE File),Oder die Speicherzuweisung für die DMA unit nicht passt. Das einlesen des Files geht. Siehe DAC DMA Init in dermain der main.c Das komplette Projekt ist .tar.gz und für ein Developmentboard mit STM32F407 Kann sich da jemand Reinfuchsen, dass Problem wird bei Initialisieren und starten der DMA liegen. Ich kom aber nicht drauf wo der Fehler ist...
Gendo I. schrieb: > brauche ich einen Cortex Experten Das Problem ist eher spezifisch für die ST Bibliotheken. > Mein Problem ist jetzt, dass entweder ... oder ....oder Dann finde doch mal heraus, welche Vermutung zutrifft. Dafür gibt es doch Debugger. Immer schön einen Schritt nach dem anderen machen. Falls sich dabei heraus stellt, dass du (wie ich) den Quellcode von ST nicht durchblickst, dann versuche es mal ohne.
Ich habe noch nichts mit LL gemacht, wenn ich aber deinen Code mit dem Beispiel vergleiche, fehlt das LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); zum Vergleich:
1 | /**
|
2 | * @brief Perform DAC activation procedure to make it ready to generate
|
3 | * a voltage (DAC instance: DAC1).
|
4 | * @note Operations:
|
5 | * - Enable DAC instance channel
|
6 | * - Wait for DAC instance channel startup time
|
7 | * @param None
|
8 | * @retval None
|
9 | */
|
10 | void Activate_DAC(void) |
11 | {
|
12 | __IO uint32_t wait_loop_index = 0; |
13 | |
14 | /* Enable DAC channel */
|
15 | LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1); |
16 | |
17 | /* Delay for DAC channel voltage settling time from DAC channel startup. */
|
18 | /* Compute number of CPU cycles to wait for, from delay in us. */
|
19 | /* Note: Variable divided by 2 to compensate partially */
|
20 | /* CPU processing cycles (depends on compilation optimization). */
|
21 | /* Note: If system core clock frequency is below 200kHz, wait time */
|
22 | /* is only a few CPU processing cycles. */
|
23 | wait_loop_index = ((LL_DAC_DELAY_STARTUP_VOLTAGE_SETTLING_US * (SystemCoreClock / (100000 * 2))) / 10); |
24 | while(wait_loop_index != 0) |
25 | {
|
26 | wait_loop_index--; |
27 | }
|
28 | |
29 | /* Enable DAC channel trigger */
|
30 | /* Note: DAC channel conversion can start from trigger enable: */
|
31 | /* - if DAC channel trigger source is set to SW: */
|
32 | /* DAC channel conversion will start after trig order */
|
33 | /* using function "LL_DAC_TrigSWConversion()". */
|
34 | /* - if DAC channel trigger source is set to external trigger */
|
35 | /* (timer, ...): */
|
36 | /* DAC channel conversion can start immediately */
|
37 | /* (after next trig order from external trigger) */
|
38 | LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); |
39 | }
|
Stefan F. schrieb: > Gendo I. schrieb: >> brauche ich einen Cortex Experten > > Das Problem ist eher spezifisch für die ST Bibliotheken. > >> Mein Problem ist jetzt, dass entweder ... oder ....oder > > Dann finde doch mal heraus, welche Vermutung zutrifft. Dafür gibt es > doch Debugger. Immer schön einen Schritt nach dem anderen machen. > > Falls sich dabei heraus stellt, dass du (wie ich) den Quellcode von ST > nicht durchblickst, dann versuche es mal ohne. Den Quellcode wirst du nicht bei ST finden hab ja extra alles Kommentiert. Logischerweise habe ich durch Debuggt, aber wenn ein Interrupt flag nicht gesetzt wird, komme ich damit auch nicht weiter. Da ich mit Low layer nicht auskenne hab ich die Init für DMA und DAC zusammen kopiert und da ist auch das Problem. Die ging nicht eins zu eins. In der Vorlage wurde ein DMA Channel angegeben, Hier kann man aber nur eine Stream angegeben. Den DAC1 habe ich auf Stream5 und DMA Channel 7 konfiguriert. Wie gesagt die Stream Flags welche ich abfrage werden nicht ausgelößt.
pegel schrieb: > LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); > } > [/c] Danke das war der Fehlende Punkt. :D Klingt zwar noch nicht richtig, aber der DMA läuft schon mal und der DAC macht krach. Für alle dies nach probieren wollen: Man muss natürlich die SD Karte noch mounten (hatte) ich bei "aufräumen" aus versehen gelöscht. z.B: FATFS *fs; /* Pointer auf das filesystem object */ fs = malloc(sizeof (FATFS)); f_mount(fs ,"", 1); und den Interrupt muss man disablen sonst hängt man nur in Interrupt routine des streams. __disable_irq();
Gendo I. schrieb: > und den Interrupt muss man disablen sonst hängt man nur in Interrupt > routine des streams. > > __disable_irq(); Gleich so massiv die IRQ's zu deaktivieren sollte nicht nötig sein. Deaktiviere nur mal den betreffenden Timerinterrupt, denn wahrscheinlich wird nur der IRQ vom DMA benötigt.
Der DMA braucht nur die interne Triggerleitung. Sobald der IRQ im Timer aktiviert ist löst der eben auch nen IRQ aus.
Mw E. schrieb: > Der DMA braucht nur die interne Triggerleitung. > Sobald der IRQ im Timer aktiviert ist löst der eben auch nen IRQ aus. Hatte ich eigentlich auch so raus gelesen aber der tut nix. Hier mit rauscht zwar mein Wave File aber es wird erst mal durch gespielt. würde lieber gleich HAL Treiber nehmen aber damit läuft es gar nicht. Und ein Beispiel source hab ich auch niergends gefunden. Aus UM1725 Datenblatt //LL_DMA_DeInit(DMA1, LL_DMA_STREAM_5); //hier springt er immer in di IRQ von stream 5 LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1); // enable DMA for Channel1 LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1); //enable Channel on DAC LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_5,(uint32_t) &DAC_Buff, LL_DAC_DMA_GetRegAddr(DAC1, LL_DAC_CHANNEL_1, LL_DAC_DMA_REG_DATA_12BITS_RIGHT_ALIGNED ), LL_DMA_DIRECTION_MEMORY_TO_PERIPH ); //Speicherbereich auf den die DMA Unit zugreift definieren LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_5, 16); // die beschreibung in UM1725 ist heir etwas dürftig ich hab einfach mal 16 für 16bit genommen LL_DMA_EnableIT_HT(DMA1,LL_DMA_STREAM_5); // Halb Transfer Interrupt für Sream5 aktivieren LL_DMA_EnableIT_TC(DMA1,LL_DMA_STREAM_5); // Complet Transfer Interrupt für Sream5 aktivieren LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); // ohne geht garnix, aber wenn an muss man __disable_irq machen LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5); //Stream5 DAC1 Starten
Also wenn jemand ein funktionierenden (am besten selber getestet), auf das wesentliche reduzierte, Bespielsource hat wie man ein file Stream (16bit wave file) mit einem DMA auf dem DAC ausgeben kann wäre ich sehr dankbar. HAL oder LL. Bin schon seit Monaten am tüfteln.
Solch einen Code hätte ich für dich, allerdings noch total unaufgeräumt und er gibt nicht über den internen DAC aus, sondern per I2S auf den DAC eines F411 Discoverys. Das hat aber eher was von Radio Erewan, denn der Codeteil deienr Verzweiflung ist ja der DMA zum internen DAC per IRQ trigger. Aber bei meinem LED Panel projekt habe ich per Timer den DMA getriggert. Gendo I. schrieb: > Mw E. schrieb: >> Der DMA braucht nur die interne Triggerleitung. >> Sobald der IRQ im Timer aktiviert ist löst der eben auch nen IRQ aus. > > Hatte ich eigentlich auch so raus gelesen aber der tut nix. Doch das geht ;) DIER Register zwar den IRQ einschalten, aber schaltest ihn für den Timer insgesamt nicht beim NVIC ein. Natürlich muss der Timer am DMA als Source nutzbar sein. Guck bei LL_DMA_SetDataLength mal in den Sourcecode+Header, das sind alles nur Wrapper um einen Registerzugriff und da muss sicher der Registerwert als enum/define rein. Zudem ist DMA1, Stream5, Channel1 kein Timertrigger, sondern das ist der I2C. Das kann schonmal nich funzen. Bitte mal ins Refman bei "Table 42. DMA1 request mapping" reingucken. Dabei achten ob da CH1/2 oder UP steht. Dann gehen nur die angebeben Timer Channel als Trigger oder das Updateevent.
Hallo, meinst du die declaration? Dort steht nämlich auch nicht ob es sind um Byte oder Bit handelt. Wenn ich hier was änder klingt es aber immer anderes. Also hat es ja eine wichtigen Einfluss, nur halt welchen. 1- 32 klingt nicht richtig und 256 oder 512 auch nicht. /** * @brief Set Number of data to transfer. * @rmtoll NDTR NDT LL_DMA_SetDataLength * @note This action has no effect if * stream is enabled. * @param DMAx DMAx Instance * @param Stream This parameter can be one of the following values: * @arg @ref LL_DMA_STREAM_0 * @arg @ref LL_DMA_STREAM_1 * @arg @ref LL_DMA_STREAM_2 * @arg @ref LL_DMA_STREAM_3 * @arg @ref LL_DMA_STREAM_4 * @arg @ref LL_DMA_STREAM_5 * @arg @ref LL_DMA_STREAM_6 * @arg @ref LL_DMA_STREAM_7 * @param NbData Between 0 to 0xFFFFFFFF * @retval None */ __STATIC_INLINE void LL_DMA_SetDataLength(DMA_TypeDef* DMAx, uint32_t Stream, uint32_t NbData) { MODIFY_REG(((DMA_Stream_TypeDef*)((uint32_t)((uint32_t)DMAx + STREAM_OFFSET_TAB[Stream])))->NDTR, DMA_SxNDT, NbData); }
Dann ist LL_DMA_SetDataLength die Anzahl der zu übertragenen Datenelemente. Also du willst ja sicherlich einen uint16 pro DMA Trigger übertragen. Daher ist das dann 1 und nicht die Anzahl an Bits. Um die Transferbreite auf 16 Bit zu setzen brauchste dann noch: LL_DMA_SetPeriphSize LL_DMA_SetMemorySize
Also bei TIM6 kann man unter DMA Settings "TIM6_Up" adden und dann entwerde mem to per oder eben andersrum auswählen. Dann hat man bei TIM6 unter NVIC Settings den DMA1 Steam1 als global interrupt und kann das bei DMA -> DMA1 Request auch adden. Im Anhang habe ich mal paar Bilder dazu.
Bloß für mein Verständniss: Ich will ja das der TIM6 den DMA1 triggert und dieser dann von I2C (Den stream des files von der SD Card) die Daten zur DAC periferi schiebt und dann die half trasfer flag (stream5?) und complet trasfer flag (stream5?) abrufen. Also ich habe ja jetzt den DMA1 stream1 bei TIM6_UP event eingetragen. Der Tim6 sollte ja jetzt den DMA triggern. Ich Starte in meinem Unterprogram den TIM6 und warte darauf das es ein Flag durch den Stream5 gibt, aber da passiert noch nichts. Die allgemeine Init hab ich jetzt mal so. LL_DAC_EnableDMAReq(DAC1, LL_DAC_CHANNEL_1); // enable DMA for Channel1 LL_DAC_Enable(DAC1, LL_DAC_CHANNEL_1); //enable Channel on DAC LL_DMA_ConfigAddresses(DMA1, LL_DMA_STREAM_5,(uint32_t) &DAC_Buff, LL_DAC_DMA_GetRegAddr(DAC1, LL_DAC_CHANNEL_1, LL_DAC_DMA_REG_DATA_12BITS_RIGHT_ALIGNED ), LL_DMA_DIRECTION_MEMORY_TO_PERIPH ); //Speicherbereich auf den die DMA Unit zugreift definieren LL_DMA_SetDataLength(DMA1, LL_DMA_STREAM_1, 1); // die beschreibung in UM1725 ist heir etwas dürftig ich hab einfach mal 16 für 16bit genommen LL_DMA_EnableIT_HT(DMA1,LL_DMA_STREAM_5); // Halb Transfer Interrupt für Sream5 aktivieren LL_DMA_EnableIT_TC(DMA1,LL_DMA_STREAM_5); // Complet Transfer Interrupt für Sream5 aktivieren // LL_DAC_EnableTrigger(DAC1, LL_DAC_CHANNEL_1); // ohne geht garnix, aber wenn an muss man __disable_irq machen LL_DMA_SetPeriphSize(DMA1, LL_DMA_STREAM_1 , 0xFFFF); LL_DMA_SetMemorySize(DMA1, LL_DMA_STREAM_1,0xFFFF ); LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_5); //Stream5 DAC1 Starten LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_1); //Stream5 DAC1 Starten //
:
Bearbeitet durch User
Jetzt passiert gar nix mehr. Das HT5 Flag wird nie ausgelöst. Die Sache ist wirklich viel kniffliger als ich anfangs dachte. Mich wundert es nur das ich anscheinend der Erste bin der das mal ausprobiert. Hab noch mal bei der Init alles auf Stream5 geändert geht aber auch nicht. Vom logischen hätte ich jetzt auch gedacht das geht. Der TIM6_UP triggert den DMA1 Stream1 peripheral to memory und der DMA1 Stream5 merory to peripheral den Speicherinhalt auf den DAC1. Welcher dann wieder mein Stream5 flags triggert. Wenn es mal laufen sollte kann ich hier ja mal ein howto bereit stellen. :)
:
Bearbeitet durch User
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.