Welcome to our seventh blog post! We are back with our newest camera module from ArduCAM which is a cracking improvement over the OV7670 that we used for testing the Deep Learning model in the last blog post.

 


This is called
the ArduCAM Mini 2MP which is technically a shield housing the OV2640, a 2 MP image sensor that would normally come with 16 pins on its own without the shield. The advantage of this shield is that it simplifies the number of pins of the module to just 6 from the above mentioned 16, and hence simplifies I/O operations brilliantly with easily available open source code to run it on many different platforms including Arduino and RPi boards. Special shoutout to Jason Perry from Nova Scotia, an old friend who was kind enough to sponsor this camera sensor and the speaker that we are going to use later for the audio output. Thanks a lot, mate!

 

This camera roughly costs about 45$ as we had to get it imported from the actual manufacturer ArduCAM to get it.  That's also the reason why it took so much time for us to get our hands on this module, exactly 30 days from the date of ordering. So this caused a lot of delay in our blog posts, hope that we're not too late and we can cover up lost time very quickly.

 

So let's get down to business, we intend on getting our hands dirty in this blog post. The aim of this blog post is to get the ArduCAM Mini 2MP running with our MKR1000 and for it to run along with the SD Proto Shield to save images into an SD card. So let's get started with it!

 

Let us start by providing some insight about ArduCAM - it is a startup company dedicated to open source hardware and software designing and manufacturing from China, especially for Arduino, Raspberry Pi camera solutions. It provides easy plug and play solutions for various boards and easily available library support on GitHub. It has camera sensors ranging from the 0.3 MP OV7670 to 8MP image sensors for RPi platform. Here we have chosen a 2 MP camera because it is optimal for our MKR1000 which will handle the tasks of saving images to SD card and also transmitting them to the model. A 5 MP is bound to get overbearing on the MKR1000 and it will also cause overheating.

 

The libraries for interfacing ArduCAMs with various platforms is available here - https://github.com/ArduCAM . We have used the library and examples for the Arduino boards stored in the first repository. The Arduino ArduCAM library has been tested for platforms like Uno, Nano, Mega etc but it is not preconfigured for our MKR1000. So it doesn't work without a slight modification in the code. The block of code required to be added to ArduCAM.h is -

 

#define MKR1000 1
#if defined(MKR1000)
 #define cbi(reg, bitmask) digitalWrite(bitmask, LOW)
 #define sbi(reg, bitmask) digitalWrite(bitmask, HIGH)
 #define pulse_high(reg, bitmask) sbi(reg, bitmask); cbi(reg, bitmask);
 #define pulse_low(reg, bitmask) cbi(reg, bitmask); sbi(reg, bitmask);
 
 #define cport(port, data) port &= data
 #define sport(port, data) port |= data
 
 #define swap(type, i, j) {type t = i; i = j; j = t;}
 
 #define fontbyte(x) cfont.font[x]  
 
 #define regtype volatile uint32_t
 #define regsize uint32_t
#endif

 

Next we have to connect the ArduCAM Mini 2 MP with the MKR1000 according to the following pin diagram -

The SD proto shield is also connected to store the images in the SD card card, for which the chip select is 4 (D4).

 

 

 

The next step is to connect the MKR1000 to our PC and upload the following code taken from the official ArduCAM library examples to save image to SD card -

 

#include <ArduCAM.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include "memorysaver.h"
//This demo can only work on OV2640_MINI_2MP or OV5642_MINI_5MP or OV5642_MINI_5MP_BIT_ROTATION_FIXED platform.
#if !(defined OV5642_MINI_5MP || defined OV5642_MINI_5MP_BIT_ROTATION_FIXED || defined OV2640_MINI_2MP || defined OV3640_MINI_3MP)
  #error Please select the hardware platform and camera module in the ../libraries/ArduCAM/memorysaver.h file
#endif
#define SD_CS 4
const int SPI_CS = 0;
#if defined (OV2640_MINI_2MP)
  ArduCAM myCAM( OV2640, SPI_CS );
#elif defined (OV3640_MINI_3MP)
  ArduCAM myCAM( OV3640, SPI_CS );
#else
  ArduCAM myCAM( OV5642, SPI_CS );
#endif


void myCAMSaveToSDFile(){
char str[8];
byte buf[256];
static int i = 0;
static int k = 0;
uint8_t temp = 0,temp_last=0;
uint32_t length = 0;
bool is_header = false;
File outFile;
//Flush the FIFO
myCAM.flush_fifo();
//Clear the capture done flag
myCAM.clear_fifo_flag();
//Start capture
myCAM.start_capture();
Serial.println(F("start Capture"));
while(!myCAM.get_bit(ARDUCHIP_TRIG , CAP_DONE_MASK));
Serial.println(F("Capture Done."));  
length = myCAM.read_fifo_length();
Serial.print(F("The fifo length is :"));
Serial.println(length, DEC);
if (length >= MAX_FIFO_SIZE) //384K
{
  Serial.println(F("Over size."));
  return ;
}
if (length == 0 ) //0 kb
{
  Serial.println(F("Size is 0."));
  return ;
}
//Construct a file name
k = k + 1;
itoa(k, str, 10);
strcat(str, ".jpg");
//Open the new file
outFile = SD.open(str, O_WRITE | O_CREAT | O_TRUNC);
if(!outFile){
  Serial.println(F("File open faild"));
  return;
}
myCAM.CS_LOW();
myCAM.set_fifo_burst();
while ( length-- )
{
  temp_last = temp;
  temp =  SPI.transfer(0x00);
  //Read JPEG data from FIFO
  if ( (temp == 0xD9) && (temp_last == 0xFF) ) //If find the end ,break while,
  {
    buf[i++] = temp;  //save the last  0XD9     
    //Write the remain bytes in the buffer
    myCAM.CS_HIGH();
    outFile.write(buf, i);    
    //Close the file
    outFile.close();
    Serial.println(F("Image save OK."));
    is_header = false;
    i = 0;
  }  
  if (is_header == true)
  { 
    //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();
      outFile.write(buf, 256);
      i = 0;
      buf[i++] = temp;
      myCAM.CS_LOW();
      myCAM.set_fifo_burst();
    }        
  }
  else if ((temp == 0xD8) & (temp_last == 0xFF))
  {
    is_header = true;
    buf[i++] = temp_last;
    buf[i++] = temp;   
  } 
} 
}


void setup(){
uint8_t vid, pid;
uint8_t temp;
Wire.begin();
Serial.begin(115200);
Serial.println(F("ArduCAM Start!"));
//set the CS as an output:
pinMode(SPI_CS,OUTPUT);
digitalWrite(SPI_CS, HIGH);
// initialize SPI:
SPI.begin();
  
//Reset the CPLD
myCAM.write_reg(0x07, 0x80);
delay(100);
myCAM.write_reg(0x07, 0x00);
delay(100);
  
while(1){
  //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(F("SPI interface Error!"));
    delay(1000);continue;
  }else{
    Serial.println(F("SPI interface OK."));break;
  }
}
//Initialize SD Card
while(!SD.begin(SD_CS)){
  Serial.println(F("SD Card Error!"));delay(1000);
}
Serial.println(F("SD Card detected."));


#if defined (OV2640_MINI_2MP)
  while(1){
    //Check if the camera module type is OV2640
    myCAM.wrSensorReg8_8(0xff, 0x01);
    myCAM.rdSensorReg8_8(OV2640_CHIPID_HIGH, &vid);
    myCAM.rdSensorReg8_8(OV2640_CHIPID_LOW, &pid);
    if ((vid != 0x26 ) && (( pid != 0x41 ) || ( pid != 0x42 ))){
      Serial.println(F("Can't find OV2640 module!"));
      delay(1000);continue;
    }
    else{
      Serial.println(F("OV2640 detected."));break;
    } 
  }
#elif defined (OV3640_MINI_3MP)
  while(1){
    //Check if the camera module type is OV3640
    myCAM.rdSensorReg16_8(OV3640_CHIPID_HIGH, &vid);
    myCAM.rdSensorReg16_8(OV3640_CHIPID_LOW, &pid);
    if ((vid != 0x36) || (pid != 0x4C)){
      Serial.println(F("Can't find OV3640 module!"));
      delay(1000);continue; 
    }else{
      Serial.println(F("OV3640 detected."));break;    
    }
 } 
#else
  while(1){
    //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(F("Can't find OV5642 module!"));
      delay(1000);continue;
    }
    else{
      Serial.println(F("OV5642 detected."));break;
    } 
  }
#endif
myCAM.set_format(JPEG);
myCAM.InitCAM();
#if defined (OV2640_MINI_2MP)
  myCAM.OV2640_set_JPEG_size(OV2640_1024x768);
#elif defined (OV3640_MINI_3MP)
  myCAM.OV3640_set_JPEG_size(OV3640_320x240);
#else
  myCAM.write_reg(ARDUCHIP_TIM, VSYNC_LEVEL_MASK);   //VSYNC is active HIGH
  myCAM.OV5642_set_JPEG_size(OV5642_320x240);
#endif
delay(1000);
}
void loop(){
myCAMSaveToSDFile();
delay(8000);
}
'





 

After this, we open the serial monitor to see the following information

 

As we can see, the serial monitor displays the initial set up completion of ArduCAM and detects the SD card along with it, then it goes ahead to to capture pictures in it's fifo. The fifo is ArduCAM's memory which is 384K in our ArduCAM Mini 2MP module. You can see the set of pictures saved in the SD card below -

 

 

Some of the images taken by our module -

 

 

Thanks for reading this blog. The next one is coming up soon!