ArduCAM / Arduino

This is ArduCAM library for Arduino boards
MIT License
472 stars 348 forks source link

ArduCAM_ESP8266_V2_OV5642_Capture2SD writes a corrupted Image to the SD Card #79

Open TU-KL-Crazyflie opened 8 years ago

TU-KL-Crazyflie commented 8 years ago

Hi,

We are using the Adafruit Feather HUZZAH ESP8266 board togehter with an Arducam OV5642 and a SD Card. The camera works well with the example "ArduCAM_ESP8266_OV5642_Capture". It takes pictures and sends them to the computer as expected.

So as the next step, we are trying to capture a picture and then save it on the SD card. We used the provided example code "ArduCAM_ESP8266_V2_OV5642_Capture2SD" (with some changes due to the SD Card's CS being connected to GPIO Pin 15. Now the problem is, that the camera does save a JPG file on the SD Card, but the file cannot be opened and seems corrupted. The file is attached.

Has someone else already had such a problem?

Thank you very much!

1

Nick223 commented 8 years ago

At first: change card reader wires a few times. I had the same problem with mine. Text file was corrupted or created but not overwritten.

ArduCAM commented 8 years ago

@Nick223, make sure if the camera work with host application with USB-Serial connection before moving to SD card. would you please attach the card reader photo? Sometimes the sd card reader is not well designed and occupy the SPI bus without tri-state capacity.

ArduCAM commented 8 years ago

@TU-KL-Crazyfile, From your JPG file, there is no JPEG header, I'm afraid that the camera is not well initialized to JPEG mode. Would you please show me your setup?

Nick223 commented 8 years ago

I'm not using SD Card reader. It's not my thread. I have bigger problems: your camera is working with Arduino but not with ESP8266. At all.

ArduCAM commented 8 years ago

@Nick223, The ESP8266 library should be modified to work with ArduCAM, you should follow the user guide from the link: http://www.arducam.com/arducam-esp8266-uno-board-arduino-camera/

Nick223 commented 8 years ago

You sent me nothing.

Arduino: 1.6.6 (Windows 10), Board: "ArduCAM ESP8266 UNO, 80 MHz, 921600, 4M (3M SPIFFS)"

WARNING: Category '' in library ArduinoJson is not valid. Setting to 'Uncategorized' WARNING: library Wire claims to run on [esp8266] architecture(s) and may be incompatible with your current board which runs on [ArduCAM_ESP8266_UNO] architecture(s). WARNING: library SPI claims to run on [esp8266] architecture(s) and may be incompatible with your current board which runs on [ArduCAM_ESP8266_UNO] architecture(s). WARNING: library ESP8266WiFi claims to run on [esp8266] architecture(s) and may be incompatible with your current board which runs on [ArduCAM_ESP8266_UNO] architecture(s). WARNING: library ESP8266WebServer claims to run on [esp8266] architecture(s) and may be incompatible with your current board which runs on [ArduCAM_ESP8266_UNO] architecture(s). C:\Arduino IDE\arduino-1.6.6\libraries\ArduCAM\examples\ESP8266\ArduCAM_ESP8266_OV5642_Capture\ArduCAM_ESP8266_OV5642_Capture.ino: In function 'void setup()':

ArduCAM_ESP8266_OV5642_Capture:206: error: 'OV5642_CHIPID_HIGH' was not declared in this scope

myCAM.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid);

                     ^

ArduCAM_ESP8266_OV5642_Capture:207: error: 'OV5642_CHIPID_LOW' was not declared in this scope

myCAM.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid);

                     ^

exit status 1 'OV5642_CHIPID_HIGH' was not declared in this scope

This report would have more information with "Show verbose output during compilation" enabled in File > Preferences.

Same thing happens with ESP8266 UNO board selected.

TU-KL-Crazyflie commented 8 years ago

@ArduCAM thanks for your help! I haven't changed the example code "ArduCAM_ESP8266_V2_OV5642_Capture2SD" apart from the CS for the SD Card and some serial print debugmessages. Since "ArduCAM_ESP8266_OV5642_Capture" works well, I believe that the ArduCam OV5642 works properly with my ESP8266 board.

I really have no idea what causes the image corruption problem.

#include <ArduCAM.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include "memorysaver.h"
// use #define OV5642_CAM_BIT_ROTATION_FIXED in memorysaver.h for our Camera

// set GPIO16 as the slave select :
const int CS = 16;
// set GPIO15 as the SD Card slave select :
const int SD_CS = 15;
ArduCAM myCAM(OV5642, CS);

void myCAMSaveToSDFile(){
  char str[8];
  byte buf[256];
  static int i = 0;
  static int k = 0;
  static int n = 0;
  uint8_t temp, temp_last;
  File file;
  //Flush the FIFO
  myCAM.flush_fifo();
  //Clear the capture done flag
  myCAM.clear_fifo_flag();
  //Start capture
  myCAM.start_capture();
  Serial.println("start Capture");
 while(!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
 Serial.println("Capture Done!");  

 //Construct a file name
 k = k + 1;
 itoa(k, str, 10);
 strcat(str, ".jpg");
 //Open the new file
 file = SD.open(str, O_WRITE | O_CREAT | O_TRUNC);
 if(! file){
  Serial.println("open file faild");
  return;
 }
 i = 0;
 myCAM.CS_LOW();
 myCAM.set_fifo_burst();
 temp=SPI.transfer(0x00);
 temp = (byte)(temp >> 1) | (temp << 7); // correction for bit rotation
 //Read JPEG data from FIFO
 while ( (temp !=0xD9) | (temp_last !=0xFF)){
  temp_last = temp;
  temp = SPI.transfer(0x00);
  temp = (byte)(temp >> 1) | (temp << 7); // correction for bit rotation
  //Write image data to buffer if not full
  if( i < 256)
   buf[i++] = temp;
   else{
    //Write 256 bytes image data to file
    myCAM.CS_HIGH();
    file.write(buf ,256);
    i = 0;
    buf[i++] = temp;
    myCAM.CS_LOW();
    myCAM.set_fifo_burst();
   }
   delay(0);  
 }

 //Write the remain bytes in the buffer
 if(i > 0){
  myCAM.CS_HIGH();
  file.write(buf,i);
  yield();
 }
 //Close the file
 file.close();
  Serial.println("CAM Save Done!");
}

void setup(){
  uint8_t vid, pid;
  uint8_t temp;

  Wire.begin();
  Serial.begin(115200);
  Serial.println("ArduCAM Start!");

  //set the CS as an output:
  pinMode(CS,OUTPUT);
  digitalWrite(CS, HIGH);

  pinMode(SD_CS, OUTPUT);
  digitalWrite(SD_CS, HIGH);
  delay(1);

  // initialize SPI:
  SPI.begin();
  SPI.setFrequency(4000000); //4MHz
  delay(1000);

  //Initialize SD Card
  if(!SD.begin(SD_CS)){
    Serial.println("SD Card Error");
  }
  else
  Serial.println("SD Card detected!");

  //Check if the ArduCAM SPI bus is OK
  myCAM.write_reg(ARDUCHIP_TEST1, 0x55);
  temp = myCAM.read_reg(ARDUCHIP_TEST1);

  Serial.println(temp, HEX);

  if (temp != 0x55){
    Serial.println("SPI1 interface Error!");
    while(1);
  }

  myCAM.clear_bit(ARDUCHIP_GPIO,GPIO_PWDN_MASK); //disable low power
  delay(100);
//Check if the camera module type is OV5642
//myCAM.wrSensorReg16_8(0xff, 0x01);
  myCAM.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid);
  myCAM.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid);

  Serial.println(vid, HEX);
  Serial.println(pid, HEX); 

   if((vid != 0x56) || (pid != 0x42))
   Serial.println("Can't find OV5642 module!");
   else
   Serial.println("OV5642 detected.");
   myCAM.set_format(JPEG);
   myCAM.InitCAM();
   myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);   //VSYNC is active HIGH
   myCAM.OV5642_set_JPEG_size(OV5642_1280x720); 
}

void loop(){
  myCAMSaveToSDFile();
  myCAM.set_bit(ARDUCHIP_GPIO,GPIO_PWDN_MASK);  //enable low power
  delay(3000);
  myCAM.clear_bit(ARDUCHIP_GPIO,GPIO_PWDN_MASK); //disable low power
  delay(2000);  

}
TU-KL-Crazyflie commented 8 years ago

@Nick223 At first the Camera did not work not with my Adafruit Feather HUZZAH ESP8266 either.

This was due to several problems with the SPI Bus and particularly the (in my oppinion) not so well documented fact, that there are two different OV5246 Versions. One requiring the additional Bit Rotation and the other revision which has it's firmware apparently already fixed. Depending on which revision you got, it's necessary to change the "memorysaver.h" accordingly.

Lastly I had the problem with "ArduCAM_ESP8266_OV5642_Capture", that testing the SPI and I²C communication sometimes was successful and sometimes not, but capturing the image almost always failed with a WDT Reset. Strangely if I connect the SD card reader together with the Camera to my ESP8266 (leaving the SD card's CS Pin on High all the time to disable the SD card's coomunication) the Camera works somehow. I dont know exactly why, but it just works. :)

Nick223 commented 8 years ago

Very interesting. I must try out adding SD card reader. But I've seen people that got this to work without it. I mean, video streaming example (ArduCAM_ESP8266_OV5642_Capture) doesn't even utilize SD cards.

TU-KL-Crazyflie commented 8 years ago

@Nick223 We wanted to use our Saleae Logic Pro 8 Logic Analyzer to find out why the SPI Bus was not working properly. Astonishingly if we connected our Saleae Logic Analyzer to the Camera's SPI Bus, initializing the Camera was always successful and taking pictures with "ArduCAM_ESP8266_OV5642_Capture" worked properly.

This must have something to do with SCK. The Logic Analyzer has a resitance of 20 mega ohm between GND and it's Signal Lines. Having it connected to the SPI Bus, effectivly acts as a Pulldown Resistor on the SCK Line.

Indeed I am not sure why this would be necessary for the SPI Bus to work properly.

Nick223 commented 8 years ago

And that's what I think is odd but interesting.

ArduCAM commented 8 years ago

@Nick223, Have you read the user guide http://www.arducam.com/downloads/ESP8266_UNO/ArduCAM_ESP8266_UNO_DS.pdf from the post: http://www.arducam.com/arducam-esp8266-uno-board-arduino-camera/ You have to manually modify the memorysaver.h in the library to enable the OV5642 camera and disable the OV2640 camera. Only one camera can be enabled at a time.

ArduCAM commented 8 years ago

@TU-KL-Crazyfile, It seems that you use the wrong SD_CS pins, please check the ESP8266 UNO pinout from http://www.arducam.com/pinout-esp8266-20160612update/

Nick223 commented 8 years ago

I didn't read it. The first thing I did was changing definitios.

Nick223 commented 8 years ago

I finally got it to work. Resets! ets Jan 8 2013,rst cause:2, boot mode:(3,7)

load 0x4010f000, len 1384, room 16 tail 8 chksum 0x2d csum 0x2d v60000318 ~ld

Nick223 commented 8 years ago

Another reset:

ets Jan 8 2013,rst cause:4, boot mode:(1,7) wdt reset

And another:

ets Jan 8 2013,rst cause:4, boot mode:(3,7)

wdt reset ets_main.c

ryonlabaw commented 7 years ago

ESP8266 + Arducam mini 5mp does work well.

According to the manual, wdt resets are due to not freeing up the processor enough during your procedures.

I solved my esp8266 wdt reset issues by adding a few delay() and yield() calls at various points (reading/writing). I haven't connected an SD yet. Although, I can confirm that the arducam mini 5mp + esp8266 is able to stream any resolution reliably over the network. It is also possible to save to the on-board flash.

320x240 has about a 1 second delay during network streaming. It may be possible to get better results.

Also, I am using the github version of esp8266-arduino library ... and using the spi.transfer() method for reading data.

ArduCAM commented 7 years ago

@Ryon, thanks for your effort. Would you please provide your example code, so we can update ours.

ryon commented 7 years ago

@ryonlabaw See above :)

ryonlabaw commented 7 years ago

@ArduCAM Here is the working sketch ... the important part of this is the "serverStream()" function ... that is where I've made the changes to your original script.

Using wget, I am seeing 17KB/s sustained transfer. My goal is to squeeze more performance out of this combo. The esp8266 can transfer data much faster. Obviously the copy spi data from the camera is slowing things down.

See this topic on fast wifi transfer... Found a way to upload data VERY fast by wifi

As far as results for the sketch below; I have been able to stream for hours without issue... longest test was about 6hrs before I shut it off to go to bed.

Hardware: Wemos D1 Mini + Arducam mini 5mp ...

`// ArduCAM Mini demo (C)2016 Lee // web: http://www.ArduCAM.com // This program is a demo of how to use most of the functions // of the library with ArduCAM ESP8266 5MP camera. // This demo was made for ArduCAM ESP8266 OV5642 5MP Camera. // It can take photo and send to the Web. // It can take photo continuously as video streaming and send to the Web. // The demo sketch will do the following tasks: // 1. Set the camera to JEPG output mode. // 2. if server.on("/capture", HTTP_GET, serverCapture),it can take photo and send to the Web. // 3.if server.on("/stream", HTTP_GET, serverStream),it can take photo continuously as video //streaming and send to the Web.

// This program requires the ArduCAM V3.4.1 (or later) library and ArduCAM ESP8266 5MP camera // and use Arduino IDE 1.5.8 compiler or above

// In "memorysaver.h", uncomment the following definition // #define OV5642_CAM // // and the others are commented out

include

include

include

include

include

include

include

include "memorysaver.h"

// Enabe debug tracing to Serial port.

define DEBUGGING

// Here we define a maximum framelength to 64 bytes. Default is 256.

define MAX_FRAME_LENGTH 64

//#define MAX_FRAME_LENGTH 256

// Define how many callback functions you have. Default is 1.

define CALLBACK_FUNCTIONS 1

// set GPIO16 as the slave select : const int CS = 16;

int wifiType = 0; // 0:Station 1:AP const char* ssid = "ssidhere"; // Put your SSID here const char* password = "passhere"; // Put your PASSWORD here

ESP8266WebServer server(80);

ArduCAM myCAM(OV5642, CS); int status = WL_IDLE_STATUS;

void start_capture() { //Flush the FIFO myCAM.flush_fifo(); //Clear the capture done flag myCAM.clear_fifo_flag(); //myCAM.write_reg(ARDUCHIP_FRAMES, 0x00); myCAM.start_capture(); }

void camCapture(ArduCAM myCAM) { uint8_t temp, temp_last;

WiFiClient client = server.client(); //client.setNoDelay(true); size_t len = myCAM.read_fifo_length(); Serial.println(">> Length: " + String(len)); if (len >= 393216) { Serial.println("Over size."); return; } else if (len == 0 ) { Serial.println("Size is 0."); return; }

myCAM.CS_LOW(); myCAM.set_fifo_burst(); SPI.transfer(0xFF); //SPI.transfer(0x00);

if (!client.connected()) return; String response = "HTTP/1.1 200 OK\r\n"; response += "Content-Type: image/jpeg\r\n"; response += "Content-Length: " + String(len) + "\r\n\r\n"; server.sendContent(response);

static const size_t bufferSize = 1760; //2048; //512; //4096; static uint8_t buffer[bufferSize] = {0xFF}; while (len) { size_t will_copy = (len < bufferSize) ? len : bufferSize; myCAM.transferBytes(&buffer[0], &buffer[0], will_copy); //delay(1); yield(); if (!client.connected()) break; client.write(&buffer[0], will_copy); //Serial.write(&buffer[0], will_copy); len -= will_copy; delay(40); yield(); }

myCAM.CS_HIGH(); }

void serverCapture() { myCAM.clear_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //disable low power delay(200); start_capture(); Serial.println("CAM Capturing");

int total_time = 0; total_time = millis(); while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK)); total_time = millis() - total_time; Serial.print("capture total_time used (in miliseconds):"); Serial.println(total_time, DEC); total_time = 0; Serial.println("CAM Capture Done!"); total_time = millis(); camCapture(myCAM); myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //enable low power total_time = millis() - total_time; Serial.print("send total_time used (in miliseconds):"); Serial.println(total_time, DEC); Serial.println("CAM send Done!"); myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //enable low power }

void serverStream() { uint8_t temp, temp_last; bool is_header = false; myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //enable low power WiFiClient client = server.client(); // not sure if this helps, no noticable speed increase. //client.setNoDelay(true); String response = "HTTP/1.1 200 OK\r\n"; response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n"; server.sendContent(response);

myCAM.clear_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //disable low power myCAM.clear_fifo_flag();

while (1) {

delay(70); // 40 == 17kbps (30 works well too)
yield();
start_capture();
yield();
while (!myCAM.get_bit(ARDUCHIP_TRIG, CAP_DONE_MASK));
size_t len = myCAM.read_fifo_length();
//Serial.println(">>Length: " + len);
if ((len >= 524288) | (len == 0))
{
  myCAM.clear_fifo_flag();
  continue;
}

myCAM.CS_LOW();
myCAM.set_fifo_burst();
//SPI.transfer(0xFF);
if (!client.connected()) break;
response = "--frame\r\n";
response += "Content-Type: image/jpeg\r\n\r\n";
server.sendContent(response);

//static const size_t bufferSize = 2048; //512; //4096;
//static uint8_t buffer[bufferSize] = {0xFF};

len--;
while ( len-- )
{
  yield();
  //if (!client.connected()) break;
  temp_last = temp;
  temp =  SPI.transfer(0x00);
  if (is_header == true)
  {

      client.write(&temp, 1);
      yield();
  }
  else if ((temp == 0xD8) & (temp_last == 0xFF))
  {
    is_header = true;

      client.write(&temp_last, 1);
      yield();
      client.write(&temp, 1);
      yield();
  }
  if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
    break;
  delayMicroseconds(12);

}
myCAM.CS_HIGH();

myCAM.clear_fifo_flag();

if (!client.connected()) break;

is_header = false;

} myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //enable low power }

void handleNotFound() { String message = "Server is running!\n\n"; message += "URI: "; message += server.uri(); message += "\nMethod: "; message += (server.method() == HTTP_GET) ? "GET" : "POST"; message += "\nArguments: "; message += server.args();

message += "\n\n /capture : camera capture"; message += "\n /stream : video streaming"; message += "\n\n /?ql=0 : 320x240"; message += "\n /?ql=1 : 640x480"; message += "\n /?ql=2 : 1280x720"; message += "\n /?ql=3 : 1920x1080"; message += "\n /?ql=4 : 2048x1563"; message += "\n /?ql=5 : 2592x1944"; message += "\n"; server.send(200, "text/plain", message);

if (server.hasArg("ql")) { myCAM.clear_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //disable low power int ql = server.arg("ql").toInt(); myCAM.OV5642_set_JPEG_size(ql); myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //enable low power Serial.println("QL change to: " + server.arg("ql")); } }

void setup() { uint8_t vid, pid; uint8_t temp;

if defined(SAM3X8E)

Wire1.begin();

else

Wire.begin();

endif

Serial.begin(115200); Serial.println("ArduCAM Start!");

// set the CS as an output: pinMode(CS, OUTPUT);

// initialize SPI: SPI.begin(); SPI.setFrequency(8000000); //4MHz -or 8MHZ //SPI.setBitOrder(MSBFIRST);

//Check if the ArduCAM SPI bus is OK myCAM.write_reg(ARDUCHIP_TEST1, 0x55); temp = myCAM.read_reg(ARDUCHIP_TEST1); if (temp != 0x55) { Serial.println("SPI1 interface Error!"); while (1); } myCAM.clear_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //disable low power delay(100); //Check if the camera module type is OV5642 //myCAM.wrSensorReg16_8(0xff, 0x01); myCAM.rdSensorReg16_8(OV5642_CHIPID_HIGH, &vid); myCAM.rdSensorReg16_8(OV5642_CHIPID_LOW, &pid); if ((vid != 0x56) || (pid != 0x42)) { Serial.println("Can't find OV5642 module!"); while (1); } else Serial.println("OV5642 detected.");

//Change to JPEG capture mode and initialize the OV5642 module myCAM.set_format(JPEG); myCAM.InitCAM(); myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK); //VSYNC is active HIGH myCAM.OV5642_set_JPEG_size(OV5642_320x240);

myCAM.clear_fifo_flag();

myCAM.write_reg(ARDUCHIP_FRAMES, 0x00); myCAM.set_bit(ARDUCHIP_GPIO, GPIO_PWDN_MASK); //enable low power

if (wifiType == 0) { // Connect to WiFi network Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(ssid);

WiFi.mode(WIFI_STA);

  WiFi.begin(ssid, password);
while ( status != WL_CONNECTED) {
  delay(1000);
  Serial.print(".");
  status = WiFi.status();
}
Serial.println("WiFi connected");
Serial.println("");
Serial.println(WiFi.localIP());

} else if (wifiType == 1) { Serial.println(); Serial.println(); Serial.print("Share AP: "); Serial.println(ssid);

WiFi.mode(WIFI_AP);
WiFi.softAP(ssid, password);
Serial.println("");
Serial.println(WiFi.softAPIP());

}

// Start the server server.on("/capture", HTTP_GET, serverCapture); server.on("/stream", HTTP_GET, serverStream); server.onNotFound(handleNotFound); server.begin(); Serial.println("Server started"); } void loop() {

server.handleClient(); } `