Ich möchte mittels DMA 6 ADC Kanäle (STM32H7, ADC3) kontinuierlich sampeln. Anyway das Problem alle Daten sind 0 und es wird ebenfalls kein Interrupt bez DMA ausgelöst. Relevantes im code in korrekter Reihenfolge: _attribute_ ((aligned (32))) unsigned int ADC3Values[6]={0,0,0,0,0,0}; -- dann im main() SCB_EnableDCache(); MX_ADC3_Init(); MX_BDMA_Init(); HAL_ADCEx_Calibration_Start(&hadc3, ADC_CALIB_OFFSET,ADC_SINGLE_ENDED); HAL_ADC_Start_DMA(&hadc3, (uint32_t*)ADC3Values, 6); -- dann im while(1) SCB_InvalidateDCache_by_Addr((uint32_t*)ADC3Values, 24); Die ADC3Values werte bleiben alle bei 0. Versuchweise hatte ich den Cache deaktiviert - es scheint nicht ein cache problem zu sein. Da die Interupts (nach deren Aktivierung) ebenfalls nicht ausgelöst werden, scheint es so dass der ADC gar nicht beginnt (oder der DMA nicht ausgelöst wird). Auffällig ist ebenfalls, dass der ADC3 init vor dem BDMA init erfolgt (dies hat der cube so generiert).
In welchem RAM liegt denn dein Array? Der BDMA kann nur auf den RAM in D3 zugreifen, wenn ich mich richtig erinnere. Früher wurde bei Cube Projekten standardmäßig der DTCM RAM benutzt, mittlerweile sind meine ich alle sections angelegt und er benutzt standardmäßig den RAM in D1. Das Speichermanagement mit DMA beim H7 ist äußerst komplex, falls das dein erstes Projekt in die Richtung ist, kann das spaßig werden.
Kevin M. schrieb: > In welchem RAM liegt denn dein Array? Der BDMA kann nur auf den RAM in > D3 zugreifen, wenn ich mich richtig erinnere. Das Array startet bei 0x24000c40 also im 0x24 Bereich welches meines wissens das D1 ist (!). Habe diesen Address Bereich auch in einem DMA tutorial gesehen, und war der default im cube... Muss das morgen mal testen, danke für den Tipp! Bus Matrix 1 und 3 sollten doch zwar paralelle AHB sein welche jedoch an einer AXI Matrix sind. Lese gerade: AXI (Advanced eXtensible Interface) SRAM (D1 domain) is mapped at address 0x2400 0000 and accessible by all system masters except BDMA through D1 domain AXI bus matrix Anscheinend doch nicht?!
MAX M. schrieb: > Anscheinend doch nicht?! Was sich immer Lohn its ein Blick ins Reference Manual: BDMA main features • Single AHB master • Peripheral-to-memory, memory-to-peripheral, memory-to-memory and eripheral-to-peripheral data transfers • Access to D3 domain SRAM and AHB/APB peripherals (BDMA) ..... Tu dir einen gefallen und leg dir für alle Speicher Bereiche sections an (sofern nicht schon geschehen). Wenn du sie initialisiert haben willst, pass das startup file entsprechend an (sofern nicht schon geschehen). Und leg dir letztlich Makros für die Speicher Bereiche an, damit du deine Variablen einfach da hin schieben kannst wo du sie brauchst. Der H7 ist ein sehr komplexer Controller, dir werden noch mehr solcher Fallstricke begegnen.
Zur Übersicht beim Programmieren des H7 hab ich diese beiden Diagramme immer zur Hand.
Ich hab was ähnliches, bei mir funktionierts (allerdings mit einem F103): ADC hab ich eigentlich gleich eingestellt, beim DMA hab ich nur "Half Word" und ich hab noch beim ADC das "global interrupt" angehacklt. Beim initialisieren kommt bei mir der DMA vor dem ADC (hat auch die IDE so rausgehauen). Das: SCB_EnableDCache(); und das: SCB_InvalidateDCache_by_Addr((uint32_t*)ADC3Values, 24); hab ich nicht (was macht das eigentlich?) Bei mir siehts dann so aus: Variable: volatile uint16_t ADCWerte[6]; //ADC Werte . . /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_DMA_Init(); MX_ADC1_Init(); MX_TIM1_Init(); MX_I2C1_Init(); MX_TIM3_Init(); MX_TIM2_Init(); MX_TIM4_Init(); /* USER CODE BEGIN 2 */ HAL_Delay(100); SSD1306_Init(); SSD1306_Clear(); HAL_Delay(100); HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_1); HAL_TIM_IC_Start(&htim2, TIM_CHANNEL_3); HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL); HAL_ADC_Start(&hadc1); HAL_ADCEx_Calibration_Start(&hadc1); HAL_Delay(150); HAL_ADC_Start_DMA(&hadc1, (uint32_t*) ADCWerte, 6); //ADC -> DMA start HAL_Delay(500); und dann auslesen: HAL_ADC_Stop_DMA(&hadc1); //ADC -> DMA stop //ADC Werte aufsummieren pot += ADCWerte[4]; sens1 += ADCWerte[0]; sens2 += ADCWerte[1]; tsens1 += ADCWerte[2]; tsens2 += ADCWerte[3]; Schalter = ADCWerte[5]; HAL_ADC_Start_DMA(&hadc1, (uint32_t*) ADCWerte, 6); //ADC -> DMA start Ich lese die Werte in einem Interrupt mit einem bestimmten Timerintervall ein, währenddessen stoppe ich den DMA. Das ist aber nicht das ADC interrupt. Vll. solltest Du auch ein Delay nach der ADC Kalibration einfügen, hab mal irgendwo gelesen, dass das sinnvoll sein soll.
:
Bearbeitet durch User
Kevin M. schrieb: > Tu dir einen gefallen und leg dir für alle Speicher Bereiche sections an > (sofern nicht schon geschehen). Danke, Nein habe ich nicht gemacht. Sehe im startup file keinen user editierbaren Bereich. Wie mache ich das dass es vom cube nicht überschrieben wird? (Kann man dies im Cube irgendwie einstellen, dass er diese sections ins startup file schreibt?) Kevin M. schrieb: > Der H7 ist ein sehr komplexer Controller, dir werden noch mehr solcher > Fallstricke begegnen. Das HAL sollte einem diese Probleme eigentlich abnehmen. Anyway schon etwas besonders, dass in der HAL_ADC_Start_DMA dies mit keinem Wort erwähnt wird. Andere Frage: Wie wird eigentlich der DMA controller ge'debug't? Hermann S. schrieb: > Das: > SCB_EnableDCache(); > und das: > SCB_InvalidateDCache_by_Addr((uint32_t*)ADC3Values, 24); > hab ich nicht (was macht das eigentlich?) Der H7 hat einen Cache (schneller Zwischenspeicher 480MHz zwischen der schnellen CPU und dem langsamen RAM/Flash (meines wissens 70MHz)). Durch diesen Cache wird die performance des H7 erst ermöglicht, daher wichtig dass dieser aktiviert wird (SCB_EnableDCache(); sowie SCB_EnableICache();, Daten und Instruktionen). Das Problem ist nun, dass der DMA Kontroller ins memory und nicht in den Cache schreibt, und dies dem CPU nicht mitteilt. Also wenn die CPU die daten Lesen will schaut er zuerst nach obs im Cache vorhanden ist und falls ja holt er sie von dort (falsche daten). Aus diesem Grund muss der Cache in Bezug zu DMA unterhalten werden. Eine Möglichkeit ist SCB_InvalidateDCache_by_Addr( wo aktiv mitgeteilt wird, dass bei einem Abruf von daten aus diesem Adressbereich diese nicht aus dem Cache geholt werden.
Hab das Problem umgangen indem ich den BDMA durch den DMA ersetzt habe, dieser kann in 0x24 addr Bereich schreiben. Das Eregebnis: Kanal eins erhält daten: "127" (erwartet gem analoger Spannung sind ca. 26200) und alle anderen werte des arrays bleiben bei "0"?!?
Hermann S. schrieb: > Ich hab was ähnliches, bei mir funktionierts (allerdings mit einem > F103): Bitte nicht Äpfel mit Birnen vergleichen. MAX M. schrieb: > (Kann man dies im Cube irgendwie einstellen, dass er > diese sections ins startup file schreibt?) Die sections legst du im Linker File (X_FLASH.ld) an, das ASM für die Initialisierung beim Booten im startup_x.s Beide werden beim Erstellen des Projekts einmalig generiert und nicht mehr überschrieben, du kannst dort also bedenkenlos Änderungen vornehmen. MAX M. schrieb: > Das HAL sollte einem diese Probleme eigentlich abnehmen. Das ist eine recht blauäugige Annahme. Die HAL nimmt dir vielleicht das Ansprechen der einzelnen Peripherien "ab" aber dennoch muss man das Zusammenspiel zwischen diesen verstehen. Auch mit der HAL kommt man nicht drum rum sich mit dem Gesamtsystem auseinander zu setzen und einen Blick ins Reference Manual zu werfen, gerade bei einem solch komplexen Controller. MAX M. schrieb: > Hab das Problem umgangen indem ich den BDMA durch den DMA ersetzt habe, Du solltest auf Nummer sicher gehen, dass der DMA auch auf den ADC kommt nur der RAM nützt dir nichts. Das sollte aber hinhauen. MAX M. schrieb: > as Eregebnis: Kanal eins erhält daten: "127" (erwartet gem analoger > Spannung sind ca. 26200) und alle anderen werte des arrays bleiben bei > "0"?!? Ist der DMA richtig konfiguriert, Wortbreite etc. MAX M. schrieb: > Wie wird eigentlich der DMA controller ge'debug't? Der hat Status Register wie alle andere Peripherie auch. PS: Statt immer SCB_InvalidateDCache_by_Addr zu verwenden kannst du dir auch einen gewissen Speicher Bereich mit der MPU als "non cacheable" markieren und Buffer für den DMA dort rein legen.
In den HAL Beispielen zu DMA sind lange Hinweise zur Cache Problematik.
Kevin M. schrieb: > Ist der DMA richtig konfiguriert, Wortbreite etc. Nun viel giebts da nicht einzustellen. Siehe Anhang. Ansonnsten alles gleich wie im orrig Post. J. S. schrieb: > In den HAL Beispielen zu DMA sind lange Hinweise zur Cache Problematik. Denke nicht dass ich ein Cache problem habe. Obwohl ich dieses aktuell, wie Kevin M. richtig bemerkt hat) auf eine inefiziente weise löse.
hier ist ein ADC circular Beispiel, da wird DMA1 verwendet, was natürlich von dem jeweiligen H7 abhängt. Wenn Cube verwendet wird, dann sollte auch der IRQ Handler generiert werden. https://github.com/STMicroelectronics/STM32CubeH7/tree/c94252df7cec24a8fef67b28933353476a1edd3c/Projects/STM32H7B3I-EVAL/Examples/ADC/ADC_DMA_Transfer Das kein Interrupt generiert wird läßt mich an meinem Problem mit dem SDMMC1 auch gerade verzweifeln, Ints gibt es komischerweise nur im PowerSafe Modus. Aber andere Baustelle.
MAX M. schrieb: > und alle anderen werte des arrays bleiben bei > "0"?!? Hast du die Interrupts an? Beim ADC bin ich gerade nicht sicher aber z.B. bei UART ist es so, dass neben dem DMA IQR auch der für den UART an sein muss, sonst bleibt der DMA nach dem ersten Transfer hängen. Das solltest du aber in den Statusregistern des DMA bzw. in der Datenstruktur des ADC sehen.
Kevin M. schrieb: > Hast du die Interrupts an? ja ist an aber HAL_ADC_ConvCpltCallback wird bez hdac3 nicht aufgerufen. Auch auffällig ist, dass der DMA für den ersten wert etwas macht. Bez der ADC einstellungen im ersten Post sollte doch der ADC durchlaufen oder - habe fast der Verdacht DMA funktioniert der ADC jedoch nicht.
Habs: Der cube initialisiert per defailt den DMA nach dem ADC. Nach dem ich dies geändert habe funktionierts (!). Nächste frage: wie mache ich diese Änderung (im nicht user editablen bereich) ohne das der cube dies überschreibt?
MAX M. schrieb: > Nächste frage: wie mache ich diese Änderung (im nicht user editablen > bereich) ohne das der cube dies überschreibt? Project Manager -> Advanced Settings -> Abschnitt "Generated Function Calls" Da gibt es einen "Rank"
Kevin M. schrieb: > Project Manager -> Advanced Settings -> Abschnitt "Generated Function > Calls" > > Da gibt es einen "Rank" Super danke. Funktioniert nun, selbst wenn ich ADC interrupt deaktiviere. :-) Anyway der DMA interrupt lässt sich im cube nicht deaktivieren. Bei deaktivierem ADC3 interrupt und nicht deaktivierem DMA interrupt wird HAL_ADC_ConvCpltCallback aufgerufen (kommt vom DMA)? Wie kann ich sämtliche interrupts bez. ADC3 deaktivieren. (An ADC3 hängen nur unspezielle signale, die jeweils einmal im while(1) loop geprüft werden (spannungsversorgunen, temps etc.). Also es genügt wenn der STM städig im mein array DMAt und ich dieses einmal pro programloop auslese/prüfe.
Die cube hat da irgendwo noch einen fetten Bug. Ich kann nicht mehr genau sagen, welchen ADC/DMA-Parameter es betrifft, aber dieser geht beim Code generieren verloren oder wird von der Cube übersprungen. Prüfe doch mal, ob auch alle deine relevanten Cube-Parameter es in den Initialisierungscode geschafft haben.
Hallo zusammen, ich stehe vor dem gleichen Problem wie der TO. Ich möchte den ADC3 auf einem Nucelo H743ZI2 verwenden. Bei mir wurde der Code korrekt generiert, zuerst wird der BDMA, dann der ADC3 initialisiert. Mein Werte Array enthält mit jedem Startup die gleichen Werte, ich vermute, dass der BDMA auf das Array nicht zugreifen kann. Habe es wie folgt definiert: ALIGN_32BYTES (uint16_t adc3_buf[ADC3_BUF_LEN]) __attribute__((section(".ARM.__at_0x38000000"))); In den Memory Regions wird für RAM_D3 used 0% angegeben. Fragen: - wie finde ich heraus, wo das Array gespeichert worden ist? - wie schaffe ich es, dass der Linker das Array in den RAM_D3 legt?
Kevin M. schrieb: > Wenn du sie initialisiert haben willst, > pass das startup file entsprechend an (sofern nicht schon geschehen). Hallo, ich würde gerne wissen, wie man die in startup file initialisieren kann. Vielen Dank Beste Grüße J.Pan
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.