«

»

Apr 25

C++ library for the C329 SPI camera module [w/ code]

Just putting it out there for whoever is trying to use the C329 camera module of the SPI variety (the URAT module has code posted online)

The UART code is at: https://github.com/svoisen/c329
But electronics123.com have a SPI module as well, without code supplied.
I took the UART code and changed it to work with Arduino's SPI library. The changes are minuscule, but someone might find them useful instead of writing them again.

I used C329 with Teensy 2.0, and connected the MISO MOSI SCLK pins to the defaults, the only thing left is to connect the SPI CS pin on the camera module (check out Page 3 in the manual) to some GPIO, I chose the Teensy's B0 pin.

So the operation of the library is very similar to the example online:

#include "CameraC329.h"
#include <SPI.h>

CameraC329 camera(PIN_B0); //set B0 as the CS pin

void getPicture_callback(uint32_t pictureSize, uint16_t packetSize, uint32_t packetStartPosition, byte* packet)
{
//do something with picture buffer
}

void setup() {
          pinMode(PIN_B0, OUTPUT);
          digitalWrite(PIN_B0,HIGH); //unselect

          SPI.setDataMode(SPI_MODE0);
          SPI.begin();

          delay(2000); //time for the module to load stuff from EEPROM

          if (!camera.sync())
          {
            Serial.println("Sync failed");
            camera.powerOff();
            SPI.end();
            return;
          } else {
            Serial.println("Camera sync");
          }
        
          if (!camera.initialize(CameraC329::BAUD14400, CameraC329::CT_JPEG, CameraC329::PR_160x120, CameraC329::JR_320x240))
          {
            Serial.println("Initialize failed");
            return;
          } else {
            Serial.println("Camera init");
          }
          
          if (!camera.setQuality(CameraC329::QL_BEST))
          {
            Serial.println("Set quality failed");
            return;
          } else {
            Serial.println("Camera quality set");
          }

          if (!camera.getPicture(CameraC329::PT_JPEG_PREVIEW, &getPicture_callback))
          {
            Serial.println("Get Picture Failed");
            return;
          }
}

The major changes to the UART library are in the sendCommand and waitForResponse functions

void CameraC329::sendCommand()
{
  uint8_t i;
//Serial.print("send command ");
  // Big endian
  for (i = 0; i < CMD_SIZE; i++)
  {
//Serial.print(outputCommand[i]); Serial.print(" ");
    digitalWrite(spi_cs_pin,LOW);
    SPI.transfer(outputCommand[i]);
    digitalWrite(spi_cs_pin,HIGH);
  }
//Serial.println();
}

bool CameraC329::waitForResponse(uint32_t timeout, byte buffer[], uint16_t bufferLength)
{
  uint8_t byteCount = 0;
  unsigned long time = millis();

//Serial.print("response: ");
  while (millis() - time <= timeout)
  {
//    while (cameraPort.available() > 0) //hmmm...
    {
      digitalWrite(spi_cs_pin,LOW);
      buffer[byteCount] = SPI.transfer(0x00); //cameraPort.read();
      digitalWrite(spi_cs_pin,HIGH);
      
//Serial.print(buffer[byteCount],DEC); Serial.print(" ");
      byteCount++;

      if (byteCount == bufferLength) {
//Serial.println();
        return true;
      }
    }
  }
//Serial.println();
  if (byteCount > 0)
    return true;

  return false;
}

But I also found the GET PIC command to be very very picky. It really only responds very sporadically, so I added a bunch of retries:

bool CameraC329::getPicture(PictureType pictureType, void (*callback)(uint32_t pictureSize, uint16_t packetSize, uint32_t packetStartPosition, byte* packet))
{
  uint32_t pictureSize = 0;

  reset(RT_STATE);

  //Although ACK is part of the spec, we're really waiting for a DATA response, so let's skip waiting for ACK and just wait for DATA
//  while (!waitForACK(RESPONSE_DELAY, CMD_GETPICTURE) && ack_counter < 100) {
//    delay(10);
//  }

  //try to send the GET PIC command for 10 times before giving up
  uint32_t get_pic_tries = 0;
  while(get_pic_tries++ < 10) {
    setOutputCommand(CMD_GETPICTURE, pictureType, 0, 0, 0);
    sendCommand();

    uint32_t max_tries = 0, total_tries = 10;
    while (!(waitForResponse(RESPONSE_DELAY) && inputCommand[3] == CMD_DATA) && max_tries++ < total_tries) {
      //this is not a DATA response (start of the image data), let's wait try again shortly
      Serial.print("not DATA ("); Serial.print(inputCommand[3]); Serial.println(")"); 
      delay(10);
    }
    
    if(max_tries < total_tries) break;
  }
  if(get_pic_tries >= 10) return false;
  
  pictureSize = inputCommand[7] << 8;
  pictureSize |= inputCommand[6] << 8;
  pictureSize |= inputCommand[5];

  uint32_t bytePosition = 0;
  uint8_t package[DEFAULT_PACKAGE_SIZE];

  while (bytePosition < pictureSize)
  {
    if (!waitForResponse(RESPONSE_DELAY, package, DEFAULT_PACKAGE_SIZE))
      return false;

    callback(pictureSize, min(DEFAULT_PACKAGE_SIZE, pictureSize - bytePosition), bytePosition, package);
    bytePosition += DEFAULT_PACKAGE_SIZE;
  }

  return true;
}

Even with that, it's not 100% stable!
I think there's still problem with the SPI timing...

Code can be grabbed at: http://web.media.mit.edu/~roys/src/CameraC329SPI.zip

Enjoy,
Roy.

Share
  • neo

    Your posts are are someone ...I always keep waiting for a new post from you in my RSS feed!

  • glenn kreisel

    Hey Roy,

    I can get one picture data after a manual power cycle of the camera but after the data is transferred I can not talk to the camera anymore. I must manually power cycle it. I've posted a dump if that can help. Also I can't set the resolution at 640x480 I get errors.
    Any ideas? How do you take repeat pictures?
    PIN 53
    send command 255 255 255 13 0 0 0 0
    Got ACK
    send command 255 255 255 14 13 0 0 0
    Camera sync
    send command 255 255 255 1 0 7 5 5
    Got ACK
    Camera init
    send command 255 255 255 16 0 0 0 0
    Got ACK
    Camera quality set
    send command 255 255 255 4 5 0 0 0
    not DATA (0)
    ACK for 4 (3)
    Size: 3056, PktSize: 128 Start:0
    Size: 3056, PktSize: 128 Start:128
    Size: 3056, PktSize: 128 Start:256
    Size: 3056, PktSize: 128 Start:384
    Size: 3056, PktSize: 128 Start:512
    Size: 3056, PktSize: 128 Start:640
    Size: 3056, PktSize: 128 Start:768
    Size: 3056, PktSize: 128 Start:896
    Size: 3056, PktSize: 128 Start:1024
    Size: 3056, PktSize: 128 Start:1152
    Size: 3056, PktSize: 128 Start:1280
    Size: 3056, PktSize: 128 Start:1408
    Size: 3056, PktSize: 128 Start:1536
    Size: 3056, PktSize: 128 Start:1664
    Size: 3056, PktSize: 128 Start:1792
    Size: 3056, PktSize: 128 Start:1920
    Size: 3056, PktSize: 128 Start:2048
    Size: 3056, PktSize: 128 Start:2176
    Size: 3056, PktSize: 128 Start:2304
    Size: 3056, PktSize: 128 Start:2432
    Size: 3056, PktSize: 128 Start:2560
    Size: 3056, PktSize: 128 Start:2688
    Size: 3056, PktSize: 128 Start:2816
    Size: 3056, PktSize: 112 Start:2944
    send command 255 255 255 14 4 99 0 0
    send command 255 255 255 8 1 0 0 255
    NO ACK

  • Wyy

    Hi Glenn

    I try to set up using SPI to STM32 microcontroller
    SPI MODE 0
    MSBFIRST
    SPI Clock @ 281kHz

    Try to perform sync but no available
    Perform signal analyzing reading and no MISO trigger at all, even after trying to repeat sync for 60 times or more.

    OV529 datasheet does not mention anything on SPI and resources is limited.