need teensy-camera help...

Status
Not open for further replies.

shuz

New member
Hello everyone.. i am trying to take picture via this camera ( https://s3.amazonaws.com/linksprite/camera/JPEG_camera_uartinterface_TTL/JPEG_Camera_2M_Manual.pdf /) and save it on SD card using Teensy 3.1.
when i used the code on arduino it was working perfectly but there were some speed issues so i switched to teensy. i don't know what problem is coming but the image is not opening..the image viewer says "invalid image". i checked the image file..it has acknowledgement numbers "76 00 32" etc. which gets deleted automatically in arduino. i tried using level shifter but no success.
the code is given below.. Please help/guide me...

Thank you

// * SD card attached to SPI bus as follows:
// * MOSI - pin 11
// * MISO - pin 12
// * CLK - pin 13
// * CS - pin 4
//*******************************************************
//#include <SoftwareSerial.h>
#include <SPI.h>
#include <SD.h>

//SoftwareSerial Serial3(5,6); // Set Arduino pin 4 and 5 as softserial

byte ZERO = 0x00;
byte incomingbyte;
long int j=0,k=0,count=0,i=0x0000;
uint8_t MH,ML;
boolean EndFlag=0;
File myFile;

void SendResetCmd()
{
Serial3.write(0x56);
Serial3.write(ZERO);
Serial3.write(0x26);
Serial3.write(ZERO);
}

/*************************************/
/* Set ImageSize :
/* <1> 0x22 : 160*120
/* <2> 0x11 : 320*240
/* <3> 0x00 : 640*480
/* <4> 0x1D : 800*600
/* <5> 0x1C : 1024*768
/* <6> 0x1B : 1280*960
/* <7> 0x21 : 1600*1200
/************************************/
void SetImageSizeCmd(byte Size)
{
Serial3.write(0x56);
Serial3.write(ZERO);
Serial3.write(0x54);
Serial3.write(0x01);
Serial3.write(Size);
}

/*************************************/
/* Set BaudRate :
/* <1> 0xAE : 9600
/* <2> 0x2A : 38400
/* <3> 0x1C : 57600
/* <4> 0x0D : 115200
/* <5> 0xAE : 128000
/* <6> 0x56 : 256000
/*************************************/
void SetBaudRateCmd(byte baudrate)
{
Serial3.write(0x56);
Serial3.write(ZERO);
Serial3.write(0x24);
Serial3.write(0x03);
Serial3.write(0x01);
Serial3.write(baudrate);
}

void SendTakePhotoCmd()
{
Serial3.write(0x56);
Serial3.write(ZERO);
Serial3.write(0x36);
Serial3.write(0x01);
Serial3.write(ZERO);
}

void SendReadDataCmd()
{
MH=i/0x100;
ML=i%0x100;
Serial3.write(0x56);
Serial3.write(ZERO);
Serial3.write(0x32);
Serial3.write(0x0c);
Serial3.write(ZERO);
Serial3.write(0x0a);
Serial3.write(ZERO);
Serial3.write(ZERO);
Serial3.write(MH);
Serial3.write(ML);
Serial3.write(ZERO);
Serial3.write(ZERO);
Serial3.write(ZERO);
Serial3.write(0x20);
Serial3.write(ZERO);
Serial3.write(0x0a);
i+=0x20;
}

void StopTakePhotoCmd()
{
Serial3.write(0x56);
Serial3.write(ZERO);
Serial3.write(0x36);
Serial3.write(0x01);
Serial3.write(0x03);
}
#include <SdFat.h>
SdFat sd;
SdFile myFile;

void setup()
{

Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}

Serial.print("Initializing SD card...");
delay(400); // catch Due reset problem

// Initialize SdFat or print a detailed error message and halt
// Use half speed like the native library.
// change to SPI_FULL_SPEED for more performance.
if (!sd.begin(chipSelect, SPI_HALF_SPEED))
{
sd.initErrorHalt();
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
Serial.println("please wait....");
}

void loop()
{
byte a[32];
int ii;
Serial3.begin(115200);
delay(200);
SendResetCmd();//Wait 2-3 second to send take picture command
delay(2000);
SetBaudRateCmd(0xAE);
delay(100);
Serial3.begin(9600);
delay(100);
SetImageSizeCmd(0x00);
delay(100);
SendTakePhotoCmd();
delay(3000);

while(Serial3.available()>0)
{
incomingbyte=Serial3.read();
}
// open the file for write at end like the Native SD library

if (!myFile.open("pic.jpg", O_RDWR | O_CREAT | O_AT_END))
{

sd.errorHalt("opening pic.jpg for write failed");
}
// if the file opened okay, write to it:
else
{
Serial.print("Writing to pic.jpg...");CHK WHAT GOES WHERE
myFile = SD.open("pic.jpg", FILE_WRITE); //DOUBTFUL LINE
while(!EndFlag)
{
j=0;
k=0;
count=0;
SendReadDataCmd();
delay(5);
while(Serial3.available()>0)
{
incomingbyte=Serial3.read();
k++;
delayMicroseconds(100);
if((k>5)&&(j<32)&&(!EndFlag))
{
a[j]=incomingbyte;
if((a[j-1]==0xFF)&&(a[j]==0xD9)) //tell if the picture is finished
EndFlag=1;
j++;
count++;
}
}

for(j=0;j<count;j++)
{
if(a[j]<0x10)
Serial.print("0");
Serial.print(a[j],HEX); // observe the image through serial port
Serial.print(" ");
}
for(ii=0; ii<count; ii++)
myFile.write(a[ii]);
Serial.println("");
}
}
myFile.close();
Serial.print("Finished writing data to file");
while(1);
}
 
Perhaps this code is the problem?

Code:
while(Serial3.available()>0)
{
incomingbyte=Serial3.read();
k++;
delayMicroseconds(100);

Assuming the camera is transmitting a huge block of data at precisely 9600 baud, each byte takes 104.167 microseconds.

A slow 8 bit AVR board will very likely take more than 4.167 microseconds to execute the code within that loop, as bytes are arriving back-to-back. Teensy 3.1 is dramatically faster. It's very likely to execute that code in less than 4 microseconds, causing the entire program to parse incoming data differently (as if the camera had stopped sending).

Whether that loop continues processing incoming data or exits to the surrounding code will be sensitive to the board's timing.

If you want to move up to a much faster board, I'm afraid you're going to have to redesign your parsing code to look only at the data. You can use elapsed time to detect timeouts, but using inter-byte timing this way is risky and almost certainly will fail when run on a different CPU. In fact, it might even someday fail on 8 bit AVR, if the Arduino devs improve their interrupt code (Teensy 2.0 has serial interrupts that use about half as much CPU time as Arduino's, so better performance is possible even on 8 bit AVR).

I didn't study every detail of how your code is parsing data, but it is pretty apparent that it will fail to detect the 2-byte end of picture marker if that loop exits early. The surrounding loop sets "j" back to zero, effectively losing all the bytes it has previously received.
 
On the plus side, if you do improve your parsing code and eliminate things like delayMicroseconds(100), you can probably run at a much faster baud rate.

My might consider using Serial1 or Serial2. Those 2 ports feature a FIFO that reduces the overhead, so they're more efficient than Serial3. But all 3 should easily be able to handle 115200 or even 256000 baud.

You might also consider using the number from available(). If available() tells you there's 26 bytes, and your array as room for all 26, why keep calling available() for every byte? You can just read all 26.

You might also look at Serial3.readBytes(). It tries to read a certain amount, and tell you how much is actually got. It things as efficiently as possible, and provides a built-in timeout feature, which you can configure with Serial3.setTimeout(). This could simplify your code.
 
On the plus side, if you do improve your parsing code and eliminate things like delayMicroseconds(100), you can probably run at a much faster baud rate.

My might consider using Serial1 or Serial2. Those 2 ports feature a FIFO that reduces the overhead, so they're more efficient than Serial3. But all 3 should easily be able to handle 115200 or even 256000 baud.

You might also consider using the number from available(). If available() tells you there's 26 bytes, and your array as room for all 26, why keep calling available() for every byte? You can just read all 26.

You might also look at Serial3.readBytes(). It tries to read a certain amount, and tell you how much is actually got. It things as efficiently as possible, and provides a built-in timeout feature, which you can configure with Serial3.setTimeout(). This could simplify your code.


Please could you tell me what exact code i must integrate or change.. it will be of great help..i am running out of time for my project submission
 
Hi

Be careful of what you are asking for here.

Are you trying to get Paul to rewrite your program for free, working blind given he doesn't have the hardware in front of him and for which you are planing to take full credit, or are you planning to pay him for the man hours involved here?

What he suggested above is reworking the Serial3.Read section to work smarter. My take on it at the moment is that it is supposed to sit at the "while(Serial3.available()>0)" line because the Arduino is never able to reach the bottom of the FIFO buffer is to moves the bytes into an array. The ugly option would be to turn that 'delay(100)' into 'delay(104)' and hope.

Less ugly option would be to change that while serial loop into a 'while (EndFlag!=1)' which appears to be how the internal loop tracks if it's done, and then loop there with a serial available line pulling the bytes as they show up into the existing parser. This has a number of potential modes of failure in timeouts etc that would need consideration but should get you there, simply by changing the while loop and adding an IF serial3.available statement straight below it (and striping that delay(100)).

The fully featured solution would be to have a main loop that is actually a main loop with a state check for serial data, and followed by a check of what stage in the photo capture process it is it at.

So
void loop();
{
If (serial3.available)
if (capturingPhoto==true) {call routine to populate array, sets photoDone on completion}
else {handle any none image data from the camera}

if (photoDone==1) {store to SD card, change file name and any other house keeping, prep for next image and unsigned long photoStartTime=millis()}

if (capturingPhoto==true&&millis()-photoStartTime>10000) {10 sec timeout for error handling of corrupted/missed serial data, reset and try again plus indicate failure in some way}

//Any other light blinking, serial sending user interface code, just be careful of delays that may allow the serial buffer to overflow
}

*note if this is running for more than 50 days you need a trap for the overflow of the millis() counter
 
Indeed, I can't get directly involved in rewriting this program.

And that is what's needed, or at least that portion which parses the incoming data. It needs to be rewritten. I tried to explain how it's (probably) deficient.

From the nature of your question "tell me what exact code i must integrate or change", my guess is you're not the original author of this code, right? If you are, well, this is going to sound a bit blunt....

My point is whoever did write this program designed it in such a way that it's highly dependent on timing. There isn't just one simple change that will magically fix this problem. The problem is that the parsing design is simply terrible. That whole section which looks for the end-of-data marker needs to be redone in a better way.
 
Last edited:
Indeed, I can't get directly involved in rewriting this program.

And that is what's needed, or at least that portion which parses the incoming data. It needs to be rewritten. I tried to explain how it's (probably) deficient.

From the nature of your question "tell me what exact code i must integrate or change", my guess is you're not the original author of this code, right? If you are, well, this is going to sound a bit blunt....

My point is whoever did write this program designed it in such a way that it's highly dependent on timing. There isn't just one simple change that will magically fix this problem. The problem is that the parsing design is simply terrible. That whole section which looks for the end-of-data marker needs to be redone in a better way.


Hello,
am sorry... i dint want to write anything absurd .. it was not intentional..i just dint realize it..wasn't trying to be blunt. and yes i am not the original writer of the code. we are bunch of few students,not so good at coding, working on college project.

and thank you for all the replies. i will share it with my team mates and will share the results here.
and sorry again.
 
Yeah, I'm afraid there simply isn't an easy answer here.

The code has a pretty terrible design, mainly depending on that 100 us delay and the 104.2 us byte timing. There's no single fix, because the basic design in that part is so flawed.

To fix this, you're going to need to dig into the coding side. The good news is Teensy 3.1 can send data to the Arduino Serial Monitor much faster than the camera is sending to Teensy (normal Arduino can't do this), so you can put a pretty good number Serial.print() lines into the parsing code to figure out what it's doing as the data arrives.

Maybe that's too much to achieve in the limited time you have? Or maybe not?

If you haven't already shared this with your instructor or advisor, the very best thing you can do is ask them for help as early as possible. Odds are slim they'll have a good answer, but involving them shows you're trying. Later, if your project doesn't achieve all your goals, explaining the challenges becomes much easier if you've involved your instructor with the issues as they came up.
 
Status
Not open for further replies.
Back
Top