Hallo zusammen, ich versuche gerade, mit meinem STM32F429 discovery einen Sharp-Entfernungsmesser auszulesen und die Werte im Log auf dem Display anzuzeigen. Dazu ist es einfach nur notwendig, mit dem ADC eine Spannung zu messen. Ich nutze im Übrigen CubeMX 4.2.0 und die aktuelle Firmware 1.1.0 Das Auslesen & Anzeigen gelingt mir bereits im ACD-Polling-Mode. Nun möchte ich auf DMA umstellen, habe aber Probleme. Bewaffnet mit Debugger und Reference-Manual habe ich mich auf die Fehlersuche begeben und einen möglichen Fehler eingegrenzt. Im Screenshot seht ihr den Aufruf __HAL_DMA_ENABLE(hdma). Dahinter steckt ein Makro, das das Enable-Bit auf "1" setzen sollte. Dennoch ist das Enable-Bit in der nächsten Codezeile wieder "0". Dazwischen kam kein Interrupt o.ä., weil ich den Debugger im Single-Step-Modus laufen ließ. Das Reference-Manual des 429 sagt zum "EN"-Bit auf S. 328: --------------------- This bit may be cleared by hardware: – on a DMA end of transfer (stream ready to be configured) – if a transfer error occurs on the AHB master buses – when the FIFO threshold on memory AHB port is not compatible with the size of the burst. --------------------- Hmm, mir sagt das alles reichlich wenig. Es wäre super, wenn mir jemand bei der weiteren Fehlersuche oder -eingrenzung helfen könnte. Vielen Dank! Grüße Klaus
Auch im Single-Step-Betrieb kommen Interrupts, von denen du nichts merkst. Ausschliessen kannst du das nur, wenn du in der ISR einen Breakpoint setzt und der nicht angelaufen wird.
Klaus L. schrieb: > Dazwischen kam kein > Interrupt o.ä., weil ich den Debugger im Single-Step-Modus laufen ließ. Aber der ADC und das DMA Peripherial selbst wird beim Debugging nicht angehalten - und das Enable Bit wird durch die Hardware am Ende des Transfers gelöscht. Das Bit würde nur dann bei "1" bleiben, wenn der Transfer länger dauert als das Auslesen via Debugger. Man könnte es mal mit einer niedriegen ADC Abtastrate probieren (z.B. < 1 Hz).
Vielen Dank für Eure Antworten. Es gibt Neuigkeiten: In meiner Applikation waren alle Peripherials des 429discovery konfiguriert, weil ich as 429discovery-Template des CubeMX verwendet habe. Damit habe ich mir natürlich potentielle Seiteneffekte eingehandelt, die ich auf jeden Fall vermeiden wollte. Ich erzeugte deshalb ein neues Projekt, in dem ausschließlich der ADC und der DMA2 konfiguriert und aktiviert werden. Den Wert der Variablen, die per DMA2 aktualisiert werden sollte , habe ich mir per semihosting auf meinem PC ausgegeben. Die Konfiguration des ADC und des DMA habe ich 1:1 vom Vorprojekt übernommen. Zunächst waren keine Interrupts außer SysTick aktiviert. Der Variablenwert wurde nicht aktualisiert. Aus purem Zufall aktivierte ich dann den DMA-Interrupt und traute meinen Augen kaum: Der Variablenwert wurde regelmäßig aktualisiert. Bitte beachtet: Ich habe keine eigene Callback-Funktion geschrieben; beim Interrupt wurde also nur der Handler der HAL und der weak-Callback ausgeführt! Ich ging einen Schritt weiter und wollte das Log-Display auf dem 429discovery wieder aktivieren, um die Werte auf dem Board direkt auszugeben. Der erste aufzurufende Initialisierungsfunktion dazu lautet "BSP_LCD_Init();". Allein dieser Funktionsaufruf genügt, um das DMA meines ADC wieder lahm zu legen. Sobald dieser Funktionsaufruf auskommentiert ist, läuft die Sache wieder. Ich habe das Reference Manual zum DMA2 durchgelesen und erkenne eigentlich keine Konflikte mit dem Display Controller. Ich verstehe zwei Dinge nicht: - Weshalb muss ich den DMA-Interrupt aktivieren, um den zyklischen Transfer am Leben zu halten? - Weshalb bewirkt der Aufruf von der Display-Initialisierungsfunktion, dass mein ADC-DMA lahm gelegt wird? Das Projekt habe ich hier hochgeladen: https://stm32tutor.googlecode.com/svn/trunk/429AdcDma Danke für Eure Hilfe! Klaus
vorweg - ich haben noch keinen stm32 vor mir gehabt aber zu deiner 1. Frage betüglich DMA interrupt: für mich klingt das recht logisch - denn die DMA ist ja im grunde nur ein schieberegister - wenn da kein interrupt die Daten weiterschiebt können auch keine neuen Daten mehr kommen zu der 2. Frage: aktiviert die LCD_init eventuell irgendwelche Teile die du schon irgendwo nutzt? timer, I/Os, DMA ... hast du schon getestet ob wirklich die DMA lahm liegt oder funktioniert der ADC an sich nicht mehr? ich hoffe ich konnte helfen
Hallo, vielleicht kollidiert Dein DMA mit dem DMA des TFT. Schonmal darüber nachgedacht?
@fuelre zu 1: Hmm, die Logik erschließt sich mir leider noch nicht. Wenn ich DMA nutze, möchte ich doch explizit auf interrupt-basierte Datenschieberei verzichten. Das End-of-Conversion-Event soll also lediglich einen DMA-Transfer auslösen, aber keinen Interrupt erzeugen. Verstehe ich da etwas falsch? @fuelre zu 2: in meinem zweiten Testprojekt konfiguriere ich ausschließlich den ADC und den DMA2. Gemäß Reference Manual hat das LCD nicht den DMA2 zu tun. Ich habe mir den Initialisierungscode des LCDs angeschaut: An keiner Stelle wird da irgendwas mit dem DMAx oder dem ADC gemacht. Der ADC an sich funktioniert weiterhin, allerdings nicht im DMA-Modus, sondern nur noch im Polling-Modus. Diesen Polling-Modus nutze ich jetzt auch mal in meinem Projekt, aber schön ist das nicht... @tom: Ja, darüber habe ich nachgedacht (siehe "@fuelre zu 2") Vielen Dank für Eure weitere Hilfe!
Hier mal ein Schnipsel von einem STM32F103. Da tut DMA ohne jeden Interrupt. So ist es ja auch gedacht.
1 | /* DMA1 channel1 configuration ----------------------------------------------*/ |
2 | DMA_DeInit(DMA1_Channel1); |
3 | DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; |
4 | DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADCConvertedValue; |
5 | DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; |
6 | DMA_InitStructure.DMA_BufferSize = 256; |
7 | DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; |
8 | DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; |
9 | DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; |
10 | DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; |
11 | DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; |
12 | DMA_InitStructure.DMA_Priority = DMA_Priority_High; |
13 | DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; |
14 | DMA_Init(DMA1_Channel1, &DMA_InitStructure); |
15 | |
16 | /* Enable DMA1 channel1 */ |
17 | DMA_Cmd(DMA1_Channel1, ENABLE); |
18 | |
19 | /* ADC1 configuration ------------------------------------------------------*/ |
20 | ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; |
21 | ADC_InitStructure.ADC_ScanConvMode = ENABLE; |
22 | ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; |
23 | ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; |
24 | ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; |
25 | ADC_InitStructure.ADC_NbrOfChannel = 1; |
26 | ADC_Init(ADC1, &ADC_InitStructure); |
27 | |
28 | /* ADC1 channel10 */ |
29 | ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5); |
30 | |
31 | /* Enable ADC1 DMA */ |
32 | ADC_DMACmd(ADC1, ENABLE); |
33 | |
34 | /* Enable ADC1 */ |
35 | ADC_Cmd(ADC1, ENABLE); |
36 | |
37 | /* Enable ADC1 reset calibration register */ |
38 | ADC_ResetCalibration(ADC1); |
39 | /* Check the end of ADC1 reset calibration register */ |
40 | while(ADC_GetResetCalibrationStatus(ADC1)); |
41 | |
42 | /* Start ADC1 calibration */ |
43 | ADC_StartCalibration(ADC1); |
44 | /* Check the end of ADC1 calibration */ |
45 | while(ADC_GetCalibrationStatus(ADC1)); |
46 | |
47 | /* Start ADC1 Software Conversion */ |
48 | ADC_SoftwareStartConvCmd(ADC1, ENABLE); |
also fakt ist, das ADC per DMA auch ohne Interrupt funktioniert (siehe Beispiel von ./.) ich habe deinen Code nicht überprüft, aber kann es sein, das vlt. nur der Clock vom DMA nicht aktiviert ist ?
Hallo Uwe, in deinem Beispiel für den F1 nutzt Du die alte "Standard Peripherial Library". Für meinen F4 nutze ich bereits die neue HAL. Aus Deinem Beisiel lässt sich also leider nur ableiten, dass ADC-DMA auf einem anderen Prozessor mit einer anderen Firmware funktioniert. Mir hilft das somit leider nur wenig weiter. Die HAL abstrahiert etwas stärker, als die alte SPL. Insbesondere das Einschalten der Clock wird von den Bibliotheksroutinen intern realisiert. Insofern kann man das Einschalten glücklicherweise nicht mehr vergessen:-) In LCD_Init() muss es irgendeine magische Wechselwirkung geben, aber ich kann mir einfach nicht vorstellen, wo. Sicherlich könnte ich jetzt Zeile für Zeile aus den Initialisierungsfunktionen des LCDs rauslöschen und wieder testen, aber sowas möchte man doch nur im äußersten Notfall machen...
Klaus L. schrieb: > Aus Deinem > Beisiel lässt sich also leider nur ableiten, dass ADC-DMA auf einem > anderen Prozessor mit einer anderen Firmware funktioniert. Mir hilft das > somit leider nur wenig weiter. > 1. Hinweis : das Beispiel ist nicht von mir 2. ich habe einen laufenden Code für den STM32F429 mit ADC per DMA (ohne Interrupt) 3. Ja, ich benutze nicht die neuen HAL Libs > Insofern kann man das Einschalten glücklicherweise nicht > mehr vergessen:-) wenn dem so wäre, würde es funktionieren... ...tut es ja aber anscheinend nicht also gehe ich davon aus, das man doch noch "manuell" etwas programmieren (oder hinzufügen) muss und um eine Fehlersuche wirst du wohl nicht rumkommmen, es sei denn, dir reicht der ADC im polling mode
Alte Lib - Neue Lib ist doch voellig egal. Ich kann die Werte auch mit einem Debugger in die Register schreiben und der DMA wird die Werte aus dem ADC in den Speicherbereich schreiben. Mein Beispiel sollte Dir nur entsprechende Mindestkonfiguration vermitteln, mit der es bei einem F103 funktioniert. Und so anders gestrickt sind die F4 da auch nicht. Wenn es bei Dir nicht funktioniert, wirst Du halt jede Einstellung von Clock, ADC und DMA an Hand des Referenzhandbuches pruefen muessen. Magische Effekte gibt es nur in Maerchen.
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.