Categories
code electronics video

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

C++ Library for the C329 camera module of the SPI variety

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.

3 replies on “C++ library for the C329 SPI camera module [w/ code]”

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

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 640×480 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

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.

Leave a Reply

Your email address will not be published. Required fields are marked *