Forum: Mikrocontroller und Digitale Elektronik OV7670 Testbild mit manchmal verschobenen Streifen


von Uli S. (uli_stone)


Angehängte Dateien:

Lesenswert?

Hi,

ich arbeite mit dem ov7670 kamera modul und kann mittlerweile ein 
"gutes" testbild darstellen.

Leider habe ich mit dem generierten Testbilder der Kamera ein Problem, 
manchmal sind die Farbspalten verschoben (1/2 Pixel manchmal mehr), mir 
ist nicht klar wie dieses Bild zu stande kommen kann. Vielleicht hat 
jemand von euch eine Idee?

Danke

von Andreas S. (igel1)


Lesenswert?

Hi Uli,

ich muss gestehen, dieses Fehlerbild habe ich noch nie gesehen ...

Sieht fast so aus, als ob Dein Programm irgendwo zwischendurch den 
Einsatz verpasst bzw. aufgehalten wird.

Evtl. durch eine ISP-Routine?

Viele Grüße

Igel1

von Fitzebutze (Gast)


Lesenswert?

Sieht nach versauten Synchronisations-Signalen oder nicht ganz 
abrissfreiem Datenstrom aus. Ohne zu wissen, mit welchem System (DMA ist 
fast ein Muss) du die Daten einziehst, kann man aber nicht viel weiter 
sinnvoll spekulieren. Das Pattern sieht sonst korrekt aus (vom etwas 
flachen Rot abgesehen). Gibst du die Daten auf einen TFT im 565 Mode 
aus?

von Uli S. (uli_stone)


Lesenswert?

Hallo Andreas und Fitzebutze,

erstmal ganz herzlichen Danke für eure Antworten!

Zu meinem Programm, ich verwende einen STM32F4 MCU:
- Bilder werden über die DCMI-Schnittstelle eingelesen
- Verwende DMA und der Modus ist zirkular (im Normal Mode bekomme ich 
keine Daten in den DMA)
- Die Farben werden im RGB565 Modus von der Kamera an den MCU gegeben 
und als RGB565 auf dem Display dargestellt.

- Mein Programm hat nur eine ISR Routine, und das habe ich mir auch 
gedacht, in Verbindung mit dem zyklischen DMA schreiben könnte das 
sein... nur ist das  eine richtige Vermuting?

Hier meine mein IRQHandler, die Variable frame_read wird in der main 
aufgegriffen und mit if, ein Bild auf das Display geschrieben. Danach 
wird dma_frame_read zurückgesetzt. Die meisten "guten" Bilder bekomme 
ich bei jedem zweiten Durchgang.
1
void DMA2_Stream1_IRQHandler(void)
2
{
3
  if ((DMA2->LISR & DMA_LISR_TCIF1) && (DMA2_Stream1->CR & DMA_SxCR_TCIE))
4
  {
5
    DMA2->LIFCR = DMA_LIFCR_CTCIF1;
6
    frame_read = 1;
7
  }
8
9
}

von Fitzebutze (Gast)


Lesenswert?

Uli S. schrieb:
> Hier meine mein IRQHandler, die Variable frame_read wird in der main
> aufgegriffen und mit if, ein Bild auf das Display geschrieben. Danach
> wird dma_frame_read zurückgesetzt. Die meisten "guten" Bilder bekomme
> ich bei jedem zweiten Durchgang.

Das ist ein Klassiker, der schief geht, leider eben typischerweise genau 
so sporadisch wie in deinem Fall. Stichwörter "Race condition" und 
"non-atomic access".
Zur Behebung: Stichwort "Buffer queue". Die meisten Implementierungen 
dieser Art nutzen zwei Pointer "head" und "tail", head darf nur die ISR 
verändern, tail nur die Polling-Routine (aus der Hauptschleife 
aufgerufen).
Im Prinzip musst du dein Programm im Disassembly scharf anschauen, und 
dir klar sein, dass die ISR irgendwann dazwischen zuschlagen kann. 
Manche Architekturen haben natürlich atomare Zugriffe präsent, aber am 
besten portabel ist es nach dem Buffer-Queue-Konzept.

von Uli S. (uli_stone)


Lesenswert?

Fitzebutze,

danke für deine Antwort!
Leider bin ich mir nicht sicher wie ich die Buffer Queue umstetzen kann 
(da Daten unterschiedlich Geschrieben und gelesen werden).
Mein Problem die durch den DMA werden die ein Buffer Array, 
dma_frame_buffer, in einem Durchgang geschreiben. Nicht jedes einzelne 
Element. Und die Daten werden gelesen, Pixel für Pixel.

Wie kann ich die Buffer Queue umsetzen so wie meine Codestruktur gerade 
ist?

Ich hoffe das ist verständlich, hier ein Überblick meines Codes:

IRQ Handler:
1
void DMA_IRQ(void)
2
{
3
    if (DMA_Full && DMA_Enabled)
4
    {
5
        DMA->CLEARFLAG = CLEAR; //Clear Interrupt Flag
6
7
        //Im Hintergrund werden die über DCMI übertragenen daten in folgendes Array geladen: dma_frame_buffer
8
9
        //DMA Indicator
10
        dma_frame_read = 1;
11
    }
12
}

Meine Main:
1
int main (void)
2
{
3
    if(dma_frame_read == 1)
4
    {
5
    for(int pixel_counter=0; pixel_counter<253; pixel_counter++)
6
    {
7
          Display_Pixel(dma_frame_buffer[pixel_counter]);
8
      dma_frame_read = 0;
9
    }
10
}

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.