Hello,I am calling a function from an interrupt, and due to timing issues I would like to preserve the state of a register very quickly when the interrupt takes place.

The C compiler generates a bunch of code to preserve registers when the ISR (or any function) is called. I want to insert some assembler which is to be run before those registers are preserved. Is this possible? Is there some directive I can add to my asm line to tell it exactly where to inject itself in the C code? Thanks.

The code looks iike this. I know- the push instructions are there to preserve registers. Consider my asm to be pseudo-code; I will figure out how to use __tmp_reg__ if I decide that my efforts are worth it. Thanks:

I would like to preserve the state of a register very quickly when the interrupt takes place.

I guess you mean you want to preserve the state of an I/O register at the earliest possible point in an ISR.

Have you thought of a way to do that without using any processor registers? Since you can't know what processor registers are in use you mustn't use them until you have preserved their state so that they can be restored afterwards.

I only provide help via the forum - please do not contact me for private consultancy.

I want to insert some assembler which is to be run before those registers are preserved.

Does the "some assembler" include an in instruction (like your pseudo-code)?

Yes, and yes. I plan on taking advantage of this:

Quote

Register r0 may be freely used by your assembler code and need not be restored at the end of your code. It's a good idea to use __tmp_reg__ ... instead of r0 or r1, just in case a new compiler version changes the register usage definitions.

I would like to preserve the state of a register very quickly when the interrupt takes place.

I guess you mean you want to preserve the state of an I/O register at the earliest possible point in an ISR.

Exactly! You hit the nail on the head. I am writing a library and I am preserving the state of an I/O register- ostensibly at the time of the interrupt- but with all the push instructions, it takes place some 4 microseconds (I figure) after the actual interrupt.

Quote

Have you thought of a way to do that without using any processor registers? Since you can't know what processor registers are in use you mustn't use them until you have preserved their state so that they can be restored afterwards.

Not really. I am aware of this:

Quote

Register r0 may be freely used by your assembler code and need not be restored at the end of your code. It's a good idea to use __tmp_reg__ and __zero_reg__ instead of r0 or r1, just in case a new compiler version changes the register usage definitions.

So I believe I can safely use r0. All I need is to use the in instruction, then save that register to RAM, and I should be good to go.

That sounds viable, although I don't know enough about the behaviour of those temp registers to know how long their contents will be preserved. For example, if they're trampled by a push operation then using one of these as a scratch area while you do the push would not work very well.

The only way I can think of to achieve that solution is to write your ISR handler in assembler, have this save your I/O register in your temp register and then call a 'C'/C++ function for whatever logic you want to code in higher level languages. You sound as if you're comfortable writing in assembler, but if you aren't you could get a starting point by listing the assembler generated for your existing handler.

I only provide help via the forum - please do not contact me for private consultancy.

... if they're trampled by a push operation then using one of these as a scratch area while you do the push would not work very well.

... write your ISR handler in assembler, have this save your I/O register in your temp register and then call a 'C'/C++ function for whatever logic you want to code in higher level languages. You sound as if you're comfortable writing in assembler, but if you aren't you could get a starting point by listing the assembler generated for your existing handler.

Excellent suggestion, thanks for the tips! I am not comfortable writing in assembler, so I am going to list the assembler generated and work from there :-) . But, I am comfortable living life on the edge! So I'm going to try it.

My intention is to get the heck out of the way of the compiler as quickly as possible, so I'm thinking I might need 2 assembly instructions: 1 to read the register, the other to save it to a C variable (ie, RAM).

I notice that my idea is not so far fetched, as a matter of fact I found this link: http://www.nongnu.org/avr-libc/user-manual/group__avr__interrupts.html . The ISR_NAKED is what I want. So, my idea is the following, pseudo-code:

ISR(PCINT0_vect, ISR_NAKED){ asm (read_in_register_to_r0) asm (store_to_ram) // The following function call will preserve the registers on the stack. Since I haven't // mucked with any but r0 thus far in my ISR, I should be ok. The function call will // also restore the necessary registers. C_function_call(); asm (reti);}

I notice that the ISR pushes a whole bunch of registers on the stack. Function calls do not necessarily save the same large set. I assume that's because the compiler is smart enough to know that a function may not stomp on all the registers, so it's judicious in its saving. Thus, it seems to me the ISR is storing such a large set because it doesn't have any foreknowledge of what it should or should not preserve, so it paints with a large brush.

But if the *only* thing my ISR does is as listed: 1. my assembly, 2. call a C function, 3. return, then I assume that the heavy lifting of pushing and popping the necessary registers, if handled solely by the C function call in the ISR, should be sufficient. There are no other dragons lying about out, are there? Again, assuming my ISR is just that lean.

Register r0 may be freely used by your assembler code and need not be restored at the end of your code. It's a good idea to use __tmp_reg__ and __zero_reg__ instead of r0 or r1, just in case a new compiler version changes the register usage definitions.

So I believe I can safely use r0. All I need is to use the in instruction, then save that register to RAM, and I should be good to go.

No, you are in an ISR. The main code might be using r0 temporarily when your ISR gets called - if you touch r0, you mess up the main code.

I once tried doing a similar thing with r1, thinking that because it should always be 0 I could quickly use it in an ISR and zero it again afterward - and it didn't work either. Turns out the zero register wasn't always zero!

An addendum to @stimmer's post... Before your interrupt service routine or any function called by your ISR uses any register (R0 - R31), the register value must be preserved. Before your interrupt service routine or any function called by your ISR performs any math operation, the status register value (SREG) must be preserved.

Quote

But if the *only* thing my ISR does is as listed: 1. my assembly, 2. call a C function, 3. return, then I assume that the heavy lifting of pushing and popping the necessary registers, if handled solely by the C function call in the ISR, should be sufficient.

Good point. I may use r0, but I'll push/pop it. Thanks- 1 push instruction won't hurt.

Not good enough. You have to preserve the registers used by your function before the function is called.

I understand about r0 (which I'll use) and SREG, but doesn't the compiler push all registers it's concerned with? I've been rummaging around in avr-objdump and I observe that the compiler preserves registers upon entry into the function, not before functions are called.

I am setting ISR_NAKED for the ISR, but when the ISR calls another function that will not be naked.

But, there is an assumption that whoever called the ISR preserved certain registers. That's the purpose of all those pushes; to do what a caller would have done if the ISR had been called like a normal function.