Forum: Mikrocontroller und Digitale Elektronik Brauche Unterstützung beim OV7670 (bzw. SCCB)


von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Liebe Community,
ich bin auf eure Hilfe angewiesen.
Ich versuche schon seit mehreren Monaten den OV7670 (VGA-Modul) mit dem 
mit einem Atmega 328P anzusteuern.

Dabei scheitere ich allerdings schon bei der ansteuerung bzw. der 
Kommunikation mit dem SCCB-Interface zur Steuerung des Moduls.

Nach studium diverser Datenblätter und Websiten dachte ich, die 
Funktionsweise verstanden zu haben und das Problem läge in einer 
fehlerhaften ungewollten Programmierung. Nachdem ich nun aber auch 
endlich stolzer Besitzer eines Oszilloskops geworden bin, muss ich 
feststellen, dass alle Pins so schalten, wie ich es mir vorstelle und 
dass ich offensichtlich nicht verstehe, was zu tun ist. Daher wende ich 
mich an euch und hoffe auf einen Hilfsbereiten der sich erbarmt meine 
Wissenslücke zu füllen.

Um die Funktionsweise des SCCB sicherzustellen sieht mein Plan vor, 
ersteinmal nur das Register 0x01 auszulesen und den Default-Wert 0x80 
als Antwort zu bekommen. Um das zu erzielen sieht mein Plan folgendes 
vor:
2-Phasen Write Zyklus gefolgt von einem 2-Phasen Read Zyklus.
Dazu sende ich folgende Befehle:
0x42 + 0 + 0x01 + 0 + 0x43 + 0 + Eingang + 1

(die Nullen bzw. 1 stellen hier die mitgeschickten Don't care Bits dar)
Nach meinem bisherigen verständnis sollte doch während der letzten Phase 
(hier mit Eingang bezeichne) die Daten vom Slave, also dem Kamaramodul 
aus geschrieben werden. Ich erhalte allerdings nur ein durchgehendes 
HIGH oder LOW jenachdem, ob ich die SIOD Leitung mit dem Pull-Up an 3,3V 
hänge.
Abweichend zu dem Anschlussplan, betreibe ich die xCLK über einen 
Arduino Nano mit einer Frequenz von 16kHz.

Gerne führe ich mein Problem weiter aus, hoffe aber schoneinmal, dass 
sich jemand dazu berufen fühlt mir zu helfen.

vielen Dank!

lg.
David

von pegel (Gast)


Lesenswert?

Moin,

ich kenne das Modul nicht, aber wenn ich mir das ansehe:
https://github.com/maslovk/STM32_OV7670/blob/master/Src/OV7670.c

wird die Reset Leitung auf L gelegt, dann 100ms gewartet, dann auf H.
Danach wird an I2C 8bit Adresse 0x42 ein 0x0A gesendet und es kommt ein 
0x76 zurück.

von pegel (Gast)


Lesenswert?

Übrigens sind die Signale schon am Maximum der Absolute Maximum Werte.

von David D. (saturi)


Lesenswert?

Bitte entschuldigt die verzögerte Antwort. Leider war ich die Woche 
beruflich sehr eingespannt, weshalb ich nicht dazu gekommen bin, weiter 
zu basteln und zu versuchen.

Zur Aussage von Pegel, das ist richtig. Da dieser Baustein in Verbindung 
mit diversen Arduino sets angeboten wird, bin ich davon ausgegangen, 
dass ich ihn direkt an dem Uno betreiben kann.
Sollte ich etwa jeden Pin noch über einen Spannungsteiler reduzieren?

von pegel (Gast)


Lesenswert?

Nimm einen Atmega mit weniger F_CPU und probier alles zusammen bei 3,3V 
aus.
Damit sollte sich das Problem einkreisen lassen.

von Olli Z. (z80freak)


Lesenswert?

Es kommt etwas drauf an welches Modul Du gekauft hast. Der Chip selbst 
(OV0706) hat eine Betriebsspannung um 3,3V. Das häufig erhältliche 
OV7670 Modul mit Linse wird oft mit 5V TTL Interface, direkt für Arduino 
angeboten. Das ist dann ein Pegelwandler enthalten.

von Olli Z. (z80freak)


Lesenswert?

Hab grad nochmal im Datenblatt nachgeschaut. Also die Vio ist dort mit 
1.7 - 3.0V angegeben. Berichten zufolgen sollen 3.3V jedoch 
"unbedenklich" sein.

Du brauchst also höchstwahrscheinlich einen Pegelwandler für jedes 
Signal zwischen Arduino und Kamera.

von Olli Z. (z80freak)


Lesenswert?

David D. schrieb:

> Ich versuche schon seit mehreren Monaten den OV7670 (VGA-Modul) mit dem
> mit einem Atmega 328P anzusteuern.
Offensichtlich verfolgst Du einen eher akademischen Ansatz, sprich Du 
bist nicht auf eine schnelle Lösung ohne Hintergrundinformation aus. Das 
ist schön, denn dann kann man sich alle Links auf die div. Umsetzungen 
sparen. Damit lernt man nämich nix, wenn man das fertige Gedankengut 
eines anderen einfach verwendet.

> Dabei scheitere ich allerdings schon bei der ansteuerung bzw. der
> Kommunikation mit dem SCCB-Interface zur Steuerung des Moduls.
Deine Vorgehensweise ist auf jeden Fall richtig. Erstmal nur das 
Kommandointerface zum laufen zu bringen und den Rest aussen vor zu 
lassen. Solange man keinen PCLK anlegt, gibt der Chip ohnehin keine 
Videosignale aus.

Die Kommunikation mit dem SCCB-Teil läuft über den 2-Wire Bus ab. Ob und 
in wie weit der zu 100% der SPI-Spezifikation entspricht konnte ich 
leider nicht ermitteln. Von daher wäre es, für den Anfang ein guter Plan 
nicht die fertigen I2C-Libs zu nutzen, sondern die Signale via 
"Bitbangig" selbst zu generieren.

Zum Glück arbeitet der 2-Draht-Bus statisch, man kann sich also ruhig 
Zeit lassen. Es gibt keine minimale Taktfrequenz, nur max. 400 kHz.

Dein Setup mittels Arduino ist vollkommen ok, nur einen Pegelwander für 
die beiden Signale solltest Du zwingend vorsehen. Ein Spannungsteiler 
wäre für die SIO_C (CLK) noch ok, aber für die SIO_D sollte es schon ein 
richtiger Pegelwandler sein. Im einfachsten Fall mit Transistoren (gibts 
hier auf der Website auch als Schaltbeispiel) oder halt ein 
entsprechendes IC. Später, bei den Videosignalen, braucht man das auch. 
Für die SCCB-Kommunikation würde anfangs sowas hier reichen: 
https://www.roboter-bausatz.de/434/i2c-pegelwandler/level-konverter-3.3v-5v-bidirektional-2-kanal

Steht die Hardware, können wir uns der Kommunikation widmen. Dafür sind 
vor allem die START- und STOP-Konditionen wichtig.

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Ohja, was noch wichtig sein dürfte. Betriebsspannung anlegen, 3.3V ;-), 
PWDN auf GND (ist Active High), RESET auf 3.3V (active low).
Und dann ist da noch der Systemtakt, XCLK. Laut Datenblatt sind hier 
wenigstens 10 MHz anzulegen. Vermutlich damit die interne Logik 
überhaupt arbeitet und damit auch das I2C Interface.
Diesen Takt kann man z.b. vom Arduino mittels PWM erzeugen lassen.
Selbstredent muss hier auf der richtige Pegel verwendet werden, also 
besser gleich einen 4fach Pegelwandler nehmen.

von Stephan C. (stephan_c)


Lesenswert?

Bei mir ist es schon wieder eine Weile her, als ich mal einen 
Omnivision-Sensor über den SCCB angesteuert hab.
Aber ist das bei SCCB nicht so, das du zum Lesen eines Registers erstmal 
einen Schreibbefehl senden mußt, um dann bei der nächsten 
Datenübertragung den Registerwert zurückzubekommen?

von Olli Z. (z80freak)


Lesenswert?

Genau so ist es. Es ist übrigens schon möglich die Arduino I2C-Lib 
("Wire.h") für die Kommunikation zu nutzen. Es kommt jetzt etwas drauf 
an wie tief der Thread-Ersteller hier einsteigen möchte. Habs grad mal 
auf die Schnelle mit einem Testaufbau nachgestellt. Klappt.

Für das grundsätzliche Verständnis wäre die eigene Implementation schon 
gut. Will man sich aber "nur" mit der Kamera beschäftigen ist es nicht 
zwingend notwendig.

: Bearbeitet durch User
von Olli Z. (z80freak)


Angehängte Dateien:

Lesenswert?

David hat sich bislang nicht mehr gerührt, aber ich fang einfach mal so 
an :-)
Eigentlich bietet fast jeder noch so kleine uC bereits ein I2C-Interface 
On-Board. Auch hat mein kleiner Test gezeigt, das der Arduino darüber 
problemlos mit dem OV7670-Modul kommunizieren kann. Daher sehe ich nicht 
viel Sinn darin die I2C-Kommunikation per Bit-Banging zu emulieren. 
Einzig David "besteht" darauf...

Wichtig dafür das es auch funktioniert ist eine vernünftige Verbindung 
beider über einen Pegelwandler. Ohne halte ich das Unterfangen für mehr 
als fraglich. Das von David gepostete Pinout kann m.E. nicht 
funktionieren, da einfach alle Signale (3.0V IO-Pegel vom OV7670 und 
5.0V Pegel vom Arduino) verbunden sind. Habe mal auf die Schnelle einen 
Eagle Schaltplan gezeichnet, wie ich es aktuell aufgebaut habe. Als 
Pegelwandler kommt fast alles in Frage, hauptsache Bidirektional 
(wichtig für I2C!).

Den Systemtakt XCLK erzeuge ich über Manipulation der Timer-Register:
1
pinMode(9, OUTPUT);
2
TCCR1A = ((1 << COM1A0));
3
TCCR1B = ((1 << WGM12) | (1 << CS10));
4
TIMSK1 = 0;
5
OCR1A = 0;
Hiermit erhalte ich an Pin 9 einen Takt von 8 MHz. mit 50% Duty-Cycle. 
Laut Datenblatt müssten es mind. 10 sein. Leider kann der Uno nicht mehr 
liefern mit seinen 16 MHz Systemtakt. Aber es scheint auch so zu 
funktionieren.

Damit wäre das Setup bereit für die Programmierung des Chips ansich.

von David D. (saturi)


Lesenswert?

Hallo zusammen,

das Thema interessiert mich immer noch brennend und ich bin dankbar für 
eure ausführlichen Beschreibungen.
Das mit dem Pegelwandler scheint für mich ein sehr unterschätzter Punkt 
zu sein, den ich als erstes betrachten und korrigieren werde.

den xCLK betreibe ich über einen zweiten Controller (Arduino Nano) an 
dem ich einfach die CKOUT-Fuse gesetzt und bekomme damit erstmal meine 
16 Mhz über den PB0 Pin geliefert. (allerdings wieder ohne 
Pegelwandlung... ja ich gestehe mir ein, ich muss den vorgegeben 
Spannungen definitiv mehr Aufmerksamkeit schenken)

ab Mittwoch wird es bei mir hoffentlich etwas ruhiger (stehe grade 
mitten in meiner Masterthesis Erstellung und der Bewerbungsphase für den 
Berufseinstieg) sodass ich mich spätestenz zum Wochenende endlich 
nochmal dem uController zuwenden kann.

den I2C benutze ich zur Zeit nicht, weil ich irgendwo gelesen hatte, 
dass das SCCB nicht ganz dem Protokoll entspricht. Lasse mich da aber 
sehr gerne belehren wenn das damit einfacher geht :)
Stelle auch gerne meinen Code zur Einsicht/Fehleridentifikation zur 
Verfügung, wobei ich grade eher die Hoffnung habe, dass der Fehler in 
der Spannungsversorgung ist.
Werde zum Wochenende hin auch hoffentlich einmal meinen ganzen 
Anschlussplan erstellen und mit euch teilen.

@Olli "Offensichtlich verfolgst Du einen eher akademischen Ansatz.."
Ob ich da jetzt wirklich wissenschaftlich an die Sache ran gehe wage ich 
noch etwas zu bezweifeln :D aber ja ich will es verstehen und nicht nur 
irgendwelchen Code Copy'n'Pasten.

von grundschüler (Gast)


Lesenswert?

Das mit dem Pegelwandler würde ich mir ersparen. Wenn du den AVR mit 8 
Mhz betreibst, reichen für diesen auch 3Volt. Für eine gescheite 
Auflösung ist der avr eh zu langsam. Ein stm32f407-board mit 
dcmi-camera-Schnittstelle kostet um die 10€. Auch damit ist der Betrieb 
des camera-Moduls noch anspruchsvoll genug.

von David D. (saturi)


Lesenswert?

Was die Auflösung und Frame Rate angeht hab ich mir auch schon gedacht, 
dass er dafür zu langsam ist. Mir reicht es aber in erster Linie auch 
erstmal einfach nur ein Bild von einem statischen Motiv zu machen.
Ich würde auch gerne bei einem AVR bleiben, weil ich nur damit 
Erfahrungen habe.

von Olli Z. (z80freak)


Lesenswert?

Mit ein paar kleinen Enschränkungen sollte das auch mit dem Uno 
funktionieren. Es gibt zwei Versionen der 0.3 MP Kamera OV7670, eine 
ohne und eine mit zusätzlichem FIFO-Bildspeicher.

Bei der Version ohne FIFO muss man die Bilddaten in der nativen 
Geschwindigkeit des Sensors erfassen können. Ist die MCU zu langsam, 
verliert man Daten und das ganze Bild ist unbrauchbar. Bei der Version 
MIT FIFO Speicher werden die Bilddaten eines Frames in diesen abgelegt 
und man hat "alle Zeit der Welt" sich die Daten abzuholen. Natürlich 
verliert man dabei Frames, aber jedes ist konsistent.

Ich habe beide Versionen der Kamera hier. Man muss auch sagen das der 
OV7670 die unterste Einsteigsklasse der Kameras ist. Wenn wir mit dem 
Modell ohne FIFO arbeiten und die Daten nicht in Echtzeit in den Arduino 
laden können, dann müssen wir einfach die Auflösung und Bildrate 
reduzieren bis es klappt. Es geht hier ja erstmal auch nur um einen 
"Proof-of-Concept", nicht wahr :-)

Neben der Hardware sollten wir auch die Software diskutieren, denn die 
ist ja nicht weniger wichtig. Um dem ganzen eine gewisse Nachhaltigkeit 
zu geben, habe ich hier in meinem Wiki mal einen Bereich dafür angelegt: 
http://e-wiki.denkdose.de/video/ccd-sensor/ov7670/start
Dort würde ich alle Eregebnisse zusammentragen.

Zur Takterzeugung:

Laut Datenblatt des OV7670 sollten es mind. 10 MHz sein. Wie gesagt hat 
es bei mir mit 8 MHz, welche sich ohne Tricks einfach per 
umprogrammierung eines PWM-Timers erzeugen lassen geklappt.

Durch ändern der FUSE-Bits kann man den, beim Arduino Uno/Nano durch 
einen externen 16 MHz Quarz erzeugten Takt auf dem PORTB Bit 0 (PB0) 1:1 
durchreichen. PB0 liegt beim Uno/Nano auf dem Port "D8". Um das zu tun 
sind jedoch einige tiefergreifende Modifikationen der IDE (boards.txt) 
notwendig, da die FUSEs sich nicht innerhalb der Software anpassen 
lassen, sondern zum Zeitpunkt der Chip-Programmierung eingestellt 
werden.

Ich schlage daher vor, den o.g. Code zu nutzen und erstmal darauf zu 
vertrauen das 8 MHz ausreichend sind. Im Prinzip könnte man auch den 
Quarz umlöten auf 20 MHz. Das hält der 328p locker aus. Aber auch das 
würde ich erst in Erwägung ziehen, wenn es zwingend sein muss.


Zur Pegelanpassung:

Das Taktsignal "XCLK" für den Kamerachip, sowie die SIO_C und SIO_D 
Leitung sollten zwingend über einen Pegelwandler betrieben werden. Das 
ist für mich alternativlos, auch wenn es Beschaltungen und Berichte gibt 
die ohne auskommen. Diese nutzen den Umstand das die IO-Pins mit 
Schutzdioden versehen sind, manche sind wenigstens so gändig und 
schalten Widerstände in Reihe. Im von Dir gezeigten Schaltbild wird man 
per Software wohl die Ausgänge ohne internen Pullup beschalten, also 
quasi Open-Collector. Den High-Pegel erzeugen dann Pullups auf 3.3V. Das 
könnte durchaus klappen, funktioniert aber bei der Clockerzeugung so 
nicht. Dafür hat man da wohl den Serienwiderstand eingebaut, quasi 
Pegelwandler für Arme ;-)
Kann man alles mal ausprobieren... was ich noch nicht untersucht habe 
ist, ob sich durch den Pegelwandler die Flankensteiheilt irgendwie 
problematisch verändert. Bislang gehe ich davon aus das der von mir 
verwendete, auf Transistoren basierende, da keinerlei Probleme 
verursacht.

Was die Datensignale angeht, könnte man durchaus auf einen Wandler 
verzichten, da man diese ja nur liest. Der TTL-Pegel ist hier 
abwärtskompatibel mit dem 3.0V Pegel des Kamerachips.

Auch wenn geht, würde ich hier ebenfalls auf Modifikationen des Uno, wie 
andere Betriebsspannung, etc. verzichten. Wenn man an einer ernsthaften 
Anwendung interessiert ist, sollte man einfach auch die passenden Chips 
dafür wählen und da ist der STM32 (Bluepill) einfach besser geeignet 
(stärker, billiger, richtiger Pegel, eigenes Interface, etc.).

Neben den Bilddaten-Pins D0-D7 benötigen wir auch den PCLK, VSYNC und 
HREF um die Daten synchron einlesen zu können. VSYNC gibt uns den Start 
eines Frames, HREF den einer jeden Zeile. PCLK zeigt uns wann welche 
Pegel (auch die der Datenbits) stabil anliegen.


Zur Software:

Wenn Dein Hardwareaufbau steht, würde ich als erstes die grundlegende 
Kommunikation (Protokoll) zwischen Arduino und OV7670 besprechen. Dies 
soll es uns am Ende ermöglichen die Register des Chips zu lesen und zu 
schreiben, sowie die für uns relevanten herauszufinden, sodass wir dem 
Chip die passenden Einstellungen geben können.

Wenn das klappt, machen wir uns Gedanken wie wir einen Frame lesen und 
daraus eine Bilddatei für den PC produzieren. Etappenziel wäre es, ein 
Einzelbild in S/W zu übertragen und darzustellen. Danach können wir uns 
allen weiteren Themen wie der Farbtransformationsmatrix (YUV<->RGB) etc. 
widmen.

Was mich persönlich noch interessiert wären die OSD-Funktionen des 
Chips. Laut Datenblatt soll man Zeichen und eine Overlaygrafik 
darstellen können. Das wäre schon interessant. Auch kann man Bereiche 
definieren in denen die Kamera auf Änderungen "reagiert" (Überwachung).

Ganz pfiffige haben Software zur Kanten- und Objekterkennung 
(Verfolgungsmodus) geschrieben. So weit werden wir es sicher nicht 
bringen...

Was aber noch denkbar ist, ist der Anschluß eines LCD-Panels um das Bild 
gleich 1:1 anzuzeigen. Mit dem Uno/Nano wird das aber langsam knapp, 
sowohl an MCU-Ressourcen als auch an Pins.

von Olli Z. (z80freak)


Lesenswert?

Die grundlegende Kommunikation auf dem SCCB entspricht der von I2C. Der 
Busaufbau ebenfalls. Die Kamera agiert dabei als Slave und der Arduino 
muss folglich den Master machen. Das heisst sowohl beim schreiben, als 
auch beim lesen von Daten geht das immer vom Master aus.

Ein Slave reagiert nur auf eine bestimmte Adresse, welche im Fall des 
Ov7676 scheinbar die 0x21 ist, auch wenn ich das im Datenblatt nirgens 
finde.

Eine Bit-Übertragung beginnt immer mit einer Start-Kondition bei der die 
SDA Leitung nach Low geht während SDC noch High ist. Der Empfänger 
stellt sich aufs lesen von Daten ein. Es folgt eine Übertragung von 8 
Bit langen Datenwörten, wiederum gefolgt von einer Stop-Kondition. Dabei 
geht der Pegel von SDA auf High während SDC bereits High-Pegel hat. Nur 
zur Info, normalerweise muss während der High-Phase von SDC der Zustand 
von SDA stabil sein.

Konzentrieren wir uns nun auf die Nutzdaten des Protokolls. Hier sendet 
der Master zuerst die Adresse des anzusprechenden Slave. Ab hier gibt es 
nun ein paar Varianten, abhängig davon was man tun will.

Im „3-Phase-Write Cycle“ wird nach der Empfänger-ID die Subadresse, im 
Fall des OV7676 ist es das zu beschreibende Register (COM...), 
übertragen. Ihr folgt der Wert welcher in das Register zu schreiben ist.

Im „2-Phase-Write Cycle“ werden nur Empfänger und Subadresse 
geschrieben. Diese Variante ist zur Vorbereitung der dritten 
Übertragungsart, dem Lesezyklus gedacht. Sie selektiert das zu lesende 
Register im Slave.

Beim „2-Phase-Read Cycle“ muss ein 3- oder 2-Phase-Write vorausgegangen 
sein. Nach dem senden der Slaveadresse wird der Master passiv und 
erwartet das der Slave nun seine Daten sendet.

Um also Daten aus dem Chip zu lesen, müssen vorher welche geschrieben 
werden. Dies resultiert aus dem Umstand das ein Slave nicht 
selbstständig auf den Bus senden darf.

Das Arduino Framework verwendet hierfür die „Wire“ Library.

Soviel erstmal zum Protokoll. Natürlich habe ich jetzt Komplexität 
wissentlich unterschlagen, wie NA und ACK Bits, Multi-Master Busse, etc.

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Guten Abend,
ja genauso hatte ich das Protokoll des SCCB auch verstanden.
Wenn du dir nochmal den Anhang in meinem Eröffnungspost anschaust, 
sollten auch die vier Zyklen erkennbar sein. Wenn man dort die einzelnen 
Bits anschaut (nach meinem Verständnis) wurden dort auch die richtigen 
Adressen gesendet. Nur das was eben vom Slave nachher zurückkommt - in 
dem letzten Zyklus - ist eben nur ein high Pegel mit falschem 
Informationsgehalt.

Nach euren Ratschlägen habe ich mir eine weiteren OV7670 diesmal mit 
AL422B Fifo und ein paar LVL-Shifter gekauft. Die sind heute angekommen.

Ich habe mich dann heute auch mal an Eagle gesetzt. Nunja um es kurz zu 
machen bin ich da noch nicht so ganz routiniert ;-) sondern eher 
komplett Neueinsteiger (ich arbeite noch an der Darstellung und der zum 
Teil unvorteilhaften Beschriftung).
Der neue OV7670 weist schon mal mehr PINs auf, was vermutlich auf das 
FIFO zurückzuführen ist. Hier tun sich für mich jetzt in erster 
Betrachtung zwei Fragen auf:
1. Wenn das Bild im FIFO abgelegt wird, wozu werden dann noch VSync und 
HREF nach außen geführt? Eventuell zum Zählen um festzustellen ob das 
Bild fertig vorliegt?
2. xCLK ist nicht mehr vorhanden. Womit gebe ich dann den Takt vor? 
eventuell befindet sich auch der Quarz schon auf der Kamera Platine?

Ich konnte mich leider noch nicht detaillierter mit der Sache 
auseinander setzten und in den Datenblättern oder dem Internet großartig 
stöbern, wollte euch aber an meinen Gedankengängen teilnehmen lassen.
lg.
David

PS: Übrigens arbeite ich nicht mit der Arduino Umgebung, sondern direkt 
mit dem Atmelstudio auf der Atmelbasis. Sind die genannten Bibliotheken 
sehr komplex? oder kann man sich das ganze auch selber 
zusammenschreiben, bzw. ummünzen?

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Hallo David. Ich würde nicht mitten drin die Verhältnisse ändern. Du 
schaffst gerade neue Probleme. Lass uns doch erstmal mit der "alten" 
Kamera ohne FIFO weiterarbeiten. Das Bild interessiert uns doch aktuell 
noch nicht. Dabei ist es völlig egal ob das Teil nene Fifo hat oder 
nicht und wie und ob die Sync-Signale genutzt werden.

Hier ein Test-Code
1
#include "Wire.h"
2
3
void setup() {
4
  // put your setup code here, to run once:
5
6
  pinMode(9, OUTPUT);
7
  TCCR1A = ((1 << COM1A0)); //0x23;
8
  TCCR1B = ((1 << WGM12) | (1 << CS10)); //0x09;
9
  TIMSK1 = 0;
10
  OCR1A = 0;
11
  
12
  Serial.begin(38400);
13
14
  Wire.begin();
15
  Wire.beginTransmission(0x21);
16
  Wire.write(0x12);
17
  Wire.write(0x80);
18
  Wire.endTransmission();
19
  delay(500);
20
21
  Wire.beginTransmission(0x21);
22
  Wire.write(0x0A);
23
  Wire.endTransmission();
24
  Wire.requestFrom(0x21, 1);
25
  while(Wire.available() == 0);
26
  while(Wire.available())
27
    Serial.println(Wire.read(), HEX);
28
29
  Wire.beginTransmission(0x21);
30
  Wire.write(0x0B);
31
  Wire.endTransmission();
32
  Wire.requestFrom(0x21, 1);
33
  while(Wire.available() == 0);
34
  while(Wire.available())
35
    Serial.println(Wire.read(), HEX);
36
37
}
38
39
void loop() {
40
  // put your main code here, to run repeatedly:
41
42
}

von Michael U. (amiga)


Lesenswert?

Hallo,

es kann vielleicht trotzdem helfen bei Arduino vorbeizuschauen.
https://github.com/ComputerNerd/ov7670-no-ram-arduino-uno

Ich habe mit der OV7670 ohne FiFo nur kurz rumgespielt, allerdings an 
einem ESP32. Eigentlich ist die OV7660 eine komplette Enttäuschung für 
mich.
Dann habe meine uralten DC3840 und MCA-25 rausgekramt...
Die DC3840 lief ja vor Jahren schließlich mal stabil bei mir an einem 
AVR-NetIO mit einem Mega32.
http://www.ulrichradig.de/home/index.php/projekte/uC-kamera

Allerdings sind diese Cams wohl inzwischen kaum noch aufzutreiben.

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

Danke für den Link zu der OV-Software, das wird später hilfreich sein! 
David und ich wollen aber erstmal bei dem ursprünglich genannten Modell 
bleiben um uns nicht zu verzetteln. Das wäre erstmal ans Laufen zu 
bringen und dann können wir das Gebiet erweitern :-)

Eine Frage zu den I2C-Leitungen vom Arduino. Laut I2C Spezifikation 
müssen die Pins für SDA und SCL open drain mit einem 2,2 k Pullup 
bestückt sein.

Auf dem Schaltplan vom Uno kann ich keinerlei externe Pullups finden.
Im Quellcode der Wire-Library (twi.c) ist für Wire.Begin():

  // activate internal pullups for twi.
  digitalWrite(SDA, 1);
  digitalWrite(SCL, 1);

und Wire.end() dieses enthalten:

  // deactivate internal pullups for twi.
  digitalWrite(SDA, 0);
  digitalWrite(SCL, 0);

Vorausgesetzt beide Ports sind als Eingänge definiert (DDR-Register), 
aktiviert bzw. deaktiviert dies in der Tat die internen Pullups und hat 
die gleiche Wirkung wie z.B.:
  pinMode(SDA, INPUT_PULLUP);
  pinMode(SCL, INPUT_PULLUP);

Sowohl SCL (wenn der Arduino als Slave arbeiten würde) als auch SDA 
können zeitweise auch als Ausgänge konfiguriert sein.

Im Datenblatt vom Atmega328p finde ich hierzu:

SCL/ADC5/PCINT13 – Port C, Bit 5
  – SCL: 2-wire Serial Interface Clock. When the TWEN bit in TWCR is set 
(one) to enable the 2-wire Serial Interface, pin PC5 is disconnected 
from the port and becomes the Serial Clock I/O pin for the 2-wire Serial 
Interface. In this mode, there is a spike filter on the pin to suppress
spikes shorter than 50 ns on the input signal, and the pin is driven by 
an open drain driver with slew-rate limitation.
SDA/ADC4/PCINT12 – Port C, Bit 4
– SDA: 2-wire Serial Interface Data. ... <der gleiche Text wie SCL>

Wenn ich das alles richtig im Quellcode vom Arduino verstehe, dann wird 
bei Wire.begin() das TWEN-Bit in TWCR gesetzt und beim Wire.end() wieder 
gelöscht. Im I2C-Modus sind beide Pins wirklich auch open-drain und 
benötigen einen Pullup. Sobald man den I2C-Modus aber wieder verlässt, 
liegen die IO-Pins wieder an.

Ich muss das manl nachmessen...

von Michael U. (amiga)


Lesenswert?

Hallo,

aua, da müßte ich jetzt auch stark das Datenblatt des Mega328 
befragen...
Meiner Erinnerung nach bleibt die PullUp-Funktion auch dann aktiv wenn 
TWEN gesetzt wird. Es wird nur die OUT-Stufe umgeschaltet, die PullUp 
müßten zur IN-Hardware gehören und damit weiterhin ein-/ausschaltbar 
sein. IN bleibt ja mit dem Pin verbunden.

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

In dem Fall wäre aber das häufig zu findende, im erster Post abgebildete 
Pinout mit den beiden externen Pullups zu 3,3V falsch. Das würde ja, 
alternativ zu einem Pegelwanlder, nur funktionieren wenn die Ausgänge 
wirklich ausschließlich opendrain wären.
Zum Einschaltzeitung (Resetphase) sollen die Pins laut Datenblatt 
Tristate sein. Soblad ich Zeit hab prüfe ich das mit einem Uno/Nano und 
dem DSO mal nach...

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

nach Rest sind sie triState und der interne PullUp ist aus.
Setze ich den Pin über DDR auf Ausgang ist die Push-Pull-Stufe aktiv.
Schalte ich TWEN aktiv ist die Ausgangsstufe openDrain, meiner 
Erinnerung nach völlig unabhängig vom Zustand des DDR-Bits (da müßte ich 
jetzt aber ins Datenblatt schauen).
Die exiernen PullUp sind für I2C nötig wegen der OpenDrain Ausgänge.
Wenn jetzt mit dem Portbit der interne Pullup eingeschaltet wird liegen 
eben diese ca. 50k  parallel zum externen PullUp, stört doch keinen.
Wenn keine externen pullUp da sind und der interne eingeschaltet wird, 
hat der I2C eben diese 50k als PullUp. Das funktioniert in der Praxis 
auch dzurchaus bei nur einem Slave am Bus und kurzen Leitungen und z.B. 
100kHz I2C-Clock. Ist aber natürlich nicht normgerecht.

Praktisch kommt bei den China-BreakOut-Board noch dazu, daß jeder macht 
was er will. Mal sind auf den Modulen PullUps an SDA/SCL, mal 
Pegelwandler, mal garnichts...

Gruß aus berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

Mir ging es nicht um die Pullups selbst, sondern vielmehr um die 
Spannungspegel. Wenn ich auf einem Uno Board zu irgendeinem Zeitpunkt 
die internen Pullups aktiviere, oder wenn die Ausgangsstufe im Push 
Modus einen High Pegel erzeugtm dann habe ich doch 5V am jeweiligen 
Signal. Da nutzt dann der externe Pullup gegen 3,3V doch auch nichts 
mehr...?,

von David D. (saturi)


Lesenswert?

Hallo zusammen, ich melde mich nach einigen versuchs Stunden.

@Olli
Ich gebe dir recht, dass wir die Startbedingungen nicht ändern sollten 
und bin deswegen wieder auf die Kamera ohne Fifo umgestiegen.
Da ich bislang, wie schon erwähnt, nicht mit der Arduino IDE gearbeitet 
habe, sondern mit dem Atmel Studio, stellen sich für mich die ganzen 
Sachen etwas komplexer dar. Um aber die Fehler eingrenzen zu können, hab 
ich mich jetzt einmal dazu durchgerungen zumindest testweise auf die 
Arduino IDE umzusteigen. Ich habe es allerdings nicht geschafft, die 
bisher genutzten Controller über diese anzusteuern. Vermutlich habe ich 
den Bootloader beim ISP Programmieren überschrieben.

Glücklicherweise habe ich noch einen unbenutzten Nano gefunden, mit dem 
ich das ganze zum laufen gebracht habe. Ich denke, ob ich jetzt zur 
Ansteuerung am Anfang den Nano oder den Uno verwende, sollte keinen 
Unterschied machen. (Bitte belehrt mich wenn ich falsch liege)

zu deinem geposteten Test-Code:
Über das I2C Interface wird das ganze definitiv viel Übersichtlicher als 
in meinem bisherigen Programmcode, in dem Ich die Übertragung zu Fuß 
abbilden wollte. Ich denke ich kann auch nachvollziehen, was du mit dem 
Code bezwecken willst, was ich hier kurz zusammenfassen möchte, um 
Missverständnisse auszuschließen:
1.Block: Register Reset
 ->Alle Register auf Default Value
2. Block
 -> Default Value von Register 0x0A auslesen
3. Block
 -> Default Value von Register 0x0B auslesen

das ganze hab ich jetzt einfach mal auf den Nano geladen.
ich bekomme allerdings "falsche" Default Werte zurück. Sie Variieren 
schon mal zwischen den beiden Registern, was schon mal sehr gut ist, 
weil ich bisher immer nur 0xFF zurück bekommen habe, allerdings bekomme 
ich für das

0x0A Register: 0xEC
0x0B Register: 0xFC

nach meinem Datenblatt sollten es aber 0x76 und 0x70 sein.
Übersehe ich was?
Was sind die Rückgabe Werte die du bekommst?
-----------------------------
Zum Thema Pull-Up Widerstände, kann ich eurer Diskussion zumindest 
folgen. Ich bin eben im Datenblatt des Atmega328P auch auf diese Stelle 
gestoßen.
Hier heißt es, dass die externen Pull-Up Widerstände nötig sind. (Wird 
aber ein paar Seiten weiter wieder relativiert und es heißt, dass für 
manche Anwendungen auch die internen Pull-Up Widerstände genutzt werden 
können).

Da hätte ich eine Verständnis Frage: ich war bislang immer der Meinung, 
dass Pull-Up Widerstände nur wichtig sind, wenn der Pin als Eingang 
konfiguriert ist. Ist das ein Fehlglaube?

Danke euch

von Michael U. (amiga)


Lesenswert?

Hallo,
David D. schrieb:
> Glücklicherweise habe ich noch einen unbenutzten Nano gefunden, mit dem
> ich das ganze zum laufen gebracht habe. Ich denke, ob ich jetzt zur
> Ansteuerung am Anfang den Nano oder den Uno verwende, sollte keinen
> Unterschied machen. (Bitte belehrt mich wenn ich falsch liege)

egal ob Uno oder Nano, ist eben ein Mega328. Die Pinbelegungen der 
Boards kannst Du ja vergleichen und die Schaltpläne für beie liegen im 
Netz.

Allgemein noch zu ArduinoIDE: Du kannst aus der IDE auch ohne Bootloader 
flashen wenn Du einen der gängigen ISP-Programmer hast.
Bei Werkzeuge-> Programmer Deinen Programmer auswählen und dann im Menü 
Sketch->Hochladen mit Programmer

Dann brauchst Du auch keinerlei Bootloader auf dem Ziel-AVR.

PullUp sind für die Eingänge soweit richtig. Eingang ist bei I2C das 
Ende, was gerade Empfangen will, bei SDA also mal der Master, mal der 
Slave.
Deshalb ja OpenDrain damit eine kurzschlüsse gibt wenn einer High setzt 
und der andere Low. Bei SCK ist es auch so: ein I2C darf zu jeder Zeit 
SCK auf Low halten und so dem Master mitteilen, daß er noch Zeit braucht 
(ClockStretching). Deshalb ist I2C auf einem AVR in reiner Software 
(also ohne das interne Hardware-TWI ziemlich tricky. Man darf dabei dann 
einen Ausgang nie auf PushPull setzen, er ist entweder Eingang (High 
dann vom PullUp irgendwo) oder Ausgang/Low.

Gruß aus Berlin
michael

von David D. (saturi)


Lesenswert?

Michael U. schrieb:

> Allgemein noch zu ArduinoIDE: Du kannst aus der IDE auch ohne Bootloader
> flashen wenn Du einen der gängigen ISP-Programmer hast.
> Bei Werkzeuge-> Programmer Deinen Programmer auswählen und dann im Menü
> Sketch->Hochladen mit Programmer
Ich habe den AVR Dragon, der ja glaube ich leider nicht dort aufgeführt 
ist. Ich habe zwar einen Beitrag gefunden, wo mehrere Dateien der IDE 
geändert wurden, um das zu ermöglichen, allerdings nutze ich auf win10 
die App von Arduino und da finde ich die Dateien nicht und bin auch 
nicht sicher, ob es genauso funktionieren würde.

> Deshalb ja OpenDrain damit eine kurzschlüsse gibt wenn einer High setzt
> und der andere Low. Bei SCK ist es auch so: ein I2C darf zu jeder Zeit
> SCK auf Low halten und so dem Master mitteilen, daß er noch Zeit braucht
> (ClockStretching). Deshalb ist I2C auf einem AVR in reiner Software
> (also ohne das interne Hardware-TWI ziemlich tricky. Man darf dabei dann
> einen Ausgang nie auf PushPull setzen, er ist entweder Eingang (High
> dann vom PullUp irgendwo) oder Ausgang/Low.

Wie genau bekomme ich einen Pin auf OpenDrain? mir sind nur die Modi In 
oder Out bekannt. Habe jetzt schon ein paar Beiträge dazu gelesen, aber 
werde nicht ganz schlau daraus. Im Datenblatt des OV7670 hab ich etwas 
von einem Widerstand in der SDA Leitung gelesen, um die Kurzschlüsse zu 
vermeiden. Das erscheint mir aber nicht allzu elegant.

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> Ich habe den AVR Dragon, der ja glaube ich leider nicht dort aufgeführt
> ist. Ich habe zwar einen Beitrag gefunden, wo mehrere Dateien der IDE
> geändert wurden, um das zu ermöglichen, allerdings nutze ich auf win10
> die App von Arduino und da finde ich die Dateien nicht und bin auch
> nicht sicher, ob es genauso funktionieren würde.
Ich habe gerade mal geschaut, ob mein "Drache" noch lebt. ;)
Ich hatte den mal in die IDE eingetragen, war etwas trickreich, habe ich 
in der aktuellen inzwischen auch nicht mehr gemacht.
Du kannst auch einfach mit Sketch->Kompilierte Binärdatei exportieren 
die von der IDE erzeugten .hex-Files exportieren. Die liegen dann bei 
Deinem Projekt im Sketch-Ordner. Einmal mit und einmal ohne Bootloader. 
Kannst Du dann ja aus dem Studio ö.ä. mit dem Dragon per ISP 
raufschreiben.
Nicht schön, funktioniert aber.
Wenn Du da mehr experimetierst würde ich die ArduinoIDE unbedingt 
portabel installieren.
IDE als ZIP runterladen, an einen Ort Deiner Wahl entpacken, IDE NICHT 
starten! Im dann vorhandenen Ordner Arduino-1.8.5 einen Ordner
portable
anlegen und dann die IDE starten.
Dann landen alle Dateien, Bibliotheken, Sketchbook usw. in diesem 
Arduino-1.8.5 Ordner. Den kann man dann auch koplett umkopieren oder die 
IDE von einem USB-Stick direkt an irgendeinem Windows-Rechner starten 
und benutzen.

> Wie genau bekomme ich einen Pin auf OpenDrain? mir sind nur die Modi In
> oder Out bekannt. Habe jetzt schon ein paar Beiträge dazu gelesen, aber
> werde nicht ganz schlau daraus. Im Datenblatt des OV7670 hab ich etwas
> von einem Widerstand in der SDA Leitung gelesen, um die Kurzschlüsse zu
> vermeiden. Das erscheint mir aber nicht allzu elegant.

Was hast Du vor? Wenn Du die TWI-Hardware des AVR nutzt muß Dich nichts 
davon interessieren, daß erledigt die Hardware komplett alleine.
Nur wenn Du TWi/I2C komplett von Hand programmieren willst mußt Du 
diverses beachten. habe ich auch schon gemacht, in ASM als die AVR noch 
keine TWI in Hardware hatten. Ist aber viele Jahre her...

Ob Du mit der OV7670 jetzt aus der Arduino-IDE redest oder on Du Dir 
eine I2C-Bibliothek in C suchst und im Atmel-Studio o.ä. programmierst, 
ist relativ egal. Von I2C mßt Du erstmal nur grundsätzliches wissen: 
Adresse, Start/RepaetStart/Stop-Condition. Die Wire.h der ArduinoIDE 
kapselst aber auch dieses schon. Wire.begin() initialisiert die 
I2C-hardware des Mega328 (setzt also taktteiler, TWIEN usw. 
beginTransmission schickt Start und Adresse, write schickt Datenbytes. 
Das ACK/NACK-Handling erledigen die Funktionen auch mit.

Ich habe auch etwas den Überblick verloren was Du zur Zeit gerade mit 
der Kamera anfangen willst...

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Vielen Dank für die Informationen. Ja ich werde dann wohl mit dem 
fertigen I2C arbeiten, um die Tücken vorerst zu umgehen.

Ja genau deswegen würde ich Vorschlagen erstmal Back-To-Topic.
Das Ziel ist es, die Funktionsweise der Kamera zu verstehen und sie dann 
auch zu betreiben. (Dabei möchte ich auf föllig fertige Librarys 
verzichten.
Der aktuell 1. Schritt ist, dass SCCB-Interface zum laufen zu bringen.

von Olli Z. (z80freak)


Lesenswert?

Sehr gut David, wir sind wieder auf einem Nenner! :-)
Um Software zum laufen zu bekommen muss man natürlich die Hardware 
beherrschen, ganz klar. Daher ist der kleine Exkurs zum Thema Arduino IO 
Ports schon wichtig.Ich wollte uns ja, durch den Einsatz eines 
Pegelwandlers von der ganzen Problematik fern halten. Genauso wie die 
ganzen vielen kleinen fiesen Details zum I2C Interface.

Kurz gesagt habe ich gestern mal einen Versuchsaufbau unternommen und 
festgestellt das man schon mit externen Pullups arbeiten kann. Im Grunde 
macht man das dann so: Solange der Port unprogrammiert ist, ist er 
Tristate. Dann programmiert man den Pin als Eingang, schreibt aber 
vorher auf den Port eine 0. Dies „entfernt“ den internen Pullup 
Widerstand. In Folge ist der Ausgang Opendrain, also offen und der 
externe Pullup zieht die Leitung auf den gewünschten Spannungspegel. Nun 
kann man durch ändern der Datenrichtung im DDR Register von Eingang aus 
Augang dafür sorgen das die Ausgangsstufe auf GND schaltet. Das Ergebnis 
ist klar, oder? ;-)

So könnte man auf einen Pegelwandler verzichten. Dieses Prinzip könnte 
man auf jeden Port anwenden, also auch auf CLK und Daten. Macht man in 
der Programmierung aber irgendwo einen Fehler, oder nutzt eine Library 
wo man nicht genau weiss was sie intern tut, ist es gleich vorbei...

Apropos Library. Jetzt verwendest Du ja keine Arduino IDE und somit auch 
keine entsprechenden Libs. Hier müssen wir noch zusammenkommen. Ich habe 
mich auf Arduino eingelassen weil der sehr verbreitet ist. Du kannst 
Deinem Nano den Bootloader nachflashen, via ISP Port.

Wir können aber auch gern die AVR Umgebung nutzen, dann müssten wir uns 
halt um das TWI Interface des Atmega selbst kümmern... geht alles, 
bringt uns aber erstmal wieder weiter weg vom Ziel.

von David D. (saturi)


Lesenswert?

Olli Z. schrieb:

> Wir können aber auch gern die AVR Umgebung nutzen, dann müssten wir uns
> halt um das TWI Interface des Atmega selbst kümmern... geht alles,
> bringt uns aber erstmal wieder weiter weg vom Ziel.

Mein langfristiges Ziel ist es, das ganze in der AVR Umgebung, bzw. über 
das Atmelstudio zu programmieren. Weil ich dann wirklich nachvollziehen 
kann, was welcher Pin wirklich wann macht. Da wir aber wie wir ja schon 
festgestellt haben auf verschiedenen Systemen arbeiten, habe ich mir zu 
Beginn des Wochenendes die Arduino IDE runtergeladen und eben auch noch 
einen auf dieser Umgebung funktionierenden Nano ausgegraben.
Für den Anfang sollte das auch in Ordnung sein. Den Transfer auf AVR 
ebene kann man dann ja im Nachgang noch vollziehen.

Damit habe ich mich dann an deinen Test-Code (s.o.) gemacht.
Hiernochmal der wichtige Part:

>zu deinem geposteten Test-Code:
>Über das I2C Interface wird das ganze definitiv viel Übersichtlicher als
>in meinem bisherigen Programmcode, in dem Ich die Übertragung zu Fuß
>abbilden wollte. Ich denke ich kann auch nachvollziehen, was du mit dem
>Code bezwecken willst, was ich hier kurz zusammenfassen möchte, um
>Missverständnisse auszuschließen:
>1.Block: Register Reset
> ->Alle Register auf Default Value
>2. Block
> -> Default Value von Register 0x0A auslesen
>3. Block
> -> Default Value von Register 0x0B auslesen
>
>das ganze hab ich jetzt einfach mal auf den Nano geladen.
>ich bekomme allerdings "falsche" Default Werte zurück. Sie Variieren
>schon mal zwischen den beiden Registern, was schon mal sehr gut ist,
>weil ich bisher immer nur 0xFF zurück bekommen habe, allerdings bekomme
>ich für das
>
>0x0A Register: 0xEC
>0x0B Register: 0xFC

>nach meinem Datenblatt sollten es aber 0x76 und 0x70 sein.
>Übersehe ich was?
>Was sind die Rückgabe Werte die du bekommst?

Ich habe mittlerweile schon zwei Datenblätter gefunden, in denen 
unterschiedliche default Values stehen. Daher würde es mich doch 
brennend interessieren, was du für Rückgabewerte hast und falls es 
andere sind, die Ursache finden, was bei mir wohl noch falsch ist.

Danke und einen schönen Sonntag :)

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Ich lese folgende Werte:
Register 0x0A = 0x76
Register 0x0B = 0x73
Darin soll ja die Produkt-ID stecken. In 0A das MSB (PID) und in 0B das 
LSB (VER). Da wirken meine Werte jetzt plausibel, denn die Product-ID 
(PID) ist laut Datenblatt 0x76 und die Versions-ID (VER) unterscheidet 
sich nur leicht (0x73 anstelle im Datenblatt 0x70).

Was ich noch nicht finde ist die tatsächliche Slave-ID. Im Datenblatt 
steht: auf Seite 10 "The device slave addresses are 42 for write and 43 
for read.". Leider weder ob das Dezimal oder Hexadezimaladressen sind, 
es ist auch anders als in den Arduino Beispielcodes zu finden, da wird 
für Read und Write diesselbe Adresse verwendet, nämlich 0x21.

Habe mal zum vergleichen den Sketch angepasst um einfach mal alle 
Register damit auslesen und anzeigen zu können. Laut Datenblatt gibt es 
nur die Register von 0x00 bis 0xC9.
1
#include "Wire.h"
2
3
void setup() {
4
  Serial.begin(38400);
5
6
  // Generate 8 MHz clock output on Pin "9"
7
  pinMode(9, OUTPUT);
8
  TCCR1A = ((1 << COM1A0)); //0x23;
9
  TCCR1B = ((1 << WGM12) | (1 << CS10)); //0x09;
10
  TIMSK1 = 0;
11
  OCR1A = 0;
12
  
13
  // Reset chip to defaults
14
  // (write 0b10000000 into register 0x12)
15
  Wire.begin();
16
  Wire.beginTransmission(0x21);
17
  Wire.write(0x12);
18
  Wire.write(0x80);
19
  Wire.endTransmission();
20
  delay(500);
21
22
  // Read out values of all registers
23
  for (int adr=0; adr<256; adr++)
24
  {
25
    Serial.print("Value of 0x");
26
    if (adr < 0x10)
27
      Serial.print("0");
28
    Serial.print(adr, HEX);
29
    Serial.print(" = ");
30
    Wire.beginTransmission(0x21);
31
    Wire.write(adr);
32
    Wire.endTransmission();
33
    Wire.requestFrom(0x21, 1);
34
    while(Wire.available() == 0);
35
    while(Wire.available()) {
36
      int b = Wire.read();
37
      Serial.print("0x");
38
      if (b < 0x10)
39
        Serial.print("0");
40
      Serial.print(b, HEX);
41
    }
42
    Serial.println("");
43
  }
44
}
45
46
void loop() {
47
48
}

Und hier mein Ergebnis dazu. Auch ich stelle teils massive Abweichungen 
zu den Defaultwerten laut Datenlbatt fest:
1
Value of 0x00 = 0x1A
2
Value of 0x01 = 0x80
3
Value of 0x02 = 0x88
4
Value of 0x03 = 0x00
5
Value of 0x04 = 0x01
6
Value of 0x05 = 0x7D
7
Value of 0x06 = 0x6E
8
Value of 0x07 = 0x40
9
Value of 0x08 = 0x7D
10
Value of 0x09 = 0x01
11
Value of 0x0A = 0x76
12
Value of 0x0B = 0x73
13
Value of 0x0C = 0x00
14
Value of 0x0D = 0x00
15
Value of 0x0E = 0x01
16
Value of 0x0F = 0x43
17
Value of 0x10 = 0x7F
18
Value of 0x11 = 0x80
19
Value of 0x12 = 0x00
20
Value of 0x13 = 0x8F
21
Value of 0x14 = 0x4A
22
Value of 0x15 = 0x00
23
Value of 0x16 = 0x00
24
Value of 0x17 = 0x11
25
Value of 0x18 = 0x61
26
Value of 0x19 = 0x03
27
Value of 0x1A = 0x7B
28
Value of 0x1B = 0x00
29
Value of 0x1C = 0x7F
30
Value of 0x1D = 0xA2
31
Value of 0x1E = 0x01
32
Value of 0x1F = 0x00
33
Value of 0x20 = 0x04
34
Value of 0x21 = 0x02
35
Value of 0x22 = 0x01
36
Value of 0x23 = 0x00
37
Value of 0x24 = 0x75
38
Value of 0x25 = 0x63
39
Value of 0x26 = 0xD4
40
Value of 0x27 = 0x80
41
Value of 0x28 = 0x80
42
Value of 0x29 = 0x07
43
Value of 0x2A = 0x00
44
Value of 0x2B = 0x00
45
Value of 0x2C = 0x80
46
Value of 0x2D = 0x00
47
Value of 0x2E = 0x00
48
Value of 0x2F = 0x72
49
Value of 0x30 = 0x08
50
Value of 0x31 = 0x30
51
Value of 0x32 = 0x80
52
Value of 0x33 = 0x08
53
Value of 0x34 = 0x11
54
Value of 0x35 = 0x1A
55
Value of 0x36 = 0x00
56
Value of 0x37 = 0x3F
57
Value of 0x38 = 0x01
58
Value of 0x39 = 0x00
59
Value of 0x3A = 0x0D
60
Value of 0x3B = 0x00
61
Value of 0x3C = 0x68
62
Value of 0x3D = 0x88
63
Value of 0x3E = 0x00
64
Value of 0x3F = 0x00
65
Value of 0x40 = 0xC0
66
Value of 0x41 = 0x08
67
Value of 0x42 = 0x00
68
Value of 0x43 = 0x14
69
Value of 0x44 = 0xF0
70
Value of 0x45 = 0x45
71
Value of 0x46 = 0x61
72
Value of 0x47 = 0x51
73
Value of 0x48 = 0x79
74
Value of 0x49 = 0x00
75
Value of 0x4A = 0x00
76
Value of 0x4B = 0x00
77
Value of 0x4C = 0x00
78
Value of 0x4D = 0x04
79
Value of 0x4E = 0x00
80
Value of 0x4F = 0x40
81
Value of 0x50 = 0x34
82
Value of 0x51 = 0x0C
83
Value of 0x52 = 0x17
84
Value of 0x53 = 0x29
85
Value of 0x54 = 0x40
86
Value of 0x55 = 0x00
87
Value of 0x56 = 0x40
88
Value of 0x57 = 0x80
89
Value of 0x58 = 0x1E
90
Value of 0x59 = 0x91
91
Value of 0x5A = 0x94
92
Value of 0x5B = 0xAA
93
Value of 0x5C = 0x71
94
Value of 0x5D = 0x8D
95
Value of 0x5E = 0x0F
96
Value of 0x5F = 0xF0
97
Value of 0x60 = 0xF0
98
Value of 0x61 = 0xF0
99
Value of 0x62 = 0x00
100
Value of 0x63 = 0x00
101
Value of 0x64 = 0x50
102
Value of 0x65 = 0x30
103
Value of 0x66 = 0x00
104
Value of 0x67 = 0x80
105
Value of 0x68 = 0x80
106
Value of 0x69 = 0x00
107
Value of 0x6A = 0x88
108
Value of 0x6B = 0x0A
109
Value of 0x6C = 0x02
110
Value of 0x6D = 0x55
111
Value of 0x6E = 0xC0
112
Value of 0x6F = 0x9A
113
Value of 0x70 = 0x3A
114
Value of 0x71 = 0x35
115
Value of 0x72 = 0x11
116
Value of 0x73 = 0x00
117
Value of 0x74 = 0x00
118
Value of 0x75 = 0x0F
119
Value of 0x76 = 0x01
120
Value of 0x77 = 0x10
121
Value of 0x78 = 0x00
122
Value of 0x79 = 0x00
123
Value of 0x7A = 0x24
124
Value of 0x7B = 0x04
125
Value of 0x7C = 0x07
126
Value of 0x7D = 0x10
127
Value of 0x7E = 0x28
128
Value of 0x7F = 0x36
129
Value of 0x80 = 0x44
130
Value of 0x81 = 0x52
131
Value of 0x82 = 0x60
132
Value of 0x83 = 0x6C
133
Value of 0x84 = 0x78
134
Value of 0x85 = 0x8C
135
Value of 0x86 = 0x9E
136
Value of 0x87 = 0xBB
137
Value of 0x88 = 0xD2
138
Value of 0x89 = 0xE5
139
Value of 0x8A = 0x00
140
Value of 0x8B = 0x00
141
Value of 0x8C = 0x00
142
Value of 0x8D = 0x0F
143
Value of 0x8E = 0x00
144
Value of 0x8F = 0x00
145
Value of 0x90 = 0x00
146
Value of 0x91 = 0x00
147
Value of 0x92 = 0x00
148
Value of 0x93 = 0x00
149
Value of 0x94 = 0x50
150
Value of 0x95 = 0x50
151
Value of 0x96 = 0x01
152
Value of 0x97 = 0x01
153
Value of 0x98 = 0x10
154
Value of 0x99 = 0x40
155
Value of 0x9A = 0x40
156
Value of 0x9B = 0x20
157
Value of 0x9C = 0x00
158
Value of 0x9D = 0x99
159
Value of 0x9E = 0x7F
160
Value of 0x9F = 0xC0
161
Value of 0xA0 = 0x90
162
Value of 0xA1 = 0x03
163
Value of 0xA2 = 0x02
164
Value of 0xA3 = 0x02
165
Value of 0xA4 = 0x00
166
Value of 0xA5 = 0x0F
167
Value of 0xA6 = 0xF0
168
Value of 0xA7 = 0xC1
169
Value of 0xA8 = 0xF0
170
Value of 0xA9 = 0xC1
171
Value of 0xAA = 0x14
172
Value of 0xAB = 0x0F
173
Value of 0xAC = 0x00
174
Value of 0xAD = 0x80
175
Value of 0xAE = 0x80
176
Value of 0xAF = 0x80
177
Value of 0xB0 = 0x00
178
Value of 0xB1 = 0x00
179
Value of 0xB2 = 0x00
180
Value of 0xB3 = 0x80
181
Value of 0xB4 = 0x00
182
Value of 0xB5 = 0x04
183
Value of 0xB6 = 0x00
184
Value of 0xB7 = 0x66
185
Value of 0xB8 = 0x00
186
Value of 0xB9 = 0x06
187
Value of 0xBA = 0x00
188
Value of 0xBB = 0x00
189
Value of 0xBC = 0x00
190
Value of 0xBD = 0x00
191
Value of 0xBE = 0x00
192
Value of 0xBF = 0x00
193
Value of 0xC0 = 0x00
194
Value of 0xC1 = 0x00
195
Value of 0xC2 = 0x00
196
Value of 0xC3 = 0x00
197
Value of 0xC4 = 0x00
198
Value of 0xC5 = 0x00
199
Value of 0xC6 = 0x00
200
Value of 0xC7 = 0x00
201
Value of 0xC8 = 0x06
202
Value of 0xC9 = 0xC0
203
Value of 0xCA = 0xC0
204
Value of 0xCB = 0xC0
205
Value of 0xCC = 0xC0
206
Value of 0xCD = 0xC0
207
Value of 0xCE = 0xC0
208
Value of 0xCF = 0xC0
209
Value of 0xD0 = 0xC0
210
Value of 0xD1 = 0xC0
211
Value of 0xD2 = 0x88
212
Value of 0xD3 = 0x88
213
Value of 0xD4 = 0x88
214
Value of 0xD5 = 0x88
215
Value of 0xD6 = 0x88
216
Value of 0xD7 = 0x88
217
Value of 0xD8 = 0x88
218
Value of 0xD9 = 0x88
219
Value of 0xDA = 0x88
220
Value of 0xDB = 0x88
221
Value of 0xDC = 0x1A
222
Value of 0xDD = 0x1A
223
Value of 0xDE = 0x1A
224
Value of 0xDF = 0x1A
225
Value of 0xE0 = 0x1A
226
Value of 0xE1 = 0x1A
227
Value of 0xE2 = 0x1A
228
Value of 0xE3 = 0x1A
229
Value of 0xE4 = 0x1A
230
Value of 0xE5 = 0x88
231
Value of 0xE6 = 0x88
232
Value of 0xE7 = 0x88
233
Value of 0xE8 = 0x88
234
Value of 0xE9 = 0x88
235
Value of 0xEA = 0x88
236
Value of 0xEB = 0x88
237
Value of 0xEC = 0x88
238
Value of 0xED = 0x88
239
Value of 0xEE = 0x1A
240
Value of 0xEF = 0x1A
241
Value of 0xF0 = 0x1A
242
Value of 0xF1 = 0x1A
243
Value of 0xF2 = 0x1A
244
Value of 0xF3 = 0x1A
245
Value of 0xF4 = 0x1A
246
Value of 0xF5 = 0x1A
247
Value of 0xF6 = 0x1A
248
Value of 0xF7 = 0x1A
249
Value of 0xF8 = 0x88
250
Value of 0xF9 = 0x88
251
Value of 0xFA = 0x88
252
Value of 0xFB = 0x88
253
Value of 0xFC = 0x88
254
Value of 0xFD = 0x88
255
Value of 0xFE = 0x88
256
Value of 0xFF = 0x88

: Bearbeitet durch User
von David D. (saturi)


Lesenswert?

Okay, dann hab ich bei mir offensichtlich noch ein Problem. Ich werde 
nochmal den Aufbau überprüfen und mich dann nochmal melden, entweder mit 
dem gefundenen Fehler oder ein paar Fotografien zur Fehleranalyse mit 
euch :D

Edit: Habe den Fehler gefunden... aber es ist mir zu peinlich zuzugeben, 
dass ich bei meinem Terminal Programm vergessen habe die Baudrate 
anzupassen xD....
Damit bin ich mit dir auf einem Nenner, manche Register zeigen zu deinen 
zwar Abweichungen, aber ich habe auch die 76 und die 73 in 0A und 0B

> Was ich noch nicht finde ist die tatsächliche Slave-ID. Im Datenblatt
> steht: auf Seite 10 "The device slave addresses are 42 for write and 43
> for read.". Leider weder ob das Dezimal oder Hexadezimaladressen sind,
> es ist auch anders als in den Arduino Beispielcodes zu finden, da wird
> für Read und Write diesselbe Adresse verwendet, nämlich 0x21.

Da kann ich Licht ins Dunkle bringen. Das ist nämlich bei beiden das 
gleiche ;-)
nur das im Datenblatt offensichtlich das Lese bzw. Schreib Bit 
dazugezählt wird, also das R/W-Bit
Sprich der Aufbau ist ja:

Die ersten 7 Bit sind die Adresse und das 8. Bit ist schreiben/lesen.
Wenn jetzt die Adresse 0x21 ist, man die aber einmal nach Links shiftet 
um das 8. Bit noch anhängen zu können erhält man: 0x42 (Multiplikation 
mit 2)
jetzt ist das R/W bit beim schreiben 0 sprich wir bleiben bei 0x42 und 
beim lesen 1 womit wir bei der 0x43 wären.
Ich hoffe das ist soweit verständlich ausgedrückt.

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> Da kann ich Licht ins Dunkle bringen. Das ist nämlich bei beiden das
> gleiche ;-)
> nur das im Datenblatt offensichtlich das Lese bzw. Schreib Bit
> dazugezählt wird, also das R/W-Bit
> Sprich der Aufbau ist ja:
>
> Die ersten 7 Bit sind die Adresse und das 8. Bit ist schreiben/lesen.
> Wenn jetzt die Adresse 0x21 ist, man die aber einmal nach Links shiftet
> um das 8. Bit noch anhängen zu können erhält man: 0x42 (Multiplikation
> mit 2)
> jetzt ist das R/W bit beim schreiben 0 sprich wir bleiben bei 0x42 und
> beim lesen 1 womit wir bei der 0x43 wären.

das ist das "übliche" I2C-Problem. I2C benutzt 7Bit-Adressen in 
Bit7...Bit1.
Bit0 ist eben R/W.
Ich kenne genug Datenblätter die es mit R/W als 2x 8Bit-Adresse angeben, 
ungefähr genausoviele, die die 7Bit-Adresse angeben und die Bitmaske des 
Bytes dazu. Bei der Software ist es sehr ähnlich.
Wird man mit leben müssen.

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

Oh ja, Danke für die Nachhilfe! :-)
0x43 = 0b0100 0011
0x42 = 0b0100 0010
0x21 = 0b0010 0001

Ja und genau das sind natürlich die "Freuden" wenn man Libs verwendet. 
Die wollen einem die Arbeit abnehmen und verursachen dadurch manchmal 
erst die Probleme ;-) Aber auch die Datenblätter sind mitunter ganz 
schön schrottig, wie in diesem Beispiel.

Zu den Defaultwerten: Keine Ahnung ob die immer so sein müssen wie im 
Datenblatt. Aber anscheinend klappt die grundsätzliche Kommunikation und 
wir könnten einen Schritt weiter gehen?! (Nur weil Du es nicht explizit 
erwänht hast: Hast Du nun den Pegelwandler zwischen den Signalen?).

Als nächstes wäre die Frage was wir als nächstes tun. Normalerweise 
würde man jetzt die Betriebsparameter für den Kamerabetrieb übermitteln, 
dann den PCLK (Pixelclock) anlegen und Bilddaten am Parallelport 
abrufen. Ein netter Test hier wäre erstmal nur die HSYNC- und 
VSYNC-Signale zu erfassen und zu zählen. Nach jedem erkannten VSYNC 
müssten ja immer eine der Auflösung entsprechende Anzahl HSYNC-Signale 
folgen. Die einfach zählen und ausgeben.

von Michael U. (amiga)


Lesenswert?

Hallo,

@Olli Z. (z80freak):
das kommt nun davon...
Arduino Nano und Pegelwandler und die OV7670 zusammengesteckt,
nur 3,3V/GND/SCL/SDA und XCLK angeschlossen.
Deinen Sketch rauf und gestartet.

Ich könnte jetzt die nächste Liste abweichender Registerwerte anbieten, 
mit dem Datenblatt habe ich noch nicht vergleichen.

Value of 0x00 = 0xF9
Value of 0x01 = 0x80
Value of 0x02 = 0x88
Value of 0x03 = 0x00
Value of 0x04 = 0x01
Value of 0x05 = 0x7A
Value of 0x06 = 0xAD
Value of 0x07 = 0x40
Value of 0x08 = 0x7A
Value of 0x09 = 0x01
Value of 0x0A = 0x76
Value of 0x0B = 0x73
Value of 0x0C = 0x00
Value of 0x0D = 0x00
Value of 0x0E = 0x01
Value of 0x0F = 0x43
Value of 0x10 = 0x7F
Value of 0x11 = 0x80
Value of 0x12 = 0x00
Value of 0x13 = 0x8F
Value of 0x14 = 0x4A
Value of 0x15 = 0x00
Value of 0x16 = 0x00
Value of 0x17 = 0x11
Value of 0x18 = 0x61
...

Gruß aus Berlin
Michael

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Guten Abend,
mein letzter Post für Heute, versprochen ;-)

also ja ich habe drei Pegelwandler zwischen der SCL,SDA und XCLK. 
Nachdem ich mir eben dachte, dass so viele Bauteile ja nicht drauf sind 
und man die auch bestimmt selber bauen kann, hab ich mir die 
Funktionsweise angeschaut und festgestellt, dass es eine High und eine 
Low Seite gibt. (Wie auch bei dir im Eagle zu sehen) Wie der Zufall es 
so will, hab ich die das Ganze Wochenende so betrieben, was bei kurzem 
Nachmessen eben die Erkenntnis brachte, dass ich die Kamera das ganze 
Wochenende an 5V Signalen betrieben habe. Jetzt passt aber alles!

Nachdem ich mir die Signalverläufe von deiner Sketch mit deinen von 
meinem AVR-Selbstgebasteltem-Kommunikationsprotokoll verglichen habe, 
ist mir aufgefallen, dass ich die Stopp und Start Sequenz zwischen den 
beiden 2-Phasen Übertragungen vergessen habe. Kaum sind die drin 
funktioniert auch mein Skript im Atmel-Studio und liefert die richtigen 
Werte! Das Wochenende war also - dank eurer Hilfe - ein voller Erfolg :)

@Michael
Value of 0x0A = 0x76
Value of 0x0B = 0x73

scheinen wenigstens bei uns dreien alle gleich zu sein. :D der Rest 
weicht offensichtlich immer vom Datenblatt ab.

@Olli
Hört sich doch schon mal nach einem Plan an.
Habe mal kurz das Oszi dran gehangen und das sieht schonmal nach nem 
vernünftigen Signal aus :)

viele Grüße aus dem Schwabenland
David

von Olli Z. (z80freak)


Lesenswert?

Prima, David! Da sind wir doch schonmal einem Problem auf die Spur 
gekommen. Die Sache mit den Start Stop Sequenzen ist ja elementar für 
I2C, logisch.

Was die „Default“-Werte angeht glaub ich fast das die sich aufgrund 
bestimmter Funktionen des Chips sofort wieder ändern. Wenn z.Bl Autogain 
für irgendwas eingestellt ist, dann könnte ich mir vorstellen das in dem 
dafür vorgesehenen Register zum einstellen der Gain im Automatikmodus 
dort der aktuelle, selbst gemessene Wert vom Chip auszulesen ist. Ich 
würde die stark abweichenden Defaults erstmal vergessen...

Also, unser Programm soll erstmal die Schnittstelle initialisieren, also 
TWI Interface aktivieren, XCLK erzeugen und abfragen ob an Slave ID 0x21 
der Wert für Register 0x0A den Wert 0x76 aufweist. In dem Fall haben wir 
wohl eine OV7670 dran ;-)

Ist das getan, sollten wir der Kamera einen Reset per Software 
verpassen, indem wir in Register 0x12 eine 0x80 (0b1000 0000) schreiben. 
Hierbeiminteressiert uns der Rest des Registers nicht, weil es sowieso 
resettet wird ;-)

Dann kämen die Kameraparameter... hier gerne Vorschläge!

von Olli Z. (z80freak)


Lesenswert?

Zuerst noch ein Wort zur Arbeitsweise der Wire-Lib von Arduino 
(https://www.arduino.cc/en/Reference/Wire). Achja, mein Beispielsketch 
oben ist wirklich nur ein Beispiel, quick'n'dirty, also bitte nicht als 
Referenzdesign nehmen ;-)

Einbinden der Lib wie üblich mit:
1
#include "Wire.h"

Initialisiert wird das I2C-Interface vom Atmega als Master (sonst käme 
eine Slave-ID in den Funktionsparameter) so:
1
Wire.begin()

Hierbei werden die Signalleitungen A4 und A5 auf Open-Drain eingestellt 
und mit SDA und SCL des I2C-controllers im Atmega verbunden. Die 
Übertragungsgeschwindigkeit wird (Prozessortaktabhängig durch Teiler) 
auf 100 kHz eingestellt und dann mittels TWEN-Bit aktiviert.

Im Prinzip gibt es auch ein "Wire.end()" was das alles wieder 
zurückdreht. Das werden wir aber wohl nie aufrufen...

Eine Übertragung sieht so aus, das man eine neue Transmission beginnt, 
die zu übertragenden Werte festlegt und startet. Etwas umständlich, aber 
naja. Das sieht dann grundsätzlich immer so aus:
1
Wire.beginTransmission(0x21);
2
...
3
Wire.endTransmission();

Wie wir gelernt haben wird die Slave-ID (hier die 0x21) als 7-Bit Wert 
angegeben. Das Write-Bit setzt die Lib selbstständig. eine 
"Transmission" ist immer eine schreibende Operation.

Nun gibt es bei SCCB den 3-Phase-Write. Dieser besagt das 3 Bytes 
hintereinander zum OV-Chip übertragen werden. Um z.B. den Wert eines 
Registers zu ändern genügt dies:
1
Wire.beginTransmission(0x21);
2
Wire.write(address);
3
Wire.write(value);
4
Wire.endTransmission();

Um den Wert eines Registers auszulesen sendet man nur die 
Register-Adresse und lauscht anschließend am Bus bis Daten kommen:
1
Wire.beginTransmission(0x21);
2
Wire.write(address);
3
Wire.endTransmission();
4
Wire.requestFrom(0x21, 1);
5
while(Wire.available() == 0);
6
while(Wire.available()) {
7
  char c = Wire.read();
8
  ...
9
}

Der erste Teil löst einen 2-Phase-Write aus und schreibt nur Slave-ID 
und Register-Adresse die man lesen möchte. Das nachfolgende 
"requestFrom()" löst einen 2-Phase-Read aus. Dieser übermittelt die 
Slave-ID (erster Parameter) und die Anzahl der zu lesenden Bytes 
(zweiter Parameter im Funktionsaufruf).

Jetzt müssen wir warten bis die Daten vom Slave im Eingangspuffer des 
I2C-Controllers stehen. Hierfür ist die erste Dummy-While-Schleife mit 
"Wire.available() == 0". Ja, das ist unsauber, weil es die 
Programmausführung blockiert und sich der Atmega hier aufhängen würde, 
käme nie eine Antwort vom Slave. In der Realität würde man hier eher 
Events bevorzugen und mittels "Wire.onReceive(handler)" einbauen.

Im Prinzip könnte man sich die nachfolgende While-Schleife um 
"Wire.read()" sparen und durch ein einzelnes read ersetzen, weil wir ja 
genau ein Byte angefragt haben. Das ist hier nur zur Sicherheit, falls 
der Client doch mal mehr oder weniger Bytes sendet als erwartet.

Um anstelle von Bytewerten mit Register- und Wertenamen arbeiten zu 
können, sollten wir das benötigte per "#define" Deklaration bekannt 
geben. Z.B.:
1
#define OV7670_I2C_ID  0x21
2
#define OV7670_PID     0x76
3
#define OV7670_COM7    0x12
4
#define OV7670_RESET   0x80

So, das müsste im groben und ganzen alles sein was wir zur Kommunikation 
mit dem OV-Chip benötigen. Hab ich was vergessen?

von Michael U. (amiga)


Lesenswert?

Hallo,

Olli Z. schrieb:
> Um anstelle von Bytewerten mit Register- und Wertenamen arbeiten zu
> können, sollten wir das benötigte per "#define" Deklaration bekannt
> geben. Z.B.:

und wenn Du jetzt "faul" bist, schau mal in meinen Post oben vom 
23.03.2018 08:58 rein...
https://github.com/ComputerNerd/ov7670-no-ram-arduino-uno
und dann schau dort in die ov7670.h

Selbstverständlich kann man es auch komplett selbst anlegen. Hängt von 
Erfahrung, Zeit und der eigenen Art zu Lernen ab.

Früher (tm) habe ich es öfter bei meinen Bastelein machen müssen, weil 
nichts dafür zu finden war. C64 ASM und Videotextdecoder (SAA5246).
Zum AVR bin ich wegen des MAS3507 (MP3-Decoder) gekommen, das war 
1999...

Zu Deiner Analyse der Wire.h: ich habe sie nur benutzt und auf die 
Funktion vertraut. Einen grund reinzuschauen hatte da konkret nicht.
Das viel Arduino-Libs blokierend sind liegt am Konzept. Natürlich kann 
man ein Event-Handling mit Interruptsteuerug auch mit den 
Arduino-Klassen machen.

PS: vielleicht als I2C-Ergänzung: die Lib muß natürlich auch das 
ACK/NACK erledigen. Bei Wire.requestFrom(0x21, 1); muß ja z.B. nach 
Senden von Adresse usw. ein RepeatStart statt Stop bei I2C geschickt 
werden wenn danach gelesen werden soll.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Habe jetzt erstmal die Pixel pro Zeile gezählt.
Da bekomme ich immer zwischen 479 und 480 Pixel raus.
vielleicht ist mein senden an den UART zu langsam, sodass ich den ersten 
Pixel verpasse.
1
/*
2
 * main.cpp
3
 *
4
 * Created: 23.07.2017 17:35:15
5
 *  Author: David
6
 */ 
7
8
 #ifndef F_CPU
9
 #define F_CPU 16000000
10
#endif
11
 
12
 #include <avr/io.h>
13
 #include <avr/interrupt.h>
14
15
#include "OV7670.h"
16
#include "OV7670.c"
17
18
#include "UART.h"
19
20
 int main(void)
21
22
 {
23
  sei();
24
  UART0_init();
25
   OV7670_init();
26
27
  int RowCount = 0;
28
  bool VSync_Flag=false;
29
  bool HREF_Flag=false;
30
   while (1)
31
   {
32
    if(((OV_VSYNC_PIN>>OV_VSYNC_PINNR)&(0x01))&&(VSync_Flag==false))
33
    {
34
      VSync_Flag=true;      
35
      UART0_senden_zahl(RowCount);
36
      UART0_senden_Byte(13);
37
      UART0_senden_Byte(10);
38
      RowCount=0;      
39
    }
40
    if(!((OV_VSYNC_PIN>>OV_VSYNC_PINNR)&(0x01))&&(VSync_Flag==true))
41
    {
42
      VSync_Flag=false;
43
      RowCount=0;
44
    }
45
    
46
    if(((OV_HREF_PIN>>OV_HREF_PINNR)&(0x01))&&(HREF_Flag==false))
47
    {
48
      HREF_Flag=true;
49
      RowCount++;
50
    }
51
52
    if(!((OV_HREF_PIN>>OV_HREF_PINNR)&(0x01))&&(HREF_Flag==true))
53
    {
54
      HREF_Flag=false;
55
    }
56
   }
57
   return 0;
58
 }

Zur Vorgehensweise würde ich als erstes Versuchen die Frequenz runter zu 
nehmen, also PCLK zu verringern und zu schauen, ob es Wirkung zeigt.
Verstehe ich es richtig, dass dann auch die V-Sync und HREF Frequenzen 
runter gehen?
Die nötigen Register hierfür wären 0x11 und 0x6B, wobei ich letzteres 
nicht ganz verstehe.

von Olli Z. (z80freak)


Lesenswert?

Die HREF und VSYNC ändern sich bei der fallenden Flanke von PCLK, sind 
also synchron zum Takt.

von Olli Z. (z80freak)


Lesenswert?

Wir sollten kurz das Pinout klären, damit wir auch auf einem Nenner 
bleiben :-) Das Problem beim Nano ist, das nur relativ wenig IO-Pins zur 
Verfügung stehen. Leider haben wir nichtmal einen kompletten 8-Bit Port 
für die Videodaten zur Verfügung. Port D ist mit 2 Bit am UART und fällt 
damit flach, sonst haben wir keine Debug-Schnittstelle. Einzige 
Alternative wäre hier SoftSerial und zwei andere Pins nehmen. Dann 
müsste man den Nano aber wohl besser über ISP flashen.

Habe das jetzt erstmal so vorgesehen:
1
 *  OV7670 Dir  Arduino   Meaning
2
 *  3v3    <-   3V3       Vcc (+3,3V)
3
 *  GND    <-   GND       GND
4
 *  SIOC   <-   A5        SCL (I2C clock) !USE LEVEL-SHIFTER!
5
 *  SIOD   <-   A4        SDA (I2C data)  !USE LEVEL-SHIFTER!
6
 *  XCLK   <-   D2        System-Clock    !USE LEVEL-SHIFTER!
7
 *  RESET  <-   3V3       Reset fixed for testing
8
 *  PWDN   <-   GND       Power-Down fixed for testing
9
 *  HREF   ->   A6        Start of new line in Videoframe
10
 *  VSYNC  ->   A7        Start of new Videoframe
11
 *  PCLK   <-   D3        Pixel clock     !USE LEVEL-SHIFTER!
12
 *  D0     ->   A0        Videodata LSB
13
 *  D1     ->   A1        Videodata
14
 *  D2     ->   A2        Videodata
15
 *  D3     ->   A3        Videodata
16
 *  D4     ->   D4        Videodata
17
 *  D5     ->   D5        Videodata
18
 *  D6     ->   D6        Videodata
19
 *  D7     ->   D7        Videodata MSB

Ich hab das Datenwort in ein low- und high-nibble geteilt und damit es 
einfach einzulesen ist, das lower auf Bit 0-3 von Port C (A0-A3) und das 
higher auf Bit 4-7 von Port D (D4-D7). So müssen wir nur beide Ports 
lesen, maskieren und oder-verknüpfen.

: Bearbeitet durch User
von David D. (saturi)


Lesenswert?

Guten Morgen,
ich verstehe deinen Einwand nicht.
Am Nano sind doch noch mehr Pins nach außen geführt als beim UNO oder?

Ich würde es sehr begrüßen, wenn wir die Pins nehmen, die auch beim UNO 
verfügbar sind, damit man das selbe Programm auf beiden Boards nutzen 
kann:

Habe an deinem Plan mal ein paar Anpassungen vorgenommen:

 *  OV7670 Dir  Arduino   Meaning
 *  3v3    <-   3V3       Vcc (+3,3V)
 *  GND    <-   GND       GND
 *  SIOC   <-   A5        SCL (I2C clock) !USE LEVEL-SHIFTER!
 *  SIOD   <-   A4        SDA (I2C data)  !USE LEVEL-SHIFTER!
 *  XCLK   <-   D2        System-Clock    !USE LEVEL-SHIFTER!
 *  RESET  <-   3V3       Reset fixed for testing
 *  PWDN   <-   GND       Power-Down fixed for testing
 *  HREF   ->   A0        Start of new line in Videoframe
 *  VSYNC  ->   A1        Start of new Videoframe
 *  PCLK   <-   D3        Pixel clock     !USE LEVEL-SHIFTER!
 *  D0     ->   D8        Videodata LSB
 *  D1     ->   D9        Videodata
 *  D2     ->   D10       Videodata
 *  D3     ->   D11       Videodata
 *  D4     ->   D4        Videodata
 *  D5     ->   D5        Videodata
 *  D6     ->   D6        Videodata
 *  D7     ->   D7        Videodata MSB

D8-D11 wäre dann der PORTB 0-3
und D4-D7 wäre PORTD 4-7

Damit verlieren wir nur den MOSI pin. Aber brauchen wir den?
Weiterhin habe ich HREF und VSYNC auf A0 und A1 geholt, weil es A6 und 
A7 auf dem UNO nicht nach außen geführt gibt.
Bist du damit einverstanden oder übersehe ich was?

lg. David

von Michael U. (amiga)


Lesenswert?

Hallo,

A6 und A7 sind beim Mega328 nur ADC-Eingänge, sie haben keine digitalen 
I/O-Funktionen. Insofern ist ohnehin Deine Version sinnvoll.

Könntest Du Deinen Source komplett als Archiv hier anhängen?
Ich würde mit den Stand gern ein wenig "mitspielen", nur aus Neugier und 
weil die Hardware nun sowieso hier rumliegt.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

kann ich machen, wenn ich zuhause bin. Noch eine Frage: Warum muss PCLK 
über einen Level-Shifter gehen? der Takt wird doch von der Kamera 
vorgegeben oder? den Lese ich doch nur aus?

von Michael U. (amiga)


Lesenswert?

Hallo,

Danke, hat keine Eile, ich spiele noch mit meiner alten DC3840 am ESP32 
weiter, die macht auch noch nicht, was soll.

Bei PCLK stimme ich Dir nach kurem Blick ins Datenblatt der OV7670 zu, 
ist Ausgang, braucht also keinen Levelshifter.

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

David D. schrieb:
> Am Nano sind doch noch mehr Pins nach außen geführt als beim UNO oder?
Du hast recht!

Das mit dem PCLK hatte ich falsch verstanden und habs unten im Pinout 
korrigiert. Ist aber auch logisch, auf die "Frequenz" der Daten haben 
wir ja keinen Einfluss. Evtl. über die Auflösung. Leider kann man die 
beim OV7670 nicht frei definieren, sondern nur zwischen VGA, QVGA und 
noch was exotischem wählen. Ich glaub das kleinste ist QVGA mit 320x200.

Mit Deinem Pinout habe ich folgendes Problem: Zur Erzeugung des XCLK 
habe ich PWM verwendet. Das geht bis max. 8MHz was aber funktioniert. Du 
wolltest das per FUSE machen, was man in der Arduino-IDE aber nicht so 
ohne weiteres einstellen kann. Wenn wir bei PWM bleiben wollen, dann 
müssen wir nur D2 und D3 vertauschen und schon gehts :-) Man könnte auch 
den PCLK auf A2 legen, dann wär das mit den anderen Signalen in einem 
Register, was vielleicht auch nicht blöd ist.

Hier mein Korrekturvorschlag:
1
  *  OV7670 Dir  Arduino   Meaning
2
  *  3v3    <-   3V3       Vcc (+3,3V)
3
  *  GND    <-   GND       GND
4
  *  SIOC   <-   A5        SCL (I2C clock) !USE LEVEL-SHIFTER!
5
  *  SIOD   <-   A4        SDA (I2C data)  !USE LEVEL-SHIFTER!
6
  *  XCLK   <-   D3        System-Clock    !USE LEVEL-SHIFTER!
7
  *  RESET  <-   3V3       Reset fixed for testing
8
  *  PWDN   <-   GND       Power-Down fixed for testing
9
  *  HREF   ->   A0        Start of new line in Videoframe
10
  *  VSYNC  ->   A1        Start of new Videoframe
11
  *  PCLK   ->   A2        Pixel clock
12
  *  D0     ->   D8        Videodata LSB
13
  *  D1     ->   D9        Videodata
14
  *  D2     ->   D10       Videodata
15
  *  D3     ->   D11       Videodata
16
  *  D4     ->   D4        Videodata
17
  *  D5     ->   D5        Videodata
18
  *  D6     ->   D6        Videodata
19
  *  D7     ->   D7        Videodata MSB


> D8-D11 wäre dann der PORTB 0-3
> und D4-D7 wäre PORTD 4-7
Um ein Datenbyte zu lesen wär dann nur sowas nötig:
1
c = (PORTD & 0b11110000) | (PORTB & 0b00001111);

> Weiterhin habe ich HREF und VSYNC auf A0 und A1 geholt, weil es A6 und
> A7 auf dem UNO nicht nach außen geführt gibt.
Stimmt! Hab ich komplett übersehen, bzw. nicht quer geprüft. A6+A7 sind 
Analog-Only und fallen eh flach.

> Bist du damit einverstanden oder übersehe ich was?
Ich glaub wir habens fast ;-)

von Michael U. (amiga)


Lesenswert?

Hallo,

warum eigentlich PWM und nicht CTC-Mode? Auch da gehen zwar nur 8MHz bei 
16MHz Clock aber der wurde ja dafür eingebaut.
Habe jetzt aber nicht nach den Ausgabepins der Timer geschaut.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Olli Z. schrieb:

> Mit Deinem Pinout habe ich folgendes Problem: Zur Erzeugung des XCLK
> habe ich PWM verwendet. Das geht bis max. 8MHz was aber funktioniert. Du
> wolltest das per FUSE machen, was man in der Arduino-IDE aber nicht so
> ohne weiteres einstellen kann. Wenn wir bei PWM bleiben wollen, dann
> müssen wir nur D2 und D3 vertauschen und schon gehts :-)
Jap sollte kein Problem machen, dann machen wir das so. Das mit der Fuse 
geht nur auf D8 also (PB0). Aber das hatte ich eh nur testweise über 
einen zweiten Controller gemacht. Also können wir da deinen Vorschlag 
übernehmen.

>Man könnte auch
> den PCLK auf A2 legen, dann wär das mit den anderen Signalen in einem
> Register, was vielleicht auch nicht blöd ist.

Der Vorteil an D3 ist, dass der Pin Interrupt fähig ist. Wenn wir es 
also in Zukunft schaffen eventuell die Bilder noch irgendwie zu 
verarbeiten, wäre der Interrupt gut, um zwischen drin nichts zu 
verpassen.
Das alle Signale auf einem Register liegen ist ja nicht unbedingt 
notwendig.
Da erscheinen mir die Vorzüge des Interrupts lukrativer und wir belegen 
nicht unnötiger Weise einen analogen Eingang.

Hier ein weiterer Korrekturvorschlag: ;-)
1
   *  OV7670 Dir  Arduino   Meaning
2
   *  3v3    <-   3V3       Vcc (+3,3V)
3
   *  GND    <-   GND       GND
4
   *  SIOC   <-   A5        SCL (I2C clock) !USE LEVEL-SHIFTER!
5
   *  SIOD   <-   A4        SDA (I2C data)  !USE LEVEL-SHIFTER!
6
   *  XCLK   <-   D3        System-Clock    !USE LEVEL-SHIFTER!
7
   *  RESET  <-   3V3       Reset fixed for testing
8
   *  PWDN   <-   GND       Power-Down fixed for testing
9
   *  HREF   ->   A0        Start of new line in Videoframe
10
   *  VSYNC  ->   A1        Start of new Videoframe
11
   *  PCLK   ->   D3        Pixel clock
12
   *  D0     ->   D8        Videodata LSB
13
   *  D1     ->   D9        Videodata
14
   *  D2     ->   D10       Videodata
15
   *  D3     ->   D11       Videodata
16
   *  D4     ->   D4        Videodata
17
   *  D5     ->   D5        Videodata
18
   *  D6     ->   D6        Videodata
19
   *  D7     ->   D7        Videodata MSB


>> D8-D11 wäre dann der PORTB 0-3
>> und D4-D7 wäre PORTD 4-7
> Um ein Datenbyte zu lesen wär dann nur sowas nötig:
1
> c = (PORTD & 0b11110000) | (PORTB & 0b00001111);
2
>
richtig, das sollte mit dem Maskieren eigentlich recht einfach gehen.

>> Weiterhin habe ich HREF und VSYNC auf A0 und A1 geholt, weil es A6 und
>> A7 auf dem UNO nicht nach außen geführt gibt.
> Stimmt! Hab ich komplett übersehen, bzw. nicht quer geprüft. A6+A7 sind
> Analog-Only und fallen eh flach.

Jetzt sind wir hoffentlich schon fast d'accord :-)

@Michael
Ich glaube, dass du da recht hast, aber es war bisher ja nur ein erster 
Gedanke und Entwurf von Olli. Aber ich habe es mal in der Liste der zu 
behandelnden Punkte geschrieben.

von David D. (saturi)


Lesenswert?

Ich habe jetzt mal einen Test zum Schreiben von einem Register gemacht.
Ich habe in das CLKRC-Register (Adresse:0x11) das Bit 7 auf 0 gesetzt 
und die Bits 0-4 auf 1 um einen Prescaler von 16 zu erhalten.

Damit ist es mir dann tatsächlich gelungen die PCLK von 16Mhz auf 500KHz 
zu drosseln. Erfreulich war, dass auch die Frequenz von HREF linear 
gesunken ist.

bei 16 MHz PCLK lag die Frequenz von HREF bei 10,2KHz.
bei 500 KHz PCLK lag sie nur noch bei 322 Hz.

Damit könnten wir es sogar schaffen, die Bild Daten testweise mal über 
den Serial Port an den PC zu übertragen. Oder verkalkulier ich mich da 
grade?

von Andreas S. (igel1)


Lesenswert?

Hi Leute,

ich habe vor ein paar Monaten die OV7670 an meinem STM32 ARM ans Laufen 
gebracht: Beitrag "Camera OV7670: Register Settings für Farbbilder gesucht"

Dasselbe auf dem ATmega stelle ich mir sehr herausfordernd vor,...

Zuerst wollte ich mir ebenfalls alles selber erschließen, aber die Doku 
zu dem Teil ist so schlecht, dass man wirklich beliebig viel Zeit 
vergeuden kann, bis alles richtig läuft. Diese Zeit war mir dann 
irgendwann zu schade und ich habe bei anderen "abgespickt".

Ich würde Euch nun natürlich gerne mit ein paar Tipps versorgen, habe 
dummerweise aktuell aber Null Zeit.

Daher hier nur auf die Schnelle meine Quellen, die mir seinerzeit sehr 
geholfen hatten:

Zum Allgemeinen Verständnis:
http://embeddedprogrammer.blogspot.de/2012/07/hacking-ov7670-camera-module-sccb-cheat.html
http://embeddedprogrammer.blogspot.de/2013/01/demo-stm32f4-ov7670-qserialterm.html

SCCB:
https://e2e.ti.com/support/embedded/linux/f/354/p/171390/862562#862562
https://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/99/t/120548
http://embeddedprogrammer.blogspot.de/2012/07/hacking-ov7670-camera-module-sccb-cheat.html
https://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/99/p/6092/22820#22820
http://forum.arduino.cc/index.php?topic=195642.msg1446591#msg1446591
https://electronics.stackexchange.com/questions/259119/ov7670-omnivision-sccb-read-sequence-issue

Die functional specification:
http://www4.cs.umanitoba.ca/~jacky/Teaching/Courses/74.795-LocalVision/ReadingList/ov-sccb.pdf

Der Implementation Guide:
http://www.haoyuelectronics.com/Attachment/OV7670%20+%20AL422B%28FIFO%29%20Camera%20Module%28V2.0%29/OV7670%20Implementation%20Guide%20%28V1.0%29.pdf

Wie ich lese, kämpft Ihr aktuell noch mit dem SCCB-Protokoll - da ist 
die Doku sogar noch halbwegs verständlich und vollständig. Spätestens 
wenn Ihr Euch mit den dutzenden Registern und ihren teils 
undokumentierten Werten und Bedeutungen herumschlagt, werdet Ihr evtl. 
auch zu meiner Erkenntnis kommen: die Doku ist Schrott und selber 
ausprobieren macht kaum Sinn, wenn's andere vor einem schon durch 
wochenlanges Herumprobieren herausbekommen haben. Selbst dann ist der 
Weg noch hinreichend steinig ...
Good luck Euch!

Viele Grüße

Igel1

von Olli Z. (z80freak)


Lesenswert?

David D. schrieb:
> Der Vorteil an D3 ist, dass der Pin Interrupt fähig ist. Wenn wir es
Gutes Argument. Das wäre bei der Verarbeitung der PCLK sicher hilfreich. 
Sehe grad das ich D3 in meinem Pinout zweimal geschrieben hab.

Aber wo wir grad bei Interrupts sind, viellecht setzen wir erstmal 
nochmal da an, bevor wir das Pinout festzurren.

Wir müssen ja PCLK (24 MHz laut Datenblatt), HSYNC (ca. 32 kHz) und 
VSYNC (50-60 Hz) verarbeiten. Ich würde vorschlagen wir tasten VSYNC ab 
bis wir einen Bildstart erkennen und setzen ein Flag. Bei jedem HSYNC 
müssen wir eine Bildzeile einlesen. Dafür brauchen wir soviel Power vom 
kleinen Atmega das wir vermutlich zu nichts anderem kommen werden?! Das 
wäre doch was für den Interrupt. Den PCLK können wir für den Interrupt 
eh nutzen, da er viel zu schnell ist.

Bitte Vorschläge hierzu :-)


P.S. An alle die ab jetzt erst mitlesen die Info: Wir wollen keine 
fertigen Lösungen sondern unsere eigene erarbeiten. Warum? Um genau auf 
all die vielen kleinen Details zu kommen die es bei einem solchen Design 
zu beachten gilt :-)

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Michael U. schrieb:
> warum eigentlich PWM und nicht CTC-Mode? Auch da gehen zwar nur 8MHz bei
> 16MHz Clock aber der wurde ja dafür eingebaut.
> Habe jetzt aber nicht nach den Ausgabepins der Timer geschaut.

Ich muss gestehen das ich da nicht somtief drin bin wie Du. Könntest Du 
mir das Konzept kurz erläutern?

von Olli Z. (z80freak)


Lesenswert?

David D. schrieb:
> Ich habe jetzt mal einen Test zum Schreiben von einem Register gemacht.
> Ich habe in das CLKRC-Register (Adresse:0x11) das Bit 7 auf 0 gesetzt
> und die Bits 0-4 auf 1 um einen Prescaler von 16 zu erhalten.

Dein Forscherdrang in allen Ehren, aber ich glaube wir müssen uns 
darüber verständigen welche Ziele wir in welcher Reihenfolge verfolgen 
und konsequent durchhalten. Sonst glaube ich, verzetteln wir uns ganz 
schnell und jeder will grad was anderes ;-) Nicht böse gemeint, ich will 
das hier nur zusammenhalten... aber es ist Dein Thread!

Eigentlich haben wir Schritt 1 doch gut geschafft, das Kommandointerface 
zur Kamera. Nun waren wir am Dateninterface. Hier sollten wir doch 
zunächst überlegen wie und wo wir die erhaltenen Bilddaten 
zwischenspeichern und zur Ansicht an den PC übertragen. Selbst in 
kleinster Auflösung mit 320x200 Bildpunkten und im YUV-Farbmodell 
benötigten wir bei 25 Bildern/s einen Datendurchsatz von ca. 4,6 MB/s. 
Standardmäßig haben wir nur die UART-Übertragung zum PC, also 
Echtzeitvideo dürfte da schonmal ausscheiden.

Das Problem ist, das wir im Arduino nicht genügend Speicher für ein 
ganzes Bild haben. Selbst mit 8-Bit s/w würden wir schon 512kb 
benötigen. Wir müssen also beim einlesen in Echtzeit zum PC streamen. Da 
hab ich noch keine Ahnung wie wir das hinbekommen...

von Michael U. (amiga)


Lesenswert?

Hallo,

@Andreas S. (igel1): das waren am Anfang des threads auch meine 
Gedanken, ich habe mal kurz mit der OV7670 am ESP32 rumgespielt.

Olli Z. schrieb:
> P.S. An alle die ab jetzt erst mitlesen die Info: Wir wollen keine
> fertigen Lösungen sondern unsere eigene erarbeiten. Warum? Um genau auf
> all die vielen kleinen Details zu kommen die es bei einem solchen Design
> zu beachten gilt :-)

Ich finde das sehr gut, findet man kaum noch, so habe ich mit µC mal 
angefangen. Keine Ahnung davon, 1979 einen MC6800 (8Bit), 512Byte Ram, 
einen MC6820 (2x 8Bit I/O) bekommen. Befehlssatz und Beschaltung aus 
einem Motorola-Handbuch im Lesesaal das Staatsbibliothek der DDR 
abgemalt...
Das ging auch für Normalsterbliche ohne Probleme, für Kopien hätte man 
aber Student einer passenden Fachrichtung sein und für Ausleihen einen 
Schrieb der Uni haben müssen. Der Rest war DDR-TTL, 7-Segmantanzeigen 
usw. gab es durchaus.

Ich habe noch ein wenig im Datenblatt der OV7670 gekramt. Der Ansatz 
wäre auch meiner. Mit PCLK auf sinvolle langsame Werte runter. Ich muß 
mir die Timingdiagramme noch genauer anschauen mal rechnen wieviel Daten 
bei sinnvoll kleiner Auflösung und Format eine Zeile sind. letztlich 
entscheide das und der Ram des Mega328 wie man es anpackt. Mit FTDI-USB 
habe ich 500kBaud beim Übertragen genutzt, da spielte es aber keine 
Rolle, wie langen der AVR zum Bereitsrtellen der Daten brauchte, habe 
ich von einem externen Ram per Portzugriffen eingesammelt. War in ASM, 
muß ich mal schauen, da habe ich die Zykluszeiten in die Kommentare 
geschrieben.

Zum Test müßte man wenigstens eine Zeile ins Ram bekommen und dann zum 
PC. Ansonsten kann man vermutlich auf einen Trick von U.Radig mit der 
DV3840 von damals zurückgreifen: eine Zeile lesen und rüberschicken, 
dann die das Auskesen der Kamera neu starten, die Zeilen mitzählen bis 
zur nächsten und die holen usw. Könnte bei der OV7670 auch gehen.
Interrupt würde bei mir höchstens den Anfang  festlegen (VSYNC), 
Einlesen mit hardwarenaher Schleife, alles andere kosten unnütz Zeit 
(INT-Aufruf, Register retten usw.). Der AVR kann in dieser Zeit sowieso 
nicht sinvolles anderes machen, also sollte er es auch nicht.

Olli Z. schrieb:
> Ich muss gestehen das ich da nicht somtief drin bin wie Du. Könntest Du
> mir das Konzept kurz erläutern?

Welcher Timer ist denn dafür genutzt? Bei Timer 1 wäre es MODE2, 
PreScaler auf max. internem Takt, OCR0A auf 1 und der zugehörige 
Zugehörige Ausgang liefert ein 50:50 Rechteck ab.
Letztlich dürfte es egal sein, ist nur ein Hinweis auf die vorhandene 
Funktion im AVR.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Andreas S. schrieb:


> Daher hier nur auf die Schnelle meine Quellen, die mir seinerzeit sehr
> geholfen hatten:

Vielen Dank für die Links, die können wir sicher noch gut brauchen.
Wir versuchen einfach mal unser bestes :)

Olli Z. schrieb:
>Eigentlich haben wir Schritt 1 doch gut geschafft, das Kommandointerface
>zur Kamera. Nun waren wir am Dateninterface. Hier sollten wir doch
>zunächst überlegen wie und wo wir die erhaltenen Bilddaten
>zwischenspeichern und zur Ansicht an den PC übertragen. Selbst in
>kleinster Auflösung mit 320x200 Bildpunkten und im YUV-Farbmodell
>benötigten wir bei 25 Bildern/s einen Datendurchsatz von ca. 4,6 MB/s.
>Standardmäßig haben wir nur die UART-Übertragung zum PC, also
>Echtzeitvideo dürfte da schonmal ausscheiden.
>
>Das Problem ist, das wir im Arduino nicht genügend Speicher für ein
>ganzes Bild haben. Selbst mit 8-Bit s/w würden wir schon 512kb
>benötigen. Wir müssen also beim einlesen in Echtzeit zum PC streamen. Da
>hab ich noch keine Ahnung wie wir das hinbekommen...

Das sehe ich auch so. Das SCCB läuft ja schon mal hervorragend.
Ich finde es gut, dass du mich bremst um uns alle in eine Richtung zu 
lenken. Ich bin mir nicht sicher, ob du in meinem Beitrag gelesen hast, 
dass ich die PCLK-Frequenz senken konnte. mit allen Prescalern komme ich 
dann auf 256KHz von PCLK was uns deutlich mehr Zeit verschafft.

Was jetzt meine Gedanken-Gang wäre:
zunächst einmal mit VSync ein neues Bild detektieren
Dann die Anzahl der Zeilen zählen, bis zum nächsten VSync.
(Das bekomme ich hin mit dem zuverlässigen Wert von 480)

Jetzt wäre der nächste Punkt in einer Zeile die Pixel zu zählen. Den 
Counter würde ich mit jeder fallenden Flanke von HREF wieder 
zurücksetzten. Hier müsste ich ja (im RGB Mode) für jedes Pixel zwei 
Bytes bekommen, sprich zwei PCLK takte. (Ich beziehe mich grade auf 
Figure 11 im Datenblatt) Sprich ich müsste 640 * 2 PCLK = 1280 
PCLK-Counter pro Zeile bekommen. Hier hänge ich gerade, weil mein 
Counter warum auch immer extrem Schwankt zwischen 30 und 60 (Hier 
scheine ich vielleicht noch nicht alles verstanden zu haben.

Mein Weitere Plan würde dann wie folgt aussehen, einfach ein Pixel 
relativ in der Mitte auszulesen und die Farbdaten in einer Variable 
festzuhalten. Dann zu schauen, ob die Farbe passt, oder erstmal ob 
Veränderungen auftreten, wenn ich bspw. eine weiße Fläche oder eine 
schwarze vor der Linse habe.

Erst wenn das Funktioniert hätte ich mir Gedanken darüber gemacht, wie 
ich ganze Bilder zusammensetzte oder Speicher oder übertrage.

Ich lasse mich aber auch gerne eines Besseren belehren :)

@Michael 1979 war mein Vater 17 und ich noch längst nicht in Planung :D
Die Idee mit dem Zeilenweisen Aufbau finde ich gar nicht mal so übel, 
wenn wir von einer statischen Aufnahme reden.

lg. David

von Olli Z. (z80freak)


Lesenswert?

Michael U. schrieb:
> Ich habe noch ein wenig im Datenblatt der OV7670 gekramt. Der Ansatz
> wäre auch meiner. Mit PCLK auf sinvolle langsame Werte runter.

100%ige Zustimmung. Evtl. kommen wir da dann an den Punkt wo es 
sinnvoller ist den OV7670+FIFO zu nutzen... Da gäbs vielleicht nur noch 
die Option eine SD-Card als Zwischenspeicher zu verwenden. Dafür 
bräuchten wir aber die SPI-Pins. Mit einem Puffer könnte man ganz 
gemütlich nach dem "Schnappschuß" übermitteln.
Dieses Problem müssten aber auch die STM32 haben, denn ein, zwei 
Megabyte RAM haben die auch nicht ;-)

> entscheide das und der Ram des Mega328 wie man es anpackt. Mit FTDI-USB
> habe ich 500kBaud beim Übertragen genutzt, da spielte es aber keine

Ich verwende nen Nano-Clone und der hat leider keinen Original FTDI 
drin. Daher könnte es sein das ich auf die 115kbaud beschränkt bin. 
Damit wäre ich bau lausigen 14 kbyte/s. Das ist noch ziehmlich weit weg 
von dem was wir bräuchten fürchte ich.

> Zum Test müßte man wenigstens eine Zeile ins Ram bekommen und dann zum
Damit fangen wir doch in jedem Fall an, oder? Auf VSYNC warten und die 
ersten 320 (oder 640) Pixel lesen und übertragen.

> PC. Ansonsten kann man vermutlich auf einen Trick von U.Radig mit der
> DV3840 von damals zurückgreifen: eine Zeile lesen und rüberschicken,
> dann die das Auskesen der Kamera neu starten, die Zeilen mitzählen bis
> zur nächsten und die holen usw. Könnte bei der OV7670 auch gehen.
Eine coole Idee :-) An sowas ähnliches hab ich auch schon gedacht, nur 
mit Halbbildern, also nur jede 2. Zeile übermitteln oder so. Wenn man 
immer ganze Zeilen überträgt spielt auch das Subsampling keine Rolle.

In dieser Richtung könnte man auch horizontal "sparen", also auf Pixel 
innerhalb einer Zeile verzichten. Zumindest im YUV-Farbraum sollte man 
dann immer zwei aufeinanderfolgende Pixel erhalten, also 2 übertragen, 2 
auslassen. Am Anfang wäre RGB zwar einfacher im Bytehandling, aber ich 
würde stand jetzt eigentlich beim YUV 4:2:2 bleiben wollen.

> Interrupt würde bei mir höchstens den Anfang  festlegen (VSYNC),
Der kommt ja so selten, da sollte man doch drauf warten können, nicht? 
Wir können ja immer nur dann ein Bild einlesen wenn wir dazu bereit 
sind. In dieser Phase würde ich einfach aufs nächste VSYNC warten und 
los gehts...

> Einlesen mit hardwarenaher Schleife, alles andere kosten unnütz Zeit
> (INT-Aufruf, Register retten usw.). Der AVR kann in dieser Zeit sowieso
> nicht sinvolles anderes machen, also sollte er es auch nicht.
Heißt das, wir sind einer Meinung?

> Olli Z. schrieb:
>> Ich muss gestehen das ich da nicht somtief drin bin wie Du. Könntest Du
>> mir das Konzept kurz erläutern?
> Welcher Timer ist denn dafür genutzt? Bei Timer 1 wäre es MODE2,
> PreScaler auf max. internem Takt, OCR0A auf 1 und der zugehörige
> Zugehörige Ausgang liefert ein 50:50 Rechteck ab.

Verstehe nur Berlin Hauptbahnhof ;-) Daher meine war meine Bitte: Wie 
hängt das alles zusammen? Timer, Modes, Pins, ... ich blicks noch nicht.

Gruß,

Olli

P.S.: Ich finde unsere aktuelle Konstellation (David und Du) wirklich 
klasse! Vor allem weil wir uns, etwas untypisch für dieses Forum, weder 
anmaulen noch sonst irgendwie im Ton vergreifen. Zudem können wir uns 
immer wieder auf einen Nenner bringen. Ich bin echt begeistert und es 
macht richtig Spaß!!! :-)

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Zum CTC Mode:
Atmega328P Datenblatt Seite 100. (Der Anfangsausschnitt im Anhang)

Im Prinzip wird damit das gleiche erreicht wie mit dem PWM Signal von 
dir.
Nur muss man einfach weniger Einstellungen treffen.
Im Prinzip gibst du einfach nur den Timer Wert vor bis zu dem gezählt 
werden soll. Wird der erreicht, wird ein Pin (OC0A beim Atmega328P ist 
das PD6)getoggelt und der Timer zurückgesetzt.
Somit kannst du relativ einfach ein Rechtecksignal erzeugen.

Was sagst du zu meiner Vorgehensweise?

lg.
David

PS: wie kann ich ein falsches Bildformat wieder löschen?

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

David D. schrieb:
> Andreas S. schrieb:
Ich lese und beantworte immer einen Post nach dem anderen. Manches 
überschneidet sich... auch ein Grund warum ich versuche möglichst immer 
nur an einem Punkt gleichzeit zu "arbeiten".

>> Daher hier nur auf die Schnelle meine Quellen, die mir seinerzeit sehr
>> geholfen hatten:
> Vielen Dank für die Links, die können wir sicher noch gut brauchen.
> Wir versuchen einfach mal unser bestes :)
Ja, sicher sehr hilfreich. Ich denke auch das wir einiges von unseren 
eigenen Erkenntnissen im Dokuwiki hinterlegen sollten/werden, auch für 
uns selbst. Hier nochmal mein Vorschlag an Dich und Michael mir mal ne 
PN mit eurer Mail zukommen zu lassen, dann lege ich für Euch einen 
Account an und ihr könnt dort mit editieren.

> Ich finde es gut, dass du mich bremst um uns alle in eine Richtung zu
> lenken. Ich bin mir nicht sicher, ob du in meinem Beitrag gelesen hast,
Danke für die "Blumen", ich verweise nur auf den letzten Absatz meines 
vorherigen Posts :-)

> dass ich die PCLK-Frequenz senken konnte. mit allen Prescalern komme ich
> dann auf 256KHz von PCLK was uns deutlich mehr Zeit verschafft.
Im Prinzip arbeiten wir ja auch an dieser Stelle. Momentan haben wir 
einen Strauß von Möglichkeiten. PCLK wäre einer. Ich bin mir mit der 
aktuellen Erfahrung nur nicht sicher ob das verringern der PCLK so ganz 
ohne Nebenwirkungen ist. Ich hätte gedacht wenn wir versuchen die 
Auflösung, Bildfrequenz, Skalierung (und was weiß ich was die Kamera 
noch alles kann) zu verringern, das sich die PCLK automatisch 
verkleinert. Wollen wir in diese Richtung mal schauen?

> Was jetzt meine Gedanken-Gang wäre:
> zunächst einmal mit VSync ein neues Bild detektieren
> Dann die Anzahl der Zeilen zählen, bis zum nächsten VSync.
> (Das bekomme ich hin mit dem zuverlässigen Wert von 480)

Ich hätte da einen Vorschlag wie wir mitbekommen können ob der Arduino 
schon überlastet ist: Wir arbeiten zeilenbasierend, sprich ein HSYNC 
löst via INT die Verarbeitung einer Bildzeile aus. Darin enthalten ist 
das auslesen der Pixelwerte, synchron zu PCLK, ggf. der Verarbeitung 
dieser (Farbraumumwandlung, Skipping, oder was weiss ich...) bis hin zu 
Übermittlung an den PC. Wenn diese Schleife komplett durchläuft ohne das 
vorher schon wieder ein HSYNC-INT ausgelöst wird, dann ist alles gut und 
wir könnten die Werte "hochdrehen" oder hätten einfach noch Luft für 
Bildbearbeitungsfunktionen. Sollten wir jedoch ein Problem erkennen, 
könnte man das Programm anhalten und eine LED blinken oder leuchten 
lassen.

> zurücksetzten. Hier müsste ich ja (im RGB Mode) für jedes Pixel zwei
> Bytes bekommen, sprich zwei PCLK takte. (Ich beziehe mich grade auf
Bei RGB sollten es 3 Byte sein, ein 8-Bit Wert für Rot, einer für Grün 
und einer Blau. 2 Byte sind es im YUV-Verfahren.

> Figure 11 im Datenblatt) Sprich ich müsste 640 * 2 PCLK = 1280
> PCLK-Counter pro Zeile bekommen. Hier hänge ich gerade, weil mein
> Counter warum auch immer extrem Schwankt zwischen 30 und 60 (Hier
> scheine ich vielleicht noch nicht alles verstanden zu haben.
Wie gesagt, ich würde noch etwas anders rangehen als sich auf das reine 
Pixelzählen zu beschränken. Es geht ja darum ein Bild zu übertragen. 
Also erstmal überlegen was man alles machen kann um die Datenflut vom 
OV-Chip zum Arduino so weit wie möglich einzudämmen.

Wir sollten vielleicht damit anfangen das Bild nur S/W zu übertragen. 
Das ist bei Daten im YUV Farbraum recht simpel, man benötigt einfach nur 
das Y-Byte (Luminanz). Das verringert die zu übertragenden Daten 
erheblich.

> Ich lasse mich aber auch gerne eines Besseren belehren :)
Deine Ideen sind nicht verkehrt, halt alles nur eine Frage worauf wir 
uns einigen. Wie siehst Du das Michael? Ich schlage folgendes vor:

1. Möglichkeiten zur Verringerung der Auflösung/Farbe/PCLK finden 
(Datenblatt und Links wühlen)
2. Auf VSYNC warten, Interrupts aktivieren und beim nächsten HSYNC-INT 
versuchen sämtliche Daten vom Chip einzulesen.
3. Kollisionserkennung implementieren (kommt während eines INT ein 
weiterer)
4. Datenübertragung zum PC (hier brauchst irgend ein "Frontend" auf dem 
PC welches die Daten über Serial entgegen nimmt und in eine (Bild)daten 
schreiben kann. Entweder was fertiges, oder ein PHP oder Python Skript?

> @Michael 1979 war mein Vater 17 und ich noch längst nicht in Planung :D
Ups, dann bin ich ja quasi der "Opa" hier unter Euch Jungfüchsen ;-))

Olli

von David D. (saturi)


Lesenswert?

Olli Z. schrieb:

> Bei RGB sollten es 3 Byte sein, ein 8-Bit Wert für Rot, einer für Grün
> und einer Blau. 2 Byte sind es im YUV-Verfahren.
Ich meinte auch RGB555

> Wir sollten vielleicht damit anfangen das Bild nur S/W zu übertragen.
> Das ist bei Daten im YUV Farbraum recht simpel, man benötigt einfach nur
> das Y-Byte (Luminanz). Das verringert die zu übertragenden Daten
> erheblich.
Das klingt gut. Mit dem Format kenne ich mich leider überhaupt nicht aus 
und habe es deshalb erstmal gekonnt ignoriert. Ich werde diese 
Wissenslücke dann jetzt erstmal füllen.

> 1. Möglichkeiten zur Verringerung der Auflösung/Farbe/PCLK finden
> (Datenblatt und Links wühlen)
Ich weiß nicht ob es uns was bringt die Auflösung runter zu schrauben. 
Das hilft uns vielleicht bei der Übertragung zum PC aber ich denke 
nicht, dass sich das auf die PCLK Frequenz auswirkt sondern einfach die 
Frames/sec hochgehen werden.

> 2. Auf VSYNC warten, Interrupts aktivieren und beim nächsten HSYNC-INT
> versuchen sämtliche Daten vom Chip einzulesen.
Jap können wir versuchen
> 3. Kollisionserkennung implementieren (kommt während eines INT ein
> weiterer)

> 4. Datenübertragung zum PC (hier brauchst irgend ein "Frontend" auf dem
> PC welches die Daten über Serial entgegen nimmt und in eine (Bild)daten
> schreiben kann. Entweder was fertiges, oder ein PHP oder Python Skript?
Ich habe am Samstag eine sehr lange Autofahrt vor mir, da werde ich mal 
im Visual Studio was mit c# rumbasteln und uns ein kleines Programmchen 
entwerfen, dass das vielleicht kann. (eventuell schaff ich es ja :) )

>> @Michael 1979 war mein Vater 17 und ich noch längst nicht in Planung :D
> Ups, dann bin ich ja quasi der "Opa" hier unter Euch Jungfüchsen ;-))
Ist doch Toll, dass wir so ein bunter Haufen sind und uns ergänzen 
können.

von Andreas S. (igel1)


Lesenswert?

Olli Z. schrieb:
> P.S.: Ich finde unsere aktuelle Konstellation (David und Du) wirklich
> klasse! Vor allem weil wir uns, etwas untypisch für dieses Forum, weder
> anmaulen noch sonst irgendwie im Ton vergreifen. Zudem können wir uns
> immer wieder auf einen Nenner bringen. Ich bin echt begeistert und es
> macht richtig Spaß!!! :-)

Das kann ich nur unterstreichen. Als Gelegenheits-Mitleser möchte ich 
Euch allein dafür ein Kompliment machen: es ist sehr angenehm, diesen 
Thread zu lesen. Hier gibt's ein Ringen um die Sache und einen 
respektvollen Umgang miteinander - so macht Elektronik (und überhaupt 
das Leben im Ganzen) Spaß. Weiter so!

Ich würde ja soooo gerne mitmachen, aber ich habe vermutlich erst in 
einigen Wochen wieder Zeit fürs Hobby. Ich kann Euch also nur ein paar 
Tipps aus meinem wochenlangen Kampf mit dem OV7670 geben - so lange 
hat's gebraucht, bis es halbwegs an meinem STM32 lief (dummerweise habe 
ich auch schon vieles wieder vergessen).

Tipp Nr.1: alle Gedanken, die Ihr Euch gerade macht (vom Interrupt, bis 
zu den anzusprechenden SCCB-Adressen), hatten auch andere, die sich mit 
dem OV7670 beschäftigt haben. Und diese anderen haben ebenfalls Wochen 
und Monate investiert.

Ich habe irgendwann für mich beschlossen, dass ich meinen Stolz, alles 
selber herauszufinden, über Bord werfe und von den Erfahrungen dieser 
anderen profitieren will - zumindest um die Doku-Defizite damit 
aufzufüllen. Daher mein Tipp: lest viele Threads und Foren-Beiträge von 
Leuten, die die Tortour schon hinter sich haben und spart Euch Eure 
Energie für's Wesentliche auf. Fehlende Hersteller-Doku per 
Try-and-Error aufzufüllen wird Euch sonst zermahlen (so meine Weissagung 
- basierend auf meinen Erfahrungen)

> 100%ige Zustimmung. Evtl. kommen wir da dann an den Punkt wo es
> sinnvoller ist den OV7670+FIFO zu nutzen...

Ja - viele andere haben sich das ebenfalls überlegt.
Meiner Meinung nach macht nur die OV7670+FIFO-Variante für einen Aufbau 
mit AVR Sinn. Alles andere überfordert den AVR oder es ist schlicht und 
einfach heillose Quälerei.

> Da gäbs vielleicht nur noch
> die Option eine SD-Card als Zwischenspeicher zu verwenden. Dafür
> bräuchten wir aber die SPI-Pins. Mit einem Puffer könnte man ganz
> gemütlich nach dem "Schnappschuß" übermitteln.
> Dieses Problem müssten aber auch die STM32 haben, denn ein, zwei
> Megabyte RAM haben die auch nicht ;-)

Richtig, daher bin ich in meinem aktuellen Projektstand bislang auch 
nicht über QVGA (320x240 Punkte) hinausgekommen.

Allerdings kann so ein STM32 trotz ca. 512k RAM auch größere Bilder 
speichern. Das hatte ich mir so überlegt:

- ich lassen den STM32 die Zeilen per DMA (bzw. DCMI) in einen 
Ringbuffer einlesen

- während also vorne eingelesen wird (DMA bzw. DCMI belasten ja die CPU 
nicht), kann ich hinten im Ringbuffer auslesen und jeweils N-Zeilen 
jpeg-kodieren. Sobald diese N-Zeilen jpeg-kodiert sind (der STM32F4 hat 
dafür auch einen DSP an Bord), ist der entsprechende Teil im Ringbuffer 
wieder frei und kann überschrieben werden.

Damit passen dann auch (komprimierte) Bilder mit der vollen 
OV7670-Auflösung in den STM32-Speicher. Irgendeiner im Internet hatte 
das wohl auch schon einmal hinbekommen.

Aber allein schon bis zum aktuellen Projektstand musste ich erst einmal 
PWM, DMA, DCMI, YUV, YCbCr & Co verstehen und beherrschen. Hat ein 
bißchen gedauert.

Der nächste Schritt wird dann JPEG und DSP sein - man braucht dafür 
einen wirklich langen Atem (insbesondere wenn's nur Hobby ist) - ich 
drücke Euch daher insbesondere die Daumen, dass Euch zwischendurch nicht 
die Puste ausgeht.

Weiterhin noch viel Spaß und Erfolg!!

Viele Grüße

Igel1


PS:

- Um überhaupt die eingelesenen Bilder testen/sehen zu können, habe
  ich ein ILI9346-Display verwendet: kostet ca. 5 € und kann per
  SPI (und auch I2C ??) vom MC angesteuert werden.
  Ist super-einfach und unkompliziert im Umgang.
  Gängige Module haben sogar auch eine SD-Card-Slot auf der Platine.
  Vielleicht wäre das auch etwas für Euch.

- Per UART an den PC senden, geht natürlich auch, ist aber auf die
  Dauer zu nervig (weil zu langsam). Insbesondere, wenn's ans
  Register-Austesten geht. Da will man nicht jedesmal 1 Minuten warten,
  bevor man das Ergebnis einer Register-Veränderung auf dem Schirm 
sieht.

- Letzter Tipp: lest Euch unbedingt meine ersten 2 Links aus meinem
  letzten Posting durch - diese Seitn sind die "Bibel" für alle OV7670-
  Einsteiger.

von David D. (saturi)


Lesenswert?

Noch eine Sache, da unser Projekt offensichtlich etwas umfangreicher und 
komplexer wird.

Habt ihr beiden schon Erfahrungen mit GitHub gemacht? Ich nur am rande. 
Habe mir grade einmal die vielseitigen Möglichkeiten und Tools 
angeschaut, die einem da an die Hand gegeben werden.

Ich denke, da könnten wir unser Projekt besser mit strukturieren, 
Aufgaben/Ideen festhalten und diskutieren als hier, wo quasi jeder Post 
untereinander kommt.

zusätzlich (bzw. ursprünglich) kann man dort seinen Programm-Code 
austauschen, zusammen dran arbeiten und vorschläge unterbreiten.

Auf den ersten Blick wirkt das ganze sehr erschlagend und wenn man der 
englischen Sprache nicht ganz so mächtig ist auch erstmal etwas 
unverständlich. Aber ich denke, dass wir das ganze damit viel 
strukturierter angehen können. Da gäbe es auch eine Wiki-Funktion, wobei 
wir da auch bei deinem bleiben können. Du nutzt deins ja noch darüber 
Hinaus für andere Projekte.

Schaut es euch mal an uns sagt mir eure Meinung.
Falls ihr begeistert seid, würde ich mal versuchen ein Projekt 
aufzusetzen und euch einzuladen.

lg.

David

von David D. (saturi)


Lesenswert?

Andreas S. schrieb:
> Ich würde ja soooo gerne mitmachen, aber ich habe vermutlich erst in
> einigen Wochen wieder Zeit fürs Hobby. Ich kann Euch also nur ein paar
> Tipps aus meinem wochenlangen Kampf mit dem OV7670 geben - so lange
> hat's gebraucht, bis es halbwegs an meinem STM32 lief (dummerweise habe
> ich auch schon vieles wieder vergessen).

Ich denke den langen Atem werden wir brauchen :D aber ich bin 
zuversichtlich. Und werden auch noch einige Wochen brauchen :D
Also du bist dann gerne Willkommen, sobald du die Zeit hast ;-)

  Ich habe irgendwann für mich beschlossen, dass ich meinen Stolz, alles
> selber herauszufinden, über Bord werfe und von den Erfahrungen dieser
> anderen profitieren will - zumindest um die Doku-Defizite damit
> aufzufüllen. Daher mein Tipp: lest viele Threads und Foren-Beiträge von
> Leuten, die die Tortour schon hinter sich haben und spart Euch Eure
> Energie für's Wesentliche auf. Fehlende Hersteller-Doku per
> Try-and-Error aufzufüllen wird Euch sonst zermahlen (so meine Weissagung
> - basierend auf meinen Erfahrungen)

Das glaube ich dir und ich bin mir auch sicher, dass wir das von anderen 
gesammelte Wissen nutzen werden. Das wir alles selber machen wollen 
bezieht sich darauf, dass wir alles verstehen wollen und keine fertigen 
Code-Schnipsel verwenden möchten. Das heißt nicht, dass wir die 
Scheuklappen aufsetzten und die Erfahrungen Anderer völlig ignorieren :)

Danke für deine Tipps :)

lg. David

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
>>> @Michael 1979 war mein Vater 17 und ich noch längst nicht in Planung :D
>> Ups, dann bin ich ja quasi der "Opa" hier unter Euch Jungfüchsen ;-))
> Ist doch Toll, dass wir so ein bunter Haufen sind und uns ergänzen
> können.

hmmm.. das bezog sich von Daniel auf meinen Kommentar zu meinen 
µC-Anfängen 1979...
Ich will nicht zuviel abschweifen:
Als Rentner habe ich jetzt die Zeit hier einfach mal "mitzuspielen".
Meine ersten Videoexperimente war ein "Videograbber" am C64-Userport.
3 Komparatoren für 4 Graustufen und TTL drumrum. Auflösung 160x200, die 
war dem C64 Multicolormode geschuldet. Kamera eine TFK500, ohnhin nur 
s/w.
Das ging natürlich nur mit einem Standbild, also wie ganz ganz früher: 
Start drücken und ca. 3 Minuten nichts bewegen...
Leider habe ich kein so erzeugtes Bild von damals mehr. Meine Kollegen 
meinten erkannten den Kopf auf dem Bild zumindest sofort. ;-)

Zum Thema: üblicherweise können diese Cam-ICs einen Snapshotmode, wo sie 
das Bild im internen Ram lassen und man es sooft wieder abholen kann wie 
man will. Man könnte sonst nie ein sauberes Bild mit anderer als der 
Sensorrate auslesen. Die Rate hängt aber direkt vom Sensor-IC, 
Lichtempfindlichkeit, interne Umladezeiten usw. usw. ab.
Man hat ja schließlich weder Blende noch Verschluß dran.
Muß ich mal ins Datenblatt der OB7660 schauen.

Ich hör erstmal auf, meine alte DC3840 am ESP32 redet inzwischen mit mir 
und schickt mir einen kaputten JFIF-Header???
Die Dc3840 hat vermutlich den Chip der OV7660 drauf, es hängt eben nur 
ein OV528 hinten dran als Serial-Bridge.
Bewegte Bilder wid es mit einem Mega328 nicht geben, Snapshots in 
640x480 in Farbe alle paar Sekunden sind mit Sicherheit machbar.

3Byte x 320 Pixel wären 960Byte Ram, bei 160 wären es 460 Byte.
Also mit 160x120 zeilenweise einlesen und zum PC schicken.
Sind dann 120 Durchläufe für ein Bild.

Zum Arduino-Nano: der CH340 kann auch 921kBit. Ob er 500 oder 460kBit 
kann hängt vom Treiber ab. Gerade mal mein Win7 gefraht: der CP2102 und 
der CH340 bieten maximal 128kBit an, der FTDI 921kBit. Das ist aber nur 
der Windows-Treiber. Der CH340 (am ESP8266) kann auch 921kBaud.
Nutzt aber alles nur bedingt, der Mega328 mit 16MHz Takt kann zwar 
250/500/1000kBaud mit 0% Fehler erzeugen, verkürzt letztlich 
Übertragungszeit zum PC, nur beleiben es mangels Ram im Mega328 trotzdem 
lauter kleine Häppchen mit Pausen dazwischen zum Lesen der Kamera.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Guten Abend,
ich probiere wieder etwas rum, um unserem Ziel einen Schritt näher zu 
kommen.

ich möchte euch auf meinen bisherigen Stand bringen:
Ich versuche das zu realisieren, was wir uns als erstes Teilziel 
festgelegt haben:

Das aufnehmen einer Zeile.

dazu habe ich zunächst mehrere Einstellungen in den Registern getroffen, 
die zwar Wirkung zeigen, ich die gänzlichen Auswirkungen noch nicht 
absehen kann:

CLKRC-Register: 0x0F
COM7-Register: 0x08
COM3: 0x08
COM14: 0x1C
COM10: 0x20
SCALING_PCLK: 0x04

Dabei sei gesagt, dass ich die Register erst auslese und nur die 
beabsichtigten Bytes verändere, damit bspw. Reserved Bits nicht 
überschrieben werden. Daher kann der tatsächliche Registerwert von 
meinen abweichen.

Mit den Einstellungen ergibt sich vollgendes Bild:
- PCLK ist stark gedrosselt, auf ca. 50kHz
- PCLK alterniert nur während HREF-High Pegel aktiv (ansonsten wird PCLK 
auf High gehalten)
- Es sollte das QCIF Format eingestellt sein mit 160x120 px (durch 
ebenfalls aktiviertes Scaling)
- Das YUV Format sollte aktiv sein.

Was ich vorhabe:
1. die positive Flanke von PCLK erkennen (mittels Interrupt)
2. Dabei die Daten von D0-D8 in ein Byte schreiben
3. Das Byte (zu Testzwecken) in einem Array ablegen
4. so viele wie mögliche Bytes erfassen

Wenn ich mit dem Oszilloskop messe, bekomme ich das Verhalten Von PCLK 
und HREF wie vorgestellt hin.
Der Interrupt löst aber nur unregelmäßig aus (obwohl die Flanke von PCLK 
auf dem Oszi sichtbar ist). Meistens immer zu V-Sync Signalen, sprich 
wenn HREF und somit PCLK länger statisch sind.

Meine Interrupt Routine ist nicht überladen:
1
 ISR(INT0_vect){
2
  PORTB |= 0x20;
3
  interruptFlag=true;
4
  i++;
5
  _delay_ms(1); //eingeführt um ein "übersehen" vom Oszi auszuschließen
6
  PORTB&= ~(0x20);
7
}

PortB 0x20 ist Pin 13 und da greife ich mir das Signal ab, wenn der 
Interrupt ausgeführt wird

Da ich nun wirklich schon mehrere Stunden an diesem Problem sitze, 
drängt sich mir die Frage auf, wie schnell denn der externe Interrupt 
eigentlich arbeiten kann, und ob es dort ebenfalls max. Frequenzen gibt. 
Leider konnte ich nichts finden. Habt ihr da schon Erfahrungen?

lg. David

von Andreas S. (igel1)


Lesenswert?

@David:

bzgl. Interrupt-Routinen, gibt es viele Seiten, die sich mit der 
Latenz-Zeit beschäftigen. Evtl. ist die ja schon hinreichend:

Beitrag "Interrupt latency"

Meine AVR-Zeiten liegen leider schon ein paar Jährchen zurück, aber ich 
habe vielleicht doch einen sehr praktischen Tipp:

Natürlich kann man die Dauer der ISR-Routine (inkl. dem Overhead zum 
Aufruf der ISR-Routine) sauber auf dem Papier ausrechnen. Das bedeutet 
aber immer viel Lesen und Nachschlagen.

Ich habe damals oftmals einfach den Debugger genutzt:

Wenn Du das Programm im Debugger laufen läßt, so kannst Du exakt 
nachverfolgen, wieviele Zyklen das Einspringen in die ISR und die 
Abarbeitung Deiner ISR benötigt.

Und ja, es gibt eine bestimmte Zeit, die ein Pegel anliegen muß, damit 
die ISR ausgelöst wird - steht irgendwo im Datenblatt.

Viele Grüße

Igel1

von Olli Z. (z80freak)


Lesenswert?

Hi David, offensichtlich müssen wir uns noch zwei grundlegende Techniken 
im Zusammenhang mit dem Arduino (Atmega) aneignen: Timer (zur 
Clock-Erzeugung) und Interrupts. Darauf basieren die wesentlichen 
Komponenten unserer Umsetzung.

Deine Ermittlung mit PCLK finde ich bemerkenswert, denn laut Datenblatt 
läge der PCLK immer an, sobald XCLK bereitgestellt wird. Aber vielleicht 
sind das eben genau die Dinge von denen Andreas gesprochen hat...

Gelesen hab ich über Timer und Interrupts schon so einiges, angewendet 
hab ich die auch schonmal, aber so ein richtig tiefgehendes Verständnis 
habe ich auch nicht dafür. Gute Voraussetzungen um hier mal "ganz unten" 
zu starten :-)

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:

> Wenn ich mit dem Oszilloskop messe, bekomme ich das Verhalten Von PCLK
> und HREF wie vorgestellt hin.
> Der Interrupt löst aber nur unregelmäßig aus (obwohl die Flanke von PCLK
> auf dem Oszi sichtbar ist). Meistens immer zu V-Sync Signalen, sprich
> wenn HREF und somit PCLK länger statisch sind.
>
> Meine Interrupt Routine ist nicht überladen:
>
1
 ISR(INT0_vect){
2
>   PORTB |= 0x20;
3
>   interruptFlag=true;
4
>   i++;
5
>   _delay_ms(1); //eingeführt um ein "übersehen" vom Oszi auszuschließen
6
>   PORTB&= ~(0x20);
7
> }
8
>
>
> PortB 0x20 ist Pin 13 und da greife ich mir das Signal ab, wenn der
> Interrupt ausgeführt wird
>
> Da ich nun wirklich schon mehrere Stunden an diesem Problem sitze,
> drängt sich mir die Frage auf, wie schnell denn der externe Interrupt
> eigentlich arbeiten kann, und ob es dort ebenfalls max. Frequenzen gibt.
> Leider konnte ich nichts finden. Habt ihr da schon Erfahrungen?

Erfahrung ja, aber leider liegt meine Atmega-Zeit schon etwas zurück, 
daher bitte meine Hinweise mit Vorsicht genießen:

1.) Ein Sprung in die ISR benötigt minimal 4 Takte:
    s. Kap. 11.7.1 im Datenblatt:
    http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf

    ABER: das kannst Du nur erreichen, wenn Du in Assembler 
programmierst
    und exakt weißt, was Du tust.
    Dein C-Compiler wird noch jede Menge Zusatz-Befehle einfügen (vor
    allem Register-Push Operationen).
    Auch benötigt der Rücksprung aus der ISR nochmals 4 Takte sowie
    vermutlich jede Menge Register-Pop-Operationen.

2.) Bei 50kHz PCLK-Frequenz ist eine Periode 20us lang, was immerhin
    320 Takten bei 16MHz Prozessortakt entspricht. Müßte eigentlich
    ausreichen, um eine ISR sauber auszuführen.

3.) Hier meine Vermutung, was bei Dir passiert:

    - Du hüpfst mit der ersten PCLK-Flanke in die ISR und schaltest
      dort Deinen Pin13 an.

    - Per "interruptFlag=true;" enables Du dann vermutlich Dein
      globales Interrupt-Flag, so dass weitere Interrupts akzeptiert
      werden - auch während Du noch in der ISR weilst.
      Du brauchst das "interruptFlag=true;" vermutlich deshalb,
      weil Deine _delay_ms(1) sonst nicht funktioniert.

    - Dann rufst Du die Delay-Routine auf.  Diese Delay-Routine wird
      vermutlich Ihrerseits ebenfalls über Interrupts abgewickelt
      werden. Je nach Implementierung wird sie jedoch niemals zu
      Ende kommen, weil ja bereits nach 20us die nächste PCLK-Flanke
      kommt, die wiederum einen Einsprung in Deine ISR bewirkt.

    - Bevor die Video-Zeile zu Ende ist (bei Deinem QCIF also nach
      160 x 20us = 3200us) plus 1ms Delay wird Dein Pin 13 also nicht
      abgeschaltet werden. Außerdem wurde die ISR zu diesem Zeitpunkt
      160x rekursiv aufgerufen - der Rücksprung wird entsprechend
      lange dauern ...

Daher mein Tipp:

    - Schmeiss unbedingt die Delay-Funktion aus Deiner ISR raus.
      Dein Oszi wird ja wohl Signale an Pin13, die > 0,1us lang
      sind, locker darstellen können.
    - Dann triggerst Du auf dem ersten Oszi-Kanal auf PCLK und
      schaust Dir auf dem 2. Oszi-Kanal Pin13 an. So solltest Du
      den Delay beim Aufruf der ISR schön sehen können.

Viele Grüße

Igel1

von Michael U. (amiga)


Angehängte Dateien:

Lesenswert?

Hallo,

PCLK auf 50kHz, da kommt alle 20µs ein Clock-Impuls.
Bei 17MHz ist die Zykluszeit des AVR 62,5ns, also maximal 320 Takte für 
ISR-Aufruf, Abarbeitung und wueder raus. Dann ist aber keinerlei Zeit 
mehr, außerhalb was zu machen. Der AVR führt nach verlassen einer ISR 
genau einen ASM-Befehl aus wenn schon wieder irgendein Interrupt 
ansteht.

 ISR(INT0_vect){
>   PORTB |= 0x20;
>   interruptFlag=true;
>   i++;
>   _delay_ms(1); //eingeführt um ein "übersehen" vom Oszi auszuschließen
>   PORTB&= ~(0x20);
> }
>
1ms Delay geht ja mal garnicht, da sind 50 PCLK vergangen...

Man könnte sich jetzt das ASM-Listing anschauen, das der Compiler 
erzeugt.
Wenn die Portzugriffe richtig optimiert (kann der GCC eigentlich), sind 
das jeweils 3 oder 4 Takte. Die Umsetzung von interruptFlag=true; und 
i++; wird wesentlich ungünster sein, weil der GCC intern C-typisch mit 
16Bit-Werten rechnet und das kostet einige Registerschiereien. Dazu 
kommt die recht umfangreiche Register-Retterei beim ISR-Aufruf und die 
Wiederherstellung beim Verlassen in C.
Ich hoffe, ich habe jetzt auf die Schnelle nicht falsch gerechnet...
Ich hatte oben schon irgendwo angedeutet, das ich den Weg nicht für 
machbar halte. Bei VSync in die ISR und dann per Busy-Loop auf H-Sync 
warten. Dann PCLK direkt abfragen und bei jeder Flanke die Daten 
einlesen und wegspeichern. Das in der ISR der AVR nur mit dem Kram 
beschäftigt ist, ist hier nur von Vorteil, außerdem ist es nur für genau 
ein Bild (oder beim Test erstmal eine Zeile). Wie man dann mit den Daten 
umgeht ist sowieso noch zu klären...

PS: meine alte DC3840 redet inzwischen am ESP32 mit mir, prinzipiell 
auch am ESP8266. Diese Camera hat vermutlich sogar den gleichen 
Bildsensor, man kommt wegen ser seriellen Bridge und deren Firmware 
allerdings nicht an dessen Register ran. Leider hat sie im Gegensatz zur 
OV7670 eine miserable Optik.
Diese Kamera lief irgendwann um 2008 schonmal mit einem Webserver von 
U.Radig auf einem Mega32 mit 14,xxx MHz Takt.
Ich habe sie mal schnell mit einer USB-Verlängerung auf den Balkon 
geklemmt, so als Anreiz. ;-)

Gruß aus Berlin
Michaeö

: Bearbeitet durch User
von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb im Beitrag #53744
> Hallo,
>
> PCLK auf 50kHz, da kommt alle 20µs ein Clock-Impuls.
> Bei 17MHz ist die Zykluszeit des AVR 62,5ns, also maximal 320 Takte für
> ISR-Aufruf, Abarbeitung und wueder raus. Dann ist aber keinerlei Zeit
> mehr, außerhalb was zu machen.

Im großen und ganzen stimme ich Michael ja zu, nicht aber beim oben 
Zitierten. (Statt 17MHz meinte Michael sicherlich 16MHz - aber das war 
bestimmt nur ein kleiner Typo und ist nicht Gegenstand meiner Kritik.)

Der Punkt, um den es geht, ist folgender: ich bin der Meinung, dass der 
Prozessor bei 320 Takten zwischen zwei PCLK-Flanken nach der Abarbeitung 
einer kurzen ISR noch >200 Takte Zeit für andere Dinge haben sollte.

David wird das hoffentlich in Kürze bestätigen, wenn er mit angepaßtem 
ISR-Code hier neue Ergebnisse posten wird.

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Der Punkt, um den es geht, ist folgender: ich bin der Meinung, dass der
> Prozessor bei 320 Takten zwischen zwei PCLK-Flanken nach der Abarbeitung
> einer kurzen ISR noch >200 Takte Zeit für andere Dinge haben sollte.

ist gut möglich, habe ich nicht weiter ins Detail gerechnet.
Ich wollte auch mehr darauf hinaus, daß es für das konrete Projekt nicht 
wirklich etwas zwischen dem Einlesen von 2 Pixeln zu tun gibt.
Wenn man also eine Zeile komplett in einer HSync-ISR einliest und 
zwischenspeichert, erspart man sich mögliche Timingprobleme mit einer 
PCLK-ISR erstmal ganz.

Man muß zum Üben und Testen nicht alle Probleme gleichzeitig lösen 
wollen. ;)

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

... ich hoffe, der Thread schläft nicht ein, bin doch zu neugierig,
wie's weitergeht.

Habe mir die HW-Aussstattung so eines Atmega328p vorhin nochmals
genauer angeschaut ... puhhh, ganz schön knapp ...

Das war für mich seinerzeit der Grund, auf ARM umzusteigen und
das wäre auch mein Rat an Euch:

OV7670 und ATmega - das paßt einfach nicht gut zusammen.
Früher oder später wird Euch die HW-Beschränkung frustrieren,
weil Ihr maximal die Pixel bei arg reduzierter Auflösung einlesen und
mehr oder weniger 1:1 irgendwohin weiterschieben könnt.

Wenn ich die Zeit betrachte, die ich benötigt habe, um vernünftige
Bilder aus der OV7670 herauszubekommen, so kann man sich in dieser
Zeit auch schon etwas vom ARM-Prozessor beibringen.

Und daraus ergibt sich meine Anregung an Euch: überlegt Euch, ob es
Sinn machen könnte, ein paar Wochen Einarbeitung in ARM-Technologie
zu stecken, um dann mit ca. 10-fach gestärkter Muskelkraft nochmals
an die OV7670 heranzutreten.

Um Euch die Sache schmackhaft zu machen:

Ein STM32F429I-Discovery-Board bekommt man für ca. 20-25 EUR in der 
Bucht.
Dort ist neben einem potenten stm32f429-Prozessor auch schon ein 
ILI9346-Display drauf - optimal zum Experimentieren mit dem OV7670

Und der Prozessor kann (aus dem Kopf geschrieben):

- Läuft auf 3,3V und kann direkt mit OV7670 gekoppelt werden
- Hat 180 MHz Taktfrequenz
- Hat ca. 256 kByte RAM, ca. 1 MB Flash
- Kann DMA  (= Daten von A nach B schieben ohne die CPU zu behelligen)
  (A oder B können sein: RAM, GPIO, UART, DCMI, SPI, ...)
- kann DCMI (= Kamera-Daten per DMA in RAM-Bereiche schieben)
- hat DSP an Board
- hat unendlich viele IO-Ports
- hat mehr als zwei Hände voller Timer
- hat mehrere unabhängige UART's, I2C's und SPI's an Board
- hat Ethernet, CAN, USB - Controller an Board
- hat sogar irgendwelche LCD-TFT-Controller an Board
- hat mehrere 12-Bit A/D- und D/A-Wandler

... ach ja: und auf dem Board stecken zufällig noch 64MB SDRAM,
Test-LED, Test-Button und ein Beschleunigungs-Sensor.

Oder schaut einfach selbst:

Board: http://www.st.com/en/evaluation-tools/32f429idiscovery.html

Prozessor - Datasheet:
http://www.st.com/resource/en/datasheet/dm00071990.pdf

Prozessor - Reference Manual:
http://www.st.com/content/ccc/resource/technical/document/reference_manual/3d/6d/5a/66/b4/99/40/d4/DM00031020.pdf/files/DM00031020.pdf/jcr:content/translations/en.DM00031020.pdf

Und das Beste: so ein ARM-Prozessor kommt mit einem "Hardware-
Debugger" daher - man kann seine Programme also Schritt für
Schritt debuggen - nicht im (buggy Atmel-)Simulator, sondern
nativ auf der Hardware (inkl. Register-Auslesen und Pi-Pa-Po)

Kurzum: ihr bekommt alles, was man sich schon immer gewünscht hat.
Im Gegenzug - das sei nicht verschwiegen - kostet so ein ARM-
Prozessor aber ein paar Wochen Einarbeitungszeit und insbesondere
der Anfang ist etwas hart.

Viele Grüße

Igel1

von David D. (saturi)


Lesenswert?

Hallo,
ich habe nicht vor diese Thread einschlafen zu lassen. Ich verfolge die 
Beiträge auch sehr interessiert. Leider bin ich diese Woche sehr 
eingespannt und werde erst ab dem Wochenende wieder dazu kommen, meinen 
ausführlichen Beitrag zu leisten.

lg.
David

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> OV7670 und ATmega - das paßt einfach nicht gut zusammen.
> Früher oder später wird Euch die HW-Beschränkung frustrieren,
> weil Ihr maximal die Pixel bei arg reduzierter Auflösung einlesen und
> mehr oder weniger 1:1 irgendwohin weiterschieben könnt.
Man kann die Pixel in maximaler Auflösung (sind ja nur 640x480) einlesen 
und kann die irgendwohin schieben (als Webseite wenn man noch einen 
ENC28J60 oder was moderneres dranhängt) oder auf eine SD-Karte 
speichern.
Was einschränkt: man kann keine Bewegtbilder bekommen, geht mit dieser 
Kamera aber sowieso nicht wirklich) und muß etwas Geduld mitbringen 
(10-15s um ein Bild in den Webbrowser zu bekommen) und man muß ein paar 
egenwillige Wege gehen.
Ich hatte am 02.04.2018 13:42 ein Bild von meiner DC3840 angehängt, 
allerdings mit einem ESP32 eingelesen und rübergeschickt.
Genau diese Kamera hing vor vielen Jahre an einem ATMega32 mit dem 
ENC28J60 als LAN-IC.
921000Baud von der Kamera und auch kein Ram. Eingelesen in 128 Byte 
Häppchen und dem TCP-Buffer in die Hand gedrückt. Wenn das Paket voll 
war rausgeschickt usw.
Ziel war nur "es müßte machbar sein".
Natürlich konnte man auch damals schon eine USB-Webcam bemühen, an einen 
kleinen PC hängen usw. Das konnte ja sozusagen jeder. ;-)
Sind 10 Jahre seitdem vergangen:
http://www.ulrichradig.de/home/index.php/projekte/uC-kamera

> Wenn ich die Zeit betrachte, die ich benötigt habe, um vernünftige
> Bilder aus der OV7670 herauszubekommen, so kann man sich in dieser
> Zeit auch schon etwas vom ARM-Prozessor beibringen.

Ich nehme an, die OV7660 ist überhaupt nur wieder aufgetaucht, weil es 
sonst wohl nichts mehr auf dem Markt gibt, mit dem man überhaupt an 
einem AVR o.ä. Chancen hätte.

Wollte ich sowas machen wäre es doch heute ein RasPi Zero W, die 
zugehöirge Cam dran und der Viedostream in HD wäre greifbar.
Man wird heute solch ein Kameramodul kaum noch irgendwo wirklich 
einsetzen wollen. Weder mit einem ARM noch überhaupt. Zu langsam, 
Auflösung zu gering, Lichtempfindlichkeit zu schlecht usw. usw.

Der Sensor der OV7670 ist der, der auch in obiger DC3840 vor 10 Jahren 
drin war... Die Optik der OV7660 ist etwas besser und lichtstärker.

Wozu also das Ganze? Man lernt Datenblätter zu lesen, man lernt I2C 
kennen, man lernt es, das Zeitverhalten eines System in Hardwarenähe zu 
beachten.
Das hilft aber auch auf anderen Systemen bei anderen Aufgaben.

Nimm es als Spaß an der Sache, Zeit bei einer Hobbyaufgabe war noch nie 
ein Kriterium.

Ich verfolge das hier interessiert weil ich es schon kenne (und auch 
schon kann) und als Rentner etwas Zeit habe.

Wäre doch lusitg (und sinnlos...): OV7670, Mega328, SX1276 
(LoRa-Funkmodul) und nach 6-7 Stunden hätte man ein komplettes Bild am 
anderen Ende. ;)

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

Hier ein Beitrag, den ich vergessen hatte, abzuschicken - er 
referenziert auf den letzten Beitrag von David.

David D. schrieb:

> Da ich nun wirklich schon mehrere Stunden an diesem Problem sitze,
> drängt sich mir die Frage auf, wie schnell denn der externe Interrupt
> eigentlich arbeiten kann, und ob es dort ebenfalls max. Frequenzen gibt.
> Leider konnte ich nichts finden. Habt ihr da schon Erfahrungen?
>
> lg. David

Zu dem "Overhead", der bei der Interrupt-Verarbeitung anfällt, hatten 
Ulrich und ich ja bereits etwas geschrieben.

Nun habe ich nochmals nachgeschaut, wie lange so ein Puls denn anliegen 
muss, damit eine Flanke denn auch wirklich einen Interrupt auslöst.

Die Antwort findet sich im Datenblatt des Atmega328p auf S. 53 und S. 
54:
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-7810-Automotive-Microcontrollers-ATmega328P_Datasheet.pdf

Aus Figure 12-1 läßt sich schon erahnen: der Pegelwechsel muss 
mindestens 1 CPU-Takt lang anliegen und auf S. 54 wird das nochmals 
bestätigt:
". If edge or toggle interrupt is selected, pulses that last longer than 
one clock period will generate an interrupt".

Wenn Dein ATmega328p-Schweinchen also mit 16MHz rennt, so können Pulse 
mit einer Dauer von 1/16MHz = 0,0625us detektiert werden. Von dort droht 
also keine Gefahr.

Das Problem bei einer Bearbeitung über Interrupts wird eher der Overhead 
für das Einspringen (min. 4 Takte), das Rückspringen (min. 4 Takte) und 
das Sichern bzw. Widerherstellen von N Registern und für ein bißchen 
ISR-Code sein.

Man liest von 50-80 Taktzyklen, die dann mal ganz fix futsch sind. Bei 
80 Taktzyklen könntest Du also frühestens nach 80 x 0,0625us = 5us die 
nächste Taktflanke per Interrupt bearbeiten. Ganz streng betrachtet 
kannst Du beim YCbCr422 Format sogar eine Flanke "schludern", weil Du ja 
nur die Y-Flanke mitbekommen mußt - aber da wind's dann schon langsam 
haarig mit den ganzen Timings.

Das beschränkt Deinen PCLK-Takt auf 1/5us = 200kHz, was wiederum am 
unteren Ende der Spaßgrenze liegt, denn:

Gemäß Tabelle 3.3 im Implementation Guide:
http://www.haoyuelectronics.com/Attachment/OV7670%20+%20AL422B%28FIFO%29%20Camera%20Module%28V2.0%29/OV7670%20Implementation%20Guide%20%28V1.0%29.pdf

... kannst Du bei 24MHz PCLK die max. 30 Frames/s erreichen.
Mit 200kHz liegst Du um den Faktor 120 darunter, was Deine Framerate auf 
30f/s / 120 = 0,25/s reduziert. Wie gesagt: am unteren Ende der 
Spaßgrenze.

Kurzum: Ein Polling-Mechanismus wäre vermutlich besser geeignet, um die 
Pixel aus der Kamera in das RAM einzulesen.

Soweit meine 10 Cent ...

Viele Grüße

Igel1

von David D. (saturi)


Lesenswert?

Guten Tag zusammen,
ich hoffe ihr könnt den Tag ebenso sonnig genießen wie ich es tue.
So sitze ich also gemütlich mit meinem Laptop auf dem Balkon und nehme 
mir wie versprochen die Zeit, einen ausführlichen Beitrag zu schreiben.

Zunächsteinmal vielen Dank für die vielen Hilfestellungen.

Zu meinem letzten Post:
Ich glaube ich sollte aufhören Nachts noch schnell einen Beitrag zu 
schreiben, sondern lieber in Ruhe vollständige Informationen liefern ;-)

Folgendes war mein (vollständiger) Gedankengang:
Ich schaue zunächst, ob neben der ISR-Routine, die den PCLK Peak 
detektieren soll, noch Zeit bleibt um in dem Hauptprogramm etwas zu 
rechnen/bearbeiten/senden/speichern etc.
Wie ich das vorhabe:
Ich lasse in der ISR-Routine einen Zähler hochlaufen und setzte eine 
FLag-Variable die anzeigt, dass ein Interrupt da war. Im Hauptprogramm 
frage ich die Flag ab und erhöhe, falls diese Vorhanden ist, einen 
zweiten Zähler und setzte die Flag dann wieder zurück.

Wenn ich jetzt im Debugging-Modus bin und Pause drücke, sollten beide 
Zähler den gleichen Wert haben, oder der ISR-Zähler maximal eins mehr 
haben.
Um einen Überlauf der int-Variablen zu verhindern habe ich noch eine 
Grenze festgelegt. Ebenso wollte ich mit dem Zählen erst bei der 
nächsten HREF-Periode beginnen, um gleichzeitig zu schauen, ob ich auch 
die eingestellt Auflösung (bzw. die erwartete Anzahl an Bytes) erhalte.

Mir ist bewusst, dass eine delay Funktion absolut nichts in einem 
Interrupt zu suchen hat (daher habe ich sie jetzt auch wieder raus 
genommen). Diese ist nur als letzter Hoffnungsschimmer eingefügt worden, 
weil ich verzweifelt gedacht habe, mein Oszi könnte die eventuell 
verpassen. (Der Kommentar im Programmcode war anscheinend nicht 
ausführlich genug)

Der Verdacht des rekursiven Aufruf gefällt mir ganz gut. Hatte aber auch 
zu Beginn und zum Ende der Routine cli() bzw. sei() gesetzt, um diesen 
Fall auszuschließen. Brachte aber leider keine Veränderung.

Hier mein Vollständiger Code (allerdings im AVR-Style)(Versuche das die 
Tage mal auf Arduino umzumünzen, damit wir wieder auf der gleichen 
Plattform sind) Ich hoffe, ihr könnt trotzdem etwas damit anfangen:
1
/*
2
 * main.cpp
3
 *
4
 * Created: 23.07.2017 17:35:15
5
 *  Author: David
6
 */ 
7
8
 #ifndef F_CPU
9
 #define F_CPU 16000000
10
#endif
11
 
12
 #include <avr/io.h>
13
 #include <avr/interrupt.h>
14
15
#include "OV7670.h"
16
#include "OV7670.c"
17
18
#include "UART.h"
19
20
21
volatile unsigned int i=0;
22
//unsigned char myBytes[100];
23
bool interruptFlag =false;
24
 int main(void)
25
 {
26
  sei();
27
28
  UART0_init();
29
   OV7670_init();
30
  OV7670_checkConnection();
31
32
33
//Reduce frequency of PCLK
34
  char ReadData =0;
35
  char MASK = ~0x80; 
36
  char WriteData; 
37
   //Read the RCLK Register to get the internal Clock
38
   OV7670_read(OV_SCCB_CLKRC,&ReadData);
39
   UART0_senden_Byte(ReadData);
40
   UART0_newLine();
41
   
42
   //Reduce PCLK by Prescaler
43
   OV7670_write(OV_SCCB_CLKRC,0x0F);
44
   
45
   //Check if change succed
46
   OV7670_read(OV_SCCB_CLKRC,&ReadData);
47
   UART0_senden_Byte(ReadData);
48
   UART0_newLine();
49
50
   //Change Format to QCIF and YUV
51
   OV7670_read(OV_SCCB_COM7,&ReadData);
52
   MASK = ReadData & 0b01000000;
53
   MASK |= 0x08;
54
   ReadData |= MASK;
55
   OV7670_write(OV_SCCB_COM7,ReadData);
56
   
57
   //activate Skaling
58
   OV7670_read(OV_SCCB_COM3,&ReadData);
59
   ReadData|=0x08;
60
   OV7670_write(OV_SCCB_COM3,ReadData);
61
62
   //Activate DCW and scaling PCLK enable (neccessary for Divide PCLK) and Divide PCLK by 16
63
   OV7670_read(OV_SCCB_COM14,&ReadData);
64
   ReadData|=0x1C;
65
   OV7670_write(OV_SCCB_COM14,ReadData);
66
67
   //deactivate PCLK during HREF Blank
68
   OV7670_read(OV_SCCB_COM10,&ReadData);
69
   ReadData|=0x20;
70
   OV7670_write(OV_SCCB_COM10,ReadData);
71
72
   //Scaling PCLK
73
   OV7670_read(OV_SCCB_SCALING_PCLK,&ReadData);
74
   ReadData &=~(0x0F);
75
   ReadData |=0x04;
76
   OV7670_write(OV_SCCB_SCALING_PCLK,ReadData);
77
78
//set Variables and Flags
79
   i=0;
80
  interruptFlag=false;
81
  bool HREF_Flag=false;
82
83
  volatile int j=0;
84
  //Setup interrupt pin
85
  EICRA |= (0b00000011);  //Interrupt at Int0-Pin at positiv change
86
  EIMSK &= ~(0b00000001);  //Disable Int0-Pin
87
88
   while (1)
89
   {
90
    //start conditions for external interrupt (Wait until HREF is LOW to make sure to get a complete Line)
91
    if((!((OV_HREF_PIN>>OV_HREF_PINNR)&(0x01)))&&(HREF_Flag==false))
92
    {
93
      i=0;
94
      j=0;
95
      EIMSK |= 0b00000001;  //Enable Int0-Pin    
96
    }
97
    
98
    //Count PCLK in Line
99
    if(((OV_HREF_PIN>>OV_HREF_PINNR)&(0x01))&&(interruptFlag==true))
100
    {
101
      j++;  //Count the Interrupts in the Main-Loop (Test if j and i have the same value)
102
      interruptFlag=false;
103
      HREF_Flag=true;  //indicate a period of HREF
104
    }
105
    
106
    //Disable Interrupt after One Line  
107
    if((!((OV_HREF_PIN>>OV_HREF_PINNR)&(0x01)))&&(HREF_Flag==true))
108
    {
109
      EIMSK &= ~0b00000001;  //Disable Int0-Pin
110
    }
111
          
112
   }
113
   return 0;
114
 }
115
116
 
117
ISR(INT0_vect){
118
  cli();
119
  PORTB |= 0x20;  //Just for measuring at oscilloscope
120
  interruptFlag=true;
121
  i++;
122
  PORTB&= ~(0x20);
123
  sei();
124
}

Derzeit stellt es sich wie folgt da:
Führe ich den Code wie oben dargestellt aus (und setzte einen Breakpoint 
in der letzten If-Schleife, so zählt der Zähler nur bis eins, was für 
mich absolut unverständlich ist.
Die interrupts kann ich nach wie vor durch Pin 13 nicht detektieren, was 
mir ebenso nicht einleuchten will.

Kommentiere ich die letzte if-Schleife aus und pausiere willkürlich über 
den Debug-Mode, haben beide Zähler den gleichen Wert. (Ich habe aber das 
gefühl, dass sie zu langsam hochzählen)
Trotzdem sehe ich die ISR-Routine nicht auf dem Oszi.

von Michael kam folgender Beitrag:

>Ich wollte auch mehr darauf hinaus, daß es für das konrete Projekt nicht
>wirklich etwas zwischen dem Einlesen von 2 Pixeln zu tun gibt.
>Wenn man also eine Zeile komplett in einer HSync-ISR einliest und
>zwischenspeichert, erspart man sich mögliche Timingprobleme mit einer
>PCLK-ISR erstmal ganz.

Da stimme ich grob erstmal mit dir überein. Für mich stellt sich dann 
aber die Frage, wie ich die PCLK-Flanken dann detektiere,
um dann jeweils das anliegende Byte zu übernehmen. Wie kann ich soetwas 
denn abbilden? Die ISR wird doch nur einmal durchlaufen. Lasse mich da 
gerne belehren :)


Auf den Beitrag von Igel1 bezogen:
>...
>Und das Beste: so ein ARM-Prozessor kommt mit einem "Hardware-
>Debugger" daher - man kann seine Programme also Schritt für
>Schritt debuggen - nicht im (buggy Atmel-)Simulator, sondern
>nativ auf der Hardware (inkl. Register-Auslesen und Pi-Pa-Po)

über das Debug-Wire und dem Dragon kann ich doch auch die Hardware 
direkt debuggen und auch die Register lesen inkl. Eingänge.
Oder liege ich da falsch?
Im Prinzip hast du vermutlich recht, dass dein Vorgeschlagener 
Controller für diese Anwendung besser geeignet ist.
Ich habe mich aber damals für die Arduino (Atmel) Reihe entschieden und 
auch bisher nur damit Erfahrungen gemacht.
Jetzt auf einen anderen Umzusteigen würde mich (zumindest für den 
Anfang) wieder auf null zurückwerfen. Dafür fehlt mir leider noch etwas 
die Zeit und die Motivation.
Mir ist bewusst, dass ich mit dem Atmega328 keine videos darstellen 
werden kann.
Für mich geht es aber, wie Michael auch schon erkannt hat:
>Wozu also das Ganze? Man lernt Datenblätter zu lesen, man lernt I2C
>kennen, man lernt es, das Zeitverhalten eines System in Hardwarenähe zu
>beachten.
>Das hilft aber auch auf anderen Systemen bei anderen Aufgaben.

Mir reicht es tatsächlich zunächst ersteinmal ein Foto zusammengesetzt 
zu bekommen.
Das ich danach in Ruhe weiterverarbeiten kann. Ich habe in ferner 
Zukunft damit dann vor, eine Art von Sortierer zu bauen. Wie gesagt, 
ferne Zukunft :D
ab dem Sommer habe ich auch privat etwas mehr Zeit und dann kann man 
sich den Schwenk auf einen ARM-Prozessor ja nochmal überlegen. :)

Dann noch der interessante letzte Beitrag von Igel1:

>Kurzum: Ein Polling-Mechanismus wäre vermutlich besser geeignet, um die
>Pixel aus der Kamera in das RAM einzulesen.
Polling sagte mir bis zur Erstellung von diesem Beitrag noch nichts. 
Sollte ich das eher mit einer While-Schleife oder If-Schleifen lösen? 
(Mein verständnis von Polling ist "aktives" Warten, bin ich da richtig?)

Ich hoffe ihr könnt mir sagen, wo ich in obrigem Code einen Denkfehler 
habe? Es ist ja nun wirklich noch keine hochkomplizierte Angelegenheit 
und ich weiß einfach nicht wo das Problem liegt.
vielen Dank für eure Hilfe!

sonnige Grüße

David

von Olli Z. (z80freak)


Lesenswert?

Hi David. Erstmal Respekt für Deine Mühen und danke das Du deine 
Gedanken mit uns teilst. Ich persönlicch finde es immer schwer mich in 
den Code anderer Leute einzudenken, daher ist eine ausführliche 
Dokumentation wichtig.

Von daher wäre mein Vorschlag bevor wir hier über Code diskutieren, den 
Programmablauf zu beschreiben. Also was genau wie und warum erfolgen 
soll. Darauf basierend kann dann jeder seinen Code schreiben, um zu 
lernen und am Ende entwickeln wir einen gemeinsamen, z.B. in Github.

Ein guter Einstieg hierzu wäre, Deine Ideen zur Initialisierung in 
Subroutinen zu gießen. Dazu müssten wir nur beschreiben was das System 
vor Beginn und am Ende der Routine für einen Zustand hat und mit welchen 
Kommandos wir dahin kommen.

Was hälst Du (sorry, ihr) von der Idee? Wollen wir so vorgehen?

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> Da stimme ich grob erstmal mit dir überein. Für mich stellt sich dann
> aber die Frage, wie ich die PCLK-Flanken dann detektiere,
> um dann jeweils das anliegende Byte zu übernehmen. Wie kann ich soetwas
> denn abbilden? Die ISR wird doch nur einmal durchlaufen. Lasse mich da
> gerne belehren :)

soviel zu belehren ist da nicht. ;-)
Du nimmst die Länge einer Zeile in Bildpunkten und damit die Anzahl PCLK 
die dazugehören. Dann rechnest Du Dir aus, wieviel zeit das in µs/ms 
ist.
Dann ignorierst Du alle Überlegungen zur Länge einer ISR und machst 
alles ab HSYNC innerhalb der ISR.
PCLK fragst Du simple per Loop ab, eben Pin einlesen und schauen, ob der 
Pegelwechsel da war. Sonst eben in der Schleife weiter abfragen.
Wenn ja Daten holen, Pixelzähler weiterzeählen und wenn noch Pixeldaten 
der Zeile fehle wieder ab in die Warteschleife auf PCLK.
Dann bist Du eben Zeit x in der ISR. Während der Zeit sind sowieso auf 
dem AVR die Interrupts gesperrt und es kann Dich keiner stören.
So bekommst Du eine Zeile. Du bekommst ja vermutlich nichtmal eine Zeile 
im Ram des AVR unter...
Ich schaue mir morgen mal das Datenblatt des OV7670 genauer an wie es 
weiter gehen könnte.

Olli Z. schrieb:
> Ein guter Einstieg hierzu wäre, Deine Ideen zur Initialisierung in
> Subroutinen zu gießen. Dazu müssten wir nur beschreiben was das System
> vor Beginn und am Ende der Routine für einen Zustand hat und mit welchen
> Kommandos wir dahin kommen.

Selbstverständlich sollte sowas in Subroutinen/Funktionen ausgelagert 
werden. InitCam() muß den kamerachip z.B. dann aus jeder Lebenslage in 
einen von uns gewünschten Zustand setzen. Erstmal das notwendigste rein, 
Register, die unbedingt auf gewünschte Werte gesetzt werden 
sollen/müssen dann nachtragen wenn nötig ist.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

@David:

Ich programmiere, wie schon gesagt, ein paar Jährchen keinen AVR mehr,
daher muss ich nicht richtig liegen, aber Deine Art der PIN-Abfrage
scheint mir etwas seltsam:
1
if((!((OV_HREF_PIN>>OV_HREF_PINNR)&(0x01)))&&(HREF_Flag==false))

Ich hätte so etwas erwartet:
1
if( !(OV_HREF_PIN & (1 << OV_HREF_PINNR)) && (HREF_Flag==false))

Außerdem wäre es gut, wenn Du den gesamten Code hier 
einstellst/anhängst.
So fehlt z.B. die Definition von OV_HREF_PIN in Deinem Code-Fragment.

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Außerdem wäre es gut, wenn Du den gesamten Code hier
> einstellst/anhängst.

hatte ich auch schonmal drum gebeten, ich würde es dann eben auf einen 
passenden AVR packen und mitschauen.
Ist bei mir reines Interesse. Wenn, dann hänge ich die OV7670 ohnehin an 
einen ESP32. Die in Gang zubekommen dürfte mir kaum Probleme bereiten, 
auch an einem Mega328 nicht. Die reale Möglichkeit habe ich ja schon vor 
etlichen Jahren mit der DC3840 genutzt. Die hängt ja im Moment am ESp32, 
siehe Posting vom 02.04.2018 13:42.

PS und OffTopic: heute 3 Stunden mit 2 Obi/Norma WLAN-Steckdosen 
verbracht.
ESP8266 drin, 10 Leute haben das im Netz mit Tasmota u.ä. in Gang 
gebracht, keiner hat ein wirklich sinnvolles wirklich Stück Doku 
hinterlassen warum es einen IO für Relais on und einen IO für relais off 
gibt. Steht zwar so auf der Platine, ist aber eigentlich etwas anders 
gemeint.
Nun schalten sie wie sie sollen, hätte ich mir die ziemlich aufwändige 
Beschaltung zwischen den ESP-Pins und dem Relais mal gleich selber 
angeschaut... 3 Halbleiter (2 Transistoren, der dritte SOT-23 nicht 
identifizierbar, könnte vom Drumrum soager ein thyristor o.ä. sein), ca. 
10 Widerstande und Kondensatoren.
Ganz verstanden habe ich noch nicht, waum die Chinesen da soviel Aufwand 
getrieben haben.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> Der Verdacht des rekursiven Aufruf gefällt mir ganz gut.

Mir auch :-)

> Hatte aber auch
> zu Beginn und zum Ende der Routine cli() bzw. sei() gesetzt, um diesen
> Fall auszuschließen. Brachte aber leider keine Veränderung.

Hmmm - auch dafür müßten wir Deinen kompletten Code sehen.

> Hier mein Vollständiger Code (allerdings im AVR-Style)(Versuche das die
> Tage mal auf Arduino umzumünzen, damit wir wieder auf der gleichen
> Plattform sind)

Oh schreck - dann hängt Ihr mich vermutlich ab ...

> Ich hoffe, ihr könnt trotzdem etwas damit anfangen:

Ja, bloß bitte den vollständigen Code hier noch nachschieben.

> Trotzdem sehe ich die ISR-Routine nicht auf dem Oszi.
1
ISR(INT0_vect){
2
  cli();
3
  PORTB |= 0x20;  //Just for measuring at oscilloscope
4
  interruptFlag=true;
5
  i++;
6
  PORTB&= ~(0x20);
7
  sei();
8
}

Vorab: "cli()" sollte meiner Meinung nach überflüssig sein,
weil beim Aufruf einer ISR das Globale Interrupt-Flag (I in SREG)
sowieso ausgeschaltet wird.

Gleiches gilt für "sei()" am Ende: Beim Rücksprung aus einer
ISR wird das globale Interrupt-Flag wieder aktiviert - das
gehört quasi zum Hotel-Service Deines MC.

Eine erneute steigende Flanke, die während einer "normalen" ISR
einläuft, wird also erst nach dem Rücksprung aus der ISR zum
neuen Interrupt führen.

Dieses (vermutlich von Dir gewünschte) Verhalten konterkarrierst
Du, indem Du sei() noch innerhalb Deiner ISR ausführst.
Das dürfte wiederum zu rekursiven ISR-Aufrufen führen.

Nun zurück zu Deiner ursprünglichen Frage/Aussage:

> Trotzdem sehe ich die ISR-Routine nicht auf dem Oszi.

Ich kontere mal und sage: trotzdem sehe ich nirgendwo, dass
Du PORTB überhaupt als Ausgang geschaltet hast ...

Viele Grüße

Igel1

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
>>Kurzum: Ein Polling-Mechanismus wäre vermutlich besser geeignet, um die
>>Pixel aus der Kamera in das RAM einzulesen.
> Polling sagte mir bis zur Erstellung von diesem Beitrag noch nichts.
> Sollte ich das eher mit einer While-Schleife oder If-Schleifen lösen?
> (Mein verständnis von Polling ist "aktives" Warten, bin ich da richtig?)

"Polling" heißt einfach: Frage aktiv Deinen PINx aus Deinem Programm 
heraus immer wieder ab. Es ist das Konzeptionelle Gegenstück zu 
Interrupts, die den Programmablauf "von sich aus" unterbrechen.

Nachteil von Polling: belastet den Prozessor, der dauernd fragen muss - 
auch wenn gar kein Flankenwechsel passiert ist. Vorteil: Du sparst Dir 
den Interrupt-Overhead.

> über das Debug-Wire und dem Dragon kann ich doch auch die Hardware
> direkt debuggen und auch die Register lesen inkl. Eingänge.
> Oder liege ich da falsch?

Nein, Du liegst da goldrichtig, nur ich kannte Debug-Wire nicht, weil's 
scheinbar erst nach meiner AVR-Zeit aufkam. Schönes Feature!

> Im Prinzip hast du vermutlich recht, dass dein Vorgeschlagener
> Controller für diese Anwendung besser geeignet ist.

Und Du hast ebenfalls recht, wenn Du Dich jetzt aktuell in kein
ARM-Abenteuer stürzen willst, wenn Du nicht viel Zeit hast.
Kann ich absolut nachvollziehen.

Viele Grüße

Igel1

von Viktor (Gast)


Lesenswert?

Andreas S. schrieb:
> Ich hätte so etwas erwartet:
> if( !(OV_HREF_PIN & (1 << OV_HREF_PINNR)) && (HREF_Flag==false))
Ich hätte eher sowas erwartet:
1
if( bit_is_clear( OV_HREF_PIN, OV_HREF_PINNR) && (HREF_Flag==false))

Aus welchem Grund auch immer diese Makros nicht empfohlen werden:
https://www.mikrocontroller.net/articles/Bitmanipulation#Hilfsfunktionen_als_C-Makro_.28nicht_empfohlen.29

Ich finde: Lesebarer Code hat oberste Priorität.

von Michael U. (amiga)


Lesenswert?

Hallo,

ich habe zu makros auch eine geteilte Meinung.
Wenn man sie selbst geschrieben hat ok, wenn man sie übernimmt manchmal 
riskant.
Prinzipiell ist es ja nur eine Textersetzung durch #define. Das kann in 
Verbindung mit zusätzlichem kontext wie auch hier
if( bit_is_clear( OV_HREF_PIN, OV_HREF_PINNR) && (HREF_Flag==false))
Nebeneffekte erzeugen, weil nach ersetzen des Makro-Part die komplette 
Auswertung ganz was anders machen kann als erwartet.
Wenn, dann würde ich da immer Funktionen vorziehen, die haben keine 
solchen Nebenwirkungen.
Ich würde selbst hier
OV_HREF_PIN & (1 << OV_HREF_PINNR)
wohl (OV_HREF_PIN & (1 << OV_HREF_PINNR) == (1 << OV_HREF_PINNR)) 
schreiben, das liefert definitiv false oder true zurück.
Ob das Ergebnis ohne den Vergleich wirklich als true und false 
interpretiert wird, kann schon vom Compiler abgängen. Die Diskussionen 
dazu im Netz sind endlos...

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

Das geht ja schon alles sehr tief in die Materie, alles hochspannend und 
sehr informativ!

Ich sehe das wir schon noch auf unterschiedlichen Ebenen unterwegs sind 
(Arduino, Atmega direkt, ESP, ARM). Persönlich würde ich auch die ohne 
Overhead vorziehen, sprich AVR direkt, selbst wenn ein Arduino-Board 
genutzt wird. Da muss man dann aber wirklich alles selbst machen, inkl. 
SPI.

Wäre das denn ein „kleinster gemeinsamer Nenner?“ für unser 
Gemeinschaftsprojekt?!

Ich glaube wir sind uns alle einige das wir mit dem Atmega328 sehr bald 
an seine Leistungsgrenze stoßen werden. Dann darf man schonmal über 
einen Nachfolger nachdenken. Da wird es in der AVR Liga schnell dünn. 
Wenn wir also die Core-Logik übertragen wollen, sollten wir drauf achten 
alle Prozessorspezifischen Aufrufe in Subroutinen auszulagern. Wenn wir 
das gleich von Anfang an machen, könnten wir vielleicht alle hier 
vertretenen Plattformen integrieren, als auch einen späteren Umstieg 
erleichtern.

P.S.: Ein Github Repository würde ich hier, unterstützend zum Thread und 
Wiki bereitstellen: https://github.com/igittigitt/ov7670
Schickt mir mal Eure Github-Accounts und ich trage die als Collaborators 
ein, damit ihr das nach belieben nutzen könnt. Gleiches gilt fürs Wiki. 
Ich hoffe das ist ok und ich nehm das hier keinem „weg“. Wenn doch, 
bitte gleich schreien, nichts ist in Stein gemeißelt! :-)

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Andreas, Deine Überlegungen zum ISR würde ich 100% teilen. Das Problem 
sind die cli()/sei() Aufrufe innerhalb der Routine. Diese Befehle sind 
für Programmcpde außerhalb von ISRs gedacht, die nicht durch einen 
solchen unterbrochen werden sollen.

von Olli Z. (z80freak)


Lesenswert?

Viktor, ich stimme mit Dir überein, lesbarer Code ist die Basis für eine 
sinnvolle Zusammenarbeit und erfolgreiches Debugging. Und lieber 
Unterfunktionen anstelle Makros.

von Olli Z. (z80freak)


Lesenswert?

Sollen wir mal versuchen einen Programmablauf zu skizzieren und 
Unterfunktionen zu nennen, die man dann mit Code füllen kann? Ich denke 
mit diesem Gedankengerüst kommt man schneller zum Ziel, weil es uns 
etwas „zusammenhält“.

von Olli Z. (z80freak)


Lesenswert?

David, könntest Du mir mal kurz erklären wie ich das mit dem Debug-Wire 
aufsetze? Welche AVR IDE benutzt Du?

von Andreas S. (igel1)


Lesenswert?

@Victor:

Yep, Dein Makro sieht tatsächlich etwas schöner aus.
Gründe, die gegen so ein Makro sprechen, fallen mir ebenfalls nicht ein,
was nicht heißt, dass es eventuell doch welche gibt.

Ich selbst bevorzuge daher immer "mainstream coding style".
Ist halt etwas Geschmackssache.


@OV7670-Kämpfer:

Olli schlug vor:
> Sollen wir mal versuchen einen Programmablauf zu skizzieren und
> Unterfunktionen zu nennen, die man dann mit Code füllen kann? Ich denke
> mit diesem Gedankengerüst kommt man schneller zum Ziel, weil es uns
> etwas „zusammenhält“.

Mit Blick auf die arg beschränkten AVR-Ressourcen, würde ich ein
Polling zum Einlesen einer beliebigen Zeile vorschlagen.

Und da das RAM des ATmega bereits nach dem Einlesen von nur
einer Zeile randvoll sein dürfte, würde ich nach dem Einlesen
der Zeile (evtl. sogar schon während des Einlesens), die
gelesenen Werte an den PC (oder an mein TFT-Display) versenden.

Erst wenn das erledigt ist, kann ich die nächste Zeile einlesen.
Dabei sollte mir bewußt sein, dass ich mich zu diesem Zeitpunkt
vermutlich schon X-Zeilen weiter im Frame befinde und daher die
nächste Zeile im folgenden Frame abpassen muß.

Der Ablauf wäre also:
1
N=0
2
while (N < Zeilenzahl_eines_Frames) {
3
  Framebeginn abpassen
4
  Alle Pixel der N.-ten Zeile einlesen
5
  Alle Pixel der N.-ten Zeile ausgeben
6
  N = N+1
7
}

Das Einlesen aller Pixel der N.-ten Zeile würde ich wie folgt angehen:

Zunächst einen scharfen Blick auf die Abbildungen "Horizontal 
Synchronization" und "VGA timing" aus meiner Lieblings-OV7670-Page 
werfen:
http://embeddedprogrammer.blogspot.de/2012/07/hacking-ov7670-camera-module-sccb-cheat.html

Oder Direktlinks:
http://2.bp.blogspot.com/-K-OIuy-inUU/UA2gp3SYgYI/AAAAAAAAAPg/Gure3RWI8G4/s1600/href.png
http://3.bp.blogspot.com/-cjOYTMj4C4M/UA2kV-db8GI/AAAAAAAAAPs/rtCGSIGjOHo/s1600/vga.png

Daraus läßt sich entnehmen:

- Die erste Zeile eines Frames beginnt,
      wenn VSYNC von Hi auf Low geht

- Die Zeile N beginnt,
      wenn HREF genau zum N.ten mal von Low auf Hi geht

- Die jeweiligen Pixel einer Zeile stehen bereit,
      wenn PCLK von Low auf Hi geht

- Die Zeile ist beendet,
      wenn HREF auf Low geht


Daraus ergibt sich folgender Pseudo-Code:
1
// Zunächst warten wir auf den Beginn eines neuen Frames
2
// (sprich: VSYNC soll von Hi auf Low springen ...)
3
4
while (VSYNC == LOW) {}   // alten Frame auslaufen lassen ...
5
while (VSYNC == HI)  {}   // Hi-Schulter abwarten ...
6
7
// Wenn Du hier ankommst, ist VSYNC von Hi auf Low 
8
// gesprungen => Framestart
9
10
// Nun pickst Du Dir die N-te Zeile raus (hier: nline) ...
11
// (Notiz: wir zählen ab 0, d.h. die erste Zeile ist nline=0)
12
13
linecnt = 0
14
15
while (nline > linecnt) {
16
   while (HREF == LOW)  {}
17
   linecnt ++
18
   while (HREF == HI)   {}
19
}
20
21
// Wenn Du hier ankommst, ist gerade die (N-1)-te Zeile vorbei
22
// und HREF ist von Hi auf Low gesprungen
23
24
// Jetzt geht's ans Einlesen der N-ten Zeile ...
25
// Pixel-Zählung beginnt bei 0
26
27
pixelcnt = 0
28
29
wunschcode1                      // Minimal Zeit, um Wunschcode auszuführen
30
while (HREF == LOW) {}           // Erst die Low-Schulter zum Zeilen-
31
                                 // beginn abwarten
32
33
while (HREF == HIGH) {
34
   wunschcode2                   // Während der PCLK-Low-Schulter ist
35
                                 // minimal Zeit, um Wunschcode auszuführen
36
   while (PCLK == LOW) {}        // Warten auf Pixeldaten
37
   pixel[pixelcnt] = OV7670_data // Daten einlesen
38
                                 // Nicht vergessen: Bei YCrCb422 besteht
39
                                 // ein Pixel aus 2 Bytes. Das pixel-Array
40
                                 // wird als 2-mal so lang wie die Anzahl
41
                                 // der Pixel in einer Zeile (oder man
42
                                 // wirft die Farbinfos weg und nimmt nur
43
                                 // den Y-Wert.
44
   pixelcnt++
45
   wunschcode3                   // Minimal Zeit, um Wunschcode auszuführen
46
   while (PCLK == HIGH) {}
47
   wait(tphl)                    // Etwas warten, da HREF nach dem letzten
48
                                 // Pixel erst um tphl verzögert auf Low
49
                                 // geht
50
}
51
52
pixelarray_ausgeben(pixel)

Zu beachten:
1
  T(wunschcode1)   <   144 * tp  // tp: siehe Timing-Diagramme
2
  T(wunschcode2)   <   (1/2 * tp - tphl)
3
  T(wunschcode3)   <   (1/2 * tp)

Soweit mein Vorschlag.

Wie immer gilt: bitte nicht ohne genaues Nachprüfen übernehmen, denn
alles ist ungetestet und der Code ist ausschließlich aus den
TimingDiagrammen abgeleitet. Da ist bestimmt noch das eine oder
andere Schnitzerchen drin ...

Viele Grüße

Igel1

: Bearbeitet durch User
von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb:
> PS und OffTopic: heute 3 Stunden mit 2 Obi/Norma WLAN-Steckdosen
> verbracht.

Auch wenn das wirklich voll Off-Topic war und wir hier nicht weiter 
abschweifen sollten, so habe ich durch Deinen Hinweis erstmals erfahren,
dass es inzwischen alternative Firmware für Sonoff's gibt - das war
sehr interessant für mich. Danke für den Hinweis!

Viele Grüße

Igel1

von Olli Z. (z80freak)


Lesenswert?

Andreas S. schrieb:
> Mit Blick auf die arg beschränkten AVR-Ressourcen, würde ich ein
> Polling zum Einlesen einer beliebigen Zeile vorschlagen.
Das halte ich auch für eine gute Idee. Da wir im Moment nichts anderes 
tun wollen als Daten von der Kamera zu lesen, gibt es eigentlich keinen 
Grund sich der Komplexität einer ISR auszuliefern. Parallel zu dieser 
würde unser Main-Code nämlich nur in einer Sinnlos-Schleife rotieren. 
Ich glaub wir sollten erstmal versuchen das mit reinem Polling hin zu 
bekommen.

Also die Main startet nach der Initialisierung mit einem Poll auf VSYNC 
und dann gehts los.

Wir arbeiten doch mit QQVGA, also 160x120 Bildpunkten. Der XCLK wird mit 
8 MHz gefahren und der PCLK schwingt sich somit auf 50 kHz ein. Das 
macht eine Periodenzeit von 20µs, unser Bezugslevel.

Nehmen wir weiter an das wir die Bilddaten im RGB565 oder RGB555 
Ausgabemodus übertragen. Ist etwas ineffektiver als YUV, aber erstmal 
leichter zu verarbeiten. Jede Bildzeile hat also dann eine Länge von 320 
Byte. Das gesamte Bild eine Größe von 38.400 Byte. Der SRAM des 
Atmega328p ist 2.048 Byte groß, wovon ein guter Teil auch für das 
Programm benötigt wird. Ich denke aber ein Zwischenpuffern von 2-3 
Zeilen sollte schon drin sein.

Das Setup des OV7670 wäre dann doch so:
1
1.) PCLK einstellen
2
    Prescaler-Register OV_SCCB_CLKRC (0x11) auf "Disable Double clock (Bit7=0)", "Prescale external clock (Bit6=0)", "durch 16 teilen (Bit0-5=01111)" (=0b0000 1111, =0x0F) stellen
3
2.) Bildformat QCIF und RGB.
4
    Register COM7 (0x12) mit Wert 0b0001 0100 laden.
5
3.) Skalierung einstellen
6
    Register COM3 (0x0C) mit Wert 0b0000 1000 laden.

>
1
> N=0
2
> while (N < Zeilenzahl_eines_Frames) {
3
>   Framebeginn abpassen
4
>   Alle Pixel der N.-ten Zeile einlesen
5
>   Alle Pixel der N.-ten Zeile ausgeben
6
>   N = N+1
7
> }
8
>
Du würdest also dadurch "Zeit schinden" indem Du einfach nur eine Zeile 
pro Frame liest und überträgst? Ok, für den Anfang eine durchaus 
brauchbare Methode. Da hat man vermutlich genug Zeit die Daten an den PC 
zu bekommen.

> - Die erste Zeile eines Frames beginnt,
>       wenn VSYNC von Hi auf Low geht
Verstanden und bestätigt.

> - Die Zeile N beginnt,
>       wenn HREF genau zum N.ten mal von Low auf Hi geht
Verstanden und bestätigt.
Laut Timingtabelle ist das nach 17*PCLK, also 340us der Fall. Wir haben 
also von der Erkennung der fallenden VSYNC-Flanke bis zur ersten Prüfung 
auf eine steigende Flanke diese Zeit zur freien Verfügung. Ob das für 
einen Kurzlurlaub reicht? ;-)

> - Die jeweiligen Pixel einer Zeile stehen bereit,
>       wenn PCLK von Low auf Hi geht
Verstanden und bestätigt, mit einer kleinen Anmerkung: Ich würde hier 
nur nicht von Pixeln, sondern von Bytes sprechen. Denn wieviele Byte pro 
Pixel benötigt werden, hängt vom Bildausgabeformat ab. In der Regel sind 
es aber immer 2 Byte pro Pixel, da die Kamera keinen nativen 
Graufstufenmodus kennt. Theoretisch könnte man den erreichen indem man 
die Kamera auf YUV-Ausgabe stellt und immer nur das erste Byte 
(Y=Luminanz) hernimmt und das zweite einfach ignoriert.

> - Die Zeile ist beendet,
>       wenn HREF auf Low geht
Verstanden und bestätigt. Das ist dann nach PCLK * H-Pixel der Fall. 
Also 20us * 160 = 0,0032us = 3,2 ms. Anschließend folgt noch die 
Austastlücke von 144 PCLK, also nochmal 0,00288us oder 2,88 ms. Dies 
wäre für mich die Zeit die wir hätten um störungsfrei zum PC zu 
übertragen.

>
1
>
> Soweit mein Vorschlag.
PERFEKT würde ich sagen, und von der Form her exakt das was wir 
diskutieren sollten bevor auch nur eine einzige Zeile Code geschrieben 
wird :-)

Ich bin begeistert! Gern würd ich das alles mal irgendwie im Wiki 
ablegen, vielleicht auch mal mit Visio ein einfaches PAP dazu zeichnen. 
Es sind ja die vielen kleinen Nebeninformationen zum Timing, etc. die 
man später braucht, wenn man "mehr will".

Oli

von Andreas S. (igel1)


Lesenswert?

Olli Z. schrieb:
> Andreas S. schrieb:
>> Mit Blick auf die arg beschränkten AVR-Ressourcen, würde ich ein
>> Polling zum Einlesen einer beliebigen Zeile vorschlagen.
> Das halte ich auch für eine gute Idee. Da wir im Moment nichts anderes
> tun wollen als Daten von der Kamera zu lesen, gibt es eigentlich keinen
> Grund sich der Komplexität einer ISR auszuliefern.

Ehrlich gesagt wäre der ISR-Ansatz der einfachere.
Aber damit kommt Ihr nicht weit, weil Aufruf und Rücksprung der ISR
halt viel Resourcen verbrauchen.

> Parallel zu dieser
> würde unser Main-Code nämlich nur in einer Sinnlos-Schleife rotieren.
> Ich glaub wir sollten erstmal versuchen das mit reinem Polling hin zu
> bekommen.

Okay.

> Also die Main startet nach der Initialisierung mit einem Poll auf VSYNC
> und dann gehts los.

Yep.

> Wir arbeiten doch mit QQVGA, also 160x120 Bildpunkten. Der XCLK wird mit
> 8 MHz gefahren und der PCLK schwingt sich somit auf 50 kHz ein. Das
> macht eine Periodenzeit von 20µs, unser Bezugslevel.

Legt Euch nicht von vorne herein auf QQVGA fest, sondern macht
den Code flexibel / konfigurierbar.

> Nehmen wir weiter an das wir die Bilddaten im RGB565 oder RGB555
> Ausgabemodus übertragen. Ist etwas ineffektiver als YUV, aber erstmal
> leichter zu verarbeiten.

Davon würde ich klar abraten.
Fangt erst einmal mit YUV an und verarbeitet zunächst nur das Y-Signal.
Das ergibt zwar nur SW-Bilder, aber das ist ideal, um überhaupt erst
einmal die Kamera einstellen zu können. Z.B. war ich lange Zeit der
Meinung, dass mein Programm nicht funktioniert und dabei war einfach
nur die Linse massiv unscharf eingestellt.

> Jede Bildzeile hat also dann eine Länge von 320
> Byte. Das gesamte Bild eine Größe von 38.400 Byte. Der SRAM des
> Atmega328p ist 2.048 Byte groß, wovon ein guter Teil auch für das
> Programm benötigt wird. Ich denke aber ein Zwischenpuffern von 2-3
> Zeilen sollte schon drin sein.

Claro, kann man gerne später dazuprogrammieren.

>
> Das Setup des OV7670 wäre dann doch so:
>
>
1
> 1.) PCLK einstellen
2
>     Prescaler-Register OV_SCCB_CLKRC (0x11) auf "Disable Double clock 
3
> (Bit7=0)", "Prescale external clock (Bit6=0)", "durch 16 teilen 
4
> (Bit0-5=01111)" (=0b0000 1111, =0x0F) stellen
5
> 2.) Bildformat QCIF und RGB.
6
>     Register COM7 (0x12) mit Wert 0b0001 0100 laden.
7
> 3.) Skalierung einstellen
8
>     Register COM3 (0x0C) mit Wert 0b0000 1000 laden.
9
>

Auch wenn's super wichtig ist - ich bin jetzt einfach mal zu faul,
das zu überprüfen ... Ich hoffe, ein anderer erbarmt sich.

Da man hier eine ganze Menge falsch machen kann, würde ich mit
einer Konfiguration beginnen, die nachweislich bei anderen Leuten
im Internet funktioniert hat.

>
>>
1
>> N=0
2
>> while (N < Zeilenzahl_eines_Frames) {
3
>>   Framebeginn abpassen
4
>>   Alle Pixel der N.-ten Zeile einlesen
5
>>   Alle Pixel der N.-ten Zeile ausgeben
6
>>   N = N+1
7
>> }
8
>>
> Du würdest also dadurch "Zeit schinden" indem Du einfach nur eine Zeile
> pro Frame liest und überträgst? Ok, für den Anfang eine durchaus
> brauchbare Methode. Da hat man vermutlich genug Zeit die Daten an den PC
> zu bekommen.

Richtig - das war der Grundgedanke.
Im nächsten Schritt läßt sich das natürlich deutlich verfeinern und
ist in Teilen im Pseudocode schon "vorgedacht":

Ihr könnt die max. Geschwindigkeit mit einer Art FiFo-Puffer erreichen:
vorne schreibt Ihr in den Puffer rein (so lange bis der Puffer voll ist)
und hinten nutzt holt Ihr die Bytes raus und übertragt sie an den PC
oder ein TFT-Display. Jedes übertragene Byte leert den FiFo-Puffer
dann wieder.

Sobald genug Platz für eine weitere Zeile ist, kann diese wieder 
eingelesen und gespeichert werden, während hinten weiterhin die Bytes 
entnommen und rausgeschrieben werden.  Das Entnehmen und rausschreiben 
kann in den oben markierten "Wunschcode"-Zeilen passieren.

>
>> - Die erste Zeile eines Frames beginnt,
>>       wenn VSYNC von Hi auf Low geht
> Verstanden und bestätigt.
>
>> - Die Zeile N beginnt,
>>       wenn HREF genau zum N.ten mal von Low auf Hi geht
> Verstanden und bestätigt.
> Laut Timingtabelle ist das nach 17*PCLK, also 340us der Fall. Wir haben
> also von der Erkennung der fallenden VSYNC-Flanke bis zur ersten Prüfung
> auf eine steigende Flanke diese Zeit zur freien Verfügung. Ob das für
> einen Kurzlurlaub reicht? ;-)

Mindestens ;-)
Alternativ kann man in ca. 80us bei 115,2 kbit/s ein Byte übertragen.

>
>> - Die jeweiligen Pixel einer Zeile stehen bereit,
>>       wenn PCLK von Low auf Hi geht
> Verstanden und bestätigt, mit einer kleinen Anmerkung: Ich würde hier
> nur nicht von Pixeln, sondern von Bytes sprechen. Denn wieviele Byte pro
> Pixel benötigt werden, hängt vom Bildausgabeformat ab. In der Regel sind
> es aber immer 2 Byte pro Pixel, da die Kamera keinen nativen
> Graufstufenmodus kennt. Theoretisch könnte man den erreichen indem man
> die Kamera auf YUV-Ausgabe stellt und immer nur das erste Byte
> (Y=Luminanz) hernimmt und das zweite einfach ignoriert.

Genau damit würde ich an Eurer Stelle anfangen.

>
>> - Die Zeile ist beendet,
>>       wenn HREF auf Low geht
> Verstanden und bestätigt. Das ist dann nach PCLK * H-Pixel der Fall.
> Also 20us * 160 = 0,0032us = 3,2 ms.

Nicht ganz: wie Du oben selber schreibt, benötigt man immer 2 Bytes
pro Pixel, also in Deinem Beispiel 6,2 ms für eine Zeile im YCrCb422-
Format.

> Anschließend folgt noch die
> Austastlücke von 144 PCLK, also nochmal 0,00288us oder 2,88 ms. Dies
> wäre für mich die Zeit die wir hätten um störungsfrei zum PC zu
> übertragen.

... Könnte man meinen, aber leider bekommst Du bei 115,2kbit/s gerade
mal max. 36 Bytes in dieser Zeit per USART über die Leitung geschoben.

Die horizontale Austastlücke reicht also nicht zur Übertragung
der Zeileninformation.

Das wiederum bedeutet im obigen Pseudocode:
es wird auf den nächsten Frame gewartet und dort die nächste Zeile
entnommen. Will sagen: pro Zeile benötigt Ihr bei diesem Ansatz einen
Frame.

Mit der weiter oben von mir berechneten "Spaßgrenze" liegt Ihr bei
einer PCLK von 50kHz bei einer Framerate von 1 Frame / 16 Sekunden ...
(wenn die Kamera überhaupt so niedrige PCLK's erlaubt)
Um also 120 Zeilen zu übertragen braucht's hier 120 * 16s = 32 Minuten.

Das wird nicht spaßig werden.

Hmmm - ich glaube, vor dem Coding ist hier doch noch etwas
Konzept-Tuning nötig ...  (wozu ich aber vermutlich heute und die
nächsten Tage nicht mehr kommen werde => Ihr seid dran ...)

>
>>
1
>>
>> Soweit mein Vorschlag.
> PERFEKT würde ich sagen, und von der Form her exakt das was wir
> diskutieren sollten bevor auch nur eine einzige Zeile Code geschrieben
> wird :-)
>
> Ich bin begeistert! Gern würd ich das alles mal irgendwie im Wiki
> ablegen, vielleicht auch mal mit Visio ein einfaches PAP dazu zeichnen.
> Es sind ja die vielen kleinen Nebeninformationen zum Timing, etc. die
> man später braucht, wenn man "mehr will".
>
> Oli

Nur zu ...

Viele Grüße

Igel1

von David D. (saturi)


Lesenswert?

Hallo:

Olli schrieb:

>Von daher wäre mein Vorschlag bevor wir hier über Code diskutieren, den
>Programmablauf zu beschreiben. Also was genau wie und warum erfolgen
>soll. Darauf basierend kann dann jeder seinen Code schreiben, um zu
>lernen und am Ende entwickeln wir einen gemeinsamen, z.B. in Github.

Ja. sehe ich genauso. (siehe meinen Post vom 28.03. 13:17)
Den hat aber jeder hier gekonnt ignoriert :D
Ich habe schon ein Github Projekt aufgesetzt und da drin zwischen 
Arduino und AVR unterschieden, um den transfert auch besser 
hinzubekommen.
Aber wir können auch gerne dein Repository nehmen. Wenn du dich damit 
auskennst, ist es vielleicht sogar besser, wenn du die Adminstration 
übernimmst, weil ich neu auf dieser Platform unterwegs bin.
Da denke ich auch, dass wir das Projektdashboard gut nutzen können, um 
aufkommende Ideen festzuhalten.

>Ein guter Einstieg hierzu wäre, Deine Ideen zur Initialisierung in
>Subroutinen zu gießen.

Ja sehe ich ebenfalls so. Ich nutze die Main-Funktion nur imme rzum 
ausprobieren. Alles was sich dann als "richtig" erweist packe ich dann 
in Routinen.

von Igel1:
>aber Deine Art der PIN-Abfrage
>scheint mir etwas seltsam:

Jap... keine Ahnung was mich da geritten hat. Deine darstellung ist die 
wohl gängigste, an die wir uns auch halten sollten.
Werde ich sofort ändern. (Nichtsdestotrotz sollte meine auch 
funktionieren. Daher scheint das für mich nicht die Ursache des Problems 
zu sein)

>Außerdem wäre es gut, wenn Du den gesamten Code hier
>einstellst/anhängst.

Jap. die werden in der OV7670_init initialisiert. Ich wollte hier nicht 
den Thread damit sprengen.
Ich denke wir werden das dann jetzt über GitHub realisieren, was das 
ganze übersichlticher machen sollte.

@Michael

>hatte ich auch schonmal drum gebeten
Ebenfalls richtig. Tut mir leid hatte ich vergessen. Aber da auf meinen 
Post mit dem Github keiner geantwortet hat war mir auch nicht klar, ob 
das noch gewünscht ist.


@Igel1

>Dieses (vermutlich von Dir gewünschte) Verhalten konterkarrierst
>Du, indem Du sei() noch innerhalb Deiner ISR ausführst.
>Das dürfte wiederum zu rekursiven ISR-Aufrufen führen.

>Nun zurück zu Deiner ursprünglichen Frage/Aussage:
>> Trotzdem sehe ich die ISR-Routine nicht auf dem Oszi.
>Ich kontere mal und sage: trotzdem sehe ich nirgendwo, dass
>Du PORTB überhaupt als Ausgang geschaltet hast ...

Rekursiv heißt doch, dass die Funktion aus der Funktion selber 
nocheinmal aufgerufen wird.
Also in dem Beispiel wäre es ja quasi nur indirekt, wenn aus der ISR 
nochmal in die ISR gesprungen wird.
Das scheint aber ja dann nicht zu gehen, wenn die Interrupts erst beim 
Rausspringen aus der ISR freigegeben werden.
Was ist dann nach deinem Verständnis ein Rekursiver aufruf?

Die initialisiserung des PORTB wird wie schon erwähnt ebenfalls in der 
OV7670_init ausgeführt.
Richitg, dass könnt ihr nicht sehen aber ich habe es schon mehrfach 
überprüft.

Wird dann sicherlich auch in GitHub als ganzes nachvollziehbar sein.

@Michael:

>Ich würde selbst hier
>OV_HREF_PIN & (1 << OV_HREF_PINNR)
>wohl (OV_HREF_PIN & (1 << OV_HREF_PINNR) == (1 << OV_HREF_PINNR))
>schreiben, das liefert definitiv false oder true zurück.
Das finde ich bisher noch am besten.

Wow ist ja eine Menge zusammengekommen diese Woche.
die letzen Posts mit dem Polling muss ich nochmal überdenken und sacken 
lassen. Für die ersten "Shots" sicherlich machbar.

Zu dem Verfahren mit dem Debug-Wire mache ich morgen ein kleines 
Tutorial (Habe ich zurzeit aber nur am UNO zum laufen gebracht, weil es 
erheblich drauf ankommt, wie die Schaltungstechnische Anbindung der 
Reset Leitung ist.
mehr Dazu morgen (bzw. heute).

lg. und danke für die rege Unterstützung.

David

von David D. (saturi)


Lesenswert?

Hier der versprochene Post zum Debug-Wire:

Benötigt:
Hardware:
Arduino UNO, AVR-Dragon
Software IDE:
Atmel-Studio

Der Atmega328P unterstützt das besagte Debug-Wire. Dazu wird mittels des 
AVR-Dragon (oder einem anderen Programmer) der/die/das Fuse DWEN mittels 
ISP Programmierung gesetzt. Vorsicht! Hier besteht jetzt die Gefahr sich 
auszusperren (wie mir erst kürzlich passiert). Das Debug-Wire 
funktioniert nämlich nur, wenn die Reset-Leitung vollkommen frei ist. 
Sprich wenn ich die Fuse gesetzt habe und Debug-Wire nicht funktioniert 
komme ich nicht mehr zurück in den ISP-Modus und muss mit HighVoltage 
Programmierung die Fuse wieder entfernen.

Beim Arduino UNO ist oben auf der Platine eine Kontaktbrücke vorgesehen. 
(Bei mir auf dem SaintSmart Board steht dort Reset ON. Diese brücke kann 
man einfach mit einem kleinen Schraubenzieher wegkratzen. Dann 
funktioniert mit dem UNO das DebugWire problemlos. Bei dem Nano geht das 
nicht ohne weiteres.

hier habe ich eine wie ich finde ausführlich und gut beschriebene 
Anleitung gefunden:

http://www.hilltop-cottage.info/blogs/adam/debugging-arduino-using-debugwire-atmel-studio-and-an-avr-dragon/

Falls danach noch weitere Fragen auftreten sollten einfach melden :)

von Michael U. (amiga)


Lesenswert?

Hallo,

ich bin ja wegen des Thread-Titels hier reingeraten weil ich mir mal 
eine OV7670 mitbestellt hatte und damit rumspielen wollte.
Inzwischen ist mir aber völlig unklar, wohin dieser Thread eigentlich 
ziehlt.
Die Absicht, mit der Kamera an einem Mega328 irgendwie irgendein Bild zu 
bekommen und irgendwie anzuzeigen/zum PC zu übertragen/zu speichern, 
scheint ja völlig unwichtig zu sein.
Die Diskussionen über Programmierstile, StyleGuides, Programmstrukture 
usw. scheinen ja Vorrang zu haben.
Ich habe damit kein Problem, es ist aber nicht der Grund meines 
Interesses.
Ich werde weiter mitlesen, sehe aber im Moment den Sinn der ganzen Übung 
nicht.

Ich bin eigentlich der Typ, der gern das macht, was nicht geht. ;)
Dazu muß das aber (für mich) irgendeinen Sinn und Zweck haben. Ein 
brauchbares "Foto" einer kleinen Kamera mit dem Mega328 zu erstellen, 
irgendwie zu übertragen und dann eben anzeigen wäre ein Zweck.
Das ist aber mit der OV7670 so nicht machbar. Referenz wäre für mich 
immernoch mein Posting zur alten DC3840. Also 640x480 in Farbe als 
Snapshot mit Übertragungszeit um 10-15s. Das hat der Mega32 vor Jahren 
als Webserver hinbekommen. Die OV7670 bietet dazu aber von ihren 
technischen Voraussetzungen keine Möglichkeit. Dazu wäre externer Ram 
nötig, am Mega328 eben SPI-Ram mit mehr als 256kB oder die OV7670 mit 
FIFO drauf.

Ich habe vorhin beim Googeln diesen link gefunden:
http://www.instructables.com/id/OV7670-Arduino-Camera-Sensor-Module-Framecapture-T/
Ich habe spaßhalber mal auf einen Arduino Nano gepackt und sein 
Javaprogramm installiert, extra noch ein 32Bit Jave installiert.
Es läuft soweit, er liest ein 320x240 in s/w aus und schikct es mit 
500kBaud direkt zum PC. Auf dem PC wartet seine Java-Software af einen 
Bildanfang, klebt den passenden BMP-Header dazu und speichert es in 
einen Ordner. Es kommt ca. alle 2-3s ein Bild an. Qualität war 
unbrauchbar, erkennbar, aber Streifen usw. Da gibt es aber einen langen 
Thread bei arduino.cc zu:
https://forum.arduino.cc/index.php?topic=159557.0

Ich habe hier jetzt nur gepostet, weil es ja ursprünglich mal um die 
Kamera am Mega328 ging...

Ich wünsche den Beteiligten natürlich weiterhin viel Erfolg.

Gruß aus berlin
Michael

von Michael U. (amiga)


Lesenswert?

Hallo,

zu DebugWire:

David D. schrieb:
> Beim Arduino UNO ist oben auf der Platine eine Kontaktbrücke vorgesehen.
> (Bei mir auf dem SaintSmart Board steht dort Reset ON. Diese brücke kann
> man einfach mit einem kleinen Schraubenzieher wegkratzen. Dann
> funktioniert mit dem UNO das DebugWire problemlos. Bei dem Nano geht das
> nicht ohne weiteres.

warum sollte ich DebugWire in dieser Kombination benutzen wollen? Weil 
es DebugWire gibt?
Wenn man den UNO wieder automatisch aus der IDE programmieren will muß 
der 100nF aber wieder ran. Beim Nano muß man ihne halt selber suchen 
(bei meinem unter neben dem Elko am Spannungsregler). Bei meiner 
Nano-Version ist auch der PullUp am Reset mit 1k bestückt statt mit 10k 
wie im Schaltplan. Kann sein, daß man den auch noch tauschen müßte.

In der ArduinoIDE kann man auch die Serielle gut genug zum Debug nutzen, 
früher kam bei mir auf die kleinen AVR eben ein SoftUART rauf, der 
konnte nur Ausgaben über einen PIN als TX.
Ein Controller würfelt nicht, der macht genau was man ihm gesagt hat, 
auch wenn es nicht unbedingt das ist, was man sagen wollte und erwartet. 
;)

Egal ob DebugWire oder Debugausgaben über einen UART: in jedem Fall 
verändert man an der Stelle das Timing bis zum Stillstand und kann 
Abhängigkeiten mit externer Hardware kaum sinnvoll erfassen weil die 
davon nichts weiß...

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Hallo Michael,

der Exkurs zum Debugwire kam nur auf Anfrage von Olli und soll in diesem 
Thread hier auch nicht weiter thematisiert werden. Mir hat er bis jetzt 
geholfen, den ein oder anderen Fehler im Code zu identifizieren. Das das 
über eine mögliche Seirielle-Debug Funktionen von der Arduino-IDE aus 
möglich ist mag richtig sein. Damit habe ich noch keine Erfahrungen 
gemacht.

Zum thematischen ausufern gebe ich dir recht. Hier werden soviele 
Informationen zuzsammen getragen, dass es schwer wird, das ganze 
beisammen zuhalten. Daher hoffe ich auf Olli  und sein Github repository 
damit wir da einen gemeinsamen Code-Überblick generieren können und uns 
in diesem Thread wieder auf die tatsächlichen Fortschritte konzentrieren 
können und die kleineren Code-Diskussionen ins GitHub verlagern.

Ich hoffe nicht, dass du das Interesse verlierst, auch wenn es an der 
ein oder anderen Stelle einmal ausufert :)

um das klar zu stellen:

Ziel ist es mit dem OV7670 und dem Atmega328 und im ersten Schritt einem 
PC ein Bild zu erzeugen. Selbst wenn wir auf eine Framerate von 1/min 
kommen :D Hauptsache ein Bild.
Danach setzen wir uns ein neues Ziel

liebe Grüße

David

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> Ziel ist es mit dem OV7670 und dem Atmega328 und im ersten Schritt einem
> PC ein Bild zu erzeugen. Selbst wenn wir auf eine Framerate von 1/min
> kommen :D Hauptsache ein Bild.
> Danach setzen wir uns ein neues Ziel

gut. Mein Problem zur zeit ist: die OV7670 scheint keinen Snapshot-Mode 
zu können. Also ein Bild "belichten" und dann genau dieses Bild aus dem 
Kameraspeicher identisch so oft auszulesen wie man möchte.
Sie scheint generell mit den eingestellten Werten zu grabben und dann 
eben das Bild abzuliefern. Damit wäre beim nächsten auuslesen der 
kameradaten das Bild nicht identisch mit dem vorhergehenden weil sich 
entweder im Bild was bewegt hat oder weil die Toleranzen des Sensors 
immer geringfügig abweichende Pixeldaten erzeugen. Damit wäre 
stückweises übertragen eines Bildes an den PC nicht ohne 
Bildfehler/Streifen/Doppelkonturen möglich.
Die Daten eines Bildes im Stück mit dem kleinen AVR zu übertragen ist 
möglich (siehe mein Link dazu) mit 500kBaud, vermutlich auch mit 1MBaud.
Da hat aber der AVR nur die Aufgabe die Daten der Kamera zu lesen und 
dem UART in die Hand zu dreüken. Es erfordert also auf dem PC eine 
spezielle Software, die die ankommenden Rohdaten in ein nutzbares Format 
packt.
Das macht oben im Link sein Java-Tool. Das ist aber für mich keine 
Option die einen wirklichen Nutzen hat. Ich sehe in der Kombi OV7670 und 
Mega328 im Moment keinen wenigstens theoretich realisierbaren Weg.

Damit lande ich zumindest dabei, daß ich mit dieser Kamera am ESP32 
weiterspiele. Da reicht sowohl der Ram um ein komplettes Bild einzulesen 
und die Rechenleistung um es dann per Webserver o.ä. zu übertragen.
Auch da kommen nur wenige Bilder/s raus, hier ist es aber die 
Kombination aus Kosten für OV7670 und ESP32. Damit kann ich "rumspielen" 
und für mich optimieren.
Reicht dann sicher z.B. als WLAN-Wettercam auf dem Balkon. Hat dann 10€ 
gekostet und ich habe vollen Zugriff auf die Software.
Für eine "richtige" Anwendung könnte ich einen raspi Zero W + seiner Cam 
nehmen. Sind dann eben 30€ und ein paar Skriptgeschichten. Brauche ich 
aber nicht...

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Hallo,

> Es erfordert also auf dem PC eine
>spezielle Software, die die ankommenden Rohdaten in ein nutzbares Format
>packt.
>Das macht oben im Link sein Java-Tool. Das ist aber für mich keine
>Option die einen wirklichen Nutzen hat. Ich sehe in der Kombi OV7670 und
>Mega328 im Moment keinen wenigstens theoretisch realisierbaren Weg.

wie von mir vor den Osterfeiertagen versprochen hatte ich mich da auch 
schon an ein Tool für den PC gemacht, dass die Empfangenen Daten in ein 
Bild umwandeln  soll. Da bin ich auch schon gut vorwärts gekommen. Da 
warte ich jetzt nur noch darauf, dass wir uns für ein 
"Übertragungsprotokoll" einigen, damit ich das dann auch Verwende. Löst 
die angesprochene Speicherkapazität nicht. Aber für einen ersten Shot 
würde ich mich auch mit Bildfehlern oder Doppelkonturen zufrieden geben.

liebe Grüße

David

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> wie von mir vor den Osterfeiertagen versprochen hatte ich mich da auch
> schon an ein Tool für den PC gemacht, dass die Empfangenen Daten in ein
> Bild umwandeln  soll. Da bin ich auch schon gut vorwärts gekommen. Da
> warte ich jetzt nur noch darauf, dass wir uns für ein
> "Übertragungsprotokoll" einigen, damit ich das dann auch Verwende. Löst
> die angesprochene Speicherkapazität nicht. Aber für einen ersten Shot
> würde ich mich auch mit Bildfehlern oder Doppelkonturen zufrieden geben.

und warum nicht "erstmal testen"? Ein festes Startzeichen asu wenigen 
Buchstaben und dann die Daten der Kamera hinterher. ComputerNerd hat RDY 
genommen. ;)
Die Anzahl Bytes pro zeile und die Anzahl Zeilen pro Bild stehen ja 
ohnehin mit dem Setzen der Cam auf eine Auflösung und ein Format fest, 
man kann also die ankommenden Bytes einfach mitzählen.
Da ich bei meinem LogicAnalyer vor Jahren die Daten des externen 32k Ram 
am AVR auch so übertragen habe weiß ich, daß es prinzipiell kein Problem 
mit 500000 Baud und den gängigen USB-Wandlern gibt. Auch FTDI, CP2102 
und CH340 können die auf den Arduinos.
Das Startzeichen sollte nur so sein, daß es in den Daten nicht oder nur 
sehr selten vorkommt, sonst bekommt der Empfänger Prpbleme den nächsten 
Bildanfang sicher zu erkennen. Klappt praktisch aber mit seinem RDY 
problemlos.
Die Beschaäftigung, die Kameraregister so zu setzen, daß möglichst ein 
erkennbares Bild dabei rauskommt, bleibt ohnehin. Normalerweise findet 
man dazu Application-Hinweise des Herstellers oder eben Beispiel von 
Leuten, die es schonmal geschafft haben.
Das kann etwas an Zeit kosten.

Die Senderoutime auf dem AVR ähnelt meiner damaligen weil sie eben nur 
aus Warten auf VSYNC, warten auf HSYNC und dann bei jedem PCLK Byte8s) 
holen und in den UART packen.
Das ist Beschäftigung für einen Nachmittag bis es prinzipiell läuft und 
Zeit für das Debug auf PC-Seite. Das hat mich damals einige Zeit 
gekosten (noch in VB6), weil die COM durchaus nicht meiner Meinung war 
was Empfangsbuffergröße usw. anging...

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> Trotzdem sehe ich die ISR-Routine nicht auf dem Oszi.

Kleine Bitte:

Könntest Du, David, den o.g. Code hier einmal vollständig als Anhang 
einstellen? Zumindest so lang, bis Olli GitHub am Laufen hat?

Ich verstehe nämlich nach wie vor nicht, warum Dein Oszi nichts anzeigt.
Hast Du die von mir vorgeschlagenen Codeänderungen einmal ausprobiert?

Viele Grüße

Andreas

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Hallo Andreas,
wie gewünscht der Code. Ich habe gerade deine Code-Änderungen noch 
eingefügt und getestet (Also die mit der Bit-Abfrage, nicht das Polling) 
leider keine Änderungen.

Im Anhang ist das ganze Projekt.
interessieren muss dich aber nur die main, OV7670 und evtl. die Uart, 
wobei die da eigentlich nicht mitmischen sollte.

lg.

David

von Michael U. (amiga)


Lesenswert?

Hallo,

ich habe mir gerade mal den Spaß gemacht das Archiv zu entpacken und die 
nötigen Dateien in die ArduinoIDE zu werfen.
Compiler läuft durch, der Nano meldet sich.
unschön: ich habe auf die Schnelle keinen Hinweis oder Kommentar 
gefunden, der mir die aktuell eingestellte Bausrate ohne Suchen verraten 
hätte.
Der Kommentar in der UART.cpp bei UBRR0L ist recht witzlos weil ich da 
erst einen umrechnen muß und die Bits dazu raussuchen...
ok, sind 38400, der Nano meldet sich.
Fehler beim Versuch mit der Kamera zu reden?
Oh, TWI sind nur Dummys...
In OV7670.c geschaut.
void OV_SCCB_Init (void)
Nanu? Da werden I2C-Clock und I2C-Data hart auf Ausgang und H gesetzt???
I2C/TWI darf NIE einen festen H-Pegel auf den Leitungen haben, der Slave 
darf diese JEDERZEIT auf aktiv L ziehen und das ist dann unlustig für 
die Treiber der Beteiligten! I2C muß IMMER ein openDrain-Ausgang sein.
Ich habe hier erstmal abgebrochen, AVR und vermutlich auch die Kamera 
sind im Allgemeinen zwar "hart im Nehmen", aber quälen muß ich die Clock 
und Data-Leitungen nun auch nicht unbedingt...

Ich vermisse auch eine Komentarübersicht, welche Pins der Kamera auf 
welchen Portpins sind. Ein Vergleichen der Anschlüsse ist so mehr als 
mühsam. Als Liste brauchte ich nur rüberzugehen um zu sehen, daß ich 
vielleicht HSYNC auf einem anderen Pin habe und dann entweder 
umzustecken oder genau diese eine Zuordnung in der OV7670.h zu ändern.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Hallo Michael,

>Nanu? Da werden I2C-Clock und I2C-Data hart auf Ausgang und H gesetzt???
>I2C/TWI darf NIE einen festen H-Pegel auf den Leitungen haben, der Slave
>darf diese JEDERZEIT auf aktiv L ziehen und das ist dann unlustig für
>die Treiber der Beteiligten! I2C muß IMMER ein openDrain-Ausgang sein.

Das scheine ich dann immernoch nicht verstanden zu haben... das mit dem 
openDrain. Da muss ich wohl nochmal in die Lektüre.

Kommentare sind es definitiv zu wenig, da gebe ich dir ohne weiteres 
recht. der Code war auch (noch) nicht für die Öffentlichkeit bestimmt.

lg.
David

PS: die Anschlüsse müssten aber so wie viel weiter oben mit Olli 
festgelegt, sein. (nur Pin 13 und evtl. die PCLK liegen an einem 
anderen)

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> Kommentare sind es definitiv zu wenig, da gebe ich dir ohne weiteres
> recht. der Code war auch (noch) nicht für die Öffentlichkeit bestimmt.

das ist eine Fehleinschätzung. Kommentare müssen erstmal helfen, den 
eigenen Kram jederzeit zu verstehen. "Jederzeit" heißt auch, wenn man es 
aus 5 Jahren mal wieder anfasst.
Ich habe es mir zur Gewohnheit gemacht, in Stichpunkten sofort zu 
kommentieren wenn eine Funktion o.ä. erstmal irgendwie läuft.
Solche Sachen fäßt man nur selten nochmal an und dann bleiben sie 
unkommentiert.

>
> PS: die Anschlüsse müssten aber so wie viel weiter oben mit Olli
> festgelegt, sein. (nur Pin 13 und evtl. die PCLK liegen an einem
> anderen)
Wenn es sich jetzt ergibt, daß jemand, so wie ich jetzt, mal mittesten 
will oder in den Code schauen will, muß er mit dem Archiv klarkommen, 
wie es ist.
Ich nehme also den Mega328, die Kamera und will es mal schnell zusammen 
bauen. Ich lade mir oft Sourcearchive aus dem Internet wenn jemand eine 
Komponente nutzt, mit der ich gerade rumbastel. Wenn das aus irgendeinen 
Forum stammt, sieht es (leider) öfter ähnlich Deinem aus.

PS: das sollen alles nur Hinweise und Vorschläge sein und vielleicht 
auch ein wenig (20 jahre?) Hobby-Erfahrung dazu und die Erkenntnis, daß 
ich alte AVR-ASM-Sourcen von vor einigen Jahren auch nur mit Mühe wieder 
verstehe weil zuwenig oder die falschen Sachen kommentiert...

Als trost für Dich: meine ASM-Source von 2000 macht I2C auf einem 
90S8515 (Vorgänger des Mega8515) macht auch genau das falsch und spielte 
trotzdem.
Zumindest zusammen mit dem benutzten I2C-Slave (MAS3507D)...

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> Hallo Michael,
>
>>Nanu? Da werden I2C-Clock und I2C-Data hart auf Ausgang und H gesetzt???
>>I2C/TWI darf NIE einen festen H-Pegel auf den Leitungen haben, der Slave
>>darf diese JEDERZEIT auf aktiv L ziehen und das ist dann unlustig für
>>die Treiber der Beteiligten! I2C muß IMMER ein openDrain-Ausgang sein.
>
> Das scheine ich dann immernoch nicht verstanden zu haben... das mit dem
> openDrain. Da muss ich wohl nochmal in die Lektüre.

Hier schön kurz und einfach erklärt (mit Schalter-Analogie):
Beitrag "Re: Open-Drain/Open-Source-Verständnis"

Oder hier ganz ausführlich:
https://www.elektronik-kompendium.de/sites/slt/1206121.htm

Oder natürlich Wikipedia:
https://de.wikipedia.org/wiki/Open-Collector-Ausgang

>
> Kommentare sind es definitiv zu wenig, da gebe ich dir ohne weiteres
> recht. der Code war auch (noch) nicht für die Öffentlichkeit bestimmt.

Es wäre jetzt etwas gemein, wenn ich zunächst laut nach dem Code
schreie, Du ihn widerwillig rausgibst (weil Du weißt, dass er noch
nicht allgemeinverständlich dokumentiert ist) und ich mich
anschließend über die schlechte Dokulage beklage ...

Ich sitze daher mit zusammengepressten Lippen auf meinem Stühlchen :-)

Allgemein stimme ich Michael zu: was man nicht sofort dokumentiert,
wird meist nie dokumentiert. Und was nicht dokumentiert ist, das
durchschaust Du bereits nach wenigen Wochen (bei mir: nach wenigen
Tagen) nicht mehr.

Im gleichen Atemzug muss ich allerdings auch zugeben, dass mein 
persönlicher, innerer Doku-Schweinehund mir auch so manchen Streich 
spielt und ich daher Null Legitimation habe, den mahnenden Zeigefinger 
zu heben ...

> PS: die Anschlüsse müssten aber so wie viel weiter oben mit Olli
> festgelegt, sein. (nur Pin 13 und evtl. die PCLK liegen an einem
> anderen)

Es wäre sehr nett, wenn Du die exakte PIN-Belegung/Verschaltung bitte 
noch nachreichen könntest. Für Dich ist das sicherlich ein Klacks, für 
einen
hilflosen Code-Reviewer ist Re-Engineering von PIN-Belegungen immer eine 
Strafarbeit ...

Ach ja: und schreibe bitte nochmals, welches Board (Arduino Nano?) und 
welche IDE (Atmel Studio, in welcher Version?) Du benutzt.

Viele Grüße

Igel1

: Bearbeitet durch User
von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Huhu,

Ja... ihr habt ja recht :D ich gelobe Besserung.
Das mit der nachträglichen einfügen der Kommentare habe ich auch bei mir 
schon festgestellt, dass ich es nicht immer beibehalte...


Atmelstudio 7 (Version 7.0.1417)
zur xCLK Erzeugung nutze ich einen Arduino Nano an dem ich die CLK Out 
fuse gesetzt habe und daher an D8 ca. 16Mhz anliegen. (controller2 im 
Schaltplan)

ansonsten nutze ich für den Controller1 das Arduino UNO Board 
(abweichend vom Schaltplan), dass aber ja die gleichen Pins (zumindest 
die von mir genutzten) nach außen geführt hat wie der Nano. (der Grund 
ist einfach die Debugging Möglichkeit, mit der ich nur Erfahrungen auf 
dem UNO habe)
Allerdings sollte das Board einfach austauschbar sein.

lg.

David

Ps. Danke für die Links, die werde ich mir heute Abend direkt anschauen 
:)

von Olli Z. (z80freak)


Lesenswert?

Michael, in einigen Posts zuvor hast Du noch gemeint das wir uns zuviel 
um Konventionen scheren, als zu coden... und jetzt wird klar als 
unfertig, unoffziell, gehackter Code diskutiert. Hmmm... so ganz komm 
ich da jetzt nicht mehr mit.

Lasst uns doch kurz die Konventionen zuende bringen und gut. Dazu gehört 
neben einem Schaltplan, den bisherigen Erkenntnissen, natürlich auch ein 
Definitions-file und selbstverständlich auch sinnvolle Kommentarierung.

Zum Schaltplan:
Ich hatte auch schonmal einen in Eagle begonnen. Musste mir dafür ein 
OV7670 Item anlegen, weil ich keins fand. Grundsätzlich gehört der Plan 
im Quellformat, als PDF und Bild ins Reprository.

Zur Takterzeugung:
Einen zweiten Arduino würde ich nicht nehmen für den Takt, außer es 
besteht hier jemand auf 16 MHZ und nicht den 8 MHZ, die man auch ganz 
ohne Fuse-Tricks erzeugen kann. Hier würde ich den Hinweis mit dem CTC 
anstelle PWM nochmal aufgreifen. Für 16 MHz sind wir später beim lesen 
mit dem Mega328 eh viiel zu langsam, also wozu der Stress ;-)

Zur Plattform:
Ich glaube die Puristen sind hier in der Mehrzahl, also würde ich mich 
dem anpassen und „reinen“ AVR-Code programmieren, ganz unabhängig von 
Arduino Libs.

Zum I2C:
Die Arduino Lib „Wire“ berücksichtigt alles genannte (Open Drain, etc.). 
Da wir aber ohne auskommen wollen, könnte man sich eine entsprechende 
Lib für reinen AVR code suchen, oder die Lib portieren. Das wäre was 
fürs Repo :-)

Apropos Repo:
Das Projekt ist öffentlich und jeder darf ziehen: 
https://github.com/igittigitt/ov7670
NOCH steht nix drin. Ich werde aber das was hier als Konvention 
rauskommt dort hinterlegen (z.b. in der Readme oder als Wikiseite).
Ich fang, wenns recht ist, einfach mal damit an eine Struktur zu 
erstellen und die wichtigen Links zu sortieren.

So und jetzt bitte schnell einigen und ran an den Speck! Ich will auch 
mal bald ein Bild sehen ;-)))

Oli...


Diese sollte den Code

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Ich sitze daher mit zusammengepressten Lippen auf meinem Stühlchen :-)

:-)))
naja, ich bin auch alles andere als Vollkommen in der Beziehung, habe 
mir eben genau deshalb recht früh einen eigenen Rahmen gesteckt und 
halte mich daran. Meist... Oft...

Andreas S. schrieb:
> Ach ja: und schreibe bitte nochmals, welches Board (Arduino Nano?) und
> welche IDE (Atmel Studio, in welcher Version?) Du benutzt.

Ich habe seinen Ordner OV7670_Kamera in meinen Sketchordner der 
ArduinoIDE gekippt, nur die main.c in OV7670_Kamera.ino umbenannt. Den 
Nano eingestellt und compiliert und aus der IDE geflasht. Lief 
problemlos durch und meldete sich. Eigentlich aber nur, weil er mit 
#include "OV7670.c die Datei in main.c includioert hat. Ist eigentlich 
falsch, nur die .h wird includiert, die .c werden ja normalerweise 
einzeln vom Compiler bearbeitet und dann nur die Objekt-Files Files vom 
Linker zusammengeknotet.

Ich wollte erst ein AVR-Studio 4 Projekt draus machen, das liegt hier 
noch startbereit, allerdings irritierten mich die .cpp Files.
Wie kommt eigentlich die Namengebeung zustande? Ich habe auf den ersten 
Blick in den .cpp Files nichts C++ typisches gesehen, ist doch reines C?

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Ursprünglich wollte ich da mit Objektorientierung ran... aber das gab 
dann Probleme beim kompilieren, bzw. einfach schon nur bei der 
Verwendung von .cpp files. Warum die main jetzt noch ein .cpp file ist 
und warum es trotzdem Funktioniert kann ich grade nicht mehr beurteilen.

... Ich bereue es immer mehr das Projekt hochgeladen zu haben :D :D :D 
... nein.. immerhin lerne ich dadurch, dass mir andere meine Fehler 
aufzeigen.

das mit dem include des c-Files nicht richtig ist, wieso das noch dadrin 
steht weiß ich grade auch nicht mehr.... hust hätte ich das mal besser 
kommentiert hust

war vermutlich nur ein Test weil er die Header Datei nicht erkannt hat 
oder sonst was... Das hat mir - auch wenn es falsch ist - über 
Fehlermeldungen hinweggeholfen, an denen man aber sicher nochmal 
ansetzten müsste

@ olli
sehr gerne, ich brenne auch schon förmlich. Es freut mich das du mit auf 
die Amtel Ebene kommst :)

liebe Grüße

David

von Olli Z. (z80freak)


Lesenswert?

Michael, wie wärs wenn Du uns mal ein sauberes GERÜST zusammenstellst. 
Verzeichnisstruktur und leere Files. Gern auch schon das .h File mit den 
defines oder zumindest der Idee davon um die ganzen Parameter zu setzen.

Ich plag mich in der Zwischenzeit mit der Installation von AVR Studio 7 
rum...

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,
da sind sie wieder, meine 3 Probleme... ;)

Ich kann es mal nach meiner Ansicht versuchen. "meine Ansicht" deshalb, 
weil:
ich kann weder C noch C++ wirklich. Grundlagen habe ich mir 
projektabhängig über die letzten Jahre zusammengesucht, C++ 
bekanntschaft erst durch die Arduino-Geschichte.
Es war und ist nur Hobby, vom Z80 über 6510 zu den ersten AVR usw. Alles 
in Assembler. C kam als Notwendigkeit weil mein Anfang einen TCP-Stack 
in ASM zu schreiben zwar durchaus gangbar war (IP ging, TCP ging, ARP 
ging ICMP-Ping ging grundsätzlich. Alles nur, weil der ENC28J60 Ethernet 
Chip bezahlbar beschaffbar war und LAN am AVR.. Super!

Dann kam U.Radig mit seinem Webserver daher und ich stand vor der 
Entscheidung, meins weitermachen oder mich in C einzulesen und seine 
Software an meine Wünsche anzupassen. Ich habe mich für seine Software 
entschieden...
Entscheidend dafür war, daß ich auf Grund meiner eigenen Basteile TCP/IP 
usw. ausreichend verstand, um recht zielsicher die C-Funktionen in 
seiner Software zuordnen zu können und auch (nach und nach) zu 
verstehen.

Das schreibe ich an David D, ich finde es gut, den Dingen weit auf den 
Grund zu gehen. Von mir kenne ich aber auch, daß es oft besser ist, 
Teile zu nutzen, die andere Funktionsfähih schon gemacht haben und sich 
auf bestimmte Sachen zu konzentrieren, die eben noch nicht wunschgemäß 
verfügbar sind.
Ds Risiko, das ein Projekt auf der Strecke bleibt, weil fehlende 
Erfolgserlebnisse und steigender Zeitaufwand eben keinen Spaß mehr 
machen, ist recht hoch.

PS: Es ist zwar etwas riskant, solchen Source in ein Forum zu packen, 
weil der generelle Verriß da dicht daneben steht. Bisher hat man uns ja 
in diesem Thread in der Beziehung in Ruhe gelassen. Ich hoffe mal, das 
bleibt auch so.

Ich habe mit dem Stand des Codes kein Problem, es ist eben schwer, im 
Internet die Vorkenntnisse usw. des Gegenüber einzuschätzen.

Also: David D... Augen zu und durch und nicht die Lust verlieren, das 
wird schon.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb:
> Nanu? Da werden I2C-Clock und I2C-Data hart auf Ausgang und H gesetzt??

Respekt, Respekt: scharfes Auge, Michael !!

> I2C/TWI darf NIE einen festen H-Pegel auf den Leitungen haben, der Slave
> darf diese JEDERZEIT auf aktiv L ziehen und das ist dann unlustig für
> die Treiber der Beteiligten!

Hmmm - schon erstaunlich, dass bislang weder Kamera noch Arduino Nano 
gehimmelt wurden.

Eventuell hat Dich der Levelshifter irgendwie gerettet.
Welchen Typ/Bauteil verwendest Du genau?

Verwendest Du einen I2C Level-Shifter oder einen Feld-Wald-Wiesentyp?

Viele Grüße

Igel1

von David D. (saturi)


Lesenswert?

Einen Feld-Wald-Wiesentyp...

Ich bin leider heute doch nicht mehr dazu gekommen, mir die Links 
anzuschauen. Das werde ich morgen nachholen.

Ich habe eben durch absoluten Zufall noch eine schöne 
Erklärung/Anleitung zur Programmierung des AVR mit C gefunden, wo einige 
Sachen drin standen, die ich auch noch nicht kannte.

http://www.ulrichradig.de/home/uploads/images/Daten_Infos_Anleitungen/AtmelCprogramming.pdf

(insbesondere die "AVR/common" lib. Die macht den Umstieg von Arduino 
auf AtmelStudio vermutlich nicht ganz so hart.

Olli hat auf der genannten GitHub Seite schon angefangen die 
Informationen zusammenzutragen. Da gibt es echt tolle Möglichkeiten, das 
ganze strukturierter und themenbezogener zu diskutieren, weshalb ich da 
hier nochmal für Werbung machen wollte :)

Mich hat es auch am Anfang erschlagen, aber mit ein bisschen 
ausprobieren kriegt man das schon schnell raus :) Also nur Mut.

https://github.com/igittigitt/ov7670

lg.

David

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
>> Nanu? Da werden I2C-Clock und I2C-Data hart auf Ausgang und H gesetzt??
>
> Respekt, Respekt: scharfes Auge, Michael !!

ich hatte ja oben extra in Stichpunkten geschrieben, was ich gemacht 
habe.
Ich krame gern und oft in fremden Source, man lernt immer wieder 
irgendwas oder erkennt eigene Fehler.

>> I2C/TWI darf NIE einen festen H-Pegel auf den Leitungen haben, der Slave
>> darf diese JEDERZEIT auf aktiv L ziehen und das ist dann unlustig für
>> die Treiber der Beteiligten!
>
> Hmmm - schon erstaunlich, dass bislang weder Kamera noch Arduino Nano
> gehimmelt wurden.

Die ICs sind meist härter im nehmen als man meint. Es ist ja erstmal ein 
thermisches Problem für die Ausgangstreiber. Es ist ja auch oft kein 
statischer Zustand sondern nur zeitweise Impulse und je nach I2C-Slave 
und dessen internem Verhalten muß es nichtmal passieren, daß das 
Gegenstück in der Zeit auf Low zieht.

Beim AVR macht man es bei I2C zu Fuß so, daß man über DDR die Pegel 
setzt.
SDA und SCL als Init Port auf Low, dann auf Eingang. Der externe PullUp 
setzt jetzt den H-Pegel. Für L an SDA/SCl setzt man das Pin im DDR auf 
1, damit ist der AVR Pin Ausgang Low. Für H am Ausgang eben DDR-Bit 
wieder auf 0 -> Eingang. Ist nach außen dann wie ein OpenDrain.
Allerdings würde ich, wenn vorhanden, immer die TWI-Hardware nehmen. Die 
Abfragerei der Zustände, ACK und NACK, Start- Stopcondition sind zwar 
simple Abläufe, nur warum soll ich das machen, wenn das schon in die 
Hardware gegossen ist.

David D. schrieb:
> Ich habe eben durch absoluten Zufall noch eine schöne
> Erklärung/Anleitung zur Programmierung des AVR mit C gefunden, wo einige
> Sachen drin standen, die ich auch noch nicht kannte.
>
> 
http://www.ulrichradig.de/home/uploads/images/Daten_Infos_Anleitungen/AtmelCprogramming.pdf

Ulrich Radig... hatte ich oben schon im Zusammenhang mit meiner alten 
Kamera und dem Webserver erwähnt. Müßte so um 2010 gewesen sein.
Auch U.Radig hat mich in der Webserver-Source mal geschafft. Alles recht 
brauchbar kommentiert. Dann habe ich eine Pin-Zuordnung o.ä. geändert 
und nichts ging mehr. Irgendwo ganz weit unten in einer Funktion hatte 
er nicht seine Definition benutzt sondern das Register mit PORTB = 0x23 
oder so gesetzt. Sowas war für mich immer Hinweis, in eigenen Sachen 
immer auf solche Kelinigkeiten zu achten, Änderungen sofort in allen 
Teilen sauber anzupassen solange man eben noch direkt den Kram im Kopf 
hat.
Von ihm stammt ja auch die Idee und Realisierung, die DC3840 auf einem 
AVR bei 921kBaud auslesen zu können.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Mahlzeit,

>Ulrich Radig... hatte ich oben schon im Zusammenhang mit meiner alten
>Kamera und dem Webserver erwähnt.

uups... entschuldige bitte.

Ich habe jetzt einmal angefangen das TWI über das AVR-Interface zu 
programmieren. Diesmal habe ich mir alle Mühe gemacht, es sauber zu 
kommentieren :D Allerdings habe ich noch keine Erfahrung mit der 
Zusammenarbeit beim Coden mit Anderen Teilnehmern gemacht, weshalb ich 
euch fragen würde, ob es von der Kommentier Weise, -Umfang ausreichend 
ist.

lg. David

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> uups... entschuldige bitte.

wofür entschuldigst Du Dich? Ich war nur zu faul im Thread hier die 
Stelle zu suchen...

Ich schaue nachher mal rein, wenn ich dazu komme. Habe es mal von gitHub 
runtergeladen.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
>
> Ich habe jetzt einmal angefangen das TWI über das AVR-Interface zu
> programmieren. Diesmal habe ich mir alle Mühe gemacht, es sauber zu
> kommentieren :D Allerdings habe ich noch keine Erfahrung mit der
> Zusammenarbeit beim Coden mit Anderen Teilnehmern gemacht, weshalb ich
> euch fragen würde, ob es von der Kommentier Weise, -Umfang ausreichend
> ist.
>

Sieht sehr hübsch aus und ich finde die Kommentierung sehr gut.

Zu Deiner Frage im Code:
1
//check if Acknowledge Bit is send by slave
2
if((TWSR & 0xF8) != TW_MT_SLA_ACK) //QUESTION: why do we MASK this with 0xF8 and not with TW_MT_SLA_ACK?

Laut util/twi.h gilt:
1
#define   TW_MT_SLA_ACK   0x18

Guckst Du Datenblatt "26.9.2.  TWI Status Register", so steht da:
"Note that the value read from TWSR contains both the 5-bit status value
and the 2-bit prescaler value. The application designer should mask the 
prescaler bits to zero when checking the Status bits. This makes status 
checking independent of prescaler setting."

Will sagen: mit 0xF8 blendest Du die Bits aus, die nicht zur 
Status-Anzeige (TWS[7:3]) gehören und mit "!= TW_MT_SLA_ACK" prüfst Du 
halt, ob TWS[7:3] genau Deinen gewünschten Wert enthalten - alles andere 
ist ein Fehler.

So wäre z.B. auch die Bitfolge "IIII I000" ein Fehler und würde mit o.g. 
Code als solcher erkannt. Würdest Du statt mit 0xF8 mit TW_MT_SLA_ACK 
maskieren, so würdest Du aus der o.g. Bitfolge "000I I000" machen, was 
keine Fehler wäre. Das wiederum wäre ein Fehler :-)

In Summe halte ich die ganze ACK-Prüfung allerdings für falsch, weil 
sich genau in diesem Punkt das SCCB-Protokoll vom I2C-Protokoll 
unterscheidet.
Daran sind schon sehr viele gescheitert ...

Hier lesen:
https://e2e.ti.com/support/dsp/davinci_digital_media_processors/f/99/t/120548

Und die SCCB-Spec lesen - siehe meine Links weiter oben.

Und hier direkt die nächste Stolperfalle, die zu beachten ist und die 
mich seinerzeit viel Zeit gekostet hat:
https://e2e.ti.com/support/embedded/linux/f/354/p/171390/862562#862562


Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

ich bin gestern nicht dazu gekommen reinzuschauen.

Ich muß auch erstmal genauer in SCCB usw. reinschauen.
Andreas S. schrieb:
> In Summe halte ich die ganze ACK-Prüfung allerdings für falsch, weil
> sich genau in diesem Punkt das SCCB-Protokoll vom I2C-Protokoll
> unterscheidet.
> Daran sind schon sehr viele gescheitert ...

Das sehe ich insofern als Problem an, weil man (auch ich) ja 
Datenblätter in bestimmten Details erst liest, wenn was klemmt.
Die Entscheidung, ob man ein ACK oder NACK erwartet, wenn man ein Byte 
liest oder ob man AC/NACH schickt wenn man Daten empfängt usw, wann man 
Start oder Stop setzt usw. passiert ja eigentlich ohnehin abhängig von 
den Wünschen eines Slaves. Ein Problem, die TWI-Hardware des AVR zu 
nutzen sehe ich im Moment nicht so richtig. Das Statusregister muß man 
ja ohnehin sinnvoll auswerten und wenn ACH/NACh mich nicht interessieren 
oder ungültig sein können, dann ignoriere ich das Flag eben 
entsprechend.

In der einzigen Source, die ich mit der OV7670 am ESP32 real kurz in 
Betrieb hatte und die auch lief, benutzt der Programmierer auch die 
existierende TWI-Lib. Allerdings auf unterster Ebene, um den Rest 
kümmert er sich selbst.
Muß ich mir aber eben alles nochmal zu Gemüte führen.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Hallo Igel,
hallo Michael,

vielen Dank!
Das mit dem Maskieren mit 0xF8 habe ich im Nachgang auch gelesen und 
verstanden.

von Michael:
>Ein Problem, die TWI-Hardware des AVR zu
>nutzen sehe ich im Moment nicht so richtig.

Ich glaube Igel1 hat sich mit dem ACK-Flag nur auf meinen Code bezogen.
Die Überprüfung habe ich nämlich eben zunächst erst einmal von der 
genannten Quelle übernommen. Im Nachgang werde ich jetzt noch prüfen 
müssen, ob diese Flags mit dem SCCB überhaupt decken. Vermutlich wie 
Igel ansprach eben nicht.

Aber da bin ich gerade dran. Ich möchte das TWI-File so aufbauen, dass 
ich es nach Möglichkeit immer nutzen kann, auch für kommende Projekte, 
die eventuell nicht auf SCCB-Weise funktionieren. Meine Vorstellung wäre 
da zum Beispiel über die initialisieren Funktion Parameter mitzugeben, 
bspw. ob Ack gesendet wird oder nicht.
Haltet ihr das für machbar (im ertragbaren Rahmen).
Und würdet ihr das TWI direkt über Interrupts machen oder erst den 
"normalen" weg?

lg. David

PS: OpenDrain habe ich jetzt auch endlich mal gerafft. Ist ja eigentlich 
relative einfach :D ... Sobald man verstanden hat, dass man über einen 
Eingangs-Pin indirekt den Leitungspegel beeinflussen kann.

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> Aber da bin ich gerade dran. Ich möchte das TWI-File so aufbauen, dass
> ich es nach Möglichkeit immer nutzen kann, auch für kommende Projekte,
> die eventuell nicht auf SCCB-Weise funktionieren. Meine Vorstellung wäre
> da zum Beispiel über die initialisieren Funktion Parameter mitzugeben,
> bspw. ob Ack gesendet wird oder nicht.
> Haltet ihr das für machbar (im ertragbaren Rahmen).

Ich selber komme zunehmend weg vom "one code fits all"-Ansatz.
Ich würde mir separate Bibliotheken für SCCB und I2C machen.

Nächstes Thema:

In Punkto ACK/NACK musst Du evtl. ein bißchen aufpassen, ob Du
Deine Hardware mit ACK konfigurierst. Dann könnte es passieren,
dass die Hardware eine gewisse Zeit auf das ACK-Bit wartet und
in dieser Zeit quasi "hängt" (bis zum timeout).

Besser ist es vermutlich, Dein I2C/TWI-Hardwaremodul direkt so
zu konfigurieren, dass es kein ACK erwartet.
Aber hier würde ich den Ansatz "Studieren geht über Probieren" fahren.

> Und würdet ihr das TWI direkt über Interrupts machen oder erst den
> "normalen" weg?

Über den "normalen" Weg - gerade bei der Kamera ist das völlig okay,
denn die wird ja sowieso zuerst konfiguriert und dann erst richtig
genutzt.

Viele Grüße

Igel1

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> PS: OpenDrain habe ich jetzt auch endlich mal gerafft. Ist ja eigentlich
> relative einfach :D ... Sobald man verstanden hat, dass man über einen
> Eingangs-Pin indirekt den Leitungspegel beeinflussen kann.

... das wiederum habe ich nicht verstanden??

Im OpenDrain-Konzept kannst Du nichts über einen Eingangspin 
beeinflussen.
Oder meintest Du den etwas schrägen Workaround, mit dem man im Atmega so 
ein OpenDrain "simuliert"? (by the way: im ARM kann man die I/O Pins in 
einen OpenDrain-Mode setzen und muss dann keine Klimmzüge machen).

Unter'm Strich hast Du halt nur einen Widerstand, der an Vcc 
angeschlossen wird und an dessen unterem Ende Du die 
Collector-Emitter-Strecke (oder die Drain-Source Strecke) beliebig 
vieler Devices gegen Masse anschließt.

Jedes der Devices kann dann das Potential an diesem unteren Ende des 
Widerstandes gegen Masse ziehen.

By the way: SCCB ist laut Datenblatt auch elektrisch kein I2C-Bus,
siehe SCCB-Spec hier: 
http://www4.cs.umanitoba.ca/~jacky/Teaching/Courses/74.795-LocalVision/ReadingList/ov-sccb.pdf
Dort: Figure 22, Figure 23 und Figure 24.
Dort wird der Bus aktiv getrieben (mit push-pull Schaltungen am Ausgang 
von Master UND Slave).

Um das Schlimmste zu vermeiden, gibt es einen "conflict-protection 
resistor", der evtl. auch des Rätsels Lösung dafür sein könnte, dass Du 
in Deiner ursprünglichen Beschaltung weder OV7670 noch AVR gegrillt 
hast. Ich vermute, dieser conflict-protection resistor steckt irgendwo 
auf dem OV7670 board.

Nevertheless - man kann SCCB mit I2C-Treibern bedienen, das haben schon 
viele Leute in der Praxis bewiesen. Aber 100% Spec-konform ist es meiner 
Meinung nach nicht.

Viele Grüße

Igel1

: Bearbeitet durch User
von David D. (saturi)


Lesenswert?

Andreas S. schrieb:
> Im OpenDrain-Konzept kannst Du nichts über einen Eingangspin
> beeinflussen.
> Oder meintest Du den etwas schrägen Workaround, mit dem man im Atmega so
> ein OpenDrain "simuliert"? (by the way: im ARM kann man die I/O Pins in
> einen OpenDrain-Mode setzen und muss dann keine Klimmzüge machen).

Okay? vielleicht habe ich es dann doch nicht verstanden?
Der Punkt ist doch, dass der High-Pegel durch den Pull-Up und nicht 
durch den Ausgang des Controllers entsteht.
Um das zu erreichen bleibt mir doch nur, den Pin des Controllers auf 
Eingang zu schalten (hohe Impedanz am Pin).

Habe meine Erkenntnisse heute morgen hier mal zusammengefasst:
https://github.com/igittigitt/ov7670/wiki/unsorted

wenn das falsch ist, bitte unbedingt bescheid geben. Dann muss ich das 
wieder löschen oder korrigieren.

lg.
David

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Um das Schlimmste zu vermeiden, gibt es einen "conflict-protection
> resistor", der evtl. auch des Rätsels Lösung dafür sein könnte, dass Du
> in Deiner ursprünglichen Beschaltung weder OV7670 noch AVR gegrillt
> hast. Ich vermute, dieser conflict-protection resistor steckt irgendwo
> auf dem OV7670 board.

Ich müßte mein Modul mal genauer mit der Lupe begutachten.

> Nevertheless - man kann SCCB mit I2C-Treibern bedienen, das haben schon
> viele Leute in der Praxis bewiesen. Aber 100% Spec-konform ist es meiner
> Meinung nach nicht.

Auf den Ausgangsüunkt des Threads bezogen hat das jetzt eine Art 
"logistisches" Problem: man sollte für den SCCB tatsächlich spezielle 
Routinen schreiben, das wäre sauber. Man kann die Kamera auch insofern 
nicht als I2C-Device betrachten, weil man sie nicht mit anderen 
i2C-Slaves an diesem Bus zusammen betreiben kann.

Problem ist, daß man sich darüber klar sein sollte, daß man das dann 
speziell für diese Kamera und  ähnliche Kamera-ICs macht. Je nach 
späteren Absichten kommt man damit vielleicht nie wieder in Berührung.
Ich habe sowas früher öfter für irgendwelche UKW/rundfunk-ICs gemacht, 
die PLLs dort hatten immer irgendwelche eigenen seltsamen Protokolle.
Sowas habe ich allerdings dann immer sehr direkt und hart gecodet mit 
Pingewackel usw. Das hat bei mir auch nie einen universellen Überbau 
bekommen weil es nicht sinnvoll allgemein nutzbar war.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> Okay? vielleicht habe ich es dann doch nicht verstanden?
> Der Punkt ist doch, dass der High-Pegel durch den Pull-Up und nicht
> durch den Ausgang des Controllers entsteht.
> Um das zu erreichen bleibt mir doch nur, den Pin des Controllers auf
> Eingang zu schalten (hohe Impedanz am Pin).
>
> Habe meine Erkenntnisse heute morgen hier mal zusammengefasst:
> https://github.com/igittigitt/ov7670/wiki/unsorted
>
> wenn das falsch ist, bitte unbedingt bescheid geben. Dann muss ich das
> wieder löschen oder korrigieren.

Nein, Entwarnung: Du hast alles richtig verstanden und Dein 
github-Dokument beschreibt es ebenfalls richtig.

Evtl. möchtest Du noch erwähnen, das ein solcher I2C-Bus niemals aktiv 
auf hight geschaltet werden sollte, weil sonst die hier 
(http://www4.cs.umanitoba.ca/~jacky/Teaching/Courses/74.795-LocalVision/ReadingList/ov-sccb.pdf) 
in Figur 24 erwähnte Konstellation auftritt - allerdings ohne den dort 
eingezeichneten Widerstand ...

Viele Grüße

Igel1

von Andreas S. (igel1)


Lesenswert?

Gibt's schon Neues aus Forschung und Technik?

von David D. (saturi)


Lesenswert?

Hallo zusammen,

entschuldigt bitte die rare Informationspolitik meinerseits.
Dadurch, dass wir es ja jetzt über das TWI-Interface des AVR gehen 
wollen, stehe ich quasi wieder am Anfang und versuche mit dem SCCB zu 
kommunizieren ;-) senden funktioniert soweit auch schon, jetzt bin ich 
grade an der Read-Funktion.
War aber das ganze Wochenende, sowie die kommende Woche komplett zu 
geplant, sodass es von meiner Seite aus erst frühestens am Sonntag Abend 
neue Erkenntnisse gibt.

aktuellen Stand habe ich grade auf das TWI-branch gepushed. kann man 
sich also in Github anschauen.

Ich nehme auch gerne Vorschläge entegen :) grade habe ich einfachmal die 
Kontrolle des ACK-Bits übersprungen.

lg.
David

von Michael U. (amiga)


Lesenswert?

Hallo,

ich habe mir das mal von github geholt.
Ich werde einfach mal Deine TWI-Sachen kopieren und eine "echte" 
SCCB-Version in der ArduinoIDE machen  und für mich speziell auf dem 
ESP32 testen.
Dann kann ich das erstmal ohne Änderungen für den Arduino Nano (Mega328) 
oder eben den ESP32 compilieren.
Außerdem kann ich dann am Mega328 auch Deine version und meine zusammen 
mit Kamera und logicAnalyzer vergleichen, falls die Kamera nicht 
erwartungsgemäß antwortet.

Die pinMode()/digitalWrite()/digitalRead() der ArduinoIDE dann duch die 
Port/Pin-Zugriffe des AVR zu replacen ist ja keine wirkliche Arbeit.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

Hi David, (und Michael),

@David: Danke für das Lebenszeichen - dann wissen wir, dass es hier in 
ca. 2 Wochen weitergeht (es sei denn Olli bekommt Lust, den Stier bei 
den Hörnern zu packen ...).

Ansonsten: kein Problem - in diesem Thread sind wir ja alle nur 
Hobbyisten und haben Zeit.

Ich selber bin eh nur "Zaungast" bei Euch, denn mein OV7670 läuft an 
einem STM32F429 - ARM-Prozessor, der das Einlesen quasi "nebenbei" mit 
seiner Peripherie macht. Da will man nicht mehr zurück zum AVR - sorry.

Daumen hoch aber für Michael, der sich hier so engagiert einbringt.
Ich habe hier ebenfalls einen ESP32 rumliegen und bislang noch nichts 
damit gemacht (keine Zeit). Kannst Du mir ein netterweise paar Tipps zur 
Einarbeitung geben? (okay, ist etwas off-topic, aber ein paar 
Stichpunkte wären einfach gut: IDE? Gute Einstiegs-URL's, was muss man 
unbedingt lesen, ...)

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Ich habe hier ebenfalls einen ESP32 rumliegen und bislang noch nichts
> damit gemacht (keine Zeit). Kannst Du mir ein netterweise paar Tipps zur
> Einarbeitung geben? (okay, ist etwas off-topic, aber ein paar
> Stichpunkte wären einfach gut: IDE? Gute Einstiegs-URL's, was muss man
> unbedingt lesen, ...)

ein wunder Punkt... Ich hatte bei Erscheinen mir ziemlich schnell damals 
ESP6266 gekauft. Die vorgefertige ID in einer VM (so von Espressif 
damals bereitgestellt) auf den Rechner geworfen und grrr... nichts ging, 
nichts klappte, Doku zu den ESP in gutem Chinesich oder lustigem aber 
unbrauchbarem Englisch.

Sie haben dann sehr schnell gelernt und parallel dazu kam die Einbindung 
des SDK in die ArduinoIDE. Das war eigentlich mein Grund für die 
Bekanntschaft mit dieser IDE. Mindestnes 2 der Programmierer, die damals 
die Arduino-Anbindung gebaut haben, arbeiten inzwischen fest für 
Espressif, deshalb ging es beim ESP32 auch viel schneller mit dem 
Anpassen usw.

Damit hast Du jetzt eigentlich 2 Wege: auf 
https://www.espressif.com/en/products/hardware/esp32/overview findest Du 
alles, was es dazu vom Hersteller gibt, die SDKs usw.
Ich bin da aber nicht direkt auf dem laufenden.
Ich nutze den ESP32 zusammen mit der ArduinoIDE.
https://github.com/espressif/arduino-esp32
Die Einbindung und Anpassung ist aber da noch nicht 100% und man kann 
einige Möglichkeiten auch (noch?) nicht nutzen. Dafür spielt das in 20 
Minuten und man hat ein Erfolgserlebnis und für meine kleinen Projekte 
reicht es mit Sicherheit.

Alles nützliche gibt es jetzt ohnehin bei github. 
https://github.com/espressif

Der ESP32 ist eigentlich recht genial gerade für kleine Projekte weil er 
fast alles an Hardwareanbindungen drin hat was man gebrauchen kann.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von David D. (saturi)


Lesenswert?

Sorry, ich glaube das aktuellste ist jetzt erst oben. Hab wohl vergessen 
nen Knopf zu drücken...

Vielen Dank, dass du das machst.
Ganz kurze Frage: kann ich mir durch die Lvl-Shifter eigentlich die 
Pull-Up Widerstände auf den Bus-Leitungen sparen? bzw. brauche ich sonst 
auf jeder Seite einen?

lg.

David

von Olli Z. (z80freak)


Lesenswert?

Beim Levelshifter benötigst Du keine zusätzlichen Pullups.
Ich werde mir Deinen TWI Code auch mal vornehmen und die Timings mit dem 
Datenblatt vom SCCB vergleichen. Die müssen ja nicht SPI entsprechen. 
Zum Glück ist das SCCB ja eh nur ein Subset von SPI, einfaches 
Master/Slave. Das macht den zu verwendenden Code schlanker.

Ich bin auch eher ein Freund davon die Dinge optimal an die Verwendung 
anzupassen, also keine Rundum-Sorglos-Für-Alles Libs. Die haben nur 
massig Implikationen due man kennen muss und die Fehlersuche ist ein 
Graus.

Warum auch nicht eine hochspezialisierte SCCB Lib machen?
Echter AVR Code dürfte auch um einiges schlanker sein als mit Arduino 
Framework drumherum. Ich habe es inzwischen (tataaa) auch geschafft das 
AVR Studio zu installieren. Nachdem ich wirklich erstmal ALLE Windows 
Visual C* Bibliotheken von meinem PC gelöscht habe. Da hatteb sich 
inzwischen gute 20 Stück angesammelt und irgendwie dafür gesorgt das die 
IDE nicht mehr die benötigte findet.

Bin also jetzt auch mit am Start :-) Lass uns erst dieses doofe SCCB 
Dong rocken, damit es ordentlich weitergehen kann.

Ich denke, sobald wir mal ein Bild irgendwie rüber haben sollteb wir auf 
die FIFO Version wechseln, sonst ist mit AVR schnell schluß.

von Michael U. (amiga)


Lesenswert?

Hallo,

Olli Z. schrieb:
> Die müssen ja nicht SPI entsprechen.
> Zum Glück ist das SCCB ja eh nur ein Subset von SPI, einfaches
> Master/Slave.

nun verwirre ihn nicht völlig, I2C, nicht SPI...

Olli Z. schrieb:
> Warum auch nicht eine hochspezialisierte SCCB Lib machen?
Prinzipiell ist es kein Problem SCCB mit BitBanging auf dem AVR zu 
machen, ein Problem sehe ich eher darin, daß es eingentlich keiner 
wirklich braucht. SCCB ist eben als Kamera-Protokoll gebaut worden, 
zumindest habe ich nichts anderes gesehen. Man wird aber gerade die 
nicht wirklich zusammen an einem AVR nutzen können, der OV7670 wird wohl 
eine Ausnahme bleiben, weil ein netter China-Hersteller die Dinger noch 
rumliegen hatte und ein breakout-Board drum gebastelt hat...

> Echter AVR Code dürfte auch um einiges schlanker sein als mit Arduino
> Framework drumherum.

Mit dem Arduino Framework ist es so eine Sache, wenn ich seine Dateien 
in einen Ordner OV7670_Kamera im Sketchbook anlege und die main.c in 
OV7670_Kamera.ino umbenenne, kümmert sich das Arduino Framework ganz 
brauchbar um das, was es da findet. Sinnigerweise mault er dann über 
bool weil in älteren AVR-Studio (4.xx) und GCC-Versionen die noch mit 
#include  <stdbool.h> selber eingebunden werden mußte. Habe ich eben 
hinzugefügt, dann läuft der Compiler komplett durch, 134 Bytes Code.
In das alte Atmel-Studio 4.18 geworfen sind es 196 Bytes. Da könnte ich 
mir jetzt die erzeugten ASM-Files von beiden mal anschauen, ich denke 
aber, da ist der uraltete GCC von 2010 im uralten Atmel-Studio schuld, 
die neueren optimieren merklich besser.
Ein neueres AVR-Studio hatte ich nur mal kurz drauf, ich brauche es für 
meine Projekte ("Spielereien") im Moment nicht wirklich.

Das sieht alles völlig anders aus, wenn man beruflich nutzen will oder 
die Projekte richtig groß werden oder eben µC aus aktuelleren 
Entwicklungen nutzen will oder muß.

Ansonsten sind es aber eben alles Grundlagen, eine Timer bleibt ein 
Timer, egal wieviele Sonderfunktionen und Modi er hat, ein IO ist ein 
IO, ob ich da wie beim AVR den Mode direkt setzen kann oder noch einer 
komplexe IO-Matrix erklären muß, welche interne Hardware jetzt an 
welchem Pin landen soll (XMega, ESP32 usw.). I2C, SPI, I2S, CAN, ... 
sind Sachen, die sind Funktionen, wo ich wissen muß (sollte) wie das 
Protokoll funktioniert, was an Spezialitäten jeweils dazugehören und wie 
ich die benutzen kann.
An welchen Registern ich drehen muß, wenn es Hardwareunterstützung im µC 
dazu gibt oder wie weit die geht (ich sage nur USI beim AVR, kann vieles 
nund nichts vollständig), das muß ich ohnehin aus dem Datenblatt, 
Applicationsbeispielen des Herstellers des konkreten µC zusammensuchen.

Der Kram ist ohnehin hier ein netter Versuchsaufbau für mich, ich werde 
nachher mal meinen (auch alten und selbstgebauten) LA ranklemmen, das 
kann dann so erstmal hier liegenbleiben zum mitmachen.
http://www.avr.roehres-home.de/logikanalyzer/index.html
Und auch die Webseite ist uralt und ungepflegt. ;)

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb:

> ein wunder Punkt... Ich hatte bei Erscheinen mir ziemlich schnell damals
> ESP6266 gekauft.

Ich ebenfalls - allerdings den ESP8266 ;-)
Zum Glück bin ich etwas später eingestiegen, aber nicht nur die 
Software, auch die Hardware hat dort üble Bugs: so mußte ich viele 
Stunden verbraten um herauszufinden, dass das WLAN-Modul die 
Meßergebnisse des AD-Wandlers beeinflußt - super Möhre ...  Erst wenn 
man Wake-Up beim WLAN deaktivierte stimmten die Ergebnisse wieder - ohne 
Worte ...

> Sie haben dann sehr schnell gelernt und parallel dazu kam die Einbindung
> des SDK in die ArduinoIDE.

Ja, habe den ESP8266 sowohl in LUA als auch in Arduino programmiert. 
Lämpchen ein-/aus geht ganz gut, aber auf anspruchsvollere Dinge möchte 
ich mich mit so einem halbgaren Teil nicht einlassen - da fressen einen 
die Bugs auf.

> Damit hast Du jetzt eigentlich 2 Wege: auf
> https://www.espressif.com/en/products/hardware/esp32/overview findest Du
> alles, was es dazu vom Hersteller gibt, die SDKs usw.
> Ich bin da aber nicht direkt auf dem laufenden.

Danke!

> Ich nutze den ESP32 zusammen mit der ArduinoIDE.
> https://github.com/espressif/arduino-esp32

Danke!

> Die Einbindung und Anpassung ist aber da noch nicht 100% und man kann
> einige Möglichkeiten auch (noch?) nicht nutzen. Dafür spielt das in 20
> Minuten und man hat ein Erfolgserlebnis und für meine kleinen Projekte
> reicht es mit Sicherheit.

Geht mir manchmal ähnlich.

> Alles nützliche gibt es jetzt ohnehin bei github.
> https://github.com/espressif

Danke!

> Der ESP32 ist eigentlich recht genial gerade für kleine Projekte weil er
> fast alles an Hardwareanbindungen drin hat was man gebrauchen kann.

Bin jetzt eine Woche auf (Dienst)reise - ideal zu abendlichen Proggen - 
und ich wollte eigentlich das kleine Tütchen mit dem ESP32 eingepackt 
haben. Nun sitze ich im Zug und was zu Hause liegt ist der ESP32 - 
grrrr....

Danke aber nochmals für Deine Tipps!

Viele Grüße

Andreas

von Olli Z. (z80freak)


Lesenswert?

Michael U. schrieb:
> nun verwirre ihn nicht völlig, I2C, nicht SPI...
Ups, Du hast natürlich recht, mein Fehler.

> Olli Z. schrieb:
>> Warum auch nicht eine hochspezialisierte SCCB Lib machen?
> Prinzipiell ist es kein Problem SCCB mit BitBanging auf dem AVR zu
> machen, ein Problem sehe ich eher darin, daß es eingentlich keiner
Ich meinte das schon unter Zuhilfenahme des I2C-Interfaces vom AVR, nur 
eben das wir nicht die fertige Wire-Lib nehmen, sondern das für unsere 
Zwecke abspecken.

> zumindest habe ich nichts anderes gesehen. Man wird aber gerade die
> nicht wirklich zusammen an einem AVR nutzen können, der OV7670 wird wohl
Jab, die Erkenntnis ist ja bereits gefestigt. Da werden wir nur mit FIFO 
halbwegs was rausbekommen. Einzige Option wäre ggf. noch ein lokal am 
AVR angeschlossenes LCD-Display, welches die empfangenen Daten der 
Kamera direkt darstellt. Aber auch das wird nur in einer sehr 
reduzierten Auflösung/Framerate möglich sein.

> hinzugefügt, dann läuft der Compiler komplett durch, 134 Bytes Code.
> In das alte Atmel-Studio 4.18 geworfen sind es 196 Bytes. Da könnte ich
Wow, das ist wirklich wenig, hätte ich nicht mit gerechnet. Da könnte 
man ja sogar noch das ASM "verstehen" ;-)

> Ein neueres AVR-Studio hatte ich nur mal kurz drauf, ich brauche es für
> meine Projekte ("Spielereien") im Moment nicht wirklich.
Ich hoffe das wir mit verschiedenen Versionen keine Probleme bekommen. 
Ich würde halt immer das aktuelle nehmen, also jetzt 7.

> Der Kram ist ohnehin hier ein netter Versuchsaufbau für mich, ich werde
Ich bin aber echt froh einen Vollblut-Programmierer hier im Thread zu 
haben. Meine Kenntnisse sind an vielen Stellen nur rudimentär. Ach, es 
gibt ja so wahnsinnig viel interessantes Zeug und so wenig Zeit ;-)

Als LA habe ich mir mal für nen 20er einen Saleae-Logic mit 8-Kanal 
zugelegt. Die Software finde ich ganz gut, hat auch Protokoll-Analyzer 
mit drin und billiger gehts kaum. Für Hobby, Spiel und Spaß genau 
richtig. Einzig das der nur für TTL-Level ausgelegt ist, also einen 
Vref-Eingang hat. 3,3V geht damit aber auch noch.

von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb:
> Der Kram ist ohnehin hier ein netter Versuchsaufbau für mich, ich werde
> nachher mal meinen (auch alten und selbstgebauten) LA ranklemmen, das
> kann dann so erstmal hier liegenbleiben zum mitmachen.
> http://www.avr.roehres-home.de/logikanalyzer/index.html
> Und auch die Webseite ist uralt und ungepflegt. ;)

Wow - bin sehr beeindruckt: ein selbstgebauter LA mit 
selbstprogrammierter Software! Nicht schlecht!

Ich selber habe einen 500MHz Intronix Logicport - ganz schnöde hier im 
Forum erstanden. Im Gegensatz zu Deinem Selbstbau also Coolnessfaktor = 
0,ist aber trotzdem eine der besten Investitionen in meinem Bastelpark.

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Ja, habe den ESP8266 sowohl in LUA als auch in Arduino programmiert.
> Lämpchen ein-/aus geht ganz gut, aber auf anspruchsvollere Dinge möchte
> ich mich mit so einem halbgaren Teil nicht einlassen - da fressen einen
> die Bugs auf.

was ist anspruchsvoll? Hier läuft ein gutes Dutzend ESP8266 dauerhaft 
und stabil. Als NTP-Client für ein paar Uhren weil DCF77 hier 
mittlerweile zuviel Ärger macht. Am PIR-Sensor zum Melden einer 
Bewegung. Als IR-Send-Bridge um den alten Sony-Receiver per IR und MQTT 
steuern zu können. Als Warner wil ich im Bad mal wieder das Licht 
angelassen habe. In WLAN-Steckdosen von Sonff und Norma/Obi. Als 
433MHz-bridge nach MQTT für meine alten Eigenbausensoren. Als Steuerung 
für einen WS2812 LED-Stripe. Bin gerade einfach mal so durchgegangen, in 
solchen Dingen sehe ich den Zweck der ESP8266 gerade durch den Preis.
Einen MP3-Streamplayer mit einem VS1053 gibt es auch noch, prizipiell 
stabil, durch den etws knappen Ram aber hier im WLAN manchmal zu 
Aussetzern neigend, war auch eher ein proof-of-concept weil das Zeug 
rumlag.
Da wird ein ESP32 einziehen, dank mehr Ram und stabil laufendem 
Software-MP3-Decoder und I2S-Ausgabe besser geeignet.

Für (unangenehme) Überraschungen ist der ESP32 aber auch noch eine Weile 
gut...

Olli Z. schrieb:
> Ich bin aber echt froh einen Vollblut-Programmierer hier im Thread zu
> haben. Meine Kenntnisse sind an vielen Stellen nur rudimentär. Ach, es
> gibt ja so wahnsinnig viel interessantes Zeug und so wenig Zeit ;-)

Hmmm... Vollblut-Programmierer... Ich sage es mal so: ein Projekt zu 
haben, das in seine sinnvollen Abschnitte zu zerlegen, Lösungsansätze 
für die Teilprobleme zu finden, Datenblätter lesen und verstehen zu 
können, kein Problem. Assembler kein Problem. C geht, oft schreibe ich 
da aber eher ASM-Abläufe, nutze also die C-Vorteile nicht immer aus 
(Struktur, Union, Bitfelder usw. usw.). C++ nur duch Arduino, keine 
wirkliche Erfahrung mit Klassen usw.

Das SCCB nagele ich wahrscheinlich hier mit dem Datenblatt der OV76770 
in 2 Stunden stabil in AVR-ASM zusammen, in C vermutlich auch, da kommen 
dann aber sicher 10 Leute, die sagen, daß man das doch in C viel 
eleganter mit nutzung aller Möglichkeiten von C machen kann...

Olli Z. schrieb:
> Wow, das ist wirklich wenig, hätte ich nicht mit gerechnet. Da könnte
> man ja sogar noch das ASM "verstehen" ;-)

vermutlich lese und verstehe ich das ASM schneller als den Inhalt einer 
C++-Klasse. ;)

Olli Z. schrieb:
> Ich hoffe das wir mit verschiedenen Versionen keine Probleme bekommen.
> Ich würde halt immer das aktuelle nehmen, also jetzt 7.

Für mich sehe ich da in diesem Zusammenhang keine wirklichen Probleme. 
Ich kopiere nur die .c und .h Dateien in mein angelegtes Projekt, egal 
ob Arduino oder Atmel-Studio und lasse den Compiler meckern. Ist 
normalerweis in diesem Umfang in 10 Minuten angepasst, Änderungen an den 
eigentlich Sourcen sollten nicht nötig sein und Sachen wie das mit dem 
#include  <stdbool.h> sind über verscheiden versionen ohnehin üblich. 
Sollte auch das aktuelle Studio nicht stören, wenn das drinsthen würde. 
Vielleicht gäbe es eine Warnung über eine doppelte Deklaration...

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

Olli Z. schrieb:
> Beim Levelshifter benötigst Du keine zusätzlichen Pullups.

Sicher?

@David: könntest Du den genauen Schaltplan Deines Levelshifters hier 
einmal posten?

Sieht der vielleicht so aus:
https://learn.sparkfun.com/tutorials/bi-directional-logic-level-converter-hookup-guide
?

Viele Grüße

Igel1

: Bearbeitet durch User
von Andreas S. (igel1)


Angehängte Dateien:

Lesenswert?

Hi,

gemäß Implementation Guide v1.0 (Chapter 8) soll man ja zunächst einen 
Reset-Command an Adresse 0x12 (auch "COM7" genannt) absetzen, indem man 
dort das Bit 7 auf 1 setzt (in Summe also eine 0x80 sendet).

Die SCCB-Abfolge dazu ist:

0.)  I2C-Startabfolge senden (SDA geht von High auf Low während
     SDC High ist)

1.)  I2C-Adresse des OV7670 (nämlich 0x21) anpiepsen
     und Schreiboperation signalisieren.
     Die ersten 7 Bit [7:1] codieren die 0x21 und das achte Bit [0] wird
     auf "0" gesetzt, um eine Schreiboperation zu signalisieren.
     In 8-Bit Schreibweise ergibt sich somit eine 0x42, die da
     gesendet wird.

2.)  I2C-Register senden (nämlich 0x12)

3.)  Registerwert senden (nämlich 0x80)

4.)  I2C-Stopabfolge senden (SDA geht von Low auf High während
     SDC High ist)

Diesen Vorgang habe ich einmal mit meinem LogicAnalyzer mitgeschnitten 
und hier als Bild angehängt (interessant: mein OV7670 scheint irgendwie 
doch ein ACK zu senden).

Viele Grüße

Igel1

von Andreas S. (igel1)


Angehängte Dateien:

Lesenswert?

Ach ja: und noch ein Stilbild von meinem traurigen Dasein in einem Hotel 
- dokumentiert mit einer OV7670.

Das Bild ist in Wirklichkeit etwas schärfer als hier hochgeladen, aber 
mit einem Handy ein Bild von einem TFT-Display zu machen, ist halt nicht 
so der Hit. Außerdem habe ich die automatische Verkleinerung beim 
Hochladen in das Forum nicht deaktiviert - das Verschlimmert die 
Qualität nochmals.

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Diesen Vorgang habe ich einmal mit meinem LogicAnalyzer mitgeschnitten
> und hier als Bild angehängt (interessant: mein OV7670 scheint irgendwie
> doch ein ACK zu senden).

irgendwo wohl in der SCCB-Doku stand eine Anmerkung wovon dieses Bit 
beeinflußt wird, es kann als 0 oder 1 kommen, ist aber kein ACK. Ich 
glaube, da stand auch in einem Diagramm was von Don't Care. Wer darf es 
nicht ändern? ich? Der SCCB-Slave? Muß ich sowieso nochmal reinschauen, 
auf Anhieb finde ich es jetzt nicht...

Andreas S. schrieb:
> Ach ja: und noch ein Stilbild von meinem traurigen Dasein in einem Hotel
> - dokumentiert mit einer OV7670.

Den Finger nicht im Bild und noch was auf den glasboden gelegt, dann ist 
der Stil sicher "Stillleben".

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Angehängte Dateien:

Lesenswert?

Andreas S. schrieb:
> Olli Z. schrieb:
>> Beim Levelshifter benötigst Du keine zusätzlichen Pullups.
> Sicher?

Ja, so einen hab ich auch. Das ist von der Schaltung her wohl sowas wie 
„der Klassiker“. Ist auch hier in der Forums Knowledgebase so drin: 
https://www.mikrocontroller.net/articles/Pegelwandler
Die Pullups sind da ja deutlich zu erkennen :-)

Und dann gibt es noch zahlreiche ICs für sowas. Z.B. 
https://www.adafruit.com/product/395 ein 8fach Bi-Direktional. Ebenso 
liefert die 74er Serie auch etliche Shifter, teils Uni (74540), teils 
auch Bi-Direktional wie der 74AVCH2T45. Die Auswahl ist riesig...

von Michael U. (amiga)


Lesenswert?

Hallo,

Olli Z. schrieb:
> Die Pullups sind da ja deutlich zu erkennen :-)

ob 10k im Zweifel niedrig genug sind muß man schauen. Hängt letztlich 
eben von der Anzahl Slaves ab und von den Leitungslängen. Bei den 
üblichen "basteleien geht es eigentlich immer so. Di Schaltung war schon 
ein Vorschlag in einem alten Philips I2C-Dokument.

Ich bin beim Experimentieren da immer recht großzügig, man muß nur im 
Hinterkopf haben, welche Bedeutung die PullUps bei I2C haben.
Sonst sucht man schnell mal die selbst eingebauten Fehler. Da kann man 
mal schnell 2,2k zusätzlich ranhängen, wenn es nichts ändert sollte man 
die richtige Ursache suchen. ;)

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

Andreas S. schrieb:
> Ein STM32F429I-Discovery-Board bekommt man für ca. 20-25 EUR in der
> Bucht.
> Dort ist neben einem potenten stm32f429-Prozessor auch schon ein
> ILI9346-Display drauf - optimal zum Experimentieren mit dem OV7670

... kleine Korrektur zu meinem alten Post:
Es handelt sich natürlich nicht um eine ILI9346 sondern um ein 
ILI9341-Display.

Viele Grüße

Igel1

von David D. (saturi)


Lesenswert?

Hallo :)
ich möchte ein kurzes Lebenszeichen absenden :)

Ende dieser Woche bin ich hoffentlich wieder in der Lage mit zu basteln, 
proggen etc.

Der selbstgebaute Logic-Analyzer wäre mal einen Nachbau wert um auch 
einen zu besitzen.

mein Level-Shifter ist dieser hier:
https://www.roboter-bausatz.de/434/i2c-pegelwandler/level-konverter-3.3v-5v-bidirektional-2-kanal

gibt es schon fortschritte in Sachen Kommunikation mit dem SCCB mittels 
des TWI(I2C)-Interface am AVR?

lg. David

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:
> Hallo :)
> ich möchte ein kurzes Lebenszeichen absenden :)

Nett von Dir!

> Ende dieser Woche bin ich hoffentlich wieder in der Lage mit zu basteln,
> proggen etc.
>
> Der selbstgebaute Logic-Analyzer wäre mal einen Nachbau wert um auch
> einen zu besitzen.

Wenn's um den reinen Bastelerfolg geht: do it!
Wenn's Dir nur um die Messmöglichkeiten als solches geht: don't do it!

Hintergrund: für 100 - 200 EUR bekommst Du auf dem Markt LA's, für
deren Funktionalität Du mindestens 2-3 Jahre designen und proggen
müsstest.

Meinen 500MHz LogicPort von Intronix bekommst Du derzeit gebraucht
z.B. für um die 100-130 EUR  (neu für ca. 170 EUR).

Sealae soll auch sehr gut sein - ob man den Clone nimmt, muss jeder
mit seinem Gewissen klar- oder eben nicht klarmachen.

> mein Level-Shifter ist dieser hier:
> 
https://www.roboter-bausatz.de/434/i2c-pegelwandler/level-konverter-3.3v-5v-bidirektional-2-kanal

Hmmm ... kann leider keinen Schaltplan finden.

Aber 2 MOS-Transistoren deuten auf dasselbe Prinzip wie beim oben 
verlinkten Pegelwandler von Sparcfun hin.

Was allerdings der VLDO auf der Platine soll, ist mir etwas unklar.
Schaltplan wäre schon schön.

> gibt es schon fortschritte in Sachen Kommunikation mit dem SCCB mittels
> des TWI(I2C)-Interface am AVR?

Ich fühle mich einfach mal nicht angesprochen, weil ich ja nur Zaungast 
bin und weiterhin beim ARM-Prozessor bleiben werde (... ich muss einfach 
nur abwarten, bis Ihr die Nase von den AVR-Einschränkungen voll habt und 
dann ebenfalls auf den ARM schwenkt :-)

Anyway - habe Euch oben einmal einen Mitschritt meines STM32F429 bei 
seiner Kommunikation mit dem OV7670 angehängt - macht die Zs.hänge etwas 
"greifbarer".

Viele Grüße

Igel1


PS:  habe mir soeben das gebrauchte Dragon-Board hier aus dem MC-Markt 
für 25€ geschnappt (nur für den Fall, dass ich doch noch mitspielen will 
...)

von Olli Z. (z80freak)


Lesenswert?

Kann für den Hausgebrauch einen Saleae nur empfehlen. Günstig und die 
Software ist leicht zu bedienen und kann was. Bin mit meinem 20€ Clone 8 
Kanal 20 Mhz hochzufrieden.

von David D. (saturi)


Lesenswert?

Hallo, kurzes Lebenszeichen.

Ich komme leider nicht mehr meinen To-Dos für meine Abschlussarbeit und 
den Job-Bewerbungen hinter her.
Ich hoffe, dass sich das in den nächsten Wochen legt und ihr trotz des 
vermutlich aufkommenden Sommers nicht die Lust verliert.

Ich werde an dem Thema dran bleiben und weiterarbeiten sobald ich auch 
nur ein bisschen Zeit übrig habe!
Aber grade muss ich eben erst einmal meinen Abschluss sichern ;-) ich 
hoffe ihr versteht das!

liebe Grüße

David

@Olli, wie siehts bei dir aus? nachdem das AtmelStudio ja jetzt bei dir 
läuft. hast du schon Neuigkeiten zur Kommunikation mit dem SCCB übers 
TWI-Interface?

von Michael U. (amiga)


Lesenswert?

Hallo,

David D. schrieb:
> Aber grade muss ich eben erst einmal meinen Abschluss sichern ;-) ich
> hoffe ihr versteht das!

wäre mir auch wichtiger gewesen, damals... ;)

Ich habe im Moment auch nichts weiter mit der Kamera gemacht, andere 
"sinnlose" Projekte hatten/haben erstmal Vorrang. Liegt aber noch alles 
griffbereit. Wie ich mich kenne, wird es nur eine Frage der Zeit sein, 
bis ich mich da wieder dran festbeiße.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

> Aber grade muss ich eben erst einmal meinen Abschluss
> sichern ;-) ich hoffe ihr versteht das!

Kommt drauf an:  Wenn der Abschluß "Professur" oder "Doktor" heißt,
dann fände ich es doch wichtiger, das Projekt hier erst einmal sauber
abzuschliessen ...

Wenn's allerdings um den Schul- oder Lehr-Abschluss geht, dann ist
der natürlich wichtiger.

Good luck!

Igel1

von Dieter F. (Gast)


Lesenswert?

Andreas S. schrieb:
> Kommt drauf an:  Wenn der Abschluß "Professur" oder "Doktor" heißt,
> dann fände ich es doch wichtiger, das Projekt hier erst einmal sauber
> abzuschliessen ...

Da Du offensichtlich weder das Eine noch das Andere vorhast wärst Du 
doch prädestiniert :-) - ich würde auch eher einen Doktortitel erwerben 
(einen Professorentitel erwirbt man i.d.R. nicht) wie hier eine 
Ansteuerung für eine Kamera zu entwerfen :-) - wenn ich das denn könnte 
:-)

von David D. (saturi)


Lesenswert?

Huhu,

also ich lebe noch und meine Abschlussarbeit läuft auf Hochturen.
Um hier mal ein Datum zu nennen, aller aller spätestens ab dem 11.7. bin 
ich wieder zu 100% dabei, weil am 10.7. meine Verteidigung sein wird.

Nein, ich strebe aktuell "noch" ;-) nicht den Doktortitel an sondern 
begnüge mich erst einmal mit einem Masterabschluss.

Ich hoffe aber, dass ich noch vor Juli die Zeit finde hier weiter zu 
machen :)

stay tuned!

lg. David

von David D. (saturi)


Lesenswert?

So meine lieben Freunde,

ich befinde mich im Endspurt und in zwei Wochen ist alles vorbei.
Ich hoffe Ihr habt eure Boards nicht verstauben lassen und steigt mit 
mir wieder so begeistert ein, wie wir aufgehört haben.

bis dahin!

Sonnige Grüße

David

von Andreas S. (igel1)


Lesenswert?

Hallo David,

eins muss man Dir lassen: Du hast wirklich Ausdauer und Biss - find' ich 
gut.
Wenn's hier weitergeht, werde ich wieder sporadisch mitmachen - je nach 
Zeitkontingent.

Allerdings ist es dieses Jahr auch ein wunderschöner Sommer - da möchte 
ich nicht zu viel vor dem Rechner hocken. Will sagen: schau'n wir mal.

Für Deine Prüfung in 2 Wochen wünsche ich Dir jedenfalls viel Glück 
(obwohl Du das nicht benötigen wirst, denn nach Deinem Schreibstil und 
nach Deiner Programmierung zu urteilen, gehörst Du sowieso zu den 
helleren Köpfen.)

Viele Grüße

Igel1

von Olli Z. (z80freak)


Lesenswert?

Bin ebenfalls mit von der Partie :-)

von Michael U. (amiga)


Lesenswert?

Hallo,

liegt hier auch noch alles griffbereit, anderer Projekte habe ich 
ausreichend. ;)
Ansonsten auch von mir: Viel Erfolg!

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Soooo nachdem nun alles vollbracht ist wollte ich mich heute endlich 
wieder meinem Hobby zuwenden :)

Also habe ich mir gemütlich eine Tasse Kaffe gemacht und die Box mit 
meinem Elektronik-Kram herausgeholt. Der erste Griff ging natürlich zu 
der Kamera, die mir dann promt aus der Hand gerutscht ist und exakt in 
der vollen Kaffetasse untergegangen ist....

Ein Traumstart quasi....

jetzt liegt sie im Salz zum trocknen und ich hoffe, dass - wenn ich sie 
dann morgen einmal anschmeiße - noch alles funktioniert. Sonst muss ich 
mir wohl oder übel eine neue bestellen.

Der erste Projekt-Wiederaufnahme-Post muss also doch noch etwas 
warten...
schade...

In diesem Sinne :D

bis die Tage

lg.
David

von Michael U. (amiga)


Lesenswert?

Hallo,

ich schmunzel jetzt etwas, auch wenn es für Dich ärgerlich ist.
Ich bestelle bei recht preiswerten Bastelobjekten meist generell 2 
Stück.
Nicht, um für solche Unfälle Reserve zu haben,
sondern nur, weil solche und ähnliche Unfälle nie passieren, wenn man 
Reserve liegen hat...

PS: von dieser Kamera habe ich nur eine, ich werde also wohl auf Kaffe 
verzichten, wenn ich den Kram raussuche.
Oder fallen Kameras womöglich auch in Cola-Becher?!?

PS: ich hätte die Optik von der Leiterplatte abgeschraubt, den Kram mit 
destilliertem Wasser abgespült (notfalls auch einfach unter dem 
Wasserhahn) und ausgiebig trocken geföhnt. In die Optik selbst dürfte 
nichts eingedrungen sein, wenn Du sie nicht stundenlang in Kaffe gebadet 
hast.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Ich finde ohnehin das wir unser Vorhaben deutlich beschleunigen wenn wir 
auf das Modell mit Fifo Speicher wechseln.
Damit können wir auf der einfachen Arduino Plattform bleiben und uns den 
Dingen widmen die wichtig sind, als mit irgendwelchen Tricksereien zu 
versuchen das ohne ans laufen zu bekommen.

von Michael U. (amiga)


Lesenswert?

Hallo,

Olli Z. schrieb:
> Damit können wir auf der einfachen Arduino Plattform bleiben und uns den
> Dingen widmen die wichtig sind, als mit irgendwelchen Tricksereien zu
> versuchen das ohne ans laufen zu bekommen.

Auf der Arduino Plattform bin ich hier ohnehin, der ist es egal, ob ich 
da Arduino spezielles oder plain C oder eine bunte Mischung von beiden 
reinpacke, die compiliert das schon richtig.

direkt gefragt: was ist das Ziel der Geschichte?
Also was will letztlich jeder hier mit der Kamera machen?

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Olli Z. (z80freak)


Lesenswert?

Ich dachte das hatten wir doch ein paar hundert Antworten weiter oben 
schon geklärt?! :-)
Wir wollten damit natürlich auch ein Biöd übertragen, aber eigentlich 
ging es ums Protokoll und die Ansteuerlokig sowie Videoformate.

: Bearbeitet durch User
von David D. (saturi)


Lesenswert?

Olli Z. schrieb:
> Ich finde ohnehin das wir unser Vorhaben deutlich beschleunigen wenn wir
> auf das Modell mit Fifo Speicher wechseln.
> Damit können wir auf der einfachen Arduino Plattform bleiben und uns den
> Dingen widmen die wichtig sind, als mit irgendwelchen Tricksereien zu
> versuchen das ohne ans laufen zu bekommen.

Das denke ich auch, dann können wir in Ruhe das Bild verarbeiten, an den 
PC schicken und dort anzeigen.
Wenn wir den ganzen ablauf dann einmal hinbekommen haben sollten, kann 
man sich die option ja offen halten, den Sprung auf die andere Kamera 
ohne Fifo zu versuchen.

Damit haben wir dann erstmal nicht das Frequenzproblem richtig?
Eine mit Fifo hab ich mir ja damals auch zu gelegt.

Darf ich euch fragen, wie ihr die Kamera anschließt?

Ich hatte mir bei der Kamera ohne Fifo ein Flachbandkabel mit 
Pfostenstecker gemacht.
müsste für die mit Fifo dann heute Abend nochmal ein neues machen oder 
habt ihr da bessere Lösungen?

von Olli Z. (z80freak)


Lesenswert?

Ich habe auch noch eine mit Fifo, dann bleiben wir erstmal dabei! :-)

Für Versuchsaufbauten finde ich ja Dupont-Stifte praktisch. Daher würde 
ich, falls nicht bereits vorhanden, an die Platine der Kamera eine 
Stiftleiste löten (am besten nach hinten gerichtet damit die Kabel 
später nicht vor der Linse rumlammern) und dann mit Buchse/Stecker 
Dupont-Wires aufs Steckbrett verbinden.

von Michael U. (amiga)


Lesenswert?

Hallo,

Olli Z. schrieb:
> Ich dachte das hatten wir doch ein paar hundert Antworten weiter oben
> schon geklärt?! :-)
> Wir wollten damit natürlich auch ein Biöd übertragen, aber eigentlich
> ging es ums Protokoll und die Ansteuerlokig sowie Videoformate.

meine Frage deshalb: die Kamera kann 640x480 als Auflösung.
Mit einem AVR sind, egal, ob mit oder ohne FiFo alle paar Sekunden ein 
Bild möglich. Das sind bei 16Bit unkomprimiert also 600kB pro Bild wenn 
ich mich nicht verrechet habe.
Wir reden also von einem Bild alle 2-3s (mit FIFO) oder alle 15s ohne 
FIFO.
Als JPEG dürfte ein Bild um die 30-50kB sind (ist betwas das, was meine 
alte DC3840 packt).
Wenn Arduino auch z.B. der ESP32 ist, sind ca. 6-10 Bilder/s direkt auf 
einem angeschlossenen Display machbar,
Als "Sucher" für einen "Fotoapparat" gerade noch nutzbar, ein solches 
Projekt liegt irgendwo in Netz.

Für mich wäre also eine denkbare Anwendung z.B. alle paar Minuten eine 
Wetteraufnahme per WLAN in mein FHEM zu schicken. Da würde ich ohnehin 
dann einen ESP32 nehmen. Das ginge prinzipiell auch mit einem AVR und 
LAN-IC dran, hier liegt sicher noch ein ENC28J60 rum...

Meine Frage ging also eher in Richtung: was könnte für Euch eine 
mögliche Anwendung in dem Umfeld sein?

Gruß aus Berlin
Michael

von Olli Z. (z80freak)


Lesenswert?

Also ich, für meinen Teil, habe und brauche keine konkrete Anwendung und 
sehe die Sache rein akademisch :-)

von Michael U. (amiga)


Lesenswert?

Hallo,

Olli Z. schrieb:
> Also ich, für meinen Teil, habe und brauche keine konkrete Anwendung und
> sehe die Sache rein akademisch :-)

ok, dann sehen wir es genauso. Ich frage nachher mal meinen Bekannten, 
ob er die mit FIFO hat, dann lege ich die erstmal neben meine ohne. ;-)
Seine liegt nähmlich auch nur sehr akademisch rum...

Aber: haben ist besser als brauchen!

Gruß aus Berlin
Michael

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Das freut mich und ich hoffe, dass dein Bekannter die Kamera entbehren 
kann :)

Ich denke wir sind uns alle einig, dass dieses Projekt nur dem 
Selbststudium (in meinem Fall) oder dem Auffrischen von vorhandenem 
Wissen (evtl. in eurem Fall) dienen soll.

Ich bin für meinen Teil schon Glücklich wenn ich ein Foto mit der Kamera 
schießen und darstellen kann ;-)

Ich kenne mich mit FIFOs nicht wirklich aus. Das Grundprinzip ist zwar 
klar, aber ich werde mich erstmal einlesen müssen.
Zunächst sollten wir aber kurz abklären, dass wir alle mit den selben 
Werkzeugen arbeiten :-)

Auf meiner Kamera ist ein AL422B Frame-Buffer Fifo verbaut. Ist das der 
gängige, der ebenfalls bei euch bestückt ist?

Angehängt habe ich euch mal das Pinlayout, dass bei mir per Stiftleiste 
zum kontaktieren bereit steht.

PCLK und XCLK scheinen weggefallen zu sein, dafür kommen weitere sechs 
Pins dazu (vermutlich zur Steuerung/Auslesen des Fifos)

Ich hoffe bei euch sieht es ähnlich aus.

liebe Grüße David

EDIT:
Bei genauerer Betrachtung habe ich gerade festgestellt, dass neben dem 
FIFO ebenfalls noch ein Quarz verbaut ist, was auch erklären würde, 
warum wir keine XCLK mehr einspeisen müssen.

: Bearbeitet durch User
von Andreas S. (igel1)


Lesenswert?

@David D.:

Musste herzlich über Deinen Kaffeetassen-Absturzbericht lachen - das 
hast Du wirklich köstlich beschrieben.

Was die FiFo-Geschichte angeht, so habe ich neben 2x OV7670 hier auch 
irgendwo eine OV7670 mit FiFo rumfliegen. Wenn die Zeit bei mir also 
ausreicht, so könnte ich auch ein bißchen mitspielen (vermutlich aber 
nicht vor Ende August).

Muss allerdings gestehen, dass mich die FiFo-Geschichte wenig reizt, da 
sie kaum anspruchsvoll sein dürfte und noch viel weniger zu meinem 
eigenen Zielszenario passt (es lautet: mit einem STM32 passable Bilder 
aus der FiFo-losen OV7670 herausfischen, dann jpeg-komprimieren und an 
einen ESP8266 zum Versand als Email-Attachment übergeben - denn meine 
Mäusefalle soll irgendwann an Ihren Besitzer Bilder von dem/den Insassen 
schicken).

Wenn's allerdings nur darauf ankommt, ein paar Bilder mit einem atmega 
aus einer OV7670 zu ziehen, so dürfte die FiFo-Version wegen nicht 
vorhandener Timing-Probleme ca. 100x einfacher auszulesen sein als die 
Non-FiFo-Version.

Nevertheless: die FiFo-Version bietet sicherlich eine gute Gelegenheit, 
sich in endlicher Zeit ein schönes Erfolgserlebnis durch erste 
ausgelesene Bilder zu verschaffen. Und danach kannst Du ja immer noch 
auf den STM32 mit Non-FiFo umsteigen :-)

Viele Grüße und Kaffee ahoi

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Wenn's allerdings nur darauf ankommt, ein paar Bilder mit einem atmega
> aus einer OV7670 zu ziehen, so dürfte die FiFo-Version wegen nicht
> vorhandener Timing-Probleme ca. 100x einfacher auszulesen sein als die
> Non-FiFo-Version.
reivoll wäre, das auf einem ESP32 komplett zu realisieren.
Ob jemand schon einen (einfachen?) JPEG-Encoder auf dem ESP32 compiliert 
hat, weiß ich nicht. SPI-PS-RAM kann man beim ESP32 direkt einbinden, es 
gibt auch Module, wo schon welcher drauf ist.

Machbar müßte es sein, auch ohne FIFO.

Gruß aus Berlin
Michael

von Tom (Gast)


Lesenswert?

Zur JPGE-Dekodierung hat elm-chan was:
http://elm-chan.org/fsw/tjpgd/00index.html

Außerdem gibt es picojpeg:
https://github.com/richgel999/picojpeg

Sollte beides vom Flashverbrauch her nicht zu dick auftragen...

von Michael U. (amiga)


Lesenswert?

Hallo,

jpeg Decoder auf dem ESP32 ist verfügbar und macht seinen Job.
Gibt ein paar Einschränkungen bei der Ausgabeskalierung, nur 
ganzzahligen Teiler usw., für eine Displayanzeige aber kein wirkliches 
Problem.
Encoder habe ich noch nichts gesehen.
Ich denke, man wird sich da sicher etwas beschränken müssen bei 
Formaten/Profilen oder so. Habe mich mit JPG-Encoding noch nie selbst 
befasst.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Guten Abend,

ja es ist ruhig geworden, aber ich denke, dass können wir alle auf die 
klimatischen Bedingungen zurückführen, die seit einigen Wochen in ganz 
Deutschland herrschen.
Ich genieße derzeit die Sonne und freue mich schon auf die verregneten 
kühleren Tagen, an denen man erträglich die Projektarbeit wieder 
aufnehmen kann :)

lg.

David

von Andreas S. (igel1)


Lesenswert?

Dito.

Viele Grüße aus bella Italia

Igel1

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Liebe Urlauber,

ich wende mich an euch mit einer Verzweiflungstat ;-)

Ich habe in den vergangenen Tagen intensiv versucht, den OV7670 mit Fifo 
über das TWI anzusteuern.
Das Ergebnis kann ich nicht ganz einordnen. Zunächst hat es nach dem 
Equipment Aufbau und erstem Test auf Anhieb funktioniert. ich konnte die 
Device ID mit 0x76 0x73 auf den Adressen 0x0A und 0x0B auslesen. Auf 
Anhieb! Damit war die Motivation gegeben Großes zu leisten.

Einziges Manko: eigentlich werden diese 2 Read Befehle in der 
Endlosschleife ausgeführt. Bei mir stoppt diese aber nach einfachem 
Durchlauf. Die Überprüfung mit dem Oszi zeigte mir, dass die SDA Leitung 
auf Low verbleibt und nicht wie vorgesehen zum Ende einer Kommunikation 
wieder auf High gezogen wird.

Nach etlichen Code Veränderungen und Stecküberprüfungen bis mitten in 
die Nacht hatte ich immer noch keinen brauchbaren Ansatz. Verschenkte 
aber weitere 3 Stunden in der Fehlersuche, in dem ich zunächst unbemerkt 
bei den genannten Stecküberprüfungen ein Kabel falsch zurücksteckte... 
no Comment! (Schieben wir es auf die Müdigkeit)

das Studium etlicher Webseiten und allen möglichen Variationen konnte 
mir keinen Erfolg bescheren. Der aktuellste Stand ist, dass manchmal die 
Kommunikation zu funktionieren scheint und manchmal nicht. Klingt für 
mich zunächst nach etwas Undefiniertem - ich kann es aber nicht finden.

Zum Schluss hat mich ein Satz im Datenblatt des SCCB besonders 
irritiert: Sinngemäß lautete dieser, dass während des Don't care bits 
(Was beim TWI dem ACK/NACK Bit entspricht) der Master sicherstellen 
muss, dass der Bus auf LOW gezogen wird.
Diese Einstellung kann ich aber beim TWI Interface gar nicht 
beeinflussen, weil dieser ja den Pin auf Eingang Schaltet, um das ACK zu 
identifizieren?

Meine aktuelle Theorie lautet also, dass entstehende High Signale beim 
ACK den Bus ins straucheln bringen. Sehr Schwammige Aussage und ich 
erwarte von euch eine bessere Erklärung. Der Code ist angehängt.

Ich habe mich dann eben wieder entschieden mein selbstgeschustertes 
BitBangig auszugraben und siehe da, alles funktioniert wie gewünscht. 
Dennoch erinnere ich mich an die Kritik von euch, unter anderem was die 
OpenDrain Beschaltung angeht.

Daher hoffe ich, dass ihr meinen Fehler im TWI Bereich findet und wir 
das Ding ans laufen kriegen. Offensichtlich gibt es genug, die das mit 
der Arduino Lib WIre.Beginn ganz simple hinbekommen....

: Bearbeitet durch User
von Tim (Gast)


Lesenswert?

David D. schrieb:
> Diese Einstellung kann ich aber beim TWI Interface gar nicht
> beeinflussen, weil dieser ja den Pin auf Eingang Schaltet, um das ACK zu
> identifizieren?
Vielleicht kannst Du dafür noch einen Pin opfern und im richtigen Moment 
die Leitung mit 100 Ohm (o.ä.) auf low ziehen.

> Ich habe mich dann eben wieder entschieden mein selbstgeschustertes
> BitBangig auszugraben und siehe da, alles funktioniert wie gewünscht.
Dann würde ich das so lassen. Wenn kein regelkonformes I2C verwendet 
wird, kann man eben die Hardwareunterstützung des Controllers nicht 
verwenden...

von David D. (saturi)


Lesenswert?

Hallo Tim, vielen Dank für Deinen Beitrag.
Den Pin im richtigen Moment auf Low zu schalten halte ich für sehr 
kompliziert. Da müsste ich ja mit einem Timer den Zeitpunkt abzielen, 
der ja von der Frequenz der Übertragung abhängt.


lg. David

von Michael U. (amiga)


Lesenswert?

Hallo,

da es ja hier recht ruhig geworden ist und die Zeit ohnehin weitergeht:
ich habe mir mal das M5Stack Cam Modul bestellt:
https://www.amazon.de/MakerHawk-M5Stack-Antenna-Arduino-Raspberry/dp/B07F2DNX6M

Die Demosource von github:
https://github.com/igrr/esp32-cam-demo
habe ich mit großer Mithilfe meines Bekannten inzwischen nicht schön 
aber lauffähig in die ArduinoIDE geworfen.

Ich fand das als Spielerei interessant, die Kamera ist durchaus 
brauchbar, max. 1600x1200 Pixel und kann auch JPEG ausgeben.

Bild gibt es morgen...

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

@Michael U.:

Das klingt wirklich sehr interessant.
Bin auf Deine Bilder gespannt.

Dient der USB-C-Anschluß zur Stromversorgung?
Wie hast Du die Kamera mit Deinem Board verbunden?
Und musstet Ihr viele Klimmzüge machen, bis das Teil lief?

Gibt es Vorteile, die Dein Modul gegenüber den 8$-Varianten
von Aliexpress hat? (vgl. 
https://www.aliexpress.com/item/OV2640-camera-module-Module-2-million-pixel-electronic-integrated-with-jpeg-compression-new-big-promotion/32886018967.html)

Viele Grüße

Igel1

von Michael U. (amiga)


Angehängte Dateien:

Lesenswert?

Hallo,

Andreas S. schrieb:
> @Michael U.:
> Dient der USB-C-Anschluß zur Stromversorgung?
ist natürlich auch COM für den ESP32.
> Wie hast Du die Kamera mit Deinem Board verbunden?
Das ist Kamera + ESP32-Board + Akkumöglichkeit + lade-IC usw.
> Und musstet Ihr viele Klimmzüge machen, bis das Teil lief?
An USB stecken, mit dem AP des ESP32 verbinden, Webseite aufrufen, 
Bilder anschauen...

> Gibt es Vorteile, die Dein Modul gegenüber den 8$-Varianten
> von Aliexpress hat?

Erklärt sich mit obigen von selbst, Kamera-Modul + ESP32-Modul + 
USB-Adapter + Akku-Lade-IC.

Soweit die Theorie.
Ich habe das Modul als Spielerei bestellt, kein Drahtverhau, einfach mit 
der Software experimentieren.

Nun die Praxis: in der Lieferung war ein Mini-Kühlkörper ohne jegelichen 
Hinweis, taucht auch in keiner Beschreibung auf.
Der ESP32 kann ja durchaus merklich warm werden, wenn wie hier 
durchgehend WLAN-Traffic gemacht wird. Stört den auch nicht. Hier gab es 
nach relativ kurzer Zeit fehlerhafte Bilder, hängende Übertragung usw.
Mit dem Kühlkörper ging es seltsamerweise, leider auch nur etwas länger 
bis zu den Fehlern.
Im M5Stack-Forum habe ich dann einen Hinweis gefunden: die Jungs haben 
als PullUp am SCCB-Bus nur die internen des ESP32 genommen. Die sind 
aber eigentlich sowieso viel zu hochohmig für I2C/SCCB, auch bei nur 
einem Slave und kurzen Leitungen. Wenn der ESP warm wird, werden sie 
vermutlich noch hochohmiger und es hagelt IO/Fehler.
Der Poster dort im Forum hat PullUps mit 4,7k nachgerüstet und die 
Probleme waren weg.
Kann ich mit leben, nur ist die einzige zugängliche Stelle die Lötseite 
des Kamera-Steckverbinders und die hat Rastermaß irgendwo um 0,x mm...
Das freut mich auf meine "alten Tage", werde nachher mal schauen, dünne 
Litzenadern an Pin 3,5 und 11 des Verbinders zu löten und daran 2 
SMD-Widerstände.

Das Bild ist ein nur beim Experimetieren mal gespeichert, 
Original-Firmware, 800x600 (kann man dort erstmal nicht verändern), 
JPEG-Kompression unbekannt.

Mal schauen, was mein Bekannter heute meldet, der hat seine gestern 
abgeholt.

Gruß aus Berlin
Michael

von Igel1 (Gast)


Lesenswert?

@Michael:

Danke für den kleine Bericht.
Gutes Bild - macht wirklich neugierig ...

Viele Grüße

Igel1

von David D. (saturi)


Lesenswert?

Guten Abend!

da sind mir eure Antworten entgangen. Da scheine ich die E-Mail 
Notifikation verpasst zu haben.

Ich wollte die Tage schon einen Post verfassen, bin aber dann doch nicht 
dazu gekommen. Ich habe die letzten Wochen nicht geruht und habe einiges 
hinbekommen (aber noch kein Bild ;-) )

morgen dann mehr...

machen wir es wie die Politiker in der Abgasaffaire :D

lg. David

von Michael U. (amiga)


Lesenswert?

Hallo,

zur M5Stack Cam: ich hatte am 22.09. nich 2 Stück bei ebay in China 
bestellt
https://www.ebay.de/itm/M5Stack-ESP32-Camera-Module-Development-Board-3D-Wifi-Antenna-Mini-Camera-Board-/173386455615
keine Ahnung, ob es der gleiche Händler ist.
Zumindest kamen die Kameras bereits am 02.10. bei mir an.

Das Problem zum SCCB-Bus tritt auch bei diesen Modulen auf. Mein 
BEkannter hat inzwischen PullUps nachgerüstet, ich muß mir da bei 0,6mm 
Pitch am Steckverbinder noch was einfallen lassen. Oder einfach meinen 
Bekannten damit beschäftigen...

Mit der Änderung läuft das Modul absolut stabil, auch stundenlang zum 
Beobachten seines 3D-Druckers beim Drucken.

Wenn man bedenkt, daß das OV2640 Modul nur mit Adapterplatine sowieso 
schon für knapp 10€ angeboten wird, diskutiere ich lieber mit der 
Software der M5Stack Cam rum.
Die Kamera bekommt man zwar einzeln für rund 3.50€ aus China oder bei 
Amazon, nur was soll ich dann mit einer 24-pol. SMD-Buchse mit 0,6mm 
Kontaktabstand anfangen?!?

So, jetzt erstmal was sinnvolles machen...

Gruß aus Berlin
Michael

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Guten Morgen,
... doch wieder zwei Tage verspätet aber dafür mit einem ausführlichen 
Bericht.
Was bisher geschah:
Wie meinem letzten, thematischen Post zu entnehmen, habe ich von der 
I2C-Variante zurück auf die eigene Bit-Banging Variante gewechselt und 
hatte damit Erfolg, eine Kommunikation aufbauen zu können.
Als nächstes musste ich mir Gedanken machen, wie der FIFO ausgelesen 
werden kann.
Bild aufnehmen:
Dafür setze ich den write pointer zurück, warte auf ein VSync Signal, 
setzte den Write Enable Pin und warte auf die nächste Flanke bei VSync. 
Dann deaktiviere ich Write Enable wieder.
An dieser Stelle sollte das Bild jetzt vollständig im FIFO liegen.
Auslesen:
Ich habe eine Funktion erstellt mit drei Input Parametern: Auflösung y 
Richtung, Auflösung x Richtung und Bytes Per Pixel. In dieser 
Reihenfolge sind die drei Parameter in For-Schleifen verschachtelt. In 
der innersten lese ich das anstehende 8Bit Signal aus und Clock den 
Read-Pointer.
das ausgelesene parallele 8 Bit Signal setzte ich zu einem Byte zusammen 
und übertrage es per Uart an den PC.
Wie aber gehe ich mit den Daten am PC um? Die ersten Versuche waren 
logischerweise mit einem fertigen Terminal Programm. Nachdem ich es aber 
geschafft habe, nicht nur FF oder 00 für jedes Byte zurückzubekommen, 
konnte ich mit der Vielzahl an Bytes nicht mehr umgehen. Also habe ich 
mich daran gemacht mit dem visual Studio ein eigenes „Terminal“ für den 
OV7670 zu schreiben. Da ich auch hier wieder viel lernen muss, zieht 
sich diese Arbeit etwas hin, besonders was die Verarbeitung von 
eingehenden Datenströmen angeht.
Aber, ich habe es geschafft, die Daten, die am fertigen Terminal 
ankommen, zu kopieren und als eine CSV Datei zu speichern. Diese Datei 
kann ich mit meinem Programm als ein Bild einlesen. Aktuell bekomme ich 
da aber nur ein „Fehler Bild“ was meiner Meinung nach, nach einem nicht 
vollgeschriebenen Fifo oder anderen Fehlern aussieht. (Siehe Anhang).
Aktuell versuche ich den eingehenden Daten stream direkt mit meinem 
Programm verarbeiten zu können.
Das ist also mein Stand. Bei Interesse gehe ich auch gerne tiefer ins 
Detail.
Ich vermisse den Olli noch in unserer kleinen Runde ?

Das Board sieht schick aus. Vlt. Werde ich auch darauf mal zurückkommen, 
sobald mein OV läuft ?
aber wie schon des Öfteren diskutiert werde ich zunächst bei Arduino 
bleiben und ggf. später einmal den ESP ausprobieren.

lg. und ein schönes Wochenende

David

von Michael U. (amiga)


Lesenswert?

Hallo,

vielleicht hätte ich mir doch von meinem Bekannten die OV760 mit FiFo 
mitnehmen sollen? Naja, kann ich am nächsten Freitag ja noch machen...
Einerseits finde ich Deine Ausdauer gut, ich bin im Moment aber etwas 
hin- und hergerissen...

Was für ein Bildformat liest Du von der kamera in den Fifo ein?
Der kann von der Größe nicht alle Formate und Größen und die Effekte, 
die sich dann ergeben, sind lustig, wie mein Bekannter feststellen 
mußte.

Den Bildern hätte ich einen passenden BMP-Header verpsst, der ist 
überschaubar auch auf dem AVR gemacht, und eben vor den Daten 
rausgeschickt.
Eingelesen hätte ich "old school" mit altem TeraTerm in den Log-Buffer 
aund dann als .bmp gespeichert und angezeigt.
Wahlweise das File in einen Hex-Editor geworfen und geschaut, was ich 
mir da für Müll geschickt habe.

Ich habe soviel Extra-drumrum auch schon programmiert, bei meinem 
LogicAnalyzer z.B. in VB6. Aber erst, nachdem die empfangenen Rohdaten 
ok waren und es um die Anwendung ging.

Ich bin durchaus noch interessiert hier mitzuspielen. Macht dann aber 
für mich nur Sinn, wenn ich einen Source durch den Compiler schicken 
kann und flashen und dann mir die Ergebnisse anschauen kann. Das mache 
ich gern auch mit Rohdaten ohne header usw, dann muß aber eindeutig 
sein, was ankommen soll, Format, Auflösung usw.

Sonst ist es zuviel stochern im Nebel für mich, wenn ich mir erst aus 
den Cam-Inits und den Loops im Source zusammenreimen soll, was 
rauskommen müßte. Ist ja auch eine Zeitfrage.

David D. schrieb:
> Das Board sieht schick aus. Vlt. Werde ich auch darauf mal zurückkommen,
> sobald mein OV läuft ?
> aber wie schon des Öfteren diskutiert werde ich zunächst bei Arduino
> bleiben und ggf. später einmal den ESP ausprobieren.

Ich sage es jetzt mal so: ist auch Spaß an der Freude. Ich darf meine 
teilweise recht bescheidenen C/C++ Kenntnisse stark aufbessern, um mich 
mit den Espressiv Demo-Source auseinanderzusetzen. Ich darf mit mit den 
Modi und dem Datenblatt der OV2640 auseinandersetzen, mit der 
Problematik, das die Jungs nicht nur den Hardware-Design-Fehler drin 
haben (mein Bekannter darf jetzt löten...) sondern dem Modul nicht auch 
noch einen PSRAM spendiert haben. Der ESP32 kann nur 128k im Stück 
reservieren, damit ist bei 800x600 JPG Ende. Ich würde aber gern die 
volle Auflösung 1600x1200 als Einzelbild übertragen bekommen.

Wehalb ich das mache? Ich könnte die Cam z.B. auf das rumliegende 20€ 
"Roboter"-Fahrgestell kleben, 640x480 mit 20-30 Frames/s sind dafür 
ausreichend und auf Knopfruck ein Standbild in voller Auflösung wäre 
gut.

Hat auch alles keinen wirklichen Nährwert...
Die Kombination OV7670 mit Mega328 hat da null Chance.
OV7660 mit ESP8266, besser ESP32 würde da noch machbar sein.

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Michael U. (amiga)


Lesenswert?

Hallo,

auch wenn es etwas am Thema vorbeigeht:
ich hatte mir noch ein OV2640 Modul bestellt
https://eckstein-shop.de/OV2640-Camera-Board
mit kurzen Dopont-kabeln an ein ESP32 DevKit gesteckt und...
Kameratyp nicht erkannt -> reset ist auf dem Modul nicht mit dem Pin 
verbunden sondern mit 0-ohm Brücke an einer R/C-Resetschaltung.
Dem Cam-modul gefiel es offenbar nicht, daß der ESP32 XCLK erst recht 
spät nach PowerOn erzeugte. Die Camera braucht aber XCLK auch z.B. für 
SCCB.
Also umgelötet und der Kameratyp wurde richtig erkannt.
Kamera war jetzt auch im Netz, das ankommende JPED aber laut Browser 
nicht dekodierbar. Nach einigem kramen in den Sourcen beschlossen, XCLK 
von 20MHz auf 10MHz runtergesetzt und jetzt gab es auch Bild.
Das Modul ist also recht sensibel am Bus mit den 10cm Leitungen...
Letztlich ist es mit 8MHz XCLK absolut stabil.

Mit der Erkenntnis ein originales M5Stack CAM Modul so geflasht und...
stabil, keine Aussetzer oder Bildehler mehr auch ohne nachgerüstete I2C 
PullUp Widerstände. Hier scheinen sich wirklich alle Toleranzen nach 
Murphy zu treffen, mit den Widerständen gehen auch die 20MHz XCLK, aber 
auch gerade noch so, wie mein Bekannter bei einer Kamera bemerkt hat.

Das als Tipp, falls ich jemand das M5Stack CAM kaufen sollte. Das in die 
ArduinoIDE verpackte cam-demo von github schicke ich dann gern per Mail 
zu, ich will es hier nicht reinstellen, weil es sich nicht mit allen 
IDF-Versionen lauffähig compilieren läßt. Mit der ESP32 
Boardmanager-Version 1.0.0 geht es auf jeden Fall erstmal.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb:
> reset ist auf dem Modul nicht mit dem Pin
> verbunden sondern mit 0-ohm Brücke an einer R/C-Resetschaltung.
> Dem Cam-modul gefiel es offenbar nicht, daß der ESP32 XCLK erst recht
> spät nach PowerOn erzeugte. Die Camera braucht aber XCLK auch z.B. für
> SCCB.
> Also umgelötet und der Kameratyp wurde richtig erkannt.

Könntest Du das bitte etwas näher erklären?
Hast Du die R/C-Resetschaltung vom Reset-Pin der Kamera getrennt
und separat herausgeführt und dann separat von Deinem ESP32
den Reset angestoßen nachdem XCKL stabil war ?

> Kamera war jetzt auch im Netz, das ankommende JPED aber laut Browser
> nicht dekodierbar. Nach einigem kramen in den Sourcen beschlossen, XCLK
> von 20MHz auf 10MHz runtergesetzt und jetzt gab es auch Bild.

Wie hast Du das Bild ausgewertet?
Hast Du es zunächst in Deinen Computer übertragen? (wenn ja: wie?)

> Das Modul ist also recht sensibel am Bus mit den 10cm Leitungen...
> Letztlich ist es mit 8MHz XCLK absolut stabil.

Welche Frameraten erreicht man damit?

> Mit der Erkenntnis ein originales M5Stack CAM Modul so geflasht und...
> stabil, keine Aussetzer oder Bildehler mehr auch ohne nachgerüstete I2C
> PullUp Widerstände. Hier scheinen sich wirklich alle Toleranzen nach
> Murphy zu treffen, mit den Widerständen gehen auch die 20MHz XCLK, aber
> auch gerade noch so, wie mein Bekannter bei einer Kamera bemerkt hat.

Interessant. Danke für die Hinweise.

> Das als Tipp, falls ich jemand das M5Stack CAM kaufen sollte. Das in die
> ArduinoIDE verpackte cam-demo von github schicke ich dann gern per Mail
> zu, ich will es hier nicht reinstellen, weil es sich nicht mit allen
> IDF-Versionen lauffähig compilieren läßt.

Bitte erkläre einem Arduino-Gelegenheitsuser noch etwas die Zs.hänge:
Du installierst den Board Manager für ESP32 - das habe ich verstanden.
Dann wählst Du Dein ESP32-Board aus (by the way: welches hast Du?).

Und wie integrierst Du dann die cam-demo von github?
(bitte poste einmal den Link zu dem cam-demo github-Projekt)
Muss man dann zunächst die cam-demo in der ESP-IDF compilieren,
um sie anschließend in Arduino als Library irgendwie importieren/
integrieren zu können?

> Mit der ESP32
> Boardmanager-Version 1.0.0 geht es auf jeden Fall erstmal.

Viele Grüße

Andreas

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Hast Du die R/C-Resetschaltung vom Reset-Pin der Kamera getrennt
> und separat herausgeführt und dann separat von Deinem ESP32
> den Reset angestoßen nachdem XCKL stabil war ?
Es geht um dieses Modul:
https://eckstein-shop.de/OV2640-Camera-Board

Auf der Rückseite sind an der Unterkannte einige 0-Ohm Brücken, die 
festlegen, ob PowerOn und Reset auf die Stiftleite gehen oder intern 
passend belegt werden.
Im Lieferzustand sind die beiden Signale nicht mit den Pins verbunden...
Hinweise dazu gibt es (natürlich) keine, man findet aber den Schaltplan 
im Netz und kann es dann selber überprüfen.
Ich mache da gern mal ein Bild der Rückseite mit Beschriftung der 
zuständigen Lötpunkte wenn jemand auch genau diese Kamera Modul-Version 
hat.

Zum Rest: ja, die Software erzeugt einen Restimpuls nachdem sie XCLK 
eingerichtet hat. Der nutze nur nicht viel, weil eben der Reset-Pin beim 
Modul nicht angeschlossen war.

>> Kamera war jetzt auch im Netz, das ankommende JPED aber laut Browser
>> nicht dekodierbar. Nach einigem kramen in den Sourcen beschlossen, XCLK
>> von 20MHz auf 10MHz runtergesetzt und jetzt gab es auch Bild.
>
> Wie hast Du das Bild ausgewertet?
> Hast Du es zunächst in Deinen Computer übertragen? (wenn ja: wie?)

Ich habe das fertige Demo von Espressif:
https://github.com/m5stack/esp32-cam-demo

Die Anpassungen, damit es sich aus der ArduionIDE compilieren läßt, hat 
mein Bekannter gemacht. Ich will die Sketch-Version hier nicht anhängen, 
weil sie eben nur eine Spielwiese ist, ich sende sie aber gern per Mail.

> Welche Frameraten erreicht man damit?
Real bei 800x600  ca. 3 Frames/s, ich habe muß mich erstmal mit der 
Software auseinandersetzen...

> Bitte erkläre einem Arduino-Gelegenheitsuser noch etwas die Zs.hänge:
> Du installierst den Board Manager für ESP32 - das habe ich verstanden.
> Dann wählst Du Dein ESP32-Board aus (by the way: welches hast Du?).

Richtig. Im Moment hängt sie an so einem ESP32 Modul im NodeMCu-Format, 
prinzipiell ist es aber eigentlich egal, als Beispiel:
https://www.amazon.de/ELEGIANT-ESP32-ESP32-DEVKITC-genuine-ESP-WROOM-32/dp/B06XWVS2SJ

> Und wie integrierst Du dann die cam-demo von github?
> (bitte poste einmal den Link zu dem cam-demo github-Projekt)
> Muss man dann zunächst die cam-demo in der ESP-IDF compilieren,
> um sie anschließend in Arduino als Library irgendwie importieren/
> integrieren zu können?
Nein, Sketchordner ESP32-Cam anlegen, alle Dateien des Demos in den 
Sketchordner, den Webserver noch dazu (liegt auch bei github). Dann die 
main.c in ESP32-Cam.ino umbenennen damit die ArduinoIDE zufrieden ist.
Es hagelt diverse Fehlermeldungen weil normalerweise im ESP-IDF einige 
Infos beim Compile abgefraht werden.
Den Kram hat mein Bekannter und ich passend nachgetragen, die "fertige" 
Version kann ich Dir, wie gesagt, per Mail zusenden.

Das Projekt geht ohne Änderungen auch auf der M5Stack Cam:
https://www.amazon.de/MakerHawk-M5Stack-Antenna-Arduino-Raspberry/dp/B07F2DNX6M/ref=sr_1_1?s=computers&ie=UTF8&qid=1539026864&sr=1-1&keywords=m5stack+cam

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

@Michael:

Danke für Deine Infos!
Toll, dass Ihr dies alles ans Fliegen bekommen habt.
Mir juckt es dabei arg in den Fingern - aber es hilft alles nichts:
Als 120% Berufstätiger habe ich aktuell schlicht nicht genügend Zeit
fürs Basteln und muss mich daher mit Kopfkino begnügen ...
Allerdings: für Letzteres hast Du einen guten Film gedreht :-)

Danke nochmals für Deine Erklär-Mühen.

Viele Grüße

Igel1

von David D. (saturi)


Angehängte Dateien:

Lesenswert?

Guten Abend/Nacht,

Die Kommunikation ist vorhanden! Wie erwähnt bastel ich grade an meinem 
kleinen Terminal PRogramm, dass in naher Zukunft auch die Bilder 
darstellen können sollte.
Heute ist mir der Durchbruch gelungen, nachdem ich Tage damit verbracht 
habe meinen Kenntnisstand um Themen wie Events, Delegaten und Threading 
in C# zu erweitern.

Herausbekommen ist folgendes:
Ich kann die einzelnen Register vom PC aus lesen.
Aufgabe für morgen ist es, die Register vom PC aus schreiben zu können. 
Um sich das dauernde Flashen des uController zu sparen, wenn man nur 
kleine Änderungen ausprobieren möchte.

Anbei ein Screenshot zum aktuellen "Roh-Modell"


lg. David

von Andreas S. (igel1)


Lesenswert?

Hallo David,

das sieht klasse aus!

Da viele Register schlecht oder gar nicht dokumentiert sind, hätte man 
mit Deinem Tool eine gute Möglichkeit, die Auswirkungen von Änderungen 
der Parameter in den OV7670-Registern ohne lange Turn-Around-Zeiten, zu 
testen.

Wirst Du den Code frei verfügbar machen? (z.B. auf GitHub?)

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Deine Ausdauer ist lobenswert, die Kenntnisse in C# zu erweitern auch.
Beruflich ist sowas mit Sicherheit ein Vorteil, für als inzwischen 
Rentner eher weniger. Mir reicht es, meine C/C++-Kenntnisse irgendwie 
auszubauen, fürher gab es auf µP und µC für mich nur ASM..

Daher mehr ein paar allgemeine Gedanken auch an Andreas S.:

Datenblätter sind selten Romane, das waren sie auch früher schon nicht 
und die Zusammenhänge zusammenzusuchen ist mühsam und kostet Zeit.
Er innert mich an meine erste größere Übung, am C64 den SAA52xx 
Videotextdecoder in Gang zu bringen. Datenblatt war verfügbar, 
Appliaktionshinweise war ziemlich nichts. Mußte ich also auch den Aufbau 
von Videotext erstmal verstehen lernen usw. Einzige Kontroll war ein 
kommerzielles Programm für den C64, das ich dann teilweise 
disassemblieren konnte. Teilweise, weil es nur 
"Maschinensprache-Monitore" gab, die eben ab einer Adresse den 
Speicherinhalt als ASM-Mnemotics versuchten auszugeben.

Sinn der Vorrede: die OV7670 hat 201 Register. Das Datenbaltt ist 
üblich, alles drin. Natürlich muß man dazu Vorkenntnisse haben. Wozu 
gibt es VSYNC und HSYNC bei einer zeilenweisen Bilddarstellung, was 
bedeuten die Bildformate und wie sind die Daten aufgebaut, ws ist 
Farbsättigung, Gamma, digitale Verstärkungsregelung usw. usw.
Das erklärt ein Datenblatt nicht.
Es gibt ein Applikation-Dokument im Netz zur OV7670 bei www.play-zone.ch
Google hat ihn gefunden, ich selbst auf der Seite nicht, deshalb hänge 
ich das pdf hier mal frech ran.

Mit einem Tool einfach so an den Registern rumzuspielen wäre für mich 
wie
Lottospielen, nur mit schlechteren Gewinnchancen...
Wenn ich die Kamera mit den beispielwerten des Herstellers auf einen 
Mode setze, muß hinten das erwarete Bild rauskommen.
Bis ich die Abhängigkeiten nur an Hand des Datenblattes verstanden 
hätte, wäre wohl 2020. Ich muß die Grundlagen verstehen, mich auf den 
Hersteller verlassen und kann dann natürlich auch mal variieren. Dann, 
wenn ein reproduzierbates Ergebnis ankommt, nicht vorher.
Vor allem: all das nutzt nur genau für diesen einen Kamera-Chip.
Ich muß aber verstanden habe, was nötig ist. Ich muß im datenbaltt 
suchen können, wie ist der Speicheraufbau, wie werden die Bilddaten 
abgelegt, wo lege ich fest, wo im Speicher Start- und Endpunkt einer 
Bildzeile ist, wo lege ich fest, wieviele Zeilen mein Bild haben soll 
usw.
Wenn ich ein bestimmtes Ausgabeformat haben will, will ich im Datenblatt 
schauen und geziehlt suchen können, ob der Chip das kann, wie ich es 
einstellen mus, damit er es ausgibt und wie gibt es es aus, 8Bit, 16Bit, 
24Bit, 32Bit, BigEndian, LittleEndian usw.
Ist bei der OV2640 mit der ich im Moment etwas rumspiele auch ein Drama: 
ein Hersteller beispiel mit den Inits für die Auflösungen wurde 
übernommen. Da wurde dann gekürzt und drumrumgeschrieben, weil z.B. mehr 
als 800x600 JPG auch auf einem ESP32 wegen der Ramverwaltung (max. 128kB 
im Stück verfügbar) nicht gehen. Mit PSRAM dran kann ich mir aber auch 
einen 4MB-Buffer holen. Das hat aber soweit ich bisher gefunden 
habe,noch keiner wirklich realisiert. Ich will aber wahlweise ein 
Standbild in 1600x1200 haben... Die Stream-Demos gegen einen 
HTML-JPG-Stream aus, besser wäre aber sehr wahrscheinlich ein 
MJPG-Videostream, hat aber wohl auch noch keiner probiert mit dem ESP32 
+ PSRAM.

Ist bei OV7670 mit FIFO doch auch ein Problem: der FIFO ist 384kB groß, 
ein 640x480 in 16Bit paßt also nur in 2 Halbbildern rein. Als komplettes 
Bild gehen nur 480x320.

PS: toller Roman wieder geworden......

Gruß aus Berlin
Michael

: Bearbeitet durch User
von Andreas S. (igel1)


Lesenswert?

Michael U. schrieb:
> Es gibt ein Applikation-Dokument im Netz zur OV7670 bei www.play-zone.ch
> Google hat ihn gefunden, ich selbst auf der Seite nicht, deshalb hänge
> ich das pdf hier mal frech ran.

Ganz so frech warst Du dann doch nicht - es hing nämlich nichts dran :-)

Hier die mir bekannten Links (hatte damals auch teils lange 
recherchiert) - vermutlich wäre der 4. Link Dein Tipp gewesen:

Datasheet V1.01  (08.07.2005):
https://www.voti.nl/docs/OV7670.pdf

SCCB functional Specification:
http://www4.cs.umanitoba.ca/~jacky/Teaching/Courses/74.795-LocalVision/ReadingList/ov-sccb.pdf

Implementation Guide V1.0 (Sept. 2005):
http://www.haoyuelectronics.com/Attachment/OV7670%20+%20AL422B%28FIFO%29%20Camera%20Module%28V2.0%29/OV7670%20Implementation%20Guide%20%28V1.0%29.pdf

Software Application Note:
https://www.play-zone.ch/en/fileuploader/download/download/?d=1&file=custom%2Fupload%2FFile-1402681702.pdf

Links zum OV7670 + AL422B(FIFO) Camera Module(V2.0):
http://www.hotmcu.com/ov7670-al422bfifo-camera-modulev20-p-19.html

Und meine absoluten Lieblingslinks:

http://embeddedprogrammer.blogspot.com/2012/07/hacking-ov7670-camera-module-sccb-cheat.html
http://embeddedprogrammer.blogspot.com/2013/01/demo-stm32f4-ov7670-qserialterm.html

Was das Register-Herumprobieren angeht, so hast Du natürlich recht: 
blind herumstochern macht keinen Sinn. Aber manchmal sind die 
Beschreibungen so missverständlich, dass man einfach prüfen muss, was 
passiert, wenn man Register X verändert und ob dies dem erwarteten 
Verhalten entspricht.

Ich für meinen Teil war mir damals jedenfalls oftmals unsicher, ob ich 
die Beschreibung korrekt verstanden hatte (und/oder ob diese nicht doch 
Buggy war).

Außerdem haben die Arduino-Anhänger ja diese 
Wahnsinns-Compile&Flash-Zeiten (die ich beim STM32 mit J-Link ja nicht 
habe). Da macht so ein Register-Tweating-Tool schon irgendwo Sinn.

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

Andreas S. schrieb:
> Ganz so frech warst Du dann doch nicht - es hing nämlich nichts dran :-)

Stimmt...
Hast recht mit dem play-zone Link, hat sich dann ja jetzt erledigt.

Andreas S. schrieb:
> Außerdem haben die Arduino-Anhänger ja diese
> Wahnsinns-Compile&Flash-Zeiten (die ich beim STM32 mit J-Link ja nicht
> habe). Da macht so ein Register-Tweating-Tool schon irgendwo Sinn.

Das stimmt natürlich schon. Angefangen habe ich ja mit EProms, noch dazu 
in der DDR. Da hat man es sich aus gant anderen Gründen gut überlegt, ob 
eine Änderung wiklich richtig und sinnvoll war. Löschen und 
Programmieren dauerte da merklich länger und außerdem konnte es je nach 
Qualität und Herkunft der Eproms schon passieren, daß nach dem 5. 
Löschen etliche zellen eben auf 0 bleiben. Vermutlich ist das bei mir 
eben auch teilweise Gewohnheit. Heute dann eher, um während compilieren 
und flashen schon zu der Erkenntnis zu kommen, daß man da gerade Mist 
gebaut hat. Naja, einen Flash bei AVR oder ESP habe ich noch nicht 
kaputt bekommen.
Mein Bekannter hat früher auch gern mal einen Linux-Kernel gebaut, da 
waren Stunden nicht unüblich zum compilieren.

Gruß aus Berlin
Michael

von David D. (saturi)


Lesenswert?

Andreas S. schrieb:
>
> Wirst Du den Code frei verfügbar machen? (z.B. auf GitHub?)
>

Hallo Zusammen, mein Job nimmt meine Zeit doch mehr in Anspruch als es 
noch als Student der Fall war. Zumindest was die flexibilität angeht.

Daher zieht sich mein Vortschritt leider etwas.
Um auf die Frage von Igel zurückzokmmen, ich würde euch den Code oder 
das Programm zur Verfügung stellen, sobald es eingermaßen "Bug-Frei" 
läuft. Derzeit gibt es noch viele interferenzen die ich noch nicht ganz 
überblicke. Ich hoffe an diesem langen Wochenende mich nocheinmal 
intensiv mit dem Thema auseinander zu setzten zu können und endlich mal 
einen Bildstream auslesen zu können.

viele Grüße

David

von Andreas S. (igel1)


Lesenswert?

David D. schrieb:

> Hallo Zusammen, mein Job nimmt meine Zeit doch mehr in Anspruch als es
> noch als Student der Fall war.

Ja, definitiv: Arbeit kann einem das ganze Leben versauen ;-)

> Daher zieht sich mein Fortschritt leider etwas.   [Zitat mit typofix]

Willkommen im Club.

> Um auf die Frage von Igel zurückzokmmen, ich würde euch den Code oder
> das Programm zur Verfügung stellen, sobald es eingermaßen "Bug-Frei"
> läuft. Derzeit gibt es noch viele interferenzen die ich noch nicht ganz
> überblicke. Ich hoffe an diesem langen Wochenende mich nocheinmal
> intensiv mit dem Thema auseinander zu setzten zu können und endlich mal
> einen Bildstream auslesen zu können.

Okay - aber lege die Latte Deines Qualitätsanspruchs an Dich selber 
lieber nicht zu hoch. Habe schon viele erlebt, die deshalb Ihre Projekte 
nie veröffentlicht haben - ich fand das immer schade.

Viele Grüße

Igel1

von Michael U. (amiga)


Lesenswert?

Hallo,

damit es hier nicht so ausgestorben aussieht... ;)

Stand meiner M5Stack Cam und Odroid Go Viewer:
Läuft prinzipiell stabil.
Prinzipiell: Cam macht QVGA (320x240) als JPG. Odroid Go holt das Bild 
im HTML-Rahmen, decodiert das JPG und zeigt es auf dem Display 
8ebenfalls 320x240) an. Sind ca. 1,5 Bilder/s, wenn ein Bild auf dem 
Display ist, fordert er die Webseite einfach weider an.
Die Idee, jetzt einen "hardware-Zoom" einzubauen: Markierung als Rahmen 
auf dem Display, mit dem Kreuzbutton verschiebbar. Dann ein Bild der 
Camera in SVGA (800x600) anfordern und den entsprechenden Ausschnitt auf 
dem Display anzeigen.
Das geht vorest nur prinzipiell.
Probleme im Viewer: Tastenabfrage lahm, weil der JPG-Decoder relativ 
lange pro Block braucht.
Ansonsten klappt die Idee so zumindest erstmal.
Bei der Camera habe ich zumindest soweit in das Cam-Demo reigefasst, daß 
ich eine Funktion zum Wechsel der Auflösung "on-the-fly" stabil in Gang 
habe. Probleme mit dem Speicher (framebuffer malloc/free führt schnell 
zur Fragmentierung und Speichermangel, also Buffer für SVGA einmal 
geholt und den behalten) sind soweit geklärt.
Jetzt bekomme ich aber nach dem Wechsel der Auflösung nur noch 
"Nachtaufnahmen", offenbar muß ich noch einige andere Einstellungen des 
Camera-Chips jeweils passen setzen, das muß ich noch klären...

PS: wenn ich es morgen nicht wieder vergesse bringe ich zumindest mal 
die OV7670 mit FIFO von meinem BEkannten mit.

Gruß aus Berlin
Michael

von Andreas S. (igel1)


Lesenswert?

@Michael U. :

Meinst Du mit "Odroid" den hier:
https://www.heise.de/make/meldung/Odroid-Go-Bastel-Game-Boy-mit-ESP32-zum-Odroid-Geburtstag-4088637.html 
?

Und hast Du die JPG-Decompression selbst programmiert?
Wenn ja: mit welcher Library?

Viele Grüße

Igel1

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.