Skip to main content
Topic: Interfacing a mysterious CMOS (Read 9780 times) previous topic - next topic

Interfacing a mysterious CMOS

I found a camera in the parts bin, and wanting to use what I had, decided to try and find out how to interface it with an arduino.
With any luck this will document some of the thinking, and the mistakes, that I went through.

Alas, as of writing, this is incomplete. (2012-05-10)
Latest post: http://http://dangerousprototypes.com/forum/viewtopic.php?f=56&t=3934&p=40315#p40315
(if I remember to update this post)
[s:]Also, I can't embed pictures or links, due to new user status. Wahey.[/s:]



So, I decided it would be fun to document how I personally went about hacking this wretched camera.
1) Firstly, why does it not just work?
A: Insane mini-din connector.

What pins do what? No way to tell without disassembly.

2) Disassembly.
Remove a few screws, unsolder that massive cable.
Take care of the CMOS sensor though, don't want a scratch in the glass.



3) Find datasheet
Fine, just [s:]google[/s:] use a popular search engine to search for the numbers written on the board, easy.
One result. One!
And it's just another hacker looking to interface it, from Lithuania.
http://http://forum.elektronika.lt/viewtopic.php?t=2884(or only result for "PMG005BJTCVSN")
Mercifully, that leads to more searching, and the product page!
http://http://www.prolink-usa.com/english/product/vc/mplite.htm (or second result for "PV-M1300")
Alas, it needs a PCI card to work with a computer. Foiled?

Drat, standard approach has failed. I need a datasheet for that sensor, and it has no writing on it.
Wait..., it probably does have some lettering from the manufacturer. If only I had a lens that would focus accurately to the scale of the sensor.
Using the lens in reverse (well, light passing through the wrong way.

Those are the gold wires leading to the die.
Nigh impossible to photograph, but using a bright light, and the human eye, I got
VVL-404AB, and in much smaller writing underneath:
.....…1996 VISION LTD
Excellent! Pop them into [s:]google[/s:] search engine of your choosing, and you get... nothing.

That failing, find this manufacturer's website, and their list of datasheets ("vision limited datasheet")
Aha, there is a VV6404, and a VV5404, seemingly colour and mono versions of the same silicon chip.
The colour version has a filter over the top, and I can see a little RGBG section on the central die, probably for calibration.
Datasheet=Acquired.

4) Search for prior art

(seach for "CMOS camera as a sensor" to get a guide for a different sensor, and an arduino mega)
http://http://www.ikalogic.com/image-processing-as-a-sensor/

5) Steal prior art
Unfortunately, I've got nowhere near the programming skill to make sense of that code in any reasonable time, and the whole sensor is different. I will steal the general principle, which is:
*Lower the CMOS clock speed, so it has a reasonable chance of being processed by an atmega328
*Do the mission critical bits in assembly



6) Map out the electronics
Now is time to find out what bits connect to what on the board. Importantly, one of the pins connects to a "zr78 l05" which the experienced among you will recognize as a 5v regulator. Excellent, that's good news for my 5v arduino. Also, looking at power consumption, it can be powered off the arduino 5v regulator (after all, that's what it's there for, rapid project making, which includes power).
Also there is a "C01A" chip, and while I don't know the brand, it appears to be a I2C eeprom chip (turns out to be half a KB).
Datasheet for that is pretty standard, and mostly goes into explaining I2C. I know it's 5v anyway.
Trouble strikes- the board is 4 layer (!), and there are a whole mess of interconnects underneath the cmos.

Hacker tip: Rather than faff around, probably getting fingerprints all over an unknown board, take pictures of it, scale them to the same size, and remove skew, and print it double sided on paper. Now the interconnects line up, and you can scribble all over the chip with labels!

Time for the needles

Now, all the pins on that 9 wire DIN  (numbering from the PCB though)are mapped out to the CMOS:
1: D[0], 2: GND, 3: D[1], 4: VREGIN, 5: D[2], 6: SCL, 7: D[3], 8 SDA, 9: CLKI
There seem to be various filtering components, like little inductors, and capacitors. Usefully, the I2C lines are pulled high.
The data lines are not though - I suspect they should be pulled low...

7) Soldering iron time!

I soldered on some more sane length wires where needed, and decided to just bypass the voltage regulator, and give the camera 5v directly. Over this cable length, it's ok (probably). They interface with a protoscrewshield, so terminate in bare wire.


Basically, I want this to be all the soldering I need to do to get the hardware ready. Then it's easy to work on software when I get the time.

8) Test the basics
Well, I know how to talk to an I2C eeprom, but can I?
I found an I2CScanner.pde, by Tod E. Kurt (link), which just sends all the addresses possible over I2C, and sees if an ACK is received.
Yes. The wires work! A quick scan of the memory chip reveals it to be empty, and some write tests show it to be 512 bytes big.
However, the cmos won't respond, and a perusal of the datasheet reveals why- it needs a clock in, for 16 cycles before, during, and after I2C. Why after? It is a mystery.

9) Figure out conceptually how the eventual program will work
10) Also 'back of the envelope' maths

What must I do to get data off this thing?
Firstly guess: Store one frame? No, attempting to get all the pixels is going to be nigh impossibly, 356*292=103952 bytes, far more than the atmega328's 2kB SRAM - no holding a frame in memory!
Secondly, the 'minimum' clock speed is 0.45 Mhz, and as a newbie programmer, I am not going to be able to read, and do stuff with the 4 data lines in, what, ~35 clock cycles of the 16 Mhz atmega328. The
Code: [Select]
digitalWrite(pin, 1)
command uses more than that!
Thirdly, I can't even pass through via serial- the baud rate is max 115200 bits per second, and that's just one signal, let alone 4.

I suppose what I ought to do is find a way of booting the camera up, as detailed in the datasheet. That's progress at least.
I very much suspect that the chip can be driven a lot slower, though the image would be awful.
It does look like the I2C interface can be used entirely to boot up the camera, and that is in the realm of possibility.
Still can't tell if it's working though - could just do digitalRead(D[0]), and look for 'random' data that's more 1's than 0's when I shine a light on it. Could just read any pixels, and gradually slow the clock signal until it stops being 'random'.

11) Project dies of complications?
Much like many other projects, this is more than I can chew.
It's pretty helpful to write down what you know, then it's much easier to get back to where you left off.

12) Write up project so far
I found a website I frequented with lots of neat projects on it, and wrote a very wordy forum post.
Sadly, the images did not appear for 24 hours, but they were later added when time permitted.

13) Panic
[s:]Now, this is where I'm up to, as of 2012-04-18[/s:]
 I don't know how I am going to get my code fast enough to read even a tenth of the pixels.
Will update as progress is made.

2012-04-19:
14) Cool off, think over again. Anything is possible.
Read the helpful comments written by people reading the write up.
Make a rough plan, do some more "napkin maths" to find feasibility.

 Plan
Learn direct port manipulation!
Mercifully, the arduino platform is fairly well documented.

Plan
#1Get the camera to 'boot'. Can check status by using I2C to read the 'current line count' and seeing if it changes with time.
Requires:
?An interrupt driven or somesuch fast CLKI signal
+The Wire library
-Frankly, a Bus Pirate, but I don't have one of them!
?Some sloppy hacked together code to send two things with a delay over I2C, and then repeatedly read one register.

Serial operation:
This seems to be quite common- a CMOS chip has an I2C part, and a bit that sends ADC bytes  from every pixel in a certain sequence. This particular one uses 4 data lines, and so requires two clock cycles to clock out one byte - in two "nibbles".
Operation is obviously designed with certain specific sequences that indicate frames, lines, etc.
However, most of the time, it goes [abcd] [efgh] for each pixel, where the brightness is proportional to the byte [abcdefgh].

Therefore, for my purposes, which is a black and white eg 84*48 pixel display, I can ignore most of the data.
Thusly if I record in an array in RAM, and get the most significant bit for every 6th pixel, so every 12th clock cycle, I might stand a chance of getting a frame. Now I've got lots of clock cycles to account for crap programming, though I guess I'll need an interrupt every 12 generated cycles of the camera.

Startup
Unsurprisingly, this digital device does not "just work". It requires a clock, and two separate serial commands, thoughtfully detailed in the datasheet.

After that, though...
Note that there is a little problem - AVR's are not known for their multitasking, though sending I2C comms is slightly abstracted from the main core. Standard
Code: [Select]
analogWrite(pin, 127);
won't be fast enough, apparently. (490 Hz? vs 'minimum' of 0.5 MHz
I bet it just comes out way overexposed though.

Sending that clock
Various things are detailed in this post further down : http://http://dangerousprototypes.com/forum/viewtopic.php?f=56&t=3934#p39548
Also:
Mainly, I need a clock or something, that essentially does:
Code: [Select]
begin_clock(pin 3 probably, 0.5 MHz);  //Can just screw with timer(2)'s registers?
also_attach_interrupt(whenever_clock_triggers, Function_to_process_stuff());
Can I just, erm, use the attachinterrupt(1, FALLING, function..); command? (this ought attach a hardware interrupt to pin 3)
Will it screw it up, having a timer triggering a pin change, then an interrupt noticing that pin change?
Answer, yes, but it's a faff

Startup, getting random data
With some code
Code: [Select]
#include <Wire.h> //for sending setup
#include <avr/io.h> //Yes, I think I do want to use inputs and outputs
#include <avr/interrupt.h> //works a lot better with this one
#include <stdint.h>

int cmosAddress = 0x10; //actually 16, hex 10
//don't freak out, uint8_t is just a byte
volatile uint8_t bytenumber=0; //starts at 0 for first uint8_t.
volatile uint8_t inputbyte;
volatile boolean uint8_tunread =0;
volatile uint8_t nibble0forMSB =0;
volatile uint8_t inputArray[2][256];
uint8_t benchstart;
uint8_t benchend;
uint8_t cyclecount =32;

boolean state=0;

void blink()
{ //remarkably, this code is really slow for what it does
  state = !state;
  PORTB =  (PORTB & B11011111 )+ (state << 5);
}

void setuptimer_2B() {
  cli(); //stop interrupts. Some other code did this, seems like a plan
  TCCR2A = _BV(WGM21) |_BV(WGM20) | _BV(COM2B1); //FastPWM, non inverting.
  //Turn off COM2B1 for normal pin use
  TCCR2B = _BV(WGM22) | _BV(CS20); //no clock divider, pin high at timer2 = 0
  //TCCR2B = _BV(WGM22) | clockbits;
  OCR2A = cyclecount; //should be ~32 cycles -timer goes to 0 after hits this
  OCR2B = cyclecount/2; //when the pin flips to low- half way
  sei(); // turn on global interrupts
}

void setupinterrupt_2B(boolean offoron) {
  cli(); //just in case, turn off global interrupts
  TIMSK2 = (TIMSK2 & B11111011) + (offoron << OCIE2B); //This bit turns on/off the interrupt.
  sei(); // turn on global interrupts
}

void readbyte2() { //new and speedy (12 cycles)
  byte tempbytenum =bytenumber;
  inputArray[0][tempbytenum] =PIND;
  bytenumber = tempbytenum +  1;
}
void readbyte1() { //old and busted (!4 cycles)
  inputArray[0][bytenumber] =PIND;
  bytenumber++;
}

ISR(TIMER2_COMPB_vect) { //INTERRUPT 2B INTERRUPT 2B
  readbyte2(); //should trigger every time pin3 is set low
}

void benchmarkinterrupt() {
  uint8_t benchstart1 = TCNT2;
  // Functiongoeshere(); //probably a better way to do this, but meh
  readbyte2();
  uint8_t benchdiff = TCNT2-benchstart1;
  Serial.println(benchdiff);
}

void benchmarkinterruptempty() {
  uint8_t benchstart1 = TCNT2;
  uint8_t benchdiff = TCNT2-benchstart1;
  Serial.println(benchdiff);
}

void setup()
{
  Wire.begin(); //need this for sending commands
  Serial.begin(115200); //Fast as lightning!
  pinMode(13,OUTPUT); //debug LED
  pinMode(3,OUTPUT); //CLKI
  pinMode(2, OUTPUT); //debug voltmeter
  pinMode(7,INPUT); //Data D3
  pinMode(6,INPUT); //Data D2
  pinMode(5,INPUT); //Data D1
  pinMode(4,INPUT); //Data D0

  //start the camera clock
  setuptimer_2B(); //prescaler of 1. Note weird binary stuff
  blink();
  delay(50);

  //send the 'soft reset' command
  Wire.beginTransmission(cmosAddress);
  Wire.write( B0010000);
  Wire.write(B00001101);
  Wire.endTransmission();
  delay(50);

  //send the 'exit low power' command
  Wire.beginTransmission(cmosAddress);
  Wire.write( B0010000);
  Wire.write(B00001000);
  Wire.endTransmission();
  delay(50);

  //set clock division to 2
  Wire.beginTransmission(cmosAddress);
  Wire.write( B0100101);
  Wire.write(uint8_t( B00000000 )); // all zeros for prescaler of 2
  Wire.endTransmission();
  delay(50);
  blink();
  setupinterrupt_2B(1); //All hell beaks loose at 0.5 MHz
}

void loop()  // LOOP ENABLE LOOP ENABLE
{
  if (bytenumber == 255) { //why 0? There
    setupinterrupt_2B(0);
    blink();
    for ( uint8_t bytenumber1 =0;bytenumber1 != 255; bytenumber1++) {
      Serial.print(inputArray[0][bytenumber1]/16,HEX);
      inputArray[0][bytenumber1] = 0;
    }// outputs that stored data
    bytenumber = 0;
    Serial.println();
    Serial.println(micros());
    nibble0forMSB =0; //from trying to be too cunning
    benchmarkinterrupt();
    nibble0forMSB =1; //some legacy code bits
    benchmarkinterrupt();
    benchmarkinterruptempty(); //should be 2 cycles of poor compiling to do nothing
    blink();   
    delay(1000);  //this stops the serial port from exploding
    //setuptimer_2B();
    setupinterrupt_2B(1);

  }
}  // LOOP END
it will do some data!
eg
Code: [Select]
996669996699966669996669996699966699966699966699996699966699966699966699966699966699966699966699966699966699966699966699966699966699966699966699966699966999966699966699966699966699966999666699966999666699966999666999666999666999666999666999666999666999666 
//the signal to lock onto- not tremendously even, really.
CB9111C9C1118D91118EC111C9811BAD9111DB911187B1218DB111BB8119A811117AE119AA1111B7811F7B111ABA111A981121DB1121B1111ABA111E8911189A11198A111A861118BA1119AB11197A1116EA111BCA111D99111CEA1118A8121A88111BBB1118E8111CE9119991111B9111AB81111989111AD811A8B111ACE11
//sensor with light blocked off
EFFFFFFFFFFFFFFF0605FEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFEEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEFFFEEEEFFFEEFFFEEEEFFFEEEFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFFEEEFFEEEEFFFE
//overexposed, and maybe a control code?
Note of course that in the interest of speed, that's just reading the bus lines every time it sets the clock low. Weirdly, it seems to do stuff every 3 cycles, or, be inconsistent upon multiple reads of the same pixel quickly.

Learn assembly
So, it has come to this. The code really needs a nice fast polling routine to check every 2 sent clock cycles (I'll keep the fast PWM to send a stable signal). The compiled code is too slow.

Alright, I've learnt some basic assembly stuff, and have proceeded. Can now get it to read a whole bunch on seeing the 'visible line' control code in the data.
This leads to shoddy pictures: http://http://dangerousprototypes.com/forum/viewtopic.php?f=56&t=3934&p=40315#p40315

As before, will update as progress is made (though that might be for my own sake, rather than anyone else's!)

Re: Interfacing a mysterious CMOS

Reply #1
Hey there Fractal (from HAD?).  Welcome! 

I think there was an 8 bit MCU camera hack a little while back featured on the front page that might be useful.  I haven't looked at the datasheet (or acquired image data from a cmos camera) so I'm probably not going to be too much help here. . .

A few thoughts:
*you should probably try and "properly" boot the sensor according to the datasheet - I'd be surprised if it worked without being properly initialized. 
*If you can get data across I2C (sounds like the only interface available), you should be able to just clock it at a speed you can deal with. 
*to pair down the image size to something that actually fits - throw away some of the LSB's.

Admittedly, I didn't read your entire post in great detail (or do any research), if I'm suggesting things you've already tried I apologize.  I can tell you that a search for your part number of interest now turns up two results (one of them being this thread :)), so the lonely Lithuanian using the same sensor now has some company!

Re: Interfacing a mysterious CMOS

Reply #2
Thanks for sharing your approach, this is always helpful info for people who are trying to hack something for the first time.

I'm sorry about the link filter, it should be gone by the next time you post. You can attach pictures directly to the post by clicking 'POSTREPLY' and then clicking on the blue attachment tab below the reply box.

Quote
And it's just another hacker looking to interface it,

Argh, my fate all too often. Even worse is when I post here, and the only result is my own posts :)
Got a question? Please ask in the forum for the fastest answers.

Re: Interfacing a mysterious CMOS

Reply #3
bearmos- I'm not from HAD forums, though I do frequent the main blog. Maybe I'll repost this there  for 'fun'.
I've taken your advice, you're spot on about the initialization step; throwing away LSB's is a very good plan also.

ian- I've had my waiting time, and put up the pictures proper. Glad to know someone else suffers the, lone hacker problem, though this is the first time I've tried to rectify it!

Oh, and this is going to be updated, whether this post is forgotten or not (so long as I actually do something- exam term is coming). Reason? It's easier than a blog.

Re: Interfacing a mysterious CMOS

Reply #4
[quote author="Fractal"]bearmos- I'm not from HAD forums, though I do frequent the main blog. Maybe I'll repost this there  for 'fun'.
I've taken your advice, you're spot on about the initialization step; throwing away LSB's is a very good plan also.[/quote]

I was referencing the blog comments there, where there is also a Fractal alias in use :)

good luck with the exams (and this project of course)!

Re: Interfacing a mysterious CMOS

Reply #5
[quote author="Fractal"]
ian- I've had my waiting time, and put up the pictures proper. Glad to know someone else suffers the, lone hacker problem, though this is the first time I've tried to rectify it!

Oh, and this is going to be updated, whether this post is forgotten or not (so long as I actually do something- exam term is coming). Reason? It's easier than a blog.[/quote]

Oh yes, I think we all have the lone hacker problem at one time or another. :P I myself have been really interested in using a CMOS sensor too, from a old point and shoot that was dropped, many years ago. If you have the logic sniffer from here, and the camera is still in working condition able to take pictures, you might be able to get something working. Cover the camera with a black piece of paper, trying to make it so that the picture you receive is as dark/black as possible, so when you put the logic sniffer onto the pins, then you will be able to sniff the data going to and fro the sensor, which would (hopefully) be mostly the control signals. You can then work from there. I2C operating at 500 Khz seems rather high, though I did not have to fortune of playing around with CMOS sensors, so maybe i2c is faster there than for other things. Are you sure that it is not SPI by any chance? Also, are you familiar with how a CMOS sensor works, fundamentally?

I know that sometimes, if not most of the time, the sensor has built in ADC's, so you get raw digital data on the output, which is a good and bad thing. A good thing, because it means you do not need to fumble with ADC's, bad because you will need to handle more data in a short amount of time. When you are taking data from the sensor, each pixel is still receiving light, meaning that the image is still changing. If you pull the data from the sensor too slowly, then you won't be able to get a full image but instead a very blurry image due to movement, unless the sensor and its target are all static objects. Check to make sure that your mcu can handle the data at the minimum clock speed supported at the cmos sensor, if you can find such information though, you might need a DMA or a faster cpu itself, in which case you could check out the PIC32's.

Awesome write up so far though, well documented efforts, and pictures. Pictures are as always something that keeps someone reading and grabs their attention, much better than huge amount of text without pictures, regardless of how interested said text is. :P

Re: Interfacing a mysterious CMOS

Reply #6
[quote author="hak8or"]
If you have the logic sniffer from here
[/quote] Alas, no. But I do have probably the datasheet, and it's fairly thorough.

[quote author="hak8or"]I2C operating at 500 Khz[/quote] Not quite, I never properly copied that bit from the datasheet to here, it's not clear at all.
The I2C and Data lines (D[3:0]) are independent, though the underlying logic for the whole chip needs a clock cycle from CLKI.

There are a couple of other pins for syncing start of each high nibble, and frames, etc, but I only have so many external interrupts. (2!)

[quote author="hak8or"]
Check to make sure that your mcu can handle the data at the minimum clock speed supported at the cmos sensor, if you can find such information though, you might need a DMA or a faster cpu itself, in which case you could check out the PIC32's.
[/quote]

The "napkin maths" in point 10 worked out that's about 35 clock cycles @16 mhz.
With just straight access to the registers (, I can store safely up to 2KB in the SRAM, which is where I assume an array of bytes goes during program operation. (do I have to make it 'volatile'?)
If I could grab one bit  of  data for every 5th pixel 'along' for every 7th line, (or even average?)
(356 x 292) /(5 x 7) = ~71 x ~41 which is close enough to my ideal - 84x48 (Yes, the nokia 5110 LCD), and only 0.4ish KB

This leads to the following almost code. Assumes various things, but mainly that the 6th bit from the ADC gives an accurate 1/0  brightness comparison. Wiring? D[0] = pin 4, ... D[3] = pin 7.


Code: [Select]
boolean inputArray[71][41];  //Where the pixels go

void functionprototype() {
if  ( !(current_pixel % 5) && !(current_line % 7) ) { 
//If the current pixel location divides exacty (zero modulus), then do this.

byte inputByteTemp = PIND & B11110000;  //Grab the most significant nibble
send_clock_cycles(1);                                //Send one clock cycle to the CMOS

byte inputByteTemp &= (PIND & B11110000) >> 4; 
//stick the least significant nibble on the end of our temp byte.

if (!is_it_a_control_code(inputByteTemp)) {
//pretty straightforward probably, I think there is a fast way of finding out.Though it might require 3 bytes.

inputArray[current_pixel][current_line] = (inputByteTemp & B00100000) >> 6;
//This oughta just record the 6th bit of the ADC read value for the pixel, and put that in the boolean array- it's a 1 or 0.

current_pixel++;
}
else {
deal_with_control_code(inputByteTemp);
}
}

OK, that is pretty godawful, and not portable. Hell, it requires that specific ordering of pins, or else it needs to shuffle around bits. But, it might just work.

This leads to the main problem- using an timer interrupt or something to send a clock signal to the CMOS, and also trigger that little function.
Does anyone have any experience in manually modifying a timer to do that compare interrupt fast?
The problem is of course that there are 3 timers, and one of them will probably break I2C, somehow.

http://http://www.mythic-beasts.com/~markt/ATmega-timers.html This link contains information on how to set the speed, and when the compare register triggers, but I don't know how to take that interrupt, and make it trigger code (can hack it by wiring it into an interrupt pin though)
I'll update the main post with this progress, though I'll probably be away for a bit- moving back to uni.
Apologies for the wall of text!

 

Re: Interfacing a mysterious CMOS

Reply #7
An update!
Despite various things, such as the I2C address being wrong on the datasheet, and most problematically of all, setting the data pins to input, not output (realized at 1 am), I now have random data that is mostly 1's when a light is shining on the cmos, and mostly 0's when it is in darkness.
Most complicated light sensor, ever.

Code: [Select]
   Wire.beginTransmission(cmosAddress);
  Wire.write( B0010000);
  Wire.write(B00001101);
  Wire.endTransmission();
  delay(500);
  //send the 'exit low power' command
  Wire.beginTransmission(cmosAddress);
  Wire.write( B0010000);
  Wire.write(B00001000);
  Wire.endTransmission();
is sufficent to start, when using a very fast pwm

Re: Interfacing a mysterious CMOS

Reply #8
[quote author="Fractal"]
Most complicated light sensor, ever.
[/quote]
:-)  Glad you have it breathing shallow breaths!

Re: Interfacing a mysterious CMOS

Reply #9
Nice work! Glad to see a followup. The light/dark trick is simple, but I never would have thought of it.
Got a question? Please ask in the forum for the fastest answers.

Re: Interfacing a mysterious CMOS

Reply #10
As you folk may have guessed, the hardware is fine, and it's pretty much software from now on. My challenge is to get it to read a unit of data, fast. How fast? Well, using the datasheet for the cmos, it appears to have a minimum clock speed corresponding to ~1 MHz input, which is divided by 2, giving a new data thing every 2 cycles.
On the 16 MHz atmega328p, this is ~32 clock cycles to read a data nibble.
That is... not long.
Code: [Select]
  void benchmarkinterrupt() {
  byte benchstart1 = TCNT2;
  Functiongoeshere();
  byte benchdiff = TCNT2-benchstart1;
  Serial.print(benchdiff);  }
  // TIMER2 counts with the system clock.- no prescaler.

Unfortunately, my code takes 35-41 cycles, at least.

Code: [Select]
 ISR(TIMER2_COMPB_vect) { //INTERRUPT 2B
  switch (nibble0forMSB) {
  case 0:
    inputArray[0][bytenumber] = (PIND & B11110000);  //grab pins 7-4
    break;
  case 1:
    inputArray[0][bytenumber] |=  (PIND & B11110000) >> (nibble0forMSB << 2); // grab the second transmission, put at end
    break;    }
  bytenumber += nibble0forMSB;
  nibble0forMSB = !nibble0forMSB;  }

Unfortunately, the prior art seen seems to use a slower camera, and they use an xmega series controller, with some fancy 'virtual registers' that allow them to do the reading part in assembler.
Is there anything similar? Or a decent way to speed up the code? I'd have though it would be quicker than it is to flip a few bits around.

Re: Interfacing a mysterious CMOS

Reply #11
If you're getting down to shaving off a few cycles, I'd probably look at the assembly being generated (keeping in mind how many cycles each instruction takes) and go from there, sometimes you can reconstruct things in a way that's a bit more efficient. 

That being said, the code you have looks to be pretty minimal to me, not sure if hand-tuned assembly would be better than your compilers output or not.  Sometimes you can shave off some time by specifying where things are located in the memory space (I'm not at all familiar with the AVR architecture, not sure if this applies).

You're also going to incur some delay entering the ISR (pushing some registers onto the stack, jumping, etc).  If you can live with it, polling on the timer2 flag would eliminate the latency from the context switch entering the interrupt.  Sometimes, rethinking program flow to accommodate a polling approach instead of interrupts is necessary.

Re: Interfacing a mysterious CMOS

Reply #12
[quote author="bearmos"]If you're getting down to shaving off a few cycles, I'd probably look at the assembly being generated (keeping in mind how many cycles each instruction takes) and go from there, sometimes you can reconstruct things in a way that's a bit more efficient. 

That being said, the code you have looks to be pretty minimal to me, not sure if hand-tuned assembly would be better than your compilers output or not.  Sometimes you can shave off some time by specifying where things are located in the memory space (I'm not at all familiar with the AVR architecture, not sure if this applies).

You're also going to incur some delay entering the ISR (pushing some registers onto the stack, jumping, etc).  If you can live with it, polling on the timer2 flag would eliminate the latency from the context switch entering the interrupt.  Sometimes, rethinking program flow to accommodate a polling approach instead of interrupts is necessary.[/quote]

Agreed with everything here pretty much. :) I was always thinking of interfacing with a cmos sensor myself, but I could never find the datasheet for it, and it is in a non working camera so I wouldn't be able to even sniff it with my logic sniffer.

Why not just hand write in assembly a loop for fetching the data off the sensor instead of using an ISR and timer? That should definitely save you quite a bit of cycles if you do a loop in assembly without using the timer. If delays are needed, just stick some NOP's in there.

Re: Interfacing a mysterious CMOS

Reply #13
[quote author="hak8or"]
Why not just hand write in assembly a loop for fetching the data off the sensor instead of using an ISR and timer? That should definitely save you quite a bit of cycles if you do a loop in assembly without using the timer. If delays are needed, just stick some NOP's in there.[/quote]

Good point on the nop's.  Since code execution is providing the majority of the delay between reads, there probably won't be too many nop's required anyway.

Re: Interfacing a mysterious CMOS

Reply #14
[quote author="hak8or"]
Why not just hand write in assembly a loop for fetching the data off the sensor instead of using an ISR and timer? [/quote] Because I don't honestly know how properly, (though that's kind of the fun of it).
[quote author="hak8or"]I was always thinking of interfacing with a cmos sensor myself[/quote]
May I recommend a microscope? The chip will have an identifying number or two in gold or someting, though they are very, very small. Post exams, I'll be able to access some nice microscope labs, so some nice pictures of the sensor should follow.
Due to the necessity of a CMOS interacting with light, the non sensor bits of the chip seem to have only a thin coating of black stuff- you can almost see the structure of it in 3D.

I'd swear there is even an instruction to do the adding 1 in one cycle - yes, all data is in bytes, though I appreciate it must be got into a register somehow.
In addition, due to the CMOS clock prescaler limiting to /2, it really needs to grab the data every 2 PWM cycles - hak8or's polling plan is seeming like a better and better idea!

I know how to put lines of assembler, like
Code: [Select]
 __asm__("nopnt""nopnt"); 
in the middle of a sketch, but I don't know how to interact with data in the c code.
Seeing the  IKALOGIC tutorial is helpful, and I can see how to make it wait for two falling edges, before reading the port values, maybe. However, how to make the c code take that register value?


I've been experimenting with the simple benchmark, and some of the things seem to incur really odd delays, like ">> 4" takes 20 cycles, /16 takes 10 cycles, and (volatile byte)"number++" takes 5.
That data array? 9 cycles to write PIND to it, vs 3 cycles to write to a simple byte value.

Code: [Select]
 void readbyte() {
inputArray[0][bytenumber] =PIND; // 9 cycles
bytenumber++; //5 cycles }  //14 cycles
The above code isn't fancy, or space efficient- I only care about the 4 MSB's of PIND, but it does only take 14 cycles. Still, pretty dreadful. "PIND & B11110000" takes only 1 cycle, though.

With a bit of [s:]second[/s:] guessing [s:]of the compiler[/s:], can get that down to 12 cycles... by making it more complex!
Much quicker to do the adding while the number is in the register anyway- now it really does add 1 in one cycle.
Code: [Select]
 void readbyte() {
byte tempbytenumber = bytenumber
inputArray[0][tempbytenumber] =PIND;  //this bit seems to take 7 cycles now
bytenumber = tempbytenumber+1; } //12 cycles total, yeah

And, this is where we stand so far - a fun distraction, and I can only really optimize when ideas strike. I do wish I had some form of display, the serial monitor on OSX seems unstable - several kernel panics have occurred when disconnecting the Arduino board when serial data was transmitted. This even occurs even when using 'screen'. The enforced 1 second delays seem to work well though to combat it.

Cheers for all the great suggestions!