STM32U575 und ILI9341 SPI DMA Problem

OP #7795858
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

Angehängte Dateien:
Moderator Persönliche Seite #7795902
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?

OP #7795990
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
}
#7796033
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.

Antwort schreiben

Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt. Bitte hier nur auf die ursprüngliche Frage antworten, für neue Fragen einen neuen Beitrag erstellen.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.