Skip to main content

Messages

This section allows you to view all Messages made by this member. Note that you can only see Messages made in areas you currently have access to.

Messages - Fractal

1
Project logs / Re: Interfacing a mysterious CMOS
Hello again!
After a long hiatus due to university work, I've got back to this project.
First thing is going to be a way of viewing the image in real time, in this case a very quick python script

Code: [Select]
import serial
ser = serial.Serial('/dev/tty.usbserial-A40090sc', 115200)
watcher = 10000 #Turns out, don't want this running forever
while watcher:
line = ser.readline().strip()  #strip off the end whitespace
frame = ""
while len(line) and watcher: #if it is not working, len(line) == False
frame += line + "n"
line = ser.readline().strip() #get the next one ready
watcher -= 1
#Tab indented loops
ser.write('*') #Acknowledge the data
print frame

Now it's much easier to test, though the arduino is still outputting characters over serial, not ideal.
Example 'image':
Code: [Select]
10	 .                                               .........::::::::::::::???????????22222
20 ...                                          ............::::::::::::::?????????222222?
30 ....                                          ................:::::::::::???????????2222
40 .:...                                          .................::::::::::::?????????222
50 .::....                                        ..................:::::::::::???????????2
60 ::::......                                .........................:::::::::::?????????2
70 ::::::.......                        .....:::????????:::..........::::::::::::????????2
80 ::::::::...........                ..::::::::???222222??::............:::::::::::??????
90 :??::::::::............          ..::??:.    ...:::??22??::................::::::::????
100 :???::::::::...........        ..:??222:.  .::::...::????::..      .........:::::::???
110 ????::::::::...........      ..:?226222?::::::???:...::???:.. 6 ?600..:60#:?#.:6#.?##:0
120 ??????::::::::......          :?22666622????::?????::::::??:.      ...    .......::::::?
130 :???::::::::......            .?22666622??:::::????::::???:.    ...      ......:::::::
140 ?????:::::.....              .?22666622??::::..:::???::::??:.    ..::::::...........::::
150 ????:::::.....                .?22222222??::::::::::?::.:::.  .::???::::............:::
160 :??:::::::.....              .:?2222222????:::::::::::.:::.            20#?0 ?6#:2  6#6
170 :??:::::??::::::....          :?222222222????::::::::::.:::                    ......:::
180 :??::??222266662222??0.::???22666666222222?????:::::::.::.                    ......:::
190 ??????22666666666662??:??2226666666666222222222222????::::...                  .....:::
200 ?????2266666666666662????22266666666662222222222222222??::.....                .....::::
210 ????22266666666666662????222266666666622222222222222222???::::.                ..0#200:.
220 ????22666666666666662?????22266666666622222222222222222662622?:.              .....::::
230 ???226666666666666662??????22??? :: ?0 6?:#6?20 ?:  ?02# . ??  0.0:#6#:#:6 . ??6 #20.266
240 ?2222666662??2266662??????22222222266622?????????22666666666662??????:::???222????:?????
250 ?222666662?:??226662?:????222222226666622?????222666666666666666666666666666666666666222
260 2226666662?::?22666??:????22222226666662222222666666666666666666666666666666666666666666
270 2266666662?::?22662??????222222266666666666666000066666666666666666666666666666666666666
280 226666662??::?22662?????2222222666666..:?#  .#0622::.:??:::.::26222??2:?2?662226662: ##2
290 2666600622????22662????22222266666666666666666666666666666666666666666666666666666666666
300 2666600622????22662222222222666666662222226666666666666666666666666666666666666666666666

Clearly, there is still some work to do with the basics! That image was gathered at a camera clock rate of ~0.87 Mhz, and there are clearly still some sync errors (e.g. line 280 loses it halfway through).
An additional problem presents itself - the image contrast and brightness leaves a lot to be desired.
Rather than leaping into an automatic function, it would be straightforward to have the arduino take a control signal over serial from the host computer, with some form of nice visual slider to adjust it in realtime. The datasheet gives the format of these control signals, sending them over i2c as usual.
Finally, the quality is pretty bad, and it's not helped by ascii rendering. The data bandwidth of the serial connection is not being used very efficiently - it's taking a byte per pixel, and rendering it in glorious 3 bit depth.
It would make some sense to be more discerning about the data in, storing 2 pixels per byte, by only looking at the high bits of the bytes the camera sends. The code was due for a rewrite anyway!
2
Project logs / Re: Interfacing a mysterious CMOS
So, I did some shoddy C coding to identify the line start signals, and on reading such a signal, reading 178 pixels worth of data, and the line number. This ran 255 times
By sorting each line by it's line number, removing duplicates, and then colouring based on the pixel reading, I present, the first image, beautifully rendered by excel.



Yeah, it's going to need some work!
Several features of note:
Something weird happens to the lines at ~byte 130. But what? My best guess is that the 2x4 bit nibbles that comprise each pixel's intensity get out of kilter with the bytes. Hopefully this is a code thing, and not some weird interrupt triggering thing.

It does have broad features, just about! I think it was pointed roughly at the ceiling, next time I'll see if I can get something a bit more black and white in front of it.

The problem so far is that the code is pretty naff, and I'm basically getting random lines, which I have to sort into an image afterwards.
I don't know how long it takes to send them all via serial, either. Ideally it would store a low res version of the image in an array somewhere, then send that all at once.
Tricky thing would be keeping the processing fast enough that it could read a whole frame in.
But, Progress!
BTW, if anyone has a decent way of triggering something very promptly when a specific sequence of readings is taken (0xFF, 0xFF, 0x00, 0xB6), otherwise I'll just hack something ugly but fast in assembler.
Cheers for the encouragement, Ian!

EDIT:

This is a picture of me. Detailed, no?
3
Project logs / Re: Interfacing a mysterious CMOS
Well, I got some reading down to stable with a PWM wavelength of 10 cycles - For comparison, that's clocking in data at 1.6 MHz.

However, in the push for ever greater speed has hit a bit of a problem-
Code: [Select]
  for (byte n=0; n<7; n++) {
    combowait_read2();
}
//works fine, but...
  for (byte n=0; n<6; n++) {
    combowait_read2();
//fails to write anything...
}

  void combowait_read2() {
    byte pinsout; //this just lets it pick any old register
    asm volatile (
  "L_3%=:" "sbis  %[temp_PIND], 3"    "nt"  //skip next instruction if bit 3 of PIND is 1
  "rjmp L_3%="    "nt" //loop back to the sbis line...
  "L_2%=:"  "sbic  %[temp_PIND], 3"    "nt"  //skip next instruction if bit 3 of PIND is 0
  "rjmp L_2%="    "nt" //loop back to the loading ...
  "in  %[temp_pinsout], %[temp_PIND]"  "nt" //load up...
  "st %a[temp_inputArray]+, %[temp_pinsout]"  "nt" //store the data. Boom. Also increment Z

  : [temp_pinsout] "=r" (pinsout)  //outputs after the first colon
  :[temp_PIND] "I" _SFR_IO_ADDR(PIND) //inputs after the second!
 ,[temp_inputArray] "e" (inputArray) );   
}

Ok, so for a little loop, gcc is completely forgoing the loop, and just repeats the code 6 times. But, it fails!
I'm not sure why- but this "combowait_read2()" function does not work when called sequentially. - except it does...
Code: [Select]
  for (byte n=0; n<7; n++) {
    combowait_read2();
    combowait_read2();
}
//this works fine! it reads 14 nibbles perfectly!

Here is the partially assemble code the compiler generates, for comparison...
Code: [Select]
//GOOD FUNCTION
void loop()  // LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE
    1c0: cf 93      push r28
    1c2: df 93      push r29
    1c4: 80 e0      ldi r24, 0x00 ; 0
  "in  %[temp_pinsout], %[temp_PIND]"  "nt" //load up...
  "st %a[temp_inputArray]+, %[temp_pinsout]"  "nt" //store the data. Boom. Also increment Z
 //stable down to 10 - booyah
  : [temp_pinsout] "=r" (pinsout)
  :[temp_PIND] "I" _SFR_IO_ADDR(PIND)
 ,[temp_inputArray] "e" (inputArray) );  //extremely crucial colons
    1c6: e5 e2      ldi r30, 0x25 ; 37
    1c8: f1 e0      ldi r31, 0x01 ; 1

000001ca <L_396>:
    1ca: 4b 9b      sbis 0x09, 3 ; 9
    1cc: fe cf      rjmp .-4      ; 0x1ca <L_396>

000001ce <L_296>:
    1ce: 4b 99      sbic 0x09, 3 ; 9
    1d0: fe cf      rjmp .-4      ; 0x1ce <L_296>
    1d2: 99 b1      in r25, 0x09 ; 9
    1d4: 91 93      st Z+, r25

}

void loop()  // LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE
{
  for (byte n=0; n<7; n++) {
    1d6: 8f 5f      subi r24, 0xFF ; 255
    1d8: 87 30      cpi r24, 0x07 ; 7
    1da: b9 f7      brne .-18    ; 0x1ca <L_396>
    1dc: c5 e2      ldi r28, 0x25 ; 37
    1de: d1 e0      ldi r29, 0x01 ; 1
}

 

  for ( byte bytenumber1 =0;bytenumber1 != 255; bytenumber1++) {
    Serial.print(inputArray[bytenumber1]/16,HEX); //that /16 is to ignore the 4 LSB's
    1e0: 68 81      ld r22, Y
    1e2: 62 95      swap r22
    1e4: 6f 70      andi r22, 0x0F ; 15
    1e6: 84 e7      ldi r24, 0x74 ; 116
    1e8: 93 e0      ldi r25, 0x03 ; 3
    1ea: 70 e0      ldi r23, 0x00 ; 0
    1ec: 40 e1      ldi r20, 0x10 ; 16
    1ee: 50 e0      ldi r21, 0x00 ; 0
    1f0: 0e 94 b4 08 call 0x1168 ; 0x1168 <_ZN5Print5printEii>
    inputArray[bytenumber1] = 0;
    1f4: 19 92      st Y+, r1
    combowait_read2();
}

 

  for ( byte bytenumber1 =0;bytenumber1 != 255; bytenumber1++) {
    1f6: 82 e0      ldi r24, 0x02 ; 2
    1f8: c4 32      cpi r28, 0x24 ; 36
    1fa: d8 07      cpc r29, r24
    1fc: 89 f7      brne .-30    ; 0x1e0 <L_296+0x12>
    Serial.print(inputArray[bytenumber1]/16,HEX); //that /16 is to ignore the 4 LSB's
    inputArray[bytenumber1] = 0;
  }// outputs that stored data
  bytenumber = 0;
    1fe: 10 92 24 01 sts 0x0124, r1
  Serial.println();
    202: 84 e7      ldi r24, 0x74 ; 116
    204: 93 e0      ldi r25, 0x03 ; 3
    206: 0e 94 af 07 call 0xf5e ; 0xf5e <_ZN5Print7printlnEv>
    Serial.println(cyclecount);
    20a: 84 e7      ldi r24, 0x74 ; 116
    20c: 93 e0      ldi r25, 0x03 ; 3
    20e: 60 91 02 01 lds r22, 0x0102
    212: 4a e0      ldi r20, 0x0A ; 10
    214: 50 e0      ldi r21, 0x00 ; 0
    216: 0e 94 56 08 call 0x10ac ; 0x10ac <_ZN5Print7printlnEhi>
  cyclecount--;
    21a: 80 91 02 01 lds r24, 0x0102
    21e: 81 50      subi r24, 0x01 ; 1
    220: 80 93 02 01 sts 0x0102, r24
  setuptimer_2B();
    224: 0e 94 8d 00 call 0x11a ; 0x11a <_Z13setuptimer_2Bv>
  delay(1000);  //this stops the serial port from exploding
    228: 68 ee      ldi r22, 0xE8 ; 232
    22a: 73 e0      ldi r23, 0x03 ; 3
    22c: 80 e0      ldi r24, 0x00 ; 0
    22e: 90 e0      ldi r25, 0x00 ; 0
    230: 0e 94 59 04 call 0x8b2 ; 0x8b2 <delay>
    setup_camViaI2C1();
    234: 0e 94 9d 00 call 0x13a ; 0x13a <_Z16setup_camViaI2C1v>

}
    238: df 91      pop r29
    23a: cf 91      pop r28
    23c: 08 95      ret


//BAD FUNCTION

void loop()  // LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE
    1c0: cf 93      push r28
    1c2: df 93      push r29
  "in  %[temp_pinsout], %[temp_PIND]"  "nt" //load up...
  "st %a[temp_inputArray]+, %[temp_pinsout]"  "nt" //store the data. Boom. Also increment Z
 //stable down to 10 - booyah
  : [temp_pinsout] "=r" (pinsout)
  :[temp_PIND] "I" _SFR_IO_ADDR(PIND)
 ,[temp_inputArray] "e" (inputArray) );  //extremely crucial colons
    1c4: e5 e2      ldi r30, 0x25 ; 37
    1c6: f1 e0      ldi r31, 0x01 ; 1

000001c8 <L_392>:
    1c8: 4b 9b      sbis 0x09, 3 ; 9
    1ca: fe cf      rjmp .-4      ; 0x1c8 <L_392>

000001cc <L_292>:
    1cc: 4b 99      sbic 0x09, 3 ; 9
    1ce: fe cf      rjmp .-4      ; 0x1cc <L_292>
    1d0: 89 b1      in r24, 0x09 ; 9
    1d2: 81 93      st Z+, r24

000001d4 <L_394>:
    1d4: 4b 9b      sbis 0x09, 3 ; 9
    1d6: fe cf      rjmp .-4      ; 0x1d4 <L_394>

000001d8 <L_294>:
    1d8: 4b 99      sbic 0x09, 3 ; 9
    1da: fe cf      rjmp .-4      ; 0x1d8 <L_294>
    1dc: 89 b1      in r24, 0x09 ; 9
    1de: 81 93      st Z+, r24

000001e0 <L_396>:
    1e0: 4b 9b      sbis 0x09, 3 ; 9
    1e2: fe cf      rjmp .-4      ; 0x1e0 <L_396>

000001e4 <L_296>:
    1e4: 4b 99      sbic 0x09, 3 ; 9
    1e6: fe cf      rjmp .-4      ; 0x1e4 <L_296>
    1e8: 89 b1      in r24, 0x09 ; 9
    1ea: 81 93      st Z+, r24

000001ec <L_398>:
    1ec: 4b 9b      sbis 0x09, 3 ; 9
    1ee: fe cf      rjmp .-4      ; 0x1ec <L_398>

000001f0 <L_298>:
    1f0: 4b 99      sbic 0x09, 3 ; 9
    1f2: fe cf      rjmp .-4      ; 0x1f0 <L_298>
    1f4: 89 b1      in r24, 0x09 ; 9
    1f6: 81 93      st Z+, r24

000001f8 <L_3100>:
    1f8: 4b 9b      sbis 0x09, 3 ; 9
    1fa: fe cf      rjmp .-4      ; 0x1f8 <L_3100>

000001fc <L_2100>:
    1fc: 4b 99      sbic 0x09, 3 ; 9
    1fe: fe cf      rjmp .-4      ; 0x1fc <L_2100>
    200: 89 b1      in r24, 0x09 ; 9
    202: 81 93      st Z+, r24

00000204 <L_3102>:
    204: 4b 9b      sbis 0x09, 3 ; 9
    206: fe cf      rjmp .-4      ; 0x204 <L_3102>

00000208 <L_2102>:
    208: 4b 99      sbic 0x09, 3 ; 9
    20a: fe cf      rjmp .-4      ; 0x208 <L_2102>
    20c: 89 b1      in r24, 0x09 ; 9
    20e: 81 93      st Z+, r24
    210: ef 01      movw r28, r30
}

 

  for ( byte bytenumber1 =0;bytenumber1 != 255; bytenumber1++) {
    Serial.print(inputArray[bytenumber1]/16,HEX); //that /16 is to ignore the 4 LSB's
    212: 68 81      ld r22, Y
    214: 62 95      swap r22
    216: 6f 70      andi r22, 0x0F ; 15
    218: 84 e7      ldi r24, 0x74 ; 116
    21a: 93 e0      ldi r25, 0x03 ; 3
    21c: 70 e0      ldi r23, 0x00 ; 0
    21e: 40 e1      ldi r20, 0x10 ; 16
    220: 50 e0      ldi r21, 0x00 ; 0
    222: 0e 94 cd 08 call 0x119a ; 0x119a <_ZN5Print5printEii>
    inputArray[bytenumber1] = 0;
    226: 19 92      st Y+, r1
    combowait_read2();
}

Who knows what's causing this? A bit of a mystery...
Why bother? Testing loops of length 1 works fine - and reads accurately down to 5 cycles- 3.2 MHz
but doing a pointless loop for nothing is silly, and it takes a ton of memory- this loop can read accurately in 5 cycles:
Code: [Select]
void loop()  // LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE LOOP ENABLE 
{
  for (volatile byte n=0; n<1; n++) {
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
    combowait_read2();
  }

Interestingly, if I ignore the volatile bit when declaring the loop, it spams the serial port with randomish data. Weird.
Yeah. making stuff volatile seems to trick the compiler to not optimise it.
Anyone have any ideas? It just does not seem to write to the array when not in it's own little loop.

EDIT: 
 for (byte n=1; n!=0; n++) {
loops 1 cycle faster than
 for (byte n=0; n!=255; n++) {

I think I've fallen for the trap of getting caught up in useless optimizations- I still need to make it recognise a command code!

DOUBLE EDIT:
Welp, trimmed down a loop to the bare minimum, didn't even have an extra variable to count 255 on, I used the lsb's of the array pointer. It was beautiful, with one function that would happily read 255 nibbles in. I found the problem on the serial- or at least solved it by declaring that loop's variable volatile.
Sadly, the optimisations matched the compiled code speed, for that  "for (byte n=1; n!=0; n++) {" loop. (9 cycles)
Well played, compiler.

Code: [Select]
     1c4:	e5 e2       	ldi	r30, 0x25	; 37
    1c6: f1 e0      ldi r31, 0x01 ; 1
    1c8: 9e 2f      mov r25, r30          //store that 0x25 for later...

000001ca <L_392>:
    1ca: 4b 9b      sbis 0x09, 3 ; 9  //wait for a 1 on pin3, then skip the next line
    1cc: fe cf      rjmp .-4      ; 0x1ca <L_392> //this jumps to the previous line, if run

000001ce <L_292>:
    1ce: 4b 99      sbic 0x09, 3 ; 9 //wait for a 0 on pin3, then skip the next line
    1d0: fe cf      rjmp .-4      ; 0x1ce <L_292> //this jumps to the previous line, if run
    1d2: 89 b1      in r24, 0x09 ; 9  //load in some port data (PIND)
    1d4: 81 93      st Z+, r24  // store that byte in the memory at location pointed to by Z (r30:r31) and increment
    1d6: 9e 13      cpse r25, r30  //compare current Z LSB with the start value, then skip the next line
    1d8: f8 cf      rjmp .-16    ; 0x1ca <L_392> //go all the way back to line 0x1ca - the start
Now it waits for falling edge, (3 cycles), reads in the data (1 cycle), stores the data and increments the pointer counter(2 cycles), compares the pointer counter LSBs with the initial value (1 cycle), and loops back (2 cycles).

Well, some of those numbers are wrong, but this thing can still read data reliably in 9 cycles- 1.78 MHz.
Removing the check for a high bit would make it better, but only at very high speeds.
Indeed- it works, for 16-7 cycles, fastest speed 2.29Mhz.

Removing both checks for an edge obviously only works at one frequency, and it's that limit I hit before, 5 cycles (3.2 MHz)
It could go quicker, but then there would be no way to limit it to only 256 readings, or exit the loop.

Yeah, that's time to call it a day- and work on reading a control code very quickly.


Since this has got to be a bit of a wall of text and ramblings, I will when this is somewhat finished, concatenate it somewhat.
Maybe find some pictures.
TL;DR  : declare some of your variables to be volatile, if all else fails.

Triple edit:
So frustrating reading through the code- I mean, sometimes to load, say "1" into a register, it will:
Load 0  into the register, then
subtract 255 from said register.
I mean, it works, but, hell, it's awful.
4
Project logs / Re: Interfacing a mysterious CMOS
Alright, apologies for the update spam, but hey, someone may care.
So, using the marvelous guide at http://http://www.nongnu.org/avr-libc/user-manual/inline_asm.html, I crafted a little C stub function
Code: [Select]
void waiter1()
{  //objective? wait one fall and one rise on pin 3 (3rd bit of PIND)
  asm volatile (  //oh yes, the %= syntax means the compiler will make a unique label. You need this.
  "L_2%=:"  "sbic  0x09, 3"    "nt"  //skip next instruction if bit 3 of PIND is 0
  "rjmp L_2%="    "nt" //loop back to the sbjc ...
    "L_3%=:"  "sbis  0x09, 3"    "nt"  //skip next instruction if bit 3 of PIND is 1
  "rjmp L_3%="    "nt" //loop back to the sbis ...
  ::);  //these colons are neccessary to make the damn thing work
}

it fits in here:

  for (byte n=0; n<255; n++) {
    waiter1();
    readbyte3();
  }

Now, that's all very interesting, and needs improvement really, but it works!
Code: [Select]
FFFFFFFFFFFFFFFFFFFFF696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969696969
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
EFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE
9979090918B8A878585817F77777472706E6A6C81FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B60737FEEEE7EBEDECEAF1EDEFF1F3FAF1EFF8F5FAFAFEFCFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE
DBEB9BEBFBBBAC0B9B8B9BFB8BEBCB7B9BBB7B9B7B6B7B9B5B4B4B2B2B1AFB0B2B1AFB0B0AEA9ABAAACA7A9A8A4A5A6A2A3A9A0A7A1A7A9A1A2A09DA19EA0A3A0A3A29FA1A59D9F9BA1A29EA29DA09A9D9D9C9F9C9B9B979C9A9E97999A98929494999694948D9390918C908B8A8B8B8A8B868485848A8384858A8BA4FFFF00
EFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE
DFEFDFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFBFCFCF8F1F3F2F9EFF3F2EEEBECEAE9F0E9E9E5E5E6EADDE1E0E0DBDADCD9E1D6DAD6D5D3D4D1D6D0D7D0D0CFD2D0CECECFCCCCCFCFCECED0CCCBCCCBCACACBC8C8C8CACAC6C3CAC9C4C8CAC6C3C6C1C5C1C0BDBDBABCB6B2B4B1ACA7A8A2
C94938D8E8E888C8A8B8A88878A8B8987868488858785807F817E867D797B7D7977757873747573757690FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B6040DFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFE
FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEF
CB3A8ADAAAFB1B0ADAAA9ACACA9A8A8B3ABA9ABACAEAEADADA8AEAFADACADADAFB1AAADACB4A7ACAAB4A6A4A39EA09E99969695918D8C8885827F7A797774726F696B6660605F59585D6B82545250514F4F52535654515455575558566457565D5C5E5F5F6061686166626263636664636766706A68676D6C6D69676768696A
6D1CED2D0CCCFD0CBD0CDCACCCBCDCFD0CED3CACDC9C8CECBCDCFCFCBC8CACCCFD1CCD2D1CACBCCD3CCD1D3CBD5CECBCDCECBCEC8CDCFD2CDCED1D0CFD2D3D3D1D3D3D3D3D5D6D5D0D4D7D1D5D8D6D6D4DBD4D7D4D6D2CFD4D2D5D0CED4D0CECDCBD0CFD1D1D0CAD1CECACDC8CFCFCACCCBCFCBCBCCCFCFCFCFD1D2D4D1D1D6
7172747173717272756F6F747972726E706E757071716C6C716F6F6B6A6B6E6A666C6667656768696662676A67686975757276777D808B8B8E969A9FA9A2ABB5BDC1D8FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B601629B8B8A8683888481848486818080807F7E7E7F808A867C7
D3C3D3C3B3D3C393F3E3F3D3E3D3E463F42413F3E45423E4147434045413E404440414244444141464541424145473E4542404342434041424342424742444443413D424E3F48414341414140414340414240434140414040423E404940403F3F404542413E43414040433F404143403F403D3E3E413E3D3B3E41403A3F4141
C8D888F8A8E8B8C878788868E8B8C8C878E84878589878C858584858285888382818284838180817E7F7B8183797C7B7B7B7E7D7A7675787777757673767573717171726F6F716C6F6C6C6C6C6D686B6A666669686366676666777E595A57585A5956555959595E58585B595C59585A5A5A5957595B5B5B585859575D5F5959
FFFFFFFFFFFFFFFFFFFFFFFFF00B6017A4C4444423E3E444142484245424045404246404643424042403F414341404640434040414743414142424C45434043434144413E42423F423E453E414343403E433E404240404141403F3F403F443F40403F413E44413D3D3E403F413F3D403F433C3C3E3E3E473E3C3F3C40413E3E
3242626202221232621222321232124232021232123211F222120242321202421201F242821231E1E222120201F222623201D21221F211E221E232023211E201E1F1F2021241F1E1F201D1A1D1F22261C21FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B60819362E2F3031312E3335
42B232B2724262C231D1E1C1D221C1E1C20232121201D1E1F1E1D1C1D1E201E221F1F1E1E1E1C1E221F1E1E1D1E1E1E1F1E1E23211D1E1E1F1D27251F1E20251F1F2326222221201F2B1F221D201F1E1F221E1C1E1F1F1D241E2120232323231D20211E211F20211E201D262B20212120201F2423241E2320221F2B241F241E
BDADBD5D4D4DBD0D3D7D1CDCDCACECBC9CECACACBCBC7C8CACBC5CDCDC8C8C5CBC9CBCDC9CAC6CBCAC7CBC7CDCBCFCAD0D0D0D2CDD0D1CED2D5CFCED2CECFCDCECCCFCBC9D2C8CACBC8C4C7CDC8C4C4C5C3C4C2BDC2BCC0BBB7BAB7B5B3B1B3BBACAEACACADABA7B7ABA6AAAED5FEA89C9594969296908E8F8D8B8C8A8D8B8B
1FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B60831FEF7F9F6F7FEF5F9FBFBFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEF8F8F4F4F3EFE9E4E6DDDEDFDBD4D4CDCFCCCACCC4C4C6C1C0C0C0BFBABABAC0B8BEBBBBBCBAC1C0BF
FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFDFEFAF5F2EFEFEFEDE8E9DFE2DDD9D7D9D6D1D3D2CACCCECED3CCCCC7C7C5C7C3C4C3C1C4C0C3C4C2C6C1C4BDBDBEB9B9BBB9B4B7B4AEB2AFAAAAA8A5A5A0A59D9B9B999396968E8D9C8784837E7E7C7B7880FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
FEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEFEDED1C8C5C8C9C0CBC4C6BFBFBFBBBFBEBEBFBBBBC0C0BFC4C3C1C1BCC1C1BFC2C2C3C1C6C0BEBEBFC1C1CAC2C3BDC5C6C2C0CAC3C2C0C3BEC8BFBDBEBCBFBABFBDBABBB8BDB3B9B4B7B5B7B5B3B3B3B6B4B9B2B3B0B3B5B2AFB2B0B3B1B0B2B
32D2C2E302C2F2C3332312B2E30302F2D30362D2E2E3033392E302D2E302E2E312D312D2B302E372E2E2E362B2F2E33302E2D3132342E312F2F2F2D2E302E2F2F2E352E2F2E2E2E2C353130303030312D2F363430362F31322D302E2F2E2F2D2B2B2A2E2C372F2E2E2E2D302D2F2E2E2F32302D2F352C2D2D313430302E2B2D
20201F1F241F2122221F212022201F231F32202121201D20FFFF0080FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00B60707201F1F1E1F201E20201E1D211F211E201F1E20211F1D211C221E22201F24241E21221E211E26231D1F1F20201E1D2121211F2020211D1F1F201F22221A1E2020231D202
1E2122221C222B1D222620251E1E1F231D1F1D23201C1F28201B211E1B201D261E1D20211D1F1D1F20201F1D1F201E1D1D1B211F211C1F1F2021201B2022201E1F1D23201E1D201E1D1F1C1E1F1E231F1F201F24241E1C1E27201F1D1F1D1D1C271F21201B1E1E1D1F1E231E1C1E1E211B201D1F201D1D1F1D1D1C201E1CFFF
is the output of 25 seconds of running.
Several new notable things- The 69696 section should be alternating and error free- it is! ( a great improvement!)
The command code is FFFF00XXDDDD, where eg FFFF0080 means end of line. usefully, FFFF00B6 and a line number follow shortly after!
Most useful,though, is the error-free nature of the first bits. That's pretty crucial- though subtle cunning has made the command codes error correctable for  a single bit error, it's not worth the effort.

Next up, trying to get a read&wait function, though I still have to figure out array access- it's weird.
Following the neatened function, I need a fast check for a command code (FFFF00)- which also syncs up the nibbles (only 4 bits transmitted at a time!)
After that, I'll aim for one line of every other green pixel, by triggering when the appropriate line number is read, and see if can detect a moving hand.
Assembler hurts my brain...

Edit: Forgot to say that it is error free with a 40 cycle pwm out, I want 32, so more speed is needed.
Fortunately I can do away with the bytenumber thing, since there be an autoincrement instruction for array(ish) writes.
5
Project logs / Re: Interfacing a mysterious CMOS
Welp, those links are very helpful bearmos!
For the whole inline thing, mercifully someone has read the avr cookbook already!
http://http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1207370768/2
Now, I've done a little exploring- you were right to suggest caution, it does exactly what you tell it to.
eg:
Code: [Select]
  
volatile byte bytenumber =0;
Serial.println(bytenumber);
    asm("mov r0,%0 nt"  // copy a to r0
"inc r0    nt"  // increment
"mov %0,r0 nt"  // copy r0 back to a
:  "+r" (bytenumber));
  Serial.print("now a = ");
compiles to
    2e8: 80 91 24 01 lds r24, 0x0124 // load from sram- 2 cycles
    2ec: 08 2e      mov r0, r24  //pointlessly move it because we said r0 - 1 cycle
    2ee: 03 94      inc r0  // add 1 - 1 cycle
    2f0: 80 2d      mov r24, r0  //pointlessly move it back - 1 cycle
    2f2: 80 93 24 01 sts 0x0124, r24  // put it back into sram- 2 cycles
wheras
Code: [Select]
 asm("inc %0    nt"
:  "+r" (bytenumber));
compiles to
    2e8: 80 91 24 01 lds r24, 0x0124  //load 'er up - 2 cycles
    2ec: 83 95      inc r24 // +1, 1 cycle
    2ee: 80 93 24 01 sts 0x0124, r24  //store the new value
Which is what we really wanted.
Now, this is not an improvement on avr-gcc, though it favours   
  2ec:   8f 5f         subi   r24, 0xFF   ; 255 //subtract 255 from your byte - 1 cycle
Just to make the code hard to read, I assume... Weirdly, it doesn't seem to take any more space, despite requiring a value.

Well, now I have to figure out array access, and then we'll be golden- load up the bytenumber (2 cycles), copy pind (1 cycle?) write to array (? cycles) (add 1 to bytenumber (1 cycle) and then write bytenumber (2 cycles)

Plan is to make it wait on falling edges of the clock, so simply 2 wait for falling edge commands will wait 2 cycles (then process, & loop back).
PWM will deal with the exact timing- there should be enough lee-way, when not using interrupts.

One final thing- having to find the assembly many times is a faff-If you are on OSX, or Linux, you may find the following script helpful:
Code: [Select]
#!/bin/bash
timestamp=$(date '+%H_%M_%S')
avr-objdump -S /var/folders/cE/cEsWjxjnHOyVvffVZrsWNk+++TI/-Tmp-/*/*.elf > ~/Documents/Arduino/assemblerout/outASM_${timestamp}.txt

Save this with .sh, and run (os x ) "chmod ug+x script.sh"
The random temp address will almost certainly need changing from my values, but should not need changing later.
6
Project logs / Re: Interfacing a mysterious CMOS
Hey bearmos, good plan, done so with "avr-objdump -S", got a horribly long file full of stuff.
Code: [Select]
void blink()
{ //remarkably, this code is really slow for what it does
  state = !state;
    29a: 90 e0      ldi r25, 0x00 ; 0
    29c: 80 91 26 03 lds r24, 0x0326
    2a0: 88 23      and r24, r24
    2a2: 09 f4      brne .+2      ; 0x2a6 <setup+0x132>
    2a4: 91 e0      ldi r25, 0x01 ; 1
    2a6: 90 93 26 03 sts 0x0326, r25
  PORTB =  (PORTB & B11011111 )+ (state << 5);
    2aa: 85 b1      in r24, 0x05 ; 5
    2ac: 92 95      swap r25
    2ae: 99 0f      add r25, r25
    2b0: 90 7e      andi r25, 0xE0 ; 224
    2b2: 8f 7d      andi r24, 0xDF ; 223
    2b4: 98 0f      add r25, r24
    2b6: 95 b9      out 0x05, r25 ; 5
Eek! That's a lotta hassle to make a blink.
Some of it doesn't seem to make much sense, like the c code has been scrambled.
Anyhow, I don't know any assembler, but I do know roughly how it works, and it's a great way to see if changing the code has any effect!
Thanks!
7
Project logs / Re: Interfacing a mysterious CMOS
[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!
8
Project logs / Re: Interfacing a mysterious CMOS
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.
9
Project logs / Re: Interfacing a mysterious CMOS
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
10
Project logs / Re: Mystery Tear down
Hmm, a mystery indeed!
So, a keyswitch, probably for power. Possibly a neon light for power indication - in which case this thing plugs into the mains.
Far object? Maybe a fuse, but the text says "____ ENABLE" Light enable?
What things need a keyswitch, a lever, some lights, and mains voltage?
A mystery...
11
Project logs / Re: Interfacing a mysterious CMOS
[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!
12
Project logs / Re: Interfacing a mysterious CMOS
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.
13
Project logs / 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!)