how to count a cycle of code [ and Dream cast coding ]resvd

Go To Last Post
77 posts / 0 new

Pages

Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a project that is very time sensitive. Each cycle must be monitored as I have to do things with in a nop. I need some help understanding what each lines costs me. Can anyone help here?

For example, are my comments right?

PORTC = 0x3;//both high ( a nop )
for ( i;i<4;i++)// one for each loop 
{	
  asm ("nop\n"  );PORTC = 0x0;//should be 3 total.
  asm ("nop\n"  );PORTC = 0x2;//should be 3 total.
}
PORTC = 0x3;//both high ( a nop )

if so I may need to remove a nop. I have a 12mhz crystal so I get 83.33 for each, 3 should give me 250, and I need to oscillate this second bit up for 3 down for 3 ( 4 times... Then end with bit 1 and 2 high.

the pattern I'm trying is simulate is here
http://img31.picoodle.com/img/im... ( see fig 1)

I dont know how to set PORTC in ASM, nor how to loop yet, but I imagine it could help a bit. Still looking in to that.

Last Edited: Mon. Aug 10, 2009 - 02:01 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I'm far not an expert but guess it would be better to look into list or assembler file after compiling and see "cost" of every instruction in your chip's datasheet. Another way is to simulate your code step-by-step in AVR Studio an look at cycle counter after each instruction passed.

P.S. sorry if I "made a LooooooooooooL" :P

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

this cycle counter will do nicely thx.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Are you trying to generate this stream, or read it as in your other thread?

I can't see why you'd need to generate it. Is this the preamble?

In any case, you have bigger problems than "costing" the port operations. Depending on your toolchain, your compiler options, and even how you write your functions the loop overhead can vary.

Do yourself a favor and unroll the loop as suggested in the other thread. Straight C should then be fairly predictable, at least with register variables and one-time loads.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

This is the start sequence , not the read. After this is done I must start the read. Not sure what you mean by unroll. But I have eliminated the loop for now. I'm just doing straight ASM steps one at a time. Perhaps this is what was meant by that.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

[/

Quote:

Not sure what you mean by unroll.

If you haven't heard of "unrolling a loop", then Id suggest a little more basic computer science/programming study before attacking a sophisticated project.

http://en.wikipedia.org/wiki/Loo...
http://en.wikipedia.org/wiki/Loo...
http://www.cs.uh.edu/~jhuang/JCH...

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
If you haven't heard of "unrolling a loop", then Id suggest a little more basic computer science/programming study before attacking a sophisticated project.
Well its a little late for that in relevance to this project as I'm on the last device I planned to read.
Thx for the info, this is basically what I have done. I have never been one to catch on to buzz words but in the interest of saving clock cycles I see what you mean.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You could als have a look at this project:
https://www.avrfreaks.net/index.php?module=Freaks%20Academy&func=viewItem&item_type=project&item_id=665
The macro _delay_cycles() will give you cycle accurate delays.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

first I suggest to like the others said check the assembly code that is generated.
I think the code is 2 and 3 cycles

2 cycles for

  asm ("nop\n"  );PORTC = 0x0;//should be 3 total. 

I think asmbly makse this of it
"
start:
    nop;
    out portc, r1
end:
 

This because the winavr compiler keeps r1 always cleared. Thus it can do this instruction in 2 cycles
the other will probably be 3 cycle:

start:
nop
ldi r0,0x02
out portc, r0
end

but if you are this time critical. did you disable all interrupts at this point? they might give you a mayor timing issue if it is this close...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

When I build (mega16 -Os) that code:

int main(void) {
    unsigned char i;

	PORTC = 0x3;//both high ( a nop ) 
	for ( i;i<4;i++)// one for each loop 
	{    
	  asm ("nop\n"  );PORTC = 0x0;//should be 3 total. 
	  asm ("nop\n"  );PORTC = 0x2;//should be 3 total. 
	} 
	PORTC = 0x3;//both high ( a nop ) 
}

I initially get:

test.c:7: warning: statement with no effect

that's because of the "for(i;", I assume this means "for(i=0;" ? If so then it generates (in the .s file):

.global	main
	.type	main, @function
main:
/* prologue: function */
/* frame size = 0 */
	ldi r24,lo8(3)	 ;  tmp48,
	out 53-32,r24	 ; ,, tmp48
	ldi r24,lo8(0)	 ;  i,
	ldi r25,lo8(2)	 ;  tmp55,
.L2:
/* #APP */
 ;  9 "test.c" 1
	nop

 ;  0 "" 2
/* #NOAPP */
	out 53-32,__zero_reg__	 ; ,,
/* #APP */
 ;  10 "test.c" 1
	nop

 ;  0 "" 2
/* #NOAPP */
	out 53-32,r25	 ; ,, tmp55
	subi r24,lo8(-(1))	 ;  i,
	cpi r24,lo8(4)	 ;  i,
	brne .L2	 ; ,
	ldi r24,lo8(3)	 ;  tmp53,
	out 53-32,r24	 ; ,, tmp53
	ldi r24,lo8(0)	 ; ,
	ldi r25,hi8(0)	 ; ,
/* epilogue start */
	ret

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson, the "char i=0;" is above and not included in my code snippet. I should have done ( ;i<4;i++). I did that to test if it causes another cycle. But the entire loop is undone now.

Quote:
did you disable all interrupts at this point?
No, I believe I need it for the usb part of the code, interesting though thx.

heinrichs.hj, that is a very interesting project thx!

I think one of my problems is the DDRC register. To set it I need to wait 5 to 6 nops before I can begin to read pins. I'm guessing this is a mcu limitation?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S_K_U_N_X wrote:
Quote:
did you disable all interrupts at this point?
No, I believe I need it for the usb part of the code, interesting though thx.

Then the loop will take at least the cycles mentionned.... if in the first nop the USB interrupt kicks in the time it takes to set the port is increased with the time it takes to run the interrupt code. SO basically you will never know how long the code takes to execute the nop and the port setting......

S_K_U_N_X wrote:

I think one of my problems is the DDRC register. To set it I need to wait 5 to 6 nops before I can begin to read pins. I'm guessing this is a mcu limitation?

set the DDRC register and one clock cycle later it is set.... there is not a 5... 6 cycle delay in that.
when writing the PORTC register and then wanting to read back the pin register you have to wait at least 1 clock cycle. This because you set the value and want the pin to have more or less settled and then read back the value...

regards

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

thx for the information.

I had another question. Due to the fact you can not trace step asm, is there any difference in this.

asm ( "nop\n nop\n")

compared this

asm ( "nop\n ")
asm ( "nop\n ")

As far as I can tell there is not, but wanted to ask. At least I can trace steps in the later.

Last Edited: Mon. Jul 20, 2009 - 01:55 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

with avr studio you can see what code is produced by the compiler.....
atleast when you start a simulation session, so you should be able to trace the answer yourzelf I think....

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok going to figure that out thx.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

Due to the fact you can not trace step asm

What makes you say that? If you have loaded the C into the simulator for debugging then just right click one of those Asm statments and select "Goto Disassembly" you are now in a view showing the C source and the generated Asm and now each use of "step" will step one AVR opcode rather than one whole C statement.

Cliff

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

What makes you say that? If you have loaded the C into the simulator for debugging then just right click one of those Asm statments and select "Goto Disassembly" you are now in a view showing the C source and the generated Asm and now each use of "step" will step one AVR opcode rather than one whole C statement.
Had no idea.. thx Cliff.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

asm ( "nop\n nop\n"); is guaranteed to produce 2 consecutive nop instructions, whilst asm("nop"); asm("nop"); may introduce extra code between the nop instructions.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

asm ( "nop\n nop\n"); is guaranteed to produce 2 consecutive nop instructions, whilst asm("nop"); asm("nop"); may introduce extra code between the nop instructions.

[full disclosure: I don't use the toolchain being discussed] OK, I'll bite: please give an example of "extra code" that the compiler might put between the nop's.

Hmmm--I suppose with code hoisting instructions could be rearranged. But I can't think of a situation where it would move code to between soem other instruction sequence.

Lee

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hey all, I didnt really want to start a new thread as its related. I was able to make some progress and I'm now reading the data. It would seem the data is not exact. and now I have to invent some sort of falling edge detection. Of course the trick here is to do it in ASM and in as few cycles as possible.

Here is what I'm attempting.

	"whi_ga1: sbis   PORTC,0x05 \n"// while its high wait..
	"rjmp whi_ga1 \n"//ok its low.
	"in  r21, PORTC\n"// get portC
	"BST r21, 4 \n"// pin4
	"BLD r26, 0 \n"//place out put on r26 

	"whi_ga2: sbis   PORTC,0x04 \n"// while its high wait.
	"rjmp whi_ga2 \n"//ok its low.
	"in  r21, PORTC\n"// get portC
	"BST r21, 5 \n"//pin5
	"BLD r26, 1 \n"//place out put on r26

	"whi_ga3: sbis   PORTC,0x05 \n"// while its high wait..
	"rjmp whi_ga3 \n"//ok its low.
	"in  r21, PORTC\n"// get portC
	"BST r21, 4 \n"//pin4
	"BLD r26, 2 \n"//place out put on r26

	"whi_ga4: sbis   PORTC,0x04 \n"// while its high wait.
	"rjmp whi_ga4 \n"//ok its low.
	"in  r21, PORTC\n"//get portC
	"BST r21, 5 \n"//pin5
	"BLD r26, 3 \n"//place out put on r26

	"whi_ga5: sbis   PORTC,0x05 \n"// while its high wait..
	"rjmp whi_ga5 \n"//ok its low.
	"in  r21, PORTC\n"// get portC
	"BST r21, 4 \n"//pin4
	"BLD r26, 4 \n"//place out put on r26

	"whi_ga6: sbis   PORTC,0x04 \n"// while its high wait.
	"rjmp whi_ga6 \n"//ok its low.
	"in  r21, PORTC\n"//get portC
	"BST r21, 5 \n"//pin5
	"BLD r26, 5 \n"//place out put on r26

	"whi_ga7: sbis   PORTC,0x05 \n"// while its high wait..
	"rjmp whi_ga7 \n"//ok its low.
	"in  r21, PORTC\n"// get portC
	"BST r21, 4 \n"//pin4
	"BLD r26, 6 \n"////place out put on r26

	"whi_ga8: sbis   PORTC,0x05 \n"// while its high wait..
	"rjmp whi_ga8 \n"//ok its low.
	"in  r21, PORTC\n"// get portC
	"BST r21, 5 \n"//pin5
	"BLD r26, 7 \n"////place out put on r26

also how can I do
"sbis r21,0x05 \n" without getting constant value required? I'd like to find a way to in the data to a temp register , then do the check, so that i have both pins read at the same time. Something like

"whi_ga1: in  r26, PORTC\n"// get portC
"sbis   r26,0x05 \n"// while its high wait..
"rjmp whi_ga1 \n"//ok its low.
"BST r26, 4 \n"// now stuff this bit /
"BLD r30, 0 \n"// in to r26

Since Port C can change to quickly ( each cycle counts ), that could be my troubles. My test has to be the same read as my result.

thx

Last Edited: Tue. Jul 28, 2009 - 03:54 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
OK, I'll bite: please give an example of "extra code" that the compiler might put between the nop's.

The C compiler is free to move code around where ever it wants, so long as the functionality remains the same. Since a NOP has no functionality as far as the compiler is concerned, it could move it pretty much anywhere. So it is theoretically possible for the compiler to move one of the NOPs and not the other (or move both to different places). Of course, the likelihood of this happening is probably extremely low. But I believe that in fact the probability is 0. Though it might be legal for a compiler to move the statement, it would not be wise for any compiler to actually do so. I would hope that the compiler writers would assume that if a programmer puts in inline assembly, they put it at that particular place for a reason.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Would a CALL/RET be too much overhead? If not you would have a MUCH easier life putting the asm into a .S file and calling the function!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
Would a CALL/RET be too much overhead? If not you would have a MUCH easier life putting the asm into a .S file and calling the function!
- I could call a single function sure, but how is putting my ASM in an .s file going to help? I'm sure there is a perfectly good reason for it, but I'm remain oblivious.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The main advantage of putting the code into a .S file is so that you can read and write it in a sensible language. I find avr-gcc gobbledygook syntax a little difficult to read.

I would also suggest that once something looks nice, you can fairly easily spot any possible improvements. If it looks horrible I just feel queasy.

You can simulate the ASM code in Studio to do the cycle counting, and check for any expected / unexpected results.

I am not sure what you are trying to do, but it looks as if you are trying to read a shift register or something. Explain or draw what your input waveform is supposed to be, and what result you want.

I would guess that there will be a simple way of achieving your result.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:

I would also suggest that once something looks nice, you can fairly easily spot any possible improvements. If it looks horrible I just feel queasy.

Spot on - my arguments for .S exactly.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hmm, well I cant find much info about doing this ( tutorial wise )but I will keep trying. --Wait are you suggesting I can write in C in the s file and then call it as ASM? If so how is this different from just type the C code in my project? This sounds interesting just not clicking yet.

Quote:
I am not sure what you are trying to do, but it looks as if you are trying to read a shift register or something. Explain or draw what your input waveform is supposed to be, and what result you want.
Hi David. you can refer to my init posts link for the wave form.

Quote:
the pattern I'm trying is simulate is here
http://img31.picoodle.com/img/im... ... 07a2d7.jpg ( see fig 1)

Its a patent by sega dream cast. In short I'm trying to read the controller. its hard do to the fact I'm trying this with a 12mhz ;) but its been fun so far and I'm finally starting to see some progress. I just need to tighten up the asm to get it right.

The code above, basically is just as you thought. I'm reading bits being blasted to me at a very high rate. At first I though these were spaced apart exact, but evidence I have suggest otherwise. So I'm inventing this falling edge detection. My troubles here are I need take PORTC and put it in a register first, then do the test and whats needed. What I'm doing is testing the port, then trying to use it based on that test, well its too late as a clock has passed.. So I'm going to try taking PORTC and putting it in PORTD, then testing and use the data in PORTD( since it wont change on me ) I dont think sbis will work with a register only a port, even though a port is a register ??? hmm..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unfortunately your link does not work correctly. But if you can upload the image here it would help.

I would also guess that if it is machine generated, it will be relatively easy to machine read it. The AVR has hardware for the purpose.

You also need to explain what you want to do with the waveform.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Oh wow, its gone? ok here ya go

I wish the image was not shrunk..

the top text says 2.2us

the the d6 -> d5 is 500 ns apart

the Dx are the data to be read, should normal be low if not pressed. High when data is significant. The sign below is an example of how it looks.

Quote:
You also need to explain what you want to do with the waveform.
I need to read the data as show in the bottom image. You can see how I wrote the ASM to look at portC pin 5 SOCKA and pin 4 SOCKB. When the edge falls I need to grab that lower bit of data At that moment. So this is why I asked about buffering it.

Also note its understandable to use A couple of 4 bit shift registers as Glitch pointed out. but the aim is to do this on a 12mhz MCU alone if possible. Once I hit a brick wall I will try that. The kicker is some hot shot , not willing to release his code did this on a mega 8.

Something I have been toying with is an OR gate. This way I dont have to switch pin reads. If I get a high I know that bit is on. This could save some time.

Attachment(s): 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
       sub  data,data ;1 clear CARRY
       ldi  count,4   ;1
scka:  sbic PINA,0    ;2
       rjmp scka      ;2
       sbic PINA.1    ;2 read SCKB on the -ve edge of SCKA
       sec            ;1
       rol  data      ;1
sckb:  sbic PINA.1    ;2
       rjmp PINA.0    ;2
       sbic PINA.1    ;2
       sec            ;1
       rol  data      ;1
       dec  count     ;1
       brne scka      ;2

I am sure there are better ways of doing this, but my calculations say that each bit takes a minimum 8 machine cycles. You are taking 7 cycles. At the end of a byte you will need to store the data register somewhere. If the bytes are consecutive, I cannot see what you could possibly do with the data.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tough of doing it 2 ways, one reading the data in to a register that can hold all of the data. Or wasting a lot of registers, one for each bit, and stripping of the first bit later on ( to save time ). They are consecutive, and with the data I just check whats high to reflect this on my output usb HID.

Thx for the code, going to take some time and see what your doing here. I dont think I will have troubles following it.

Quote:
my calculations say that each bit takes a minimum 8 machine cycles. You are taking 7 cycles.
- My compiler shows one clock for "sbic PINA,0 " strange...If its 2 this is why I'm getting no where. and how is a rjmp 2 clocks? I need to do the testing in 3 clocks, and I have 6 total.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Unrolling and reading into a mirror. And using PINA.0 for SCKA and PINA.7 for SCKB

scka:  in   mirror,PINA ;1
       andi mirror,1  ;1
       brne scka      ;1/2
       rol  mirror    ;1 get PINA.7 into CARRY
       rol  data      ;1
sckb:  in   mirror,PINA ;1
       andi mirror,128 ;1
       brne sckb      ;1/2
       lsr  mirror    ;1 get PINA.0 into CARRY
       rol  data      ;1

This gets a bit-time to 5 or 9 depending on whether it has found the -ve edge.

On the other hand once you have got synchronisation, you could assume that you are always going to read one line when the other is low. So you could possibly just synchronise at the beginning of a byte and assume a 6 cycle bit-time to always read at the right place.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Right good thought, thx David.
-------
Ah nutz, I forgot the entire point here was that the "6 cycle bit-time" may not be realistic. I have to watch for the falling edge. From the patent doc its a minimum of 6 cycles but could be longer.

but this info does help me. thx.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It has become apparent that I wont get this to work without detecting a falling edge, that is to say assuming the next 12, 6 or even 4 will not be what is expected. I dont think this waveform is precise. After all it was designed for the listener to watch for falling edges.

I tested this and it failed..

"wait:  in   r26,PINC	
"andi r26,16 \n"
"BRNE wait   \n" 
"in r26,PINC\n  BST r26, 4 \n  BLD r30, 0 \n 

This is 4 apart and it seems to miss beets.

So my last hope is some sort of interrupt. I'd have to enable it, check for falling edge, and disable it in 4 clocks. Anyone have any tips on that, or other suggestions? Else I guess I will look into a faster clock or additional hardware.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
So my last hope is some sort of interrupt. I'd have to enable it, check for falling edge, and disable it in 4 clocks.

Interrupt response time is a minimum of 4 clocks. Then you have the interrupt handler itself, then the RETI statement (another 4 or 5 clocks, depending on which AVR you use). So there is no way to do this in 4 clocks with interrupts.

Regards,
Steve A.

The Board helps those that help themselves.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
wait:  in   r26,PINC  ;1 
       andi r26,16    ;1
       BRNE wait      ;1/2
       in   r26,PINC  ;1
       BST  r26, 4    ;1
       BLD  r30, 0    ;1

My calculations are 6 cycles if the edge found immediately, 10 otherwise.
As Steve has said, there is no hope of using IRQs. I think you will have to use some external gates, or alternatively go to a 16MHz crystal if you want a pure software solution.

I cannot think of a way to detect the edge without this 3 or 4-cycle jitter. Now a nice 6502 would have set flags according to the IN instruction and you could avoid the ANDI.

                      ;NO    ONE BRANCH
edge:  SBIC   PINC,5  ;2     1,2
       RJMP   edge    ;-     2,-
       ...            ;2 or  5 cycles
                      ;NO    ONE BRANCH
edge:  IN     r26,PINC;1     1,1
       ANDI   r26,32  ;1     1,1
       BRNE   edge    ;1     2,1
       ...            ;3 or  7 cycles

Have you tried just synchronising on the SCKA line? But even with a double edge-detect you should catch up the lost cycles with every 5 cycle bit. e.g. 9+5+5+5=24 cycles

Using the 3-cycle jitter:

scka:  sbic PINA,1    ;2   1,2
       rjmp scka      ;-   2,-
       in   mirror,PINA ;1
       rol  mirror    ;1 get PINA.7 into CARRY
       rol  data      ;1
sckb:  sbic PINA,7    ;2   1,2
       rjmp sckb      ;-   2,-
       in   mirror,PINA ;1
       lsr  mirror    ;1 get PINA.0 into CARRY
       rol  data      ;1

This gives a 5 or 8 cycle bit-time hence you could have a sequence: 8+5+5+5+8+5+5... and you will possibly keep in synchronisation.

David.

p.s. having printed out your waveform, I see that you have to detect an edge within 167ns. Anything outside of this is useless. So you would have a 67% chance of getting synchronisation with the SBIC. Then you are stuck with a fixed 6-cycle bit read from then on. Move to a 16MHz AVR and you have 8 whole cycles to read a bit, and you stand a better 88% chance of achieving the initial synchronisation.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
Move to a 16MHz AVR and you have 8 whole cycles to read a bit, and you stand a better 88% chance of achieving the initial synchronisation.
I will look in to that option. Thx for the help !

One thing that I dont under stand is in your rol examples, it looks like your using pins 1 and 7. How is that possible?

also where do I fail to understand the count?

Quote:
My calculations are 6 cycles if the edge found immediately, 10 otherwise.

case one:
in r26,PINC ;1
andi r26,16 ;2
BRNE wait ;3
in r26,PINC;4 //jumped back to wait.

case two :
in r26,PINC ;1
andi r26,16 ;2
BRNE wait ;3
in r26,PINC ;4
and move data..

it is still 4 in between reads right?

Quote:
I see that you have to detect an edge within 167ns
The first detection does not need to be saved. As in I dont need that first data. So does that not leave we with 333.33 for the first detect. This leaves 333.33 for the next read and save, I guess the problem is here here huh?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S_K_U_N_X wrote:
Quote:
Move to a 16MHz AVR and you have 8 whole cycles to read a bit, and you stand a better 88% chance of achieving the initial synchronisation.
I will look in to that option. Thx for the help !

One thing that I dont under stand is in your rol examples, it looks like your using pins 1 and 7. How is that possible?


You have two lines SCKA and SCKB. SCKA connected to PINx.0 and SCKB connected to PINx.7
This just means you can get the CARRY flag by shifting left or right. A subsequent ROL will shift this CARRY bit into the target DATA register.

Quote:

also where do I fail to understand the count?
Quote:
My calculations are 6 cycles if the edge found immediately, 10 otherwise.

A BRxx instruction takes 2 cycles if the branch is taken, only 1 if it falls through. Likewise a SBIx instruction takes 2 cycles if it does the skip, 1 if it falls through.
Quote:

case one:
in   r26,PINC  ;1
andi r26,16    ;2
BRNE wait      ;3
in   r26,PINC  ;4 //back to wait.

case two :
in   r26,PINC  ;1
andi r26,16    ;2
BRNE wait      ;3
in   r26,PINC  ;4

and move data..

it is still 4 in between reads right?

No. If the branch is NOT taken this sequence is 4 cycles. If it is taken then it will be 8 cycles.

You can check the cycle timing in the simulator. I have only done this on paper.

So far, I am convinced that you have a lost cause. The only way of reliably getting within 82ns synchronisation (12MHz) is by having a magic lead-in sequence. You compare the decoded lead-in for correctness, and skip the relevant number of NOPs to get your AVR clock in step. A bit like an auto-baud algorithm for a UART.

Perhaps there is an ASM expert who can see how to get an instruction sequence to line up exactly with the falling edge of SCKA, but surely it is easier to just use some gates to clock a real hardware shift register.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
You have two lines SCKA and SCKB. SCKA connected to PINx.0 and SCKB connected to PINx.7
I guess I just dont understand how I get a 7th pin from a 6 pin port?

But I would agree, going to look in to converting my 12mhz code to 16...

Quote:
SBIx instruction takes 2 cycles
Right, I did under count that thx./

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

You have never specified which AVR you are using, or indeed whether you are constrained to use a specific AVR at all. Having search through this thread, I see that your colleague has used a Mega8. This has a PORTD.7 and PORTD.0

But since you will probably just have a fixed 6 (or 8 with 16MHz) cycles per bit, you can afford extra shifts or a SBIC / SEC sequence.

Anyway, having determined that this is all a fairly tight procedure, what would you actually do with your decoded DATA? Or more to the point, what does your colleague do with the DATA.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your right it was not in this thread, its a 168. I started on the 8 but migrated to the 168 (atmega168-pu). I see where you are coming from now. I'm using portd.1 is in use. I could use portC.0 and PortB.0 if you felt that would be a big help?

The data should be processed later. I was hopping to load a register up with the data I retrieve. And later use the data as it was intended and pass the information to my HID.

the data coming in..

Bit Control
0 C
1 B
2 A
3 START
4 UP
5 DOWN
6 LEFT
7 RIGHT
8 Z
9 Y
10 X
11 D
12 UP2
13 DOWN2
14 LEFT2
15 RIGHT2
16 Analogue R trigger
17 Analogue L trigger
18 Analogue horizontal
19 Analogue vertical
20 Analogue horizontal 2
21 Analogue vertical 2

then I just send this info to my report bytes.

David, thx so much for the help!

Last Edited: Wed. Jul 29, 2009 - 09:43 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you just want to receive these 22 bytes, and they come as 22x8 consecutive bits.

You just want to record both bit-streams into SRAM. Then you can quietly decode it afterwards. Since you also have the initial start pattern, you can decode everything perfectly.

I assumed that this was some dynamic bit stream that you had to process on the fly.

You can literally do:

      nop              ;experimental alignment NOPs
      ...
      ldi   r17,0
more: in    r16,PIND   ;1
      st    X+,r16     ;2
      dec   r17        ;1
      brne  more       ;2

and start it off with a pin-change IRQ, Or just take 256 samples and stop. You should get a predictable IRQ response +- one cycle. And this will get your code in reasonable synch with the odd NOPs. You are sampling every 6 cycles, you just need to be reading shortly after the -ve transition. So experiment with 0,1,2,3,4,5 NOPs.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok this is quite the turn around.. I had ask for this type of idea many times and no one suggested such a thing( not on this board). Sounds like what I need indeed...

Quote:
Since you also have the initial start pattern, you can decode everything perfectly.
yes..

Quote:
I assumed that this was some dynamic bit stream that you had to process on the fly.
- Yes the console in the live situation watches for falling edges and decodes on the fly. And in most cases I would do that same, but I agree that this is not one of those cases as that data is way too fast.

I get the general idea but I'm missing a few bits ( no pun intended ) of how it works. So let me know how I did understanding the asm

"      ldi   r26,0  \n"//push 0 in to r26
"more: in    r30,PORTC \n"//load in portc
"      st    X+,r30 \n"//read from r30 and move ptr
"      dec   r26    \n"// -- the value of r26?
"      brne  more   \n"if its full do more

So start by pushing a 0 on to r26, then in my port data to r30, then read in the first bit of r30 to r26? then decrease r26, and get next data?

I'm sure I have some of that wrong, but this gets both bits on both pins?

Then you unfortunately lost me with the IRQ stuff.

Sorry way over my head on this one. I'm going to see what I can learn from the info you gave me, any additional comments appreciated, but I hate to ask any more of you.

Last Edited: Wed. Jul 29, 2009 - 09:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

If you want to do something like this, you need to know how the AVR works. i.e. how many cycles per instruction and how many cycles are involved in responding to an IRQ, and saving the state of the MCU.

Yes. Of course this just reads the port and copies to SRAM. So it reads both bits. You can connect SCKA, SCKB to whichever pins you like. After it has captured the bit-stream, you process it and presumably output the decoded result on a USB port.

You have 88us worth of data to capture. So what if it takes 1000us to process and output over the USB. A Human will not notice.

If you cannot follow the data capture, how will you cope with USB output?

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
If you cannot follow the data capture, how will you cope with USB output? 

This method of Data capture is totally new to me. Dealing with the usb for the most part is done with usb-v (a usb avr project )So generally I dont need to do much with it. All I need to do is process data and prepared the report data.

I think you have given me enough information I will just run with it and see what I can learn. I just dont have the time to be an expert at everything. I like to tinker, its only a hobby for me.

Quote:
and start it off with a pin-change IRQ, Or just take 256 samples and stop. You should get a predictable IRQ response +- one cycle. And this will get your code in reasonable synch with the odd NOPs. You are sampling every 6 cycles, you just need to be reading shortly after the -ve transition. So experiment with 0,1,2,3,4,5 NOPs.
- Ok totality read that wrong, I read that as change as in pin assignments... Now I see what you meant as in a change in data..Yeah I'm not sure about the irq timing but I got it to work this way.

"in   r26,PORTC \n"//find the first low on pin 4
"CPI r26,0x2f\n"
"BREQ  start \n" 
"in   r26,PORTC  \n"//try again
"CPI r26,0x2f\n"
"BREQ  start \n" 
"in   r26,PORTC  \n"//try again
"CPI r26,0x2f\n"
"BREQ  start \n"
"in   r26,PORTC  \n"//try again
"CPI r26,0x2f\n"
"BREQ  start \n"

I may need a few more tests but it seem to sync up nicely.

After looking at this method I'm not even sure how it would work as its 6 clocks apart. As mentioned before I have to anticipate longer irregular spacing, hence all of the edge detection. Although its a nice way to get the data if it was 6 exactly apart. Something that is is interesting is that the total response is 100 us. The first bit is just a response code that I skip. However the total time never changes.. Yet the distance between the edges do. That or they are just a bit more then 500 in some cases and less in others. Either way I have tried to get all relevant data assuming 6 clocks and its not right. I sure wish my scope could sample that fast..

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I still do not really know what you are trying to do.

However, with my crystal ball, I am guessing that you need 12MHz for USB. The data from your toy will be crystal controlled and hence every -ve transition is at exactly 500ns spacing. You have no software alternative to sampling at 500ns intervals (6 cycles).

If your data packet is the start pattern + 22 bytes then you can only attempt to synchronise as best you can, and read every 500ns. A software polling loop is just too coarse for the edge detection.

However the AVR hardware IRQ response is as soon as its current instruction finishes.

If you want me to write your ISR, then just say so. I would write a regular .S file that would decode your data into a global buffer. You would just add this file to your project in the regular way.

If you want to write it yourself, I strongly advise that you write in readable gobbledygook:

"start: \n"
"      in    r26,PORTC  \n" //find the first low on pin 4
"      CPI   r26,0x2f   \n"
"      BREQ  start      \n"

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Quote:
However, with my crystal ball, I am guessing that you need 12MHz for USB.
I should not have made two topics, sorry most of it was explained in the other post. But your crystal ball is correct.

Quote:
The data from your toy will be crystal controlled and hence every -ve transition is at exactly 500ns spacing.
Well I would have agreed but it’s not. I mean originally I was thinking it had to be. If you read the waveform with no buttons down and assume the 6 clock spacing it will not be as you would think. The first bit will be as expected, and the second about 99% of the time is correct but each bit after drops in reliability. Maybe it’s just clock drift, but either way it’s not working.

Quote:
If you want me to write your ISR, then just say so. I would write a regular .S file that would decode your data into a global buffer.
If you think, given the fact there is an irregularity here, that there is a possible hope for a 12mhz to do the job. I would be ever so grateful if you could help me get started. I have started looking for tutorials to figure out how this (.s) files gets used. Any examples or assistance could save me a month. I dont think cluttering up the forum here would be useful. Maybe best to take this off the forum, up to you.

I have always learned by example. I only had to piss in to the wind once… If I need to learn something the first thing I do is search for examples. I don’t know what is entailed so it’s hard to outright ask that of you. If you have the time, please by all means point my in the right direction.

If you disagree about the timing ( taking note I’m not the first to discover that ), what can I do to eliminate the possibility. My tests were as follows.
Just in to the wave form

detect the first falling edge, allowing for a read as well.
Read the next bit at the right clock.
Do 3 more..
Then display the results.
[always correct] [97-99% of the time its right ] [75%][each after is more like [50/50] ]

------
FYI: I was able to create an .s file and tested it with my existing code.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I was bored. Or more to the point it was more interesting than what I should have been doing.

I wrote a mega168 program with a single pin-change IRQ for PORTC.5 to detect the 2.25us low pulse.

The ISR reads the data at 500ns intervals starting at 2.50us for the 22 bytes. It decodes them into a global array readable by C.

Looking at your waveform, if you read every 500ns (at the arrows) you should have some leeway for the other signal.

Anyway, I simulated with Simulator#1 and Simulator#2 and it seems to decode ok.

I would assume the waveform is created by hardware with a clock of some description. I would guess even a toy uses a crystal or ceramic resonator. So 22 bytes should stay in sync ok. You would need hardware for continuous decoding. It is similar to re-creating the clock from a disk-drive head.

I am going to the pub, but ask if you want the code and stimulus files.

David.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david, I would love to see the code. Mainly for 3 reasons.

1) I'm attempting to get the pin change interrupt to work for my self. I'm able to fire the call to my function, but cant seem to get a inline trigger. I'm convinced I need the the trigger to happen outside, but dont see how I can use the response once I'm in another function. Not a dual core here.. I would need to..

enter func.
set my pins to output.
send start seq
set my pins to input.
delay to get close to the response
clear pin-change flag.
while (pin-change not changed)
exit while
start reading.

Or something like that.. So maybe your code will help me see how to do that.

2) I remain convinced you can not possibly predict this timing. If you get a way with it, I'm going to have a lot of fun rubbing that in Mr. Hotshots face. Just dont see it possible. However again, I agree with your logic, it should be using a crystal.

3) I'm going to learn a lot.

Toys dont imply child like craftsmanship. Every controller I have come across in the past year or so, ( about 30 ) Aside from the basic simple switch types ( atari) use a clock signal. The console always sets the freq. In this case, I'm told the device ( both recipient and sender ) send their data via pulses. And the Receiving end counts falling edges. Agreed, in order to create such a fast pulses your going to need some sort of resonator. There is no crystal in the controller, how they dont it is beyond me.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

S_K_U_N_X wrote:

PORTC = 0x3;//both high ( a nop )
for ( i;i<4;i++)// one for each loop 
{	
  asm ("nop\n"  );PORTC = 0x0;//should be 3 total.
  asm ("nop\n"  );PORTC = 0x2;//should be 3 total.
}
PORTC = 0x3;//both high ( a nop )

if so I may need to remove a nop. I have a 12mhz crystal so I get 83.33 for each, 3 should give me 250, and I need to oscillate this second bit up for 3 down for 3 ( 4 times... Then end with bit 1 and 2 high.

Do you really want cycles here or clock ticks?
If cycles: Are you banking on cycles always being an even number of clock ticks?
I am trying to visualize how this works.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

jonsoons, Its most likely my word usage that is confusing you.

I know that a 12mhz gives me 83.33333~ NS per ( call it what you will ). Six of them gives me 500 NS.

So counting the clocks I see in my debugger is 1 clock per NOP.

This is what I'm referring to.

Last Edited: Sat. Aug 1, 2009 - 06:16 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I am attaching "sdcka.zip" which should read via the Pin Change interrupt.

Let me know how it functions. You may need to add or remove a single NOP to synchronise with your signal.

You can see the simulated data in the .STIM file for Simulator2. The .STI file is for Simulator #1.
You need to ALWAYS have a disassembler View if you are debugging in either Simulator. And you probably need to change the breakpoints by hand.

David.

Attachment(s): 

Pages