PIC18 - problemas para hacer que la rutina del ensamblador en línea funcione

3

(EDITAR: Se agregó el código de desensamblaje C18)

Necesito optimizar una función escrita en C para un PIC18f4585. Estoy usando C18 para compilar.

La función que estoy intentando volver a escribir en el ensamblaje es:

void readResetTimers (void)
{
   register unsigned char tmr0_temp;
   register unsigned char tmr1_temp;

   tmr0_temp = TMR0L;
   TMR0L = 0;
   tmr1_temp = TMR1L;
   TMR1L = 0;

   tmr0_value = tmr0_temp;
   tmr1_value = tmr1_temp;
}

Pensé que podría usar el código de ensamblaje para cargar el valor de cada registro en las variables tmr0_value & El valor tmr1 como se declara en el espacio de nombres global, sin embargo, mi sistema no funciona cuando sustituyo el siguiente código en:

void readResetTimers (void)
{
_asm
    MOVF    TMR0L, 0, 1
    MOVWF   tmr0_value, 1
    CLRF    TMR0L,0

    MOVF    TMR1L, 0, 1
    MOVWF   tmr1_value, 1
    CLRF    TMR1L,0
_endasm
}

Cualquier idea sería apreciada, Saludos.

 void readResetTimers (void)
  04D4    CFD9     MOVFF 0xfd9, 0xfe6
  04D6    FFE6     NOP
  04D8    CFE1     MOVFF 0xfe1, 0xfd9
  04DA    FFD9     NOP
  04DC    0E02     MOVLW 0x2
  04DE    26E1     ADDWF 0xfe1, F, ACCESS
405:               {
406:                  register unsigned char tmr0_temp;
407:                  register unsigned char tmr1_temp;
408:               
409:                  /* Read the two timers into CPU registers and reset them
410:                   * as quickly as absolutely possible.
411:                   */
412:               
413:                  tmr0_temp = TMR0L;
  04E0    50D6     MOVF 0xfd6, W, ACCESS
  04E2    6EDF     MOVWF 0xfdf, ACCESS
414:                  TMR0L = 0;
  04E4    6AD6     CLRF 0xfd6, ACCESS
415:                  tmr1_temp = TMR1L;
  04E6    0E01     MOVLW 0x1
  04E8    CFCE     MOVFF 0xfce, 0xfdb
  04EA    FFDB     NOP
416:                  TMR1L = 0;
  04EC    6ACE     CLRF 0xfce, ACCESS
417:               
418:                  tmr0_value = tmr0_temp;
  04EE    CFDF     MOVFF 0xfdf, 0xe4
  04F0    F0E4     NOP
419:                  tmr1_value = tmr1_temp;
  04F2    CFDB     MOVFF 0xfdb, 0xe5
  04F4    F0E5     NOP
431:               
432:               }
    
pregunta chib

1 respuesta

1

Ya que desea reemplazar toda la subrutina, el ensamblador en línea es un poco tonto. Escribir toda la rutina en ensamblador. De esa manera, el compilador no puede interferir haciendo cosas al entrar y salir de la rutina y similares.

También sería mejor explicar qué es lo que realmente quiere que haga esta rutina que definirla implícitamente con el código C. Tienes:

  tmr0_temp = TMR0L;
  TMR0L = 0;
  tmr1_temp = TMR1L;
  TMR1L = 0;

  tmr0_value = tmr0_temp;
  tmr1_value = tmr1_temp;

Aparentemente desea una instantánea del temporizador 0 en modo de 16 bits en una variable separada. Tu código anterior no funcionará para eso en todos los casos, ya que no trataste el incremento de bytes alto entre las dos lecturas.

A menos que acceda a los dos registros finales en una rutina que podría ser interrumpida por este, no es necesario el registro temporal. En realidad, sin deshabilitar las interrupciones, no se puede garantizar que el valor final de 16 bits se escriba atómicamente de todos modos. O te importa la actualización atómica o no. Su método no tiene sentido ya que parece importarle en una parte, pero al final no lo garantiza.

También está restableciendo el temporizador a 0, lo que suele ser una mala idea. Este suele ser el resultado de querer realizar mediciones secuenciales de intervalos de tiempo sin haberlo pensado muy bien. Si la razón por la que necesita que esta rutina se ejecute tan rápido es porque desea minimizar las instrucciones que pierde debido al restablecimiento del temporizador, entonces esta es definitivamente la forma incorrecta de hacerlo. Tome una instantánea en cada punto en el que desee medir el intervalo, luego haga una resta de 16 bits sin firmar. Eso le dará el intervalo sin que se pierda ningún ciclo cuando se reinicie el temporizador.

Si puede permitir que el temporizador se apague por unos pocos ciclos, entonces apáguelo, léalo, bórrelo y reinícielo. Realmente no veo un caso donde tu método tenga sentido.

En cualquier caso, aquí hay un fragmento de código de ejemplo que toma una instantánea constante del temporizador 0 mientras lo deja en ejecución (sin probar, ni siquiera con la sintaxis marcada):

         extern  t0snapshot  ;16 bit snapshot of timer 0

;*********************************************************************
;
;   Subroutine T0_GRAB
;
;   Grab the current timer 0 value into T0SNAPSHOT.  The timer will
;   continue running the whole time.
;
         global  t0_grab
t0_grab
         banksel t0snapshot  ;set bank for access to output variable
t0_retry                     ;back here if high byte changed
         movf    tmr0h, w    ;get the timer high byte
         movwf   t0snapshot+1 ;save it
         movff   tmr0l, t0snapshot+0 ;grab the low byte
         xorwf   tmr0h, w    ;check the high byte again
         bnz     t0_retry    ;high byte changed, try again ?

         return

Note esta construcción llamada "comentarios" en esta rutina. Esas son cosas muy útiles que necesitas aprender. El código no documentado es en realidad ningún código.

    
respondido por el Olin Lathrop

Lea otras preguntas en las etiquetas