Forum: Mikrocontroller und Digitale Elektronik STM32U575 und ILI9341 SPI DMA Problem


von Daniel S. (sany)


Angehängte Dateien:

Lesenswert?

Hallo,

Ich nutze einen "relativ" neuen STM32U575RGTX, an diesem habe ich ein 
2.8" ILI9341 TFT Screen angeschlossen. (War wohl keine Schlaue Idee, man 
findet kaum Tutorials zur CPU)

(Ich nutze einen ILI9341 Treiber, den ich auch mit einem STM32F4 nutze 
nur mit einem größeren Display. Daher weiß ich, das der Treiber 
funktioniert)

Mein Problem ist nun, der ILI9341 Treiber füllt das Display mit den 
Farben ROT, GRÜN, BLAU nur dann korrekt, wenn ich die DMA funktion 
weglasse, was natürlich tierisch langsam im Bildaufbau ist:

ili9341_gfx.c:
1
void ili9341_transmit_color(ili9341_t *lcd, uint16_t size,
2
    uint16_t color[]/* already byte-swapped (LE) */, ili9341_bool_t wait)
3
{
4
  if ((NULL == lcd) || (0 == size) || (NULL == color))
5
    { return; }
6
7
  HAL_SPI_Transmit(lcd->spi_hal, (uint8_t *)color, size,500);
8
9
  if (ibOK(wait))
10
    { ili9341_transmit_wait(lcd); }
11
}

Wenn ich aber nun die Originalfunktion mit HAL_SPI_Transmit_DMA nehme:
1
void ili9341_transmit_color(ili9341_t *lcd, uint16_t size,
2
    uint16_t color[]/* already byte-swapped (LE) */, ili9341_bool_t wait)
3
{
4
  if ((NULL == lcd) || (0 == size) || (NULL == color))
5
    { return; }
6
7
  HAL_SPI_Transmit_DMA(lcd->spi_hal, (uint8_t *)color, size);
8
9
  if (ibOK(wait))
10
    { ili9341_transmit_wait(lcd); }
11
}

Gibt das Display falsche Farben aus, also bei 
ROT=Magenta,Grün=Grün,Blau= Schwarz.

Nun scheint ja der Fehler in der GPDMA1 konfiguration zu liegen, leider 
finde ich die GPDMA1 etwas kompliziert, so dass ich es aktuell nicht 
geschafft habe, die GPDMA1 so zu konfigurieren, dass Sie so läuft wie 
die "Ursprüngliche" die ich aus den STM32F4 kenne..

Kann mir hier jemand weiterhelfen?

vielen Dank,
Daniel

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Die Funktion ili9341_transmit_color() erhält ein Array color[], deren 
Elemente 16 Bit groß sind. Diese castest Du in einen 8-Bit Pointer - 
soweit scheint das in Ordnung zu sein. Aber was ist mit der Variablen 
"size"? Ist das die Anzahl der Elemente oder die Anzahl in Bytes?

Was ist mit dem Array color[]? Bleibt das während des kompletten 
DMA-Transfers unangetastet? Wenn ja, wie garantierst Du das?

: Bearbeitet durch Moderator
von Daniel S. (sany)


Lesenswert?

Moin,

Korrekt, das Display ist im 16-Bit Modus konfiguriert, der SPI läuft auf 
8-Bit, MSB.

Wenn ich HAL_SPI_Transmit nutze, dann werden die richtigen Farben 
angezeigt, aber sobald ich HAL_SPI_Transmit_DMA nutze, scheint irgendwas 
anders zu sein, vermutlich geswappte Bits oder ähnliches.

Ich kenne mich leider in der neuen GPDMA1 Konfiguration des STM32U575 
nicht so gut aus..

Ich weiß nur, das der Code ohne DMA funktioniert, mit DMA sind die Color 
falsch, scheinbar wird hier nochmal was "gedreht"

Hier mal die ganzen Funktionen:
main.c:
1
  MX_GPIO_Init();
2
  MX_GPDMA1_Init();
3
  MX_CRC_Init();
4
  MX_TIM2_Init();
5
  MX_SPI1_Init();
6
  MX_ICACHE_Init();
7
  /* USER CODE BEGIN 2 */
8
9
  _lcd = ili9341_new(&hspi1, LCD_RESET_GPIO_Port, LCD_RESET_Pin, LCD_NSS_GPIO_Port, LCD_NSS_Pin, LCD_DC_GPIO_Port, LCD_DC_Pin, isoLandscape, LCD_CS_GPIO_Port,LCD_CS_Pin, LCD_IRQ_GPIO_Port, LCD_IRQ_Pin, itsNONE, itnNormalized);
10
  ili9341_fill_screen(_lcd, ILI9341_RED);

Funktionen:
1
void ili9341_fill_screen(ili9341_t *lcd, ili9341_color_t color)
2
{
3
  ili9341_fill_rect(lcd, color,
4
      0, 0, lcd->screen_size.width, lcd->screen_size.height);
5
}
6
7
void ili9341_fill_rect(ili9341_t *lcd, ili9341_color_t color,
8
    int16_t x, int16_t y, uint16_t w, uint16_t h)
9
{
10
  // verify we have something within screen dimensions to be drawn
11
  if (ibNOT(ili9341_clip_rect(lcd, &x, &y, &w, &h)))
12
    { return; }
13
14
  uint32_t num_pixels = w * h;
15
  uint32_t rect_wc    = num_pixels;
16
17
  uint32_t block_wc = rect_wc;
18
  if (block_wc > __SPI_TX_BLOCK_MAX__)
19
    { block_wc = __SPI_TX_BLOCK_MAX__; }
20
21
  // fill entire block with ordered color data
22
  uint16_t color_le = __LEu16(&color);
23
  for (uint16_t i = 0; i < block_wc; ++i)
24
    { spi_tx_block[i] = color_le; }
25
26
  // select target region
27
  ili9341_spi_tft_set_address_rect(lcd, x, y, (x + w - 1), (y + h - 1));
28
  ili9341_spi_tft_select(lcd);
29
30
  HAL_GPIO_WritePin(lcd->data_command_port, lcd->data_command_pin, __GPIO_PIN_SET__);
31
32
  // repeatedly send MIN(remaining-words, block-words) words of color data until
33
  // all rect words have been sent.
34
  uint32_t curr_wc;
35
  while (rect_wc > 0) {
36
    curr_wc = rect_wc;
37
    if (curr_wc > block_wc)
38
      { curr_wc = block_wc; }
39
    ili9341_transmit_color(lcd, curr_wc * 2/*16-bit words*/, spi_tx_block, ibYes);
40
    rect_wc -= curr_wc;
41
  }
42
43
  ili9341_spi_tft_release(lcd);
44
}
45
46
void ili9341_transmit_color(ili9341_t *lcd, uint16_t size,
47
    uint16_t color[]/* already byte-swapped (LE) */, ili9341_bool_t wait)
48
{
49
  if ((NULL == lcd) || (0 == size) || (NULL == color))
50
    { return; }
51
52
  HAL_SPI_Transmit_DMA(lcd->spi_hal, (uint8_t *)color, size);
53
54
  if (ibOK(wait))
55
    { ili9341_transmit_wait(lcd); }
56
}

: Bearbeitet durch User
von Gregor J. (Firma: Jasinski) (gregor_jasinski)


Lesenswert?

Daniel S. schrieb:
> Ich kenne mich leider in der neuen GPDMA1 Konfiguration des STM32U575
> nicht so gut aus..

Diesen Zustand kann man ändern, indem man das Datenblatt studiert.

von J. S. (jojos)


Lesenswert?

Viele Treiber sind da schlecht implementiert, auch bei lvgl Beispielen 
ist das meist so das SPI auf 8 Bit eingestellt wird und damit müssen die 
colors geswapped abgelegt werden.
Es ist geschickter mit 16 Bit SPI zu arbeiten, das ist schneller als 
zwei 8 Bit Transfers und man spart den Schritt mit dem Byte tauschen.
Der DMA steht hier auf Half Word, das sind schon 16 Bit. Es werden also 
16 Bit an den 8 Bit SPI geschickt, damit gehen 8 Bit verloren.
Beim 16 Bit SPI passt es mit den 16 Bit colors, nur viele Kommandos 
bestehen aus einer ungeraden Anzahl an Bytes. Dafür muss entweder SPI 
auf 8 Bit umgestellt werden oder eine 0 als Füllbyte angehängt werden. 
Ersteres habe ich schon so gemacht, letzteres sollte nach ILI Datenblatt 
funktionieren, habe ich aber noch nicht ausprobiert.

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.