sexta-feira, 13 de junho de 2014

Rotina de interrupção em Assembly dentro do Arduino

A sintaxe do Assembly Inline do GCC é meio confusa, e isso me deu bastante trabalho para conseguir embutir um pouco de código Assembly dentro da IDE do Arduino. Mas finalmente consegui.

Eis o código para tratar a interrupção:

asm volatile ( 
   "in __tmp_reg__,__SREG__ \n\t"   // Salva registrador de Status  
   
   "ldi r26,lo8(mapa) \n\t"         // Ponteiro X = endereço de Keymap
   "ldi r27,hi8(mapa)\n\t"          //
   
   "ldi r18,0x1f \n\t"              // Mascara inicial => bits 0..5 em 1
   
   "in r19,%0 \n\t"                 // Amostra bits PB 0..5 (A8..A13)
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[0] 
   "sbrs R19,0 \n\t"                // Bit [0] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[0] para R18
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[1] 
   "sbrs R19,1 \n\t"                // Bit [1] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[1] para R18   
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[2] 
   "sbrs R19,2 \n\t"                // Bit [2] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[2] para R18
   
   "ld r20,X+ \n\t"                 // R20 = Keymap[3] 
   "sbrs R19,3 \n\t"                // Bit [3] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[3] para R18   

   "ld r20,X+ \n\t"                 // R20 = Keymap[4] 
   "sbrs R19,4 \n\t"                // Bit [4] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[4] para R18   

   "ld r20,X+ \n\t"                 // R20 = Keymap[5] 
   "sbrs R19,5 \n\t"                // Bit [5] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[5] para R18

   "in r19,%1 \n\t"                 // Amostra bits PD 6..7 (A14..A15)

   "ld r20,X+ \n\t"                 // R20 = Keymap[6] 
   "sbrs R19,4 \n\t"                // Bit [6] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[6] para R18   

   "ld r20,X+ \n\t"                 // R20 = Keymap[7] 
   "sbrs R19,5 \n\t"                // Bit [7] = 0 ? 
   "and r18,r20 \n\t"               // sim, copia os bits '0' de Keymap[7] para R18
   
   "out %2,r18 \n\t"                // Escreve resultado nos bits D0-D4 do LS365 e libera Wait State
   "nop \n\t"
   "sbi %2,5 \n\t"                  // libera flip flop
   
   "out __SREG__,__tmp_reg__ \n\t"  // restaura registrador de Status
    
   :: "I" (_SFR_IO_ADDR(PINB)), "I" (_SFR_IO_ADDR(PIND)) , "I" (_SFR_IO_ADDR(PORTC)) );
}


Cabe observar que eu tentei antes incluir uma função externa em assembly e incluir no projeto, mas o Arduino não compila.

Pelas minhas contas são necessários 32 ciclos de clock entre a interrupção e a liberação do Wait, o que significa 1,6us a 20MHz ou 4us a 8MHz (clock interno).

Nenhum comentário: