I have some issue reading PORTB. I read it like so:
uint8_t tmp;
__asm__ __volatile__ (
"in %[tmp], %a[in_port]" "\n\t"
: [tmp] "+a" (tmp) // constraint: simple upper register for in and output
: [in_port] "M" (_SFR_IO_ADDR (PORTB))
:
)
(lots of other lines deleted).
However it fails to read PORTB, instead it reads something completely unrelated. I suspect that that I have not set the constraints properly. but I can not determine what is wrong. Any hints for me?
And no: I can not do it in C. It is very time critical, I try to be precise to the microsecond. Hence I switched to assembler.
You can do direct port reading in C, and with the optimization done by gcc I would be very surprised if it was any slower then your inline asm. Give it a test before dismissing.
the issue is not only code optimzation. The issue is proper phase. Although the gcc is optimized good enough I can not control it's phase. I want to have microsecond precise timing. But if I use a compiler I can not guarantee that the code will not be to fast or to slow. That is using the compiler it is extraordinary hard to avoid phase jitter. That's the reason why I implement some small pieces in assembler.
What baffles me though is why I can't read port B with the in statement. If I spend one more cycle and do a ld then I can read it.
I know that the offset must be different. I even double checked with avr-objdump, the inline assembler seems to properly access the port. Maybe it does not properly transfer the register into the desired variable. I did not yet figure out how to see the variables in the obj dump. Any hints on this?
Have you looked at the code produced with objdump? (oops. I see that you did. I should read more carefully) It looks sort of OK to me, even when I pass tmp on to additional functions:
How do you know it's not reading port B? What does the surrounding code look like?
I'm not sure what the initial ldi is doing there; I guess because you told it the register was input as well as output. But this raises an interesting point.
If your main interest is highly accurate relative timing, It would probably be a good idea to use much larger chunks of asm code and worry less about the (elaborate, complex, and confusing) interface between C code and asm code that gcc provides. (Hmm. I see that that removes your ability to use symbol constants? Sigh.)
Well, I would post the code but I think this won't really help. It is already >3000 lines and >30 files. All the arduino libs are patched by now. I do not think that anyone would be willing to invest the time to understand what is going on in my code.
How I know that it is this statement? Very good question. I stripped down the code to the smallest segment that still reproduced the error.
The ldi was in to see if it loads anything at all into the register.
Do you know of any good tutorial how to create asm code with a standalone assembler and link it to C for the arduino later on?
Yes and strange enough my code seems to work with other ports. Obviously I must be doing something completely ignorant. The processor can not be the reason because then the digitalRead/Write statements should not work.
Maybe I just let this part of the code rest for one or two weeks and then see if I learned something in between. For the time being I will stick to the ld statement.
Can you generate an example of what you're doing that is long enough to actually show the error occuring, but not so long as to require us to understand your whole program? You said your trimmed it down to the bare minimum that showed the error, but the piece you posted wasn't runnable on its own.
The ldi I mentioned was in the object code produced when I used your inline ASM in an otherwise useless sketch. Like I said, the code produced looked correct...