Camera data to SD corrupted when using SPI

My goal here is to get a VC0706 camera working on my DUE. I was advised to use this library which should do just as that.

By following the instruction of the README I’ve successfully captured images using UART mode through hardware serial but this takes about a whole minute to capture and save. Meanwhile with SPI enabled the image is saved in about a second. The downside here is that the SPI transferred image is corrupted every single time. The COM output shows that each image is exactly the same size so I know right away the image is bad. Enabling the debug option didn’t point to any real error either. (Just a read error that shows up after every reset, which it does in successful UART trials anyways).

So could anyone lend some input? I’m assuming my wiring is correct or else I wouldn’t be able to save images through UART mode to begin with.

Your picture is not a schematic, it's very difficult to see connections with shadows !

I understand that you communicate thru Serial1 to the camera, and you store pictures in the SD card via SPI and I guess you followed readme instructions of the library with the SPI option.

I have seen lots of threads reporting issues with SD card in SPI. Sometimes, the device won't tri-state properly, see this tutorial:

https://www.dorkbotpdx.org/blog/paul/better_spi_bus_design_in_3_steps

Thanks for the reply, here's at least a description of my wiring

SD breakout board: CS -> Pin 10 DI -> MOSI DO -> MISO CLK -> SCK GND -> GND 5V -> 5V

Camera: TX -> RX1 RX -> TX1 GND -> GND 5V -> 5V

And yes the data from the camera is coming from Serial1 and as far as I believe that shouldn't be affected by the change from UART/SPI. However from looking at the code the size of the images seem to be independent from any SPI functions, so I'm not sure why I'm seeing corrupted file size measurements each time in SPI mode. SPI mode is already enabled by default so the only changes I'm making to the code is switching it from software serial to hardware serial.

Thanks for the link but after doing some troubleshooting nothing has changed. A pull up resistor didn't help and I also checked the MISO line and measured the voltage I was expecting (about 1.7V so half of 3.3V). The third step didn't seem especially useful when I only have one SPI device so I didn't try to alter any code with that.

Did you try to make your SD card device work alone (read/write a short file) in SPI?

BTW, I would be cautious with powering DUE peripherals with 5V without logic level shifters...

ard_newbie: Did you try to make your SD card device work alone (read/write a short file) in SPI?

Yes I just used the example SD ReadWrite program, seems to be no issues there. Successfully read/wrote through SPI and when I plugged the SD into my computer I got a proper uncorrupted text file.

Seeing that the SPI example works I'm beginning to think that the camera program's SPI functions are outdated (seeing that it was last updated 4 years ago). Albeit after trying two older versions of the IDE (1.5.7 & 1.6 which are about as old as the last update) I'm still not seeing any differences.

ard_newbie: BTW, I would be cautious with powering DUE peripherals with 5V without logic level shifters...

Wait I'm a little confused here, why would I step down a 5V signal if that's what the devices call for?

The Due is a 3v3 device, not 5v, all of its I/O is 3v3, so connecting 5v devices could cause damage to either/both.

What speed are you writing at when using SPI? Wiring it as you have will likely fail at high speed, I had to use coax cable for the clock to make it work in a similar wiring scenario.

weird_dave: The Due is a 3v3 device, not 5v, all of its I/O is 3v3, so connecting 5v devices could cause damage to either/both.

Right I knew that they were 3.3V but didn't think a 5V peripheral would effect the I/O pins. I checked anyways and didn't measure any voltages over 3.3V on the I/O lines but I'll keep that in mind.

weird_dave: What speed are you writing at when using SPI? Wiring it as you have will likely fail at high speed, I had to use coax cable for the clock to make it work in a similar wiring scenario.

By default the divider is 4 so about 21MHz, I changed it to 5 for 16MHz without change. In fact I tried various dividers and the transfer time was still approximately 500ms each time which doesn't seem right. I'm not that familiar enough with coax cables, how did that effect anything? Reduce interferences?

What are you using to measure the voltages on the IO pins? What are the part numbers of the devices you're using, datasheets are the proper way to check. The coax stopped the clock spewing RF all over the place, it was causing corruption on the data lines, but my wires/cables were a bit longer (I now have a PCB made with appropriate shielding of the SPI lines).

There might be a fault with the code, it may be worth pasting it here.

weird_dave:
What are you using to measure the voltages on the IO pins?
What are the part numbers of the devices you’re using, datasheets are the proper way to check.

An Agilent 34461a.

Well I can’t seem to find a data sheet for the breakout board but it’s made by Adafruit:

and the SD card:

The camera is a “PTC08” according to the data sheet also courtesy of Adafruit:

weird_dave:
The coax stopped the clock spewing RF all over the place, it was causing corruption on the data lines, but my wires/cables were a bit longer (I now have a PCB made with appropriate shielding of the SPI lines).

There might be a fault with the code, it may be worth pasting it here.

Okay that makes sense, my clock line is about 3 inches or so but at least works with other SPI programs.

Sure I’m not sure how much I should paste here because it’s all contained in the github link in my original post but here’s some of the important bits/lines I changed.

This is the main code that had only some minor changes to initialize hardware serial (just involved commenting out 3 lines regarding software serial and uncommenting the hardware serial option):

//#include "SoftwareSerial.h"
#include <VC0706_UART.h>
#include <SD.h>
#include <SPI.h>
#define SS_SD  10

//use software serial
//SoftwareSerial cameraconnection(2,3);//Rx, Tx
//VC0706 cam = VC0706(&cameraconnection);
//use hardware serial
VC0706 cam = VC0706(&Serial1);

void setup() 
{
    Serial.begin(9600);
    Serial.println("VC0706 Camera Snapshot Test ...");
    
    if (!SD.begin(SS_SD)) {
        Serial.println("SD Card init failed...");
        return;
    }  
    if(true == cameraInit()){
        snapShot();
    }else{
        Serial.println("camera init error...");
    }
}

void loop() 
{
    //nothing to do
}

bool cameraInit()
{
    cam.begin(BaudRate_19200);
    char *reply = cam.getVersion();
    if (reply == 0) {
        Serial.println("Failed to get version");
        return false;
    } else {
        Serial.println("version:");
        Serial.println("-----------------");
        Serial.println(reply);
        Serial.println("-----------------");
        return true;
    }
}

void snapShot()
{
    Serial.println("Snap in 3 secs...");
    delay(3000);
    if (! cam.takePicture()){ 
        Serial.println("Failed to snap!");
    }else { 
        Serial.println("Picture taken!");
    }
    // Create an image with the name IMAGExx.JPG
    char filename[13];
    strcpy(filename, "IMAGE00.JPG");
    for (int i = 0; i < 100; i++) {
        filename[5] = '0' + i/10;
        filename[6] = '0' + i%10;
        // create if does not exist, do not open existing, write, sync after write
        if (! SD.exists(filename)) {
            break;
        }
    }
    // Open the file for writing
    File imgFile = SD.open(filename, FILE_WRITE);
    Serial.print("create ");
    Serial.println(filename);
    uint16_t jpglen = cam.getFrameLength();
    Serial.print("wait to fetch ");
    Serial.print(jpglen, DEC);
    Serial.println(" byte image ...");
    int32_t time = millis();
    cam.getPicture(jpglen);
    uint8_t *buffer;
    while(jpglen != 0){
         uint8_t bytesToRead = min(32, jpglen);
         buffer = cam.readPicture(bytesToRead);     
         imgFile.write(buffer, bytesToRead);
         //Serial.print("Read ");  Serial.print(bytesToRead, DEC); Serial.println(" bytes");
         jpglen -= bytesToRead;   
    } 
    imgFile.close();
    time = millis() - time;
    Serial.println("Done!");
    Serial.print("Took "); Serial.print(time); Serial.println(" ms");
    cam.resumeVideo();    
}

The actual SPI protocols aren’t in the main file but in the library’s cpp file, here’s a snippet of where things may be acting up. I’ve tried different setting for the clock divider and data mode without luck. I also manually swapped SLAVE_PIN with pin 10 because it almost seems like SLAVE_PIN is set in the header file to pin 8 yet is set to pin 10 in the main file and isn’t changed. I almost thought I had solved the problem but that didn’t change anything either.

#if TRANSFER_BY_SPI
	pinMode(SLAVE_PIN, OUTPUT);
	digitalWrite(SLAVE_PIN,HIGH);
	SPI.setBitOrder(MSBFIRST);
	SPI.setClockDivider(SPI_CLOCK_DIV4);
	SPI.setDataMode(SPI_MODE0);
	SPI.begin(); 
#endif

And in the header file the only changes were commenting out SoftwareSerial.h and setting USE_SOFTWARE_SERIAL to 0.

wnekid: An Agilent 34461a.

I'm wary of using multimeters for checking the level of switching waveforms, even though it has min/max. But let's see what the datasheets say...

wnekid: Well I can't seem to find a data sheet for the breakout board but it's made by Adafruit: https://www.adafruit.com/product/254?gclid=EAIaIQobChMIgrO8grTz2AIVRRppCh1b0A-EEAQYAiABEgLYT_D_BwE and the SD card: https://www.adafruit.com/product/1294

Click on technical details on the right, it will scroll you down to a link to the schematic, 5v just provides 3v3 so we're all good with this part.

wnekid: The camera is a "PTC08" according to the data sheet also courtesy of Adafruit: https://www.adafruit.com/product/397

Did you modify the board as per the instructions to get 3v3 I/O operation rather than RS232 levels?

There's two things I would consider doing at this point. 1) get a scope on the SPI lines and see what's happening. 2) Junk the SPI method used and use SPI.beginTransaction.

However, from what you've posted it looks like you're trying to read the data from the camera via SPI, which (obviously?) won't work. (I had assumed the problem was saving the data via SPI to the SD card instead of serial to a PC).

You're talking about that modification in page 2 of the data sheet? Then no I have not physically altered anything.

I hope it's not actually trying to capture the image through SPI because from my understanding it was using serial to get the image and using UART or SPI to actually "transfer" the image.

I'll give SPI.beginTransaction a shot and start using a scope to see if what's going on.

Rs232 levels with a max232 will give you about +/-7v on the IO pins, this isn't particularly good, there is 400R in-line so that's probably saving you.

Can you clarify exactly what you're doing. There are 2 transfer mechanisms in place, one for the camera and one for the SD card. The SD card can only use SPI. The camera can only use RS232 (preferably as 3v3 levels!). Are you trying to transfer the image from the camera using SPI? (you can't)

In a nutshell I simply want to snap and image and have it saved to the SD card in a reasonable amount of time (maybe less than a few seconds). The library has two options for transmission, UART and SPI. While UART works fine it takes too long (about a minute to save to the SD). So I was thinking switching to SPI mode would work much quicker as its an option in the library. From my understanding the image is taken using serial and put in a buffer before being saved either through UART or SPI.

The SPI code in the VC0706 library is for communicating with the camera only, nothing to do with saving to the SD card. (Note that your camera doesn't have the SPI port available, so this won't work, and if you did have one you'd need to connect it to the SPI port too). The SD card comms should already be using SPI, which is why it's connected to the SPI port.

Hm looks like I misunderstood the library then. Odd that they give you the option to use SPI on that very same product without any mention of some very important board alterations...

Oh well I've decided to just stick with the UART mode, I don't exactly get amazing save speeds but bumping up the baud rate and reducing image resolution might just work for my purposes.

Thanks for all you help.

It’s a generic library for the VC0706 camera DSP, not the specific board you have (there are boards with SPI available), they would expect the buyer to understand that a lack of SPI connectivity would mean you wouldn’t enable SPI mode. They do however give some nice instructions on altering the board for logic level serial comms, which you really should do.

weird_dave: It's a generic library for the VC0706 camera DSP, not the specific board you have (there are boards with SPI available), they would expect the buyer to understand that a lack of SPI connectivity would mean you wouldn't enable SPI mode.

The board that's linked in the library is the exact one that I have.

weird_dave: They do however give some nice instructions on altering the board for logic level serial comms, which you really should do.

Wait whose instructions? The only instructions I saw were from the data sheet and there's not much depth to them.

Yeah, it is a bit misleading, it also says TTL level which it isn't without modding it.

This datasheet in the downloads portion of the product page: PTC-08 module datasheet contains dimensional drawings https://cdn-shop.adafruit.com/product-files/397/P397+Datasheet.pdf bottom line of page 1 and the top of page 2.