Open tmk opened 2 years ago
Another workaound would be fixed register. https://gcc.gnu.org/wiki/avr-gcc#Fixed_Registers https://gcc.gnu.org/onlinedocs/gcc/Global-Register-Variables.html#Global-Register-Variables
GCC option -ffixed-<reg>
is required to define a fixed register.
https://gcc.gnu.org/onlinedocs/gcc/Code-Gen-Options.html
Note that the option doesn't effect precompiled libraries, which can already use the fixed register. Actually avr-libc can use all registers, for example r2
is referred in some functions we don't need to link at this time, like qsort, longjump, setjmp, strftime and vfprintf. This will causes problem if those fuctions are used. In that case we have to save and restore the register.
// register to store pin state temporarily
volatile register uint8_t STORED_PIN asm("r2");
ISR(IBMPC_INT_VECT, ISR_NAKED)
{
asm volatile (
"in r2, %[pin]" "\n\t"
"rjmp ibmpc_isr" "\n\t"
:
: [pin] "I" (_SFR_IO_ADDR(PIND))
);
}
// define normal ISR
extern "C" void ibmpc_isr(void) __attribute__ ((signal,__INTR_ATTRS));
void ibmpc_isr(void)
{
...
if (STORED_PIN & data_mask) ...
...
}
Makefile:
EXTRAFLAGS ?= -ffixed-r2
This naked ISR can reads the pin in 8 cycles. [5(interrupt) + 3(jmp in vector table)] 62.5ns * 8 = 500ns
https://github.com/tmk/tmk_keyboard/tree/ibmpc_naked_isr_fixed_reg
We have to read data line as early as possible for IBM XT keyboard within 5us.
https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol#note-for-start0 https://github.com/tmk/tmk_keyboard/wiki/IBM-PC-XT-Keyboard-Protocol#isr-prologue
With normal ISR its prologue(pushing registers) is inevitable and it can consume tens of clocks before reading data pin. We have to read the pin before the prologue especially when ISR requires many registers and prologue is long.
To circumvent the ISR prologue we can use naked ISR which doesn't generate prologue. But there is no general purpose register(r0-r31) to store pin store safely in naked ISR.
One of possible workaround would be to store data pin state(PIND) temporarily in unused IO register(0x01) instead of general purpose register. ATMega32u2/4 has no PORTA but 0x01(DDRA) can seem to be used for this purpose. DDRE is another candidate.
This naked ISR can reads the pin in 10 cycles. [5(interrupt) + 3(jmp in vector table) + 2(push r0)] One cycle time is 62.5ns at 16MHz.
ATmeaga32U4 datasheet:
https://github.com/tmk/tmk_keyboard/tree/ibmpc_naked_isr_io_reg