Forum: Mikrocontroller und Digitale Elektronik STM32F7 Bitmap auf SD-Karte speichern via DMA2D


von Adri G. (dgst)


Angehängte Dateien:

Lesenswert?

Hallo allerseits,

ich habe eine kleine Kamera Demo Plattform für den MT9D111-Sensor von 
Aptina auf einem STM32F7-discovery Board entwickelt. Ich habe mich dabei 
an die Beispiele aus der HAL-Library von ST gehalten.

Der Datenfluss für die Preview ist wie folgt:
DCMI-Interface -> DMA -> Frame Ringbuffer im SDRAM (0xC0260000). Nach 
jeder übertragenen Zeile gibt es ein Interrupt, wo dann der DMA2D 
benutzt wird, um die Zeile von RGB565 in ARGB8888 zu wandeln und in den 
Display Buffer (0xC0130000) zu kopieren.

Außerdem habe ich eine Fotofunktion implementiert, bei der ein Bild mit 
höherer Auflösung (VGA) in einen weiteren Bereich des SDRAMs 
(0xC0390000) gepeichert wird. Dieses Bild kann auch wieder über den 
DMA2D in den LCD Framebuffer kopiert werden, damit man es sich ansehen 
kann.

Das funktioniert alles wunderbar, daher nun zum eigentlichen Problem:
Ich möchte nun ein Bild aus der Fotofunktion als Bitmap auf einer FAT 
formatierten SD-Karte speichern, um es mir am PC anzugucken.

Hier der Code dafür:
1
void SD_write_image(void)
2
{
3
  uint8_t sd_check = SD_Check();//check if SD card is inserted
4
5
  switch (sd_check)
6
  {
7
  case SD_NOT_PRESENT:
8
  {
9
    BSP_LCD_DisplayStringAt(10, 154, (uint8_t*)"No SD card!", LEFT_MODE);
10
    HAL_Delay(1000);
11
    Draw_UI();
12
    break;
13
  }
14
  case SD_PRESENT:
15
  {
16
    FIL file; //file object
17
    char file_str[30] = "image01.bmp";//filename
18
19
    DMA2D_HandleTypeDef hdma2d_buf;
20
21
    int32_t i, j;
22
    uint32_t tmp = 0;
23
24
    uint16_t img_buf[640];
25
26
    UINT bytes_written;
27
28
    FRESULT fs_error;
29
30
    file_str[6] = (char)((img_counter % 10) + 48);//increase the filename
31
    file_str[5] = (char)(((img_counter/10) % 10) + 48);
32
33
    //create a test pattern, black
34
    for(j = 0; j < 640; j++)
35
    {
36
      if((j%2) == 0) img_buf[j] = 0x0;
37
      else img_buf[j] = 0x0;
38
    }
39
40
    fs_error = SD_Mount();
41
    if(fs_error != FR_OK) Filesystem_ErrorHandler(fs_error);
42
43
    fs_error = SD_OpenFile(&file, file_str, F_WR_CLEAR);
44
    if(fs_error != FR_OK) Filesystem_ErrorHandler(fs_error);
45
46
    fs_error = f_write(&file, bmp_fileheader640, 138, &bytes_written);
47
48
    if(fs_error != FR_OK)
49
    {
50
      Filesystem_ErrorHandler(fs_error);
51
    }
52
53
    for(i = 0; i < 480; i++)//480 lines
54
    {
55
      //copy one line in a RAM buffer using DMA2D
56
57
      /* Enable DMA2D clock */
58
      __HAL_RCC_DMA2D_CLK_ENABLE();
59
60
      /* Configure the DMA2D Mode, Color Mode and output offset */
61
      hdma2d_buf.Init.Mode         = DMA2D_M2M;
62
      hdma2d_buf.Init.ColorMode    = DMA2D_RGB565;
63
      hdma2d_buf.Init.OutputOffset = 0;
64
65
      /* Foreground Configuration */
66
      hdma2d_buf.LayerCfg[1].AlphaMode = DMA2D_NO_MODIF_ALPHA;
67
      hdma2d_buf.LayerCfg[1].InputAlpha = 0xFF;
68
      hdma2d_buf.LayerCfg[1].InputColorMode = CM_RGB565;
69
      hdma2d_buf.LayerCfg[1].InputOffset = 0;
70
71
      hdma2d_buf.Instance = DMA2D;
72
73
      /* DMA2D Initialization */
74
      if(HAL_DMA2D_Init(&hdma2d_buf) == HAL_OK)
75
      {
76
        if(HAL_DMA2D_ConfigLayer(&hdma2d_buf, 1) == HAL_OK)
77
        {
78
          if (HAL_DMA2D_Start(&hdma2d_buf, (uint32_t)(CAPTURE_FRAME_BUFFER + tmp), (uint32_t)&img_buf, 640, 1) == HAL_OK)
79
          {
80
            /* Polling For DMA transfer */
81
            HAL_DMA2D_PollForTransfer(&hdma2d_buf, 10);
82
          }
83
        }
84
      }
85
86
87
88
      fs_error = f_write(&file, img_buf, 1280, &bytes_written);
89
      if(fs_error != FR_OK)
90
      {
91
        Filesystem_ErrorHandler(fs_error);
92
      }
93
      tmp = tmp + 640*sizeof(uint16_t);//increase the SDRAM address
94
    }
95
96
}
97
98
    fs_error = SD_CloseFile(&file);
99
    if(fs_error != FR_OK) Filesystem_ErrorHandler(fs_error);
100
101
    fs_error = SD_UnMount();
102
    if(fs_error != FR_OK) Filesystem_ErrorHandler(fs_error);
103
104
    img_counter++;
105
    sprintf((char*)text, "Images stored: %d", (int)img_counter);
106
    BSP_LCD_DisplayStringAt(5, LINE(9), (uint8_t*)text, LEFT_MODE);
107
108
    break;
109
  }
110
  default: break;
111
  };
112
}

Kurze Erklärung dazu:
Ich hole immer eine Zeile des Bildes via DMA2D aus dem SDRAM und 
speichere sie im onchip SRAM. Pixel Format Conversion ist hier nicht 
notwendig, da der BMP-Header entsprechend angepasst ist (alles RGB565, 
2Byte/pixel).
*Nun bekomme ich aber offensichtlich nicht die richtigen bzw. 
unvollständige Daten aus dem SDRAM. Das BMP sieht aus wie im Anhang.*

Teilweise sind schon Bilddaten zu sehen, aber was mich am meisten 
verwundert sind die schwarzen Balken. Diese kommen daher, dass ich den 
Zeilenpuffer im SRAM vor der DMA2D-Aktion mit Nullen beschreiben.
Nach meinem Verständnis sollten die aber später alle wieder 
überschrieben werden.

Habt ihr vielleicht eine Ahnung, wo der Fehler liegen könnte?
Ich stehe gerade echt auf dem Schlauch, vor allem da zwei ähnliche 
Funktionen ohne Probleme funtionieren.

von Jim M. (turboj)


Lesenswert?

Ich mag da was übersehen haben, aber müsste nicht ein
1
fs_error = f_write(&file, (uint8_t*)CAPTURE_FRAME_BUFFER, 640*480*2, &bytes_written);

auch ganz ohne den HAL DMA funktionieren? Das ist hier doch nur ein 
memcpy() Ersatz.

von Adri G. (dgst)


Lesenswert?

Hätte ich auch gedacht und habe es deswegen auch erst so probiert.

Da bekomme ich dann allerdings eine Hard Fault exception (auch wenn ich 
das zeilenweise mache).

von Dr. Sommer (Gast)


Lesenswert?

Adrian O. schrieb:
> Da bekomme ich dann allerdings eine Hard Fault exception (auch wenn ich
> das zeilenweise mache).

Das liegt vermutlich daran, dass du einen unaligned Zugriff auf den 
SDRAM machst (d.h. Halfword-Zugriff mit ungerader Adresse, oder 
Word-Zugriff mit Adresse die kein Vielfaches von 4 ist). Wenn du die 
f_write Routine dementsprechend korrigierst, solltest du direkt aus dem 
SDRAM schreiben können, ohne das erst per DMA umkopieren zu müssen.

von Adri G. (dgst)


Angehängte Dateien:

Lesenswert?

Hm ok, die f_write gehört zu der FATFS Library und da wollte ich 
eigentlich ungerne drin rumfuhrwerken. Zumal ich auch nur rudimentär 
verstehe, was da drin passiert.

Ich muss auch nicht direkt aus dem SDRAM schreiben. Es würde mich schon 
glücklich machen, wenn das mit dem DMA funktionieren würde.
Irgendwelche Datan bekomme ich da ja, es ist nur rätselhalft wieso es 
nicht die richtigen sind.

Edit:
Habe mal im Debugging die Speicheradressen ab 0xC0390000 mit meiner 
ersten Zeile in img_buf verglichen. Siehe dazu die beiden Screenshots.

Das komische ist ja auch, dass bei Adresse 0xC0390000 der richtige Wert 
drin steht (passt von der Farbe her zu meinem Bild), aber er den in 
img_buf nicht überschreibt...Da bleibt einfach die Null mit der ich 
vorher initialisiert habe.

Ab Adresse 0xC039001C passt es dann und irgendwann kommen dann wieder 
ein paar Nullen usw.

Woran kann es denn liegen, dass schon das nicht korrekt funktioniert?

Edit2:

Außerdem seltsam: Wenn ich die Funktion mehrmals hintereinander aufrufe, 
ohne ein neues bild gemacht zu haben, bekomme ich trotzdem 
unterschiedliche Ergebnisse.

: Bearbeitet durch User
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.