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

Re: Interfacing a mysterious CMOS

Reply #15
i'm not familiar with aurdino at all, but with most cross compilers, you have the option of looking at the compiler generated assembly code, which (for simple operations) is a good way of gaining some understanding of the assembly code you're working with (being able to see the "C" and "asm" in line is really helpful).  This can uncover some choices the compiler is making (like memory accesses that take varying amounts of time).  on some architectures, you can sometimes use a register to store a value (as opposed to ram) and gain some speed this way.

Re: Interfacing a mysterious CMOS

Reply #16
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!

Re: Interfacing a mysterious CMOS

Reply #17
Yeah, that looks about right - this is why you hear people saying assembly is more efficient :)  Although the well-versed engineers will also tell you that there's more to the C vs. assembler debate than just efficiency.  As evidenced from the popularity of C for embedded apps, raw efficiency often takes a back seat to maintainability and development time!

At any rate, here are a few links to AVR assembly stuff, for your perusal (hopefully after finals ;-) !):

First, the official guide from Atmel:
http://http://www.atmel.com/Images/doc1022.pdf
I would probably print out pages 4-7 and 4-8 for quick reference when you're looking through the code.

Here's a site that appears to have a TON of supporting text with lots of background as to what's going on:
http://http://www.avr-asm-tutorial.net/avr_en/beginner/index.html

Have fun ;-)!

Re: Interfacing a mysterious CMOS

Reply #18
Wohh, the AVR seems to have a lot more instructions than the PIC's do! I am only familiar with the PIC assembly sadly.

The reason for assembly taking a back seat to C in stuff like this is for a few reasons. Like bearmos said, it is a lot easier to maintain and develop because for starters, it is far more readable. Also, C provides a very good level of abstraction. In C all you need to do is write a for statement, and the compiler generates the assembly and from there the machine code. If you wanted to do that in assembly, you would have to find the instructions for it, and assembly is very very specific to the CPU and architecture. It is not really worth it for most hobbysts to learn assembly for each microcontroller they use, because we tend to often try out many, not to mention that it is very time intensive to REALLY learn assembly for a given mcu.

And, sometimes the concept that hand written assembly is faster than C goes flying out the window when you begin looking at more complex instruction sets, such as X86. Often times when you have a CISC architecture, a compiler will do much better than a human at fast and small code, take a look at how GCC does it for example. When you look at it, just as you are looking at the assembly for the avr, it looks ridiculous and over the top, but actually it is employing tricks to make it go faster which many humans never even considered. Though, this depends greatly on the compiler. If the compiler is garbage for example, or no optimization's enabled, it will make horrendous but maybe readable assembly, but if the optimization's are all enabled, then chances are it will create very good code in terms of speed and space, but be nigh impossible to read.

Though, writing in assembly is EXTREMELY satsfying, for my at least. I did it with the PIC18F's to just blink a led, then incrementing of a value and displaying it on leds, and it was a blast, and I learned a huge amount about the way the mcu functions, which let me code better in C too.

Ok, end of long speech. :P Some of the instructions that should interest you are
- STS (Store Direct to SRAM)
- NOP (No operation, wastes a cycle, used for delays)
- CALL (Call Subroutine)
and one of the branch's

When you do assembly you are essentially getting rid of all the abstraction C provides, but you get access to a lot more, and if you know what you are doing, can get it going much faster than what the compiler is currently generating. Best of luck! :)

Some more links!
http://www.attiny.com/assembly.htm
http://necrobious.blogspot.com/2010/06/ ... steps.html
http://www.avrbeginners.net/getting_sta ... r_2_2.html
http://dotasm.com/sample-code/101-the-flashing-led/

Re: Interfacing a mysterious CMOS

Reply #19
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.

Re: Interfacing a mysterious CMOS

Reply #20
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.

Re: Interfacing a mysterious CMOS

Reply #21
[quote author="Fractal"]The 69696 section should be alternating and error free- it is![/quote]
Excellent, there's nothing like getting back valid data after tuning a piece of code!  Congrats!

[quote author="Fractal"]Next up, trying to get a read&wait function, though I still have to figure out array access- it's weird.[/quote]
Again, no direct AVR experience here, but you might be able to define where in memory you'd like to put your array when you first define it, and then directly access those addresses with the assembly.

It certainly looks like you're making good progress.

Re: Interfacing a mysterious CMOS

Reply #22
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.

Re: Interfacing a mysterious CMOS

Reply #23
Nice job, and congratulations on your initial success.
Got a question? Please ask in the forum for the fastest answers.

Re: Interfacing a mysterious CMOS

Reply #24
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?

 

Re: Interfacing a mysterious CMOS

Reply #25
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!