Library for COMedia C328R Serial Camera

Hello All,

I recently finished a library for the COMedia C328R serial camera. (Google it. This is my first post so apparently I can't add the link ...)

If anyone has one of these cameras and is interested in testing the library, please let me know. This is my first Arduino library, and my C++ was a little rusty :D But, it does provide a nice easy way to take pictures using the Arduino.

In addition to the camera, you will need some external storage mechanism, given the size of the images (approx 10-11K for 640x480 JPEGs). I use an external SPI EEPROM, store the image on the EEPROM, the send the data to my computer for local filesystem storage using Processing.

Cleaning up the sample usage code now ...

Nice project. Waiting for link since I did a google and didn’t find anything “arduino C328R”.

Where did you buy the camera?

Here's the camera: http://www.electronics123.com/s.nl/it.A/id.2581/.f

The different models are just different lens types.

Hi Sean,

You remember me, I've contacted you by mail to know more about this lib last week :)

I've also began to code a lib to use this cam, i've got inspiration from the C lib coded for another controller

Could you send me a link for you lib so that I can test it ?

For now, i can synchronise with the cam, set params, and launch snapshot, now i get problem to store the image in a SD card.

See you soon

Here's a link to version 001 of the library: http://gimbalsandbits.com/downloads/arduino/

It's the file c328r_001.zip

I'm going to try and post sample code later today or tomorrow, but if you know how the camera works then you should be able to figure it out. The main thing to understand is the getJPEGPicture method, which takes the address to a callback method ... every time this callback is called that means a new packet containing JPEG data has arrived. In this callback is where I add the incoming JPEG data to a 64 byte page buffer, then when the buffer is full, write it to the EEPROM.

More to follow ...

Sean

Hi Sean,

Your code is very good ! I can certainly put mine in a trashcan :) I'm going to test that now

I've however small remarks on it

  • sendACK() should use 2 arguments and not just one, in fact it acknowledge a command, so you should put a 'command' argument as a first argument, for example last ACK for getRawPicture should be AA 0E 0A 00 00 00, instead of AA 0E 00 00 00 00 as you've put.

And by adding this argument in sendACK(), you'll be able afterwards to delete the createCommand(CMD_ACK, CMD_SYNC, 0, 0, 0); sendCommand in init() which should be sendACK(CMD_SYNC, 0)

  • again on SYNC, for getJPEGPicture, the last ACK is a special ACK that acknowledge the last package, this ack should be AA 0E 00 00 F0 F0, whatever the packageCount may be

  • I don't know well yet the wire language, but I think you can use lowByte() and highByte in functions sendAck(), setPackageSize(), snapshot() instead of p & 0xFF, p >> 8

  • I don't know if arduino supports Serial.begin() several times to change the baudrate during communication, but if yes, I think you should add a Serial.begin(baudRate) in setBaudRate()

  • In the documentation (FAQ), it's said that "After synchronization, the camera needs a little time for AEC and AGC to be stable. Users should wait for 1-2 sec before capturing the first picture" => I think you should add a delay(2000) at the end of the sync() function

  • Maybe there's a rare bug that may occurs in waitForResponse(), indeed millis() goes back to 0 every 52 days, so millis() - time may give bad result at the end of the 52 days

  • Maybe it would be an enhancement of the lib, in fact in getJPEGPicture, the package given to the callback contains 6 bytes which are not jpeg data (the user needs to drop 4 first bytes and 2 last bytes of the package to get the data)

  • last thing, i'm not so sure, but in the documentation, it says to do the sync at 14 400bps, however i've done some tests at 9600, it works...

Hope this helps !

Thanks guy

Great suggestions!

Here’s my thoughts:

sendACK() should use 2 arguments and not just one, in fact it acknowledge a command, so you should put a ‘command’ argument as a first argument, for example last ACK for getRawPicture should be AA 0E 0A 00 00 00, instead of AA 0E 00 00 00 00 as you’ve put.

Good point, per your argument about simplifying the code in SYNC. I think I had planned on doing this, and then forgot about it.

again on SYNC, for getJPEGPicture, the last ACK is a special ACK that acknowledge the last package, this ack should be AA 0E 00 00 F0 F0, whatever the packageCount may be

This is what getJPEGPicture is doing, line 260. Am I missing something? In the manual, F0F0h seems to be just an example packageId number, correct?

I don’t know well yet the wire language, but I think you can use lowByte() and highByte in functions sendAck(), setPackageSize(), snapshot() instead of p & 0xFF, p >> 8

I’ll look into this. I’m not too familiar with all the Wiring functions either. I imagine the savings would be minimal though …

I don’t know if arduino supports Serial.begin() several times to change the baudrate during communication, but if yes, I think you should add a Serial.begin(baudRate) in setBaudRate()

It does … but I was attempting to leave this up to the programmer using the library. So that he/she calls Serial.begin() after a return true from the baud rate change. Ultimately, I’d really like to reduce reliance on Serial altogether, so that developers have the option of using the hardware or a software serial library like NewSoftSerial.

Do you think more control should be built into the library?

In the documentation (FAQ), it’s said that “After synchronization, the camera needs a little time for AEC and AGC to be stable. Users should wait for 1-2 sec before capturing the first picture”
=> I think you should add a delay(2000) at the end of the sync() function

Same as above … I was leaving this up to the developer so that I don’t force a 2 second delay (maybe they want to use that 2 seconds to do processing?) But I suppose it’s not a bad idea … my testing with the camera was that waiting 2 seconds here made no difference anyway, but probably good to add.

Maybe there’s a rare bug that may occurs in waitForResponse(), indeed millis() goes back to 0 every 52 days, so millis() - time may give bad result at the end of the 52 days

My understanding is that delay() internally uses millis() No? Is this bug avoidable? I’ll do some more research.

Maybe it would be an enhancement of the lib, in fact in getJPEGPicture, the package given to the callback contains 6 bytes which are not jpeg data (the user needs to drop 4 first bytes and 2 last bytes of the package to get the data)

Agreed. I was planning on doing this but wanted to get the code out to you for testing.

last thing, i’m not so sure, but in the documentation, it says to do the sync at 14 400bps, however i’ve done some tests at 9600, it works…

Hmm … it seems to sync no matter what baud rate you use. I’ve tried 9600, 14400, 38400 …

Good points, all of them! I’ll make the changes and post a new version, or if you have made them already, feel free to send the modified files.

  • Sean

Hi

Quote: again on SYNC, for getJPEGPicture, the last ACK is a special ACK that acknowledge the last package, this ack should be AA 0E 00 00 F0 F0, whatever the packageCount may be

This is what getJPEGPicture is doing, line 260. Am I missing something? In the manual, F0F0h seems to be just an example packageId number, correct?

F0F0h is a special code and is not an example packageId Number. Have a look at page 7 of the specs, you'll be able to read this: "ACK (AA0Eh) This command indicates the success of last operation.[...]The host should send this command with package ID F0F0h after receiving a package to end the package transfer. Note that the field "command ID" should be 00h when request image data package."

Quote: I don't know if arduino supports Serial.begin() several times to change the baudrate during communication, but if yes, I think you should add a Serial.begin(baudRate) in setBaudRate()

It does ... but I was attempting to leave this up to the programmer using the library. So that he/she calls Serial.begin() after a return true from the baud rate change. Ultimately, I'd really like to reduce reliance on Serial altogether, so that developers have the option of using the hardware or a software serial library like NewSoftSerial.

Do you think more control should be built into the library?

Yes you're completely right, but it would need an example that shows the use of this function and inform the developper to add the Serial.begin() :)

I agree with you also for 2 sec delay, but same remark, would be good to have a well explained example for developers that won't read the specs ;)

By the way, it would be nice to add a keywords.txt to put in color the name of the lib and package it to be imported in arduino

There are some misc warnings also on compilation, minor things...

I was able to run your lib 1 hour ago, and now I always get an error on compilation, I really don't know how i've broken my arduino, pff... >:(

Hi Again,

I’ve lost my time yesterday making my little sketch work, in fact someone on IRC told me to add #include <WProgram.h> at the top of my sketch and all worked. You may encounter this problem.

I think this bug comes from arduino 013 (not present in arduino 012), should be corrected soon

I’ve tested successfully your lib sean !

One arduino takes a picture via Serial and sends it via ZigBee using SoftwareSerial to another arduino which just dumps output to my laptop (using hterm to retrieve the jpeg), mounting:

However the picture taken is rather pink, I don’t know why for now
Have any idea Sean ?

Perhaps Sean can include <WProgram.h> in the library header file so it does not need to be included explicitly in the sketch.

Another thing

I've now tried to use the cam on pins others than 0 and 1. Therefore I've used NewSoftSerial (I think I can't use SoftwareSerial, as SoftwareSerial.available() doesn't exist)

I've made very few changes to the lib to handle NewSoftSerial, but I didn't succeeded in making the lib work

However, i've just put in comment Serial.flush() as NewSoftSerial doesn't handle this function. I don't think this function is compulsory, as I've read the spec, but maybe yes...

You've succeeded in making the lib work with NewSoftSerial Sean ?

Awesome! I've also taken several pictures with the camera and they were also slightly on the pink side. I noticed that under fluorescent lighting in our lab, however, that it would come out more brightly. The focus also seems very sensitive.

Mem has a good suggestion: I will add WProgram.h. Sorry I didn't send you my sample use code, could've saved you some trouble. I store my images in an EEPROM and then use Processing to write them to disk.

I'm going to be working on it this afternoon, so I will make the changes then and try some more pictures. I will also try NewSoftSerial if I get a chance. I'm not really sure flushing the serial buffer is necessary there anyway, but I did it just in case.

Sean

Also, if you get a chance to try the getRawPicture method, I'd be interested in knowing the results. That's the only one I haven't tried yet and my ultimate goal is to see what kind of speed (framerate) can be achieved with this camera on various color settings (2-bit, 8-bit, 16-bit).

Cheers, Sean

Under bright light the camera seems to take reasonably good pictures (as good as can be expected I suppose). The focus is sensitive ... about 2mm out seems to produce good results. Here's an outdoor and an indoor sample, both taken here at UC Irvine:

HI Sean,

Well good pictures with a better light :) Gonna test that also outside to know more

I haven't tested getRawPicture, sorry. In fact I haven't even tried because this function has to put all the picture in memory (no other way), and my ram won't be enough However, i have a 328p in the arduino which comes with 2ko of ram

Maybe I could try a very very low greyscale picture, humm... gonna try that tomorrow

Hi Sean

Have you been able to add the changes we've discussed above ?

I can test the new lib as soon as you want :)

Cheers

I am having a very hard time with this camera. I do a sync, an initilization, and a snapshot. All those return success. But if I do a second snapshot it fails. So it seems like I am stuck taking only one picture. Is there a command I have to send to it saying OK I want to take another snapshot clear what you have? My hairline thanks you in advance.

Hi Rick

When you take another snapshot, you start again an initial ?

You need to sync one time, than take a picture which involves to make an initial first, and etc...

Have a look on page 9 and so on of the specs

Thank you for your response enzo, I tried that and the initial function returns false if I call it again. I posted my code below, I hope I don’t bother anybody by doing that. If someone has working code would you mind posting it? I realize I am not doing anything with my callback function, but I was going to implement that later. Thanks again.

#include <WProgram.h>
#include “CameraC328R.h”

const int STATUSPIN = 13;
const int ERRORPIN = 12;

CameraC328R myCamera;
bool syncSuccess;
int iteration;

void setup()
{
iteration = 0;
Serial.begin(9600);

/* Setup pins */
pinMode(STATUSPIN, OUTPUT);
pinMode(ERRORPIN, OUTPUT);

syncSuccess = false;

/* Signal init process */
StatusLED(STATUSPIN, 2);

if( !myCamera.sync() )
{
return;
}
digitalWrite(STATUSPIN, HIGH); //Sync OK

syncSuccess = true;
}

void loop()
{
if( syncSuccess == false)
{
digitalWrite(ERRORPIN, HIGH);
delay(30000);
return;
}

if( !myCamera.initial(CameraC328R::CT_COLOR_16, CameraC328R::PR_80x60, CameraC328R::JR_160x128) )
{
StatusLED(ERRORPIN, 3);
delay(30000);
return;
}

if( !myCamera.setPackageSize(72) )
{
StatusLED(ERRORPIN, 5);
delay(30000);
return;
}

if( !myCamera.snapshot(CameraC328R::ST_COMPRESSED, 0) )
{
StatusLED(ERRORPIN, 7);
delay(30000);
return;
}

if( !myCamera.getJPEGPicture(CameraC328R::PT_SNAPSHOT, 1000, sendPacket) )
{
StatusLED(ERRORPIN, 9);
delay(30000);
return;
}

StatusLED(STATUSPIN, 3);
delay(10000);
}
/*
This function is called to send the packet to the pc
*/
void sendPacket(uint16_t picSize, uint16_t packPicDataSize, uint16_t packCount, byte pack)
{

}

void StatusLED( int Pin, int blinks )
{
digitalWrite(Pin, LOW);
delay(1000);

for( int i = 0; i < blinks; i++ )
{

digitalWrite(Pin, LOW);
delay(250);
digitalWrite(Pin, HIGH);
delay(250);
}

}

Hi

Here's a simple working code, a picture is shoot at every loop:

// Wake up & sync with the camera if (!c328.sync()) { return false; } if (!c328.setLightFrequency(c328.FT_50Hz)) { return false; }

// Some delay because the camera needs a little time for AEC and AGC to be stable // See the FAQ of the C328R User Manual delay(2200);

if (!c328.initial(c328.CT_JPEG, c328.PR_80x60, c328.JR_640x480)) { return false; } if (!c328.setPackageSize(PACKAGE_SIZE)) { return false; } if (!c328.snapshot(c328.ST_COMPRESSED, 0)) { return false; } if (!c328.getJPEGPicture(c328.PT_JPEG, 1000, camera_callback)) { return false; }

// Now put the camera asleep if (!c328.powerOff()) { return false; }