Ich bin seit ein paar Tagen stolzer Besitzer eines STM32H735 Disco Boards. Ich bekomme aber HAL DMA2D nicht ans Laufen. Folgender Code soll eine Pixelzeile aus dem RAM in den Framebuffer kopieren: DMA2D_HandleTypeDef hdma2d; static void ConvertLineToRGB(uint32_t *pSrc, uint32_t *pDst, uint32_t xSize) { hdma2d.Instance = DMA2D; /* Configure the DMA2D Mode, Color Mode and output offset */ hdma2d.Init.Mode = DMA2D_M2M; hdma2d.Init.ColorMode = DMA2D_OUTPUT_ARGB8888; hdma2d.Init.OutputOffset = 0; /* Foreground Configuration */ hdma2d.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; //hdma2d.LayerCfg[1].InputAlpha = 0xFF; hdma2d.LayerCfg[1].InputColorMode = DMA2D_INPUT_ARGB8888; hdma2d.LayerCfg[1].InputOffset = 0; /* DMA2D Initialization */ if(HAL_DMA2D_Init(&hdma2d) == HAL_OK) { if(HAL_DMA2D_ConfigLayer(&hdma2d, 1) == HAL_OK) { HAL_DMA2D_Start(&hdma2d, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1); HAL_DMA2D_PollForTransfer(&hdma2d, 25); } } //memcpy(pDst, pSrc, xSize * 4); } Im Debugger sehe ich, dass HAL_DMA2D_Start() den Zielspeicher mit Nullen vollschreibt, statt aus pSrc zu kopieren. Wenn ich den memcpy() darunter aktiviere, werden die Daten korrekt kopiert und das Display stellt die Grafik richtig dar. Ich habe inzwischen den Eindruck, der HAL hat einen Bug. Tatsächlich gibt es eine ähnliche Funktion LL_ConvertLineToRGB() im BSP (Board Support Package). Allerdings ist auch im BSP der DMA2D Code per #define deaktiviert und die Pixel werden "zu Fuss" kopiert. DMA2D scheint bei ST auch nicht funktioniert zu haben. Hat jemand eine Idee?
ein möglicherweise ähnliches Problem hatte ich ja gerade hier geschildert: Beitrag "komplexes Problem mit Grafik und Dateisystem auf Disco-F746NG" Allerdings mit dem F746 und F769. Da funktionierte DMA2/DMA2D prinzipiell und z.B. beim F746 war der auch für ConvertLine aktiv:
1 | static void LL_ConvertLineToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ColorMode) |
2 | {
|
3 | /* Configure the DMA2D Mode, Color Mode and output offset */
|
4 | hDma2dHandler.Init.Mode = DMA2D_M2M_PFC; |
5 | hDma2dHandler.Init.ColorMode = DMA2D_ARGB8888; |
6 | hDma2dHandler.Init.OutputOffset = 0; |
7 | |
8 | /* Foreground Configuration */
|
9 | hDma2dHandler.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA; |
10 | hDma2dHandler.LayerCfg[1].InputAlpha = 0xFF; |
11 | hDma2dHandler.LayerCfg[1].InputColorMode = ColorMode; |
12 | hDma2dHandler.LayerCfg[1].InputOffset = 0; |
13 | |
14 | hDma2dHandler.Instance = DMA2D; |
15 | |
16 | /* DMA2D Initialization */
|
17 | if(HAL_DMA2D_Init(&hDma2dHandler) == HAL_OK) |
18 | {
|
19 | if(HAL_DMA2D_ConfigLayer(&hDma2dHandler, 1) == HAL_OK) |
20 | {
|
21 | if (HAL_DMA2D_Start(&hDma2dHandler, (uint32_t)pSrc, (uint32_t)pDst, xSize, 1) == HAL_OK) |
22 | {
|
23 | /* Polling For DMA transfer */
|
24 | HAL_DMA2D_PollForTransfer(&hDma2dHandler, 10); |
25 | }
|
26 | }
|
27 | }
|
28 | }
|
um einen rechteckigen Bereich zu übertragen habe ich eine weitere Funktion hinzugefügt:
1 | /**
|
2 | * @brief Converts an area to an ARGB8888 pixel format.
|
3 | * @param pSrc: Pointer to source buffer
|
4 | * @param pDst: Output color
|
5 | * @param xSize: Buffer width
|
6 | * @param ySize: Buffer width
|
7 | * @param ColorMode: Input color mode
|
8 | * @retval None
|
9 | */
|
10 | static void LL_ConvertAreaToARGB8888(void *pSrc, void *pDst, uint32_t xSize, uint32_t ySize, uint32_t ColorMode) |
11 | {
|
12 | /* Configure the DMA2D Mode, Color Mode and output offset */
|
13 | hDma2dHandler.Init.Mode = DMA2D_M2M_PFC; |
14 | hDma2dHandler.Init.ColorMode = ColorMode; |
15 | hDma2dHandler.Init.OutputOffset = BSP_LCD_GetXSize() - xSize; |
16 | |
17 | /* Foreground Configuration */
|
18 | hDma2dHandler.LayerCfg[1].AlphaMode = DMA2D_REPLACE_ALPHA; |
19 | hDma2dHandler.LayerCfg[1].InputAlpha = 0xff; |
20 | hDma2dHandler.LayerCfg[1].InputColorMode = ColorMode; |
21 | hDma2dHandler.LayerCfg[1].InputOffset = 0; |
22 | |
23 | // Background
|
24 | hDma2dHandler.LayerCfg[0].AlphaMode = DMA2D_NO_MODIF_ALPHA; |
25 | hDma2dHandler.LayerCfg[0].InputColorMode = DMA2D_INPUT_ARGB8888; |
26 | hDma2dHandler.LayerCfg[0].InputOffset = BSP_LCD_GetXSize() - xSize; |
27 | |
28 | hDma2dHandler.Instance = DMA2D; |
29 | |
30 | /* DMA2D Initialization */
|
31 | if(HAL_DMA2D_Init(&hDma2dHandler) == HAL_OK) |
32 | {
|
33 | if(HAL_DMA2D_ConfigLayer(&hDma2dHandler, 1) == HAL_OK) |
34 | {
|
35 | #ifdef _USE_DMA2D_POLLING_
|
36 | if (HAL_DMA2D_Start(&hDma2dHandler, (uint32_t)pSrc, (uint32_t)pDst, xSize, ySize) == HAL_OK) |
37 | {
|
38 | /* Polling For DMA transfer */
|
39 | HAL_DMA2D_PollForTransfer(&hDma2dHandler, 100); |
40 | }
|
41 | #else
|
42 | if (HAL_DMA2D_Start_IT(&hDma2dHandler, (uint32_t)pSrc, (uint32_t)pDst, xSize, ySize) == HAL_OK) |
43 | {
|
44 | // DMA Complete Interrupt should be prepared
|
45 | }
|
46 | #endif
|
47 | }
|
48 | }
|
49 | }
|
50 | |
51 | void BSP_LCD_SetDMACpltCallback( void (*fn)(DMA2D_HandleTypeDef *hdma2d)) |
52 | {
|
53 | hDma2dHandler.XferCpltCallback = fn; |
54 | }
|
55 | |
56 | /**
|
57 | * @brief override weak DMA2D ISR
|
58 | call HAL handler, which calls callbacks
|
59 | */
|
60 | |
61 | void DMA2D_IRQHandler(void) |
62 | {
|
63 | HAL_DMA2D_IRQHandler(&hDma2dHandler); |
64 | }
|
Die DMA Funktion muss aber vorher auch initialisiert werden, wird das im H735 BSP ausgeführt? Sinnvoll wird DMA erst richtig mit Interrupt und double buffering, warten und Zeit verbraten ist wenig effektiv. Da muss man sich aber mit den fürchterlichen weak Deklarationen rumschlagen. Die Probleme die ich hatte liessen sich am einfachsten durch Abschalten des D-Cache lösen, letztlich ging es aber durch das ClearInvalidate vor der DMA Operation. Und bitte keine HAL bashing, die bügelt eigentlich eher die Hardwarefehler aus. Von den H7 gibt es teilweise schon mehrere Revisionen und die HAL hat Workarounds eingebaut. Das H735 Board liegt aber auch schon vor meiner Nase und ist der nächste Kandidat für die Portierung :)
> Die DMA Funktion muss aber vorher auch initialisiert werden, wird das im
H735 BSP ausgeführt?
Ich habe das BSP Projekt kopiert und dort meine Änderungen eingefügt. In
main() wird BSP_LCD_Init() aufgerufen, dass - soweit ich das sehe -
DMA2D initialisiert?
um welches Beispiel geht es denn konkret? Im CubeH7 sind ja mehrere drin. https://github.com/STMicroelectronics/STM32CubeH7
Das Projekt heisst "BSP". https://github.com/STMicroelectronics/STM32CubeH7/tree/master/Projects/STM32H735G-DK/Examples/BSP
Habe das Beispiel in die CubeIDE importiert, aber der Compiler meckert. Es fehlen includes oder Includepfade stimmen nicht. Andere Beispiele ließen sich kompilieren. Habe mich schon lange nicht mehr mit Eclipse gequält.
habe das Beispiel kompiliert bekommen, man musste noch einen Teil lizensierten Code von ST runterladen der nicht im Repo enthalten ist. Sowas dürfte ruhig im readme stehen, aber nun läufts. Ich sehe nur Beispiele mit aktivem DMA2D und die Beispiele funktionieren auch. Im readme findet man aber den Hinweis auf die RAM/Cache Problematik die mir auch zu schaffen macht. Wenn aus Speicher im DTCM kopiert wird, dann stört der Cache nicht weil dieser RAM nicht gecashed wird. Bei RAM an anderen Bussen wird es komplizierter. Entweder Cache vor dem DMA durchschreiben (mit SCB_CleanDCache()), oder die MPU konfigurieren das write through gemacht wird. Letzteres ist mir aber nicht gelungen, und ich habe zig Einstellungen probiert. Edit: jetzt habe ich die Stellen gefunden die du vermutlich meinst, da kann eingestellt werden ob DMA oder Pixelweises füllen verwendet werden soll. Und wenn DMA, dann noch ob Cache Pflege nötig ist, was ja von dem Speicher abhängt.
Johannes S. schrieb: > musste noch einen Teil > lizensierten Code von ST runterladen Das kann man sich ersparen, wenn man mit der CubeIDE die Firmware-Pakete für das Board installiert. Es war in der Tat der Cache schuld. Nachdem ich I und D Caches beide deaktiviert hatte, funktionierte es. Bin bisher nur Mikrocontroller ohne Caches gewohnt. > write through MPU_InitStruct.IsBufferable = MPU_ACCESS_NOT_BUFFERABLE; sollte write-through aktivieren. > jetzt habe ich die Stellen gefunden die du vermutlich meinst, da kann > eingestellt werden ob DMA oder Pixelweises füllen verwendet werden soll. > Und wenn DMA, dann noch ob Cache Pflege nötig ist, was ja von dem > Speicher abhängt. Ich sehe da nichts für Cache-Einstellungen. In der Datei stm32h735g_discovery_conf.h steht die Zeile: #define USE_DMA2D_TO_FILL_RGB_RECT 0U Also ist DMA für die FillRGBRect() Funktion deaktiviert. Die hatten wohl auch das Problem mit den Caches. :-) In der Datei stm32h735g_discovery_lcd.c ist übrigens noch ein Bug: BSP_LCD_Ctx_t LcdCtx[LCD_INSTANCES_NBR]; Es muss Lcd_Ctx heißen.
Johannes S. schrieb: > lange nicht mehr mit Eclipse > gequält. Welche IDE benutzt du denn? Ich finde die CubeIDE auch nicht besonders gut. Aber sie ist kostenlos.
Thorsten S. schrieb: > Ich sehe da nichts für Cache-Einstellungen. In der Datei > stm32h735g_discovery_conf.h steht die Zeile: > > #define USE_DMA2D_TO_FILL_RGB_RECT 0U > > Also ist DMA für die FillRGBRect() Funktion deaktiviert. Die hatten wohl > auch das Problem mit den Caches. :-) aber das define kann man ja ändern. Nur muss man dann wie im readme.txt zu den Projekten sich auch um den Cache kümmern. entweder - Sourcebuffer (komplett) in DTCM legen, das hat 0 Waitstates und den Cache nicht aktiv oder - Sourcebuffer in SRAM und vor dem DMA Cache Clean ausführen (kostet aber Zeit, je nach Größe des Buffers) oder - Sourcebuffer in SRAM und Write through konfigurieren. Da war noch das Alignment wichtig, siehe meinen anderen Thread. > Es war in der Tat der Cache schuld. Nachdem ich I und D Caches beide > deaktiviert hatte, funktionierte es. Bin bisher nur Mikrocontroller ohne > Caches gewohnt. In diesem Fall sollte es reichen den D-Cache deaktiviert zu lassen. Ja, es gibt ja nicht so viele µC mit Cache und ich kannte die Fallstricke auch noch nicht. Bei F7/H7 ist definitv Schluss mit einfachem µC. Da stellt sich sowieso die Frage ob für Grafiklastige Anwendungen so ein µC noch die richtige Wahl ist oder schon ein embedded Linux auf Cortex-A passender wäre. Aber ST scheint da ja einen Markt für zu haben. > Welche IDE benutzt du denn? Ich finde die CubeIDE auch nicht besonders > gut. Aber sie ist kostenlos. Wenn man mit CubeMX arbeitet, dann ist die IDE schon ok. Das Eclipse ist nur übermächtig und ein allgemeines Framework, daher sind einige Einstellungen sehr versteckt. Ich benutze lieber VSCode und C++ Komponenten mit Mbed-OS, den Codegenerator von CubeMX dann nur für Teile die das OS nicht unterstützt.
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.