TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: Marttyn en 04 de Noviembre de 2008, 01:08:44

Título: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 04 de Noviembre de 2008, 01:08:44
Hola!
Vengo de otro post:
http://www.todopic.com.ar/foros/index.php?topic=23351.msg189945#msg189945
Aqui hablan algunas cosas muy interesantes sobre "retrasos" del timer0. Alli me di cuenta de unas cosas, pero como no pertenecian al tema principal, y para no desviarlo prefiero abrir un tema nuevo.

Me gustaria poder modificar las instrucciones generadas para la "entrada" y "salida" de las interrupciones por el compilador C (en mi programa se generan a partir de la linea 4 de codigo ASM hasta el RETFIE).
Digo esto porque tal cual genera el ASM el CCS, una misma interrupcion no siempre tarda lo mismo desde que se produce la interrupcion hasta llegar a la primera instruccion de la misma, ya que depende en que pagina estemos, que valores tengan algunos registros, etc...
Estoy haciendo un programa que requiere bastante precision, y quiero tener medidos todos los tiempos, pero solo con C no soy capaz, y quiero hacerlo en ASM, pero desde el CCS no se como  :(
Alguna idea?

PS: ayer --> ASM = CHINO
hoy imprimi y encuaderne todo el datasheet de mi pic y llevo todo el dia mirando instruccion por instruccion que significa cada cosa y comparandolo con mi codigo C, y la verdad es entretenido ASM  :mrgreen:
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: jacrmr en 04 de Noviembre de 2008, 01:27:59
Sin ningún interés de calentar los ánimos entre la ya tan conocida discusión de "qué es mejor, si ASM ó C", sin duda alguna has llegado al punto de que una aplicación la debes hacer forzosamente en ASM ya que el C no fue funcional. Definitivamente creo que "maquillar" la salida del compilador de C ajustando tú mismo el ASM no es lo más conveniente. No te va a quedar otra que aprender ASM, así que no te desanimes. No es tan difícil como parece y al final te acostumbrarás a tener ambos bandos, C y ASM, según cuando requieras aplicaciones en donde cada ciclo de instrucción cuenta, como trabajar con video por ejemplo; las sólas instrucciones del reestablecimiento del stack o de variables en C son suficientes para que se pierda el sincronismo o el trazo adecuado del video.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 04 de Noviembre de 2008, 02:45:04
Hola Marttyn.

Bueno, como primera instancia sería bueno que publiques el código C de las interrupciones, y su correspondiente asm generado de salida como para poder ir ayudandote y orientandote.

Es importante que lo hagas vos, porque eso depende inclusive de la versión del compilador que estés usando.

Saludos.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 04 de Noviembre de 2008, 11:31:32
Este es el codigo C que estoy usando para hacer pruebas. Simplemente lo uso para hacer saltar las interrupciones y ver que codigo genera cada cosa y como optimizarlo.

Código: C
  1. #include <12F683.h>
  2. #device adc=8
  3.  
  4. #FUSES NOWDT,NOMCLR,PUT,INTRC_IO
  5. #use delay(clock=4000000)
  6.  
  7. #int_TIMER0
  8. void TIMER0_isr(void) {
  9.         delay_cycles(1);
  10. }
  11. #int_TIMER1
  12. void TIMER1_isr(void) {
  13.         //delay_cycles(1);
  14.         set_timer1(45574);
  15. }
  16. #int_TIMER2
  17. void TIMER2_isr(void) {
  18.         delay_cycles(1);
  19. }
  20. #int_CCP1
  21. void CCP1_isr(void){
  22.         delay_cycles(1);
  23. }
  24. void main() {
  25.        
  26.         setup_adc_ports(NO_ANALOGS|VSS_VDD);
  27.         setup_adc(ADC_CLOCK_INTERNAL);
  28.         setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  29.         setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  30.         setup_timer_2(T2_DIV_BY_1,255,1);
  31.         setup_ccp1(CCP_COMPARE_INT);
  32.         setup_comparator(NC_NC);
  33.         setup_vref(FALSE);
  34.         //enable_interrupts(INT_CCP1);
  35.         //enable_interrupts(INT_TIMER0);
  36.         enable_interrupts(INT_TIMER1);
  37.         //enable_interrupts(INT_TIMER2);
  38.         enable_interrupts(GLOBAL);
  39.         setup_oscillator(OSC_4MHZ);
  40.        
  41.         CCP_1 = 55574;
  42.         set_timer1(65533);
  43.         //set_timer0(254);
  44.         //set_timer2(254);
  45.         delay_cycles(1);
  46.         delay_cycles(1);
  47.         delay_cycles(1);
  48.         delay_cycles(1);
  49.         do{                    
  50.  
  51.         }while(TRUE);  
  52. }

El codigo ASM equivalente es:

Código: ASM
  1. 1:                 #include <12F683.h>
  2.    000    3000     MOVLW 0
  3.    001    008A     MOVWF 0xa
  4.    002    285F     GOTO 0x5f
  5.    003    0000     NOP
  6.    004    1A83     BTFSC 0x3, 0x5
  7.    005    280A     GOTO 0xa
  8.    006    00A5     MOVWF 0x25
  9.    007    0E03     SWAPF 0x3, W
  10.    008    00A6     MOVWF 0x26
  11.    009    280F     GOTO 0xf
  12.    00A    1283     BCF 0x3, 0x5
  13.    00B    00A5     MOVWF 0x25
  14.    00C    0E03     SWAPF 0x3, W
  15.    00D    00A6     MOVWF 0x26
  16.    00E    14A6     BSF 0x26, 0x1
  17.    00F    080A     MOVF 0xa, W
  18.    010    00AD     MOVWF 0x2d
  19.    011    018A     CLRF 0xa
  20.    012    1383     BCF 0x3, 0x7
  21.    013    0EA5     SWAPF 0x25, F
  22.    014    0804     MOVF 0x4, W
  23.    015    00A7     MOVWF 0x27
  24.    016    0820     MOVF 0x20, W
  25.    017    00A8     MOVWF 0x28
  26.    018    0821     MOVF 0x21, W
  27.    019    00A9     MOVWF 0x29
  28.    01A    0822     MOVF 0x22, W
  29.    01B    00AA     MOVWF 0x2a
  30.    01C    0823     MOVF 0x23, W
  31.    01D    00AB     MOVWF 0x2b
  32.    01E    0824     MOVF 0x24, W
  33.    01F    00AC     MOVWF 0x2c
  34.    020    1283     BCF 0x3, 0x5
  35.    021    308C     MOVLW 0x8c
  36.    022    0084     MOVWF 0x4
  37.    023    1C00     BTFSS 0, 0
  38.    024    2827     GOTO 0x27
  39.    025    180C     BTFSC 0xc, 0
  40.    026    2850     GOTO 0x50
  41.    027    308C     MOVLW 0x8c
  42.    028    0084     MOVWF 0x4
  43.    029    1C80     BTFSS 0, 0x1
  44.    02A    282D     GOTO 0x2d
  45.    02B    188C     BTFSC 0xc, 0x1
  46.    02C    2857     GOTO 0x57
  47.    02D    1E8B     BTFSS 0xb, 0x5
  48.    02E    2831     GOTO 0x31
  49.    02F    190B     BTFSC 0xb, 0x2
  50.    030    284C     GOTO 0x4c
  51.    031    308C     MOVLW 0x8c
  52.    032    0084     MOVWF 0x4
  53.    033    1E80     BTFSS 0, 0x5
  54.    034    2837     GOTO 0x37
  55.    035    1A8C     BTFSC 0xc, 0x5
  56.    036    285B     GOTO 0x5b
  57.    037    0827     MOVF 0x27, W
  58.    038    0084     MOVWF 0x4
  59.    039    0828     MOVF 0x28, W
  60.    03A    00A0     MOVWF 0x20
  61.    03B    0829     MOVF 0x29, W
  62.    03C    00A1     MOVWF 0x21
  63.    03D    082A     MOVF 0x2a, W
  64.    03E    00A2     MOVWF 0x22
  65.    03F    082B     MOVF 0x2b, W
  66.    040    00A3     MOVWF 0x23
  67.    041    082C     MOVF 0x2c, W
  68.    042    00A4     MOVWF 0x24
  69.    043    082D     MOVF 0x2d, W
  70.    044    008A     MOVWF 0xa
  71.    045    0E26     SWAPF 0x26, W
  72.    046    0083     MOVWF 0x3
  73.    047    1283     BCF 0x3, 0x5
  74.    048    0E25     SWAPF 0x25, W
  75.    049    18A6     BTFSC 0x26, 0x1
  76.    04A    1683     BSF 0x3, 0x5
  77.    04B    0009     RETFIE
  78. 2:                 #device adc=8
  79. 3:                
  80. 4:                 #FUSES NOWDT,NOMCLR,PUT,INTRC_IO
  81. 5:                 #use delay(clock=4000000)
  82. 6:                
  83. 7:                 #int_TIMER0
  84. 8:                 void TIMER0_isr(void) {
  85. 9:                      delay_cycles(1);
  86.    04C    0000     NOP
  87. 10:                }
  88.    04D    110B     BCF 0xb, 0x2
  89.    04E    118A     BCF 0xa, 0x3
  90.    04F    2837     GOTO 0x37
  91. 11:                #int_TIMER1
  92. 12:                void TIMER1_isr(void) {
  93. 13:                     //delay_cycles(1);
  94. 14:                     set_timer1(45574);
  95.    050    30B2     MOVLW 0xb2
  96.    051    008F     MOVWF 0xf
  97.    052    3006     MOVLW 0x6
  98.    053    008E     MOVWF 0xe
  99. 15:                }
  100.    054    100C     BCF 0xc, 0
  101.    055    118A     BCF 0xa, 0x3
  102.    056    2837     GOTO 0x37
  103. 16:                #int_TIMER2
  104. 17:                void TIMER2_isr(void) {
  105. 18:                     delay_cycles(1);
  106.    057    0000     NOP
  107. 19:                }
  108.    058    108C     BCF 0xc, 0x1
  109.    059    118A     BCF 0xa, 0x3
  110.    05A    2837     GOTO 0x37
  111. 20:                #int_CCP1
  112. 21:                void CCP1_isr(void){
  113. 22:                     delay_cycles(1);
  114.    05B    0000     NOP
  115. 23:                }
  116.    05C    128C     BCF 0xc, 0x5
  117.    05D    118A     BCF 0xa, 0x3
  118.    05E    2837     GOTO 0x37
  119. 24:                void main() {
  120.    05F    0184     CLRF 0x4
  121.    060    301F     MOVLW 0x1f
  122.    061    0583     ANDWF 0x3, F
  123.    062    3061     MOVLW 0x61
  124.    063    1683     BSF 0x3, 0x5
  125.    064    008F     MOVWF 0xf
  126.    065    1283     BCF 0x3, 0x5
  127.    066    131F     BCF 0x1f, 0x6
  128.    067    1683     BSF 0x3, 0x5
  129.    068    101F     BCF 0x1f, 0
  130.    069    109F     BCF 0x1f, 0x1
  131.    06A    111F     BCF 0x1f, 0x2
  132.    06B    119F     BCF 0x1f, 0x3
  133.    06C    3007     MOVLW 0x7
  134.    06D    1283     BCF 0x3, 0x5
  135.    06E    0099     MOVWF 0x19
  136. 25:                    
  137. 26:                     setup_adc_ports(NO_ANALOGS|VSS_VDD);
  138.    06F    131F     BCF 0x1f, 0x6
  139.    070    1683     BSF 0x3, 0x5
  140.    071    101F     BCF 0x1f, 0
  141.    072    109F     BCF 0x1f, 0x1
  142.    073    111F     BCF 0x1f, 0x2
  143.    074    119F     BCF 0x1f, 0x3
  144. 27:                     setup_adc(ADC_CLOCK_INTERNAL);
  145.    075    161F     BSF 0x1f, 0x4
  146.    076    169F     BSF 0x1f, 0x5
  147.    077    131F     BCF 0x1f, 0x6
  148.    078    1283     BCF 0x3, 0x5
  149.    079    139F     BCF 0x1f, 0x7
  150.    07A    141F     BSF 0x1f, 0
  151. 28:                     setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
  152.    07B    1683     BSF 0x3, 0x5
  153.    07C    0801     MOVF 0x1, W
  154.    07D    39C7     ANDLW 0xc7
  155.    07E    3808     IORLW 0x8
  156.    07F    0081     MOVWF 0x1
  157. 29:                     setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
  158.    080    3085     MOVLW 0x85
  159.    081    1283     BCF 0x3, 0x5
  160.    082    0090     MOVWF 0x10
  161. 30:                     setup_timer_2(T2_DIV_BY_1,255,1);
  162.    083    3000     MOVLW 0
  163.    084    00A1     MOVWF 0x21
  164.    085    3804     IORLW 0x4
  165.    086    0092     MOVWF 0x12
  166.    087    30FF     MOVLW 0xff
  167.    088    1683     BSF 0x3, 0x5
  168.    089    0092     MOVWF 0x12
  169. 31:                     setup_ccp1(CCP_COMPARE_INT);
  170.    08A    1505     BSF 0x5, 0x2
  171.    08B    300A     MOVLW 0xa
  172.    08C    1283     BCF 0x3, 0x5
  173.    08D    0095     MOVWF 0x15
  174. 32:                     setup_comparator(NC_NC);
  175.    08E    3007     MOVLW 0x7
  176.    08F    0099     MOVWF 0x19
  177.    090    1683     BSF 0x3, 0x5
  178.    091    0805     MOVF 0x5, W
  179.    092    3003     MOVLW 0x3
  180.    093    1283     BCF 0x3, 0x5
  181.    094    00A0     MOVWF 0x20
  182.    095    0BA0     DECFSZ 0x20, F
  183.    096    2895     GOTO 0x95
  184.    097    0819     MOVF 0x19, W
  185.    098    118C     BCF 0xc, 0x3
  186. 33:                     setup_vref(FALSE);
  187.    099    1683     BSF 0x3, 0x5
  188.    09A    0199     CLRF 0x19
  189. 34:                     //enable_interrupts(INT_CCP1);
  190. 35:                     //enable_interrupts(INT_TIMER0);
  191. 36:                     enable_interrupts(INT_TIMER1);
  192.    09B    140C     BSF 0xc, 0
  193. 37:                     //enable_interrupts(INT_TIMER2);
  194. 38:                     enable_interrupts(GLOBAL);
  195.    09C    30C0     MOVLW 0xc0
  196.    09D    1283     BCF 0x3, 0x5
  197.    09E    048B     IORWF 0xb, F
  198. 39:                     setup_oscillator(OSC_4MHZ);
  199.    09F    3061     MOVLW 0x61
  200.    0A0    1683     BSF 0x3, 0x5
  201.    0A1    008F     MOVWF 0xf
  202. 40:                    
  203. 41:                     CCP_1 = 55574;
  204.    0A2    30D9     MOVLW 0xd9
  205.    0A3    1283     BCF 0x3, 0x5
  206.    0A4    0094     MOVWF 0x14
  207.    0A5    3016     MOVLW 0x16
  208.    0A6    0093     MOVWF 0x13
  209. 42:                     set_timer1(65533);
  210.    0A7    30FF     MOVLW 0xff
  211.    0A8    008F     MOVWF 0xf
  212.    0A9    30FD     MOVLW 0xfd
  213.    0AA    008E     MOVWF 0xe
  214. 43:                     //set_timer0(254);
  215. 44:                     //set_timer2(254);
  216. 45:                     delay_cycles(1);
  217.    0AB    0000     NOP
  218. 46:                     delay_cycles(1);
  219.    0AC    0000     NOP
  220. 47:                     delay_cycles(1);
  221.    0AD    0000     NOP
  222. 48:                     delay_cycles(1);
  223.    0AE    0000     NOP
  224. 49:                     do{                    
  225. 50:                
  226. 51:                     }while(TRUE);  
  227.    0AF    28AF     GOTO 0xaf
  228.    0B0    0063     SLEEP

Lo realmente interesante va de la linea 4  hasta el RETFIE de la linea 4B, que salva el contexto, elige la interrupcion y luego devuelve el contexto.
En resumen, para que no tengais que analizar todo el codigo:

basicamente quisiera meter algunos NOP para que sea cual sea la interrupcion que hay que atender, y el estado del pic, se tarde lo mismo siempre en entrar o salir de cualquiera de las interrupciones.
Hay alguna manera de hacerlo sin tener que editar TODO el codigo en ASM como cuenta el amigo jacrmr?

Tambien hay un par de cosillas que no me cuadran:
*Porque al guardar STATUS en la linea 7 y linea C se hace un swap a los bits, y luego se hace otro swap al devolverlos en la linea 45? Para que el swap?
*Porque se devuelve el contenido de W con un swap en la linea 48 si al guardarlo no se le hizo swap?
*Al salvar el contexto (de E a 1F) se guardan los valores de 0x20 hasta 0x24. 0x20 se utiliza en la linea 94, 0x21 se usa en la linea 84. El resto para que se guardan? no veo que se utilicen para nada  :?  Serian unos cuantos ciclos que me ahorro a la entrada y salida de las interrupciones.

Bueno, gracias a todos por la ayuda. Esto de ASM me esta gustando  :-)  aunque no tanto como para hacer todo el programa con el  :P
Salu2
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: PalitroqueZ en 04 de Noviembre de 2008, 14:45:20
....basicamente quisiera meter algunos NOP para que sea cual sea la interrupcion que hay que atender, y el estado del pic, se tarde lo mismo siempre en entrar o salir de cualquiera de las interrupciones.
Hay alguna manera de hacerlo sin tener que editar TODO el codigo en ASM como cuenta el amigo jacrmr?

...

claro que si la hay, pero es algo que no tiene que ver con el lenguaje, sino con los ensayos fisicos.

1.- Podrias usar el mplab-sim y colocar un breakpoints en sitios estrategicos y medir el tiempo transcurrido y en base a esto, ajustar con delay_cycles(n) hasta completar el tiempo

1.1- En ccs es imposible medir el tiempo con precisión, porque el compilador mete unas lineas adicionales (transparentes al usuario) para hacer otros calculos, eso creo que lo llaman stack frame.

Así escribas un nop en main igual te escribe un encabezado por defecto

2.- podrias usar un osciloscopio y con togglear un pin, podrias medir el tiempo transcurrido con mayor precisión.

Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Giovanny en 04 de Noviembre de 2008, 15:25:01
TOMADO DE LA AYUDA DE CCS
--------------------------------------------------------------------------------
#ASM
#ENDASM

--------------------------------------------------------------------------------
Syntax:
 #asm
   or
#asm ASIS
   code
 #endasm
 
Elements:
 code is a list of assembly language instructions
 
Purpose:
 The lines between the #ASM and #ENDASM are treated as assembly code to be inserted.    These may be used anywhere an expression is allowed.   The syntax is described on the following page.   The predefined variable _RETURN_ may be used to assign a return value to a function from the assembly code.    Be aware that any C code after the #ENDASM and before the end of the function may corrupt the value.

 If the second form is used with ASIS then the compiler will not do any automatic bank switching for variables that cannot be accessed from the current bank.  The assembly code is used as-is.  Without this option the assembly is augmented so variables are always accessed correctly by adding bank switching where needed.
 
Examples:

Código: [Seleccionar]
int find_parity (int data)    {

int count;
#asm
movlw   0x8
movwf   count
movlw   0
loop:
xorwf   data,w
rrf     data,f
decfsz  count,f
goto    loop
movlw   1
awdwf   count,f
movwf   _return_
#endasm
}
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: MLO__ en 04 de Noviembre de 2008, 17:57:59
Hola.

Para que funcione lo de la ayuda hay que hacer el direccionamiento de los registros con #byte y #bit. Sin embargo a mi no me ha funcionado bien que digamos ....

Saludos
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 04 de Noviembre de 2008, 18:30:36
Hola Marttyn

*Porque al guardar STATUS en la linea 7 y linea C se hace un swap a los bits, y luego se hace otro swap al devolverlos en la linea 45? Para que el swap?

Porque la instrucción swapf no afecta ningún flag del registro STATUS.

*Porque se devuelve el contenido de W con un swap en la linea 48 si al guardarlo no se le hizo swap?

Porque para guardarlo sólo se debe hacer movwf registro_aux(que no afecta ningún flag del STATUS), pero si quisieras restaurarlo haciendo, por ejemplo, movf registro_aux,w esto afecta al flag Z del registro STATUS y no es lo correcto. Por eso se utilizan los SWAPF para restaurar los registros.

*Al salvar el contexto (de E a 1F) se guardan los valores de 0x20 hasta 0x24. 0x20 se utiliza en la linea 94, 0x21 se usa en la linea 84. El resto para que se guardan? no veo que se utilicen para nada  Confused  Serian unos cuantos ciclos que me ahorro a la entrada y salida de las interrupciones.

Probablemente el Compilador reserve por defecto esas posiciones de memoria para ciertos módulos o funciones especiales.

En cuanto a la inyección de NOPs, creo que vas a tener que hacerlo desde el código ASM de salida, porque no creo que haya lugar para poder inyectarlos dentro de la ISR desde el compilador. No va a ser tarea fácil, por ahí como te han recomendado con el MPLAB SIM lo hagas mucho más rápido.

Saludos.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 05 de Noviembre de 2008, 04:36:59
Hola a todos!
Gracias por vuestros comentarios!

Pali:
Efectivamente estoy usando el Stopwatch, y analizando el codigo directamente en ASM desde el MPLAB.

Giovanny:
Conozco lo de #asm para insertar codigo ASM entre medio del codigo C, pero el problema es que quiero insertar ASM en lugares donde el codigo C no llega, esas lineas transparentes al usuario que habla palitroquez.

BrunoF:
*Porque al guardar STATUS en la linea 7 y linea C se hace un swap a los bits, y luego se hace otro swap al devolverlos en la linea 45? Para que el swap?

Porque la instrucción swapf no afecta ningún flag del registro STATUS.

y en vez de usar la instruccion SWAPF, no se podria usar la instruccion MOVELW? Tampoco afecta al registro Z.

Citar
*Porque se devuelve el contenido de W con un swap en la linea 48 si al guardarlo no se le hizo swap?

Porque para guardarlo sólo se debe hacer movwf registro_aux(que no afecta ningún flag del STATUS), pero si quisieras restaurarlo haciendo, por ejemplo, movf registro_aux,w esto afecta al flag Z del registro STATUS y no es lo correcto. Por eso se utilizan los SWAPF para restaurar los registros.

Ok, no me habia dado cuenta que al guardar NO hace SWAP, pero lo hace unas instrucciones mas adelante sobre el valor guardado, por eso al recuperar el contexto le vuelve a hacer el SWAP.
Aun asi sigo sin entender que importancia tiene modificar el registro Z, en realidad al guardar los registros del 0x20 al 0x24 lo hace con MOVF y MOVWF, con lo que estan modificando Z.

Citar
*Al salvar el contexto (de E a 1F) se guardan los valores de 0x20 hasta 0x24. 0x20 se utiliza en la linea 94, 0x21 se usa en la linea 84. El resto para que se guardan? no veo que se utilicen para nada  Confused  Serian unos cuantos ciclos que me ahorro a la entrada y salida de las interrupciones.

Probablemente el Compilador reserve por defecto esas posiciones de memoria para ciertos módulos o funciones especiales.

Si mi programa no usa esas posiciones de memoria, puedo omitir salvar el contexto de dichas posiciones, y tambien omitir restaurarlas? Me ahorro 10 instrucciones en la entrada y otras 10 en la salida de la interrupcion!

Citar
En cuanto a la inyección de NOPs, creo que vas a tener que hacerlo desde el código ASM de salida, porque no creo que haya lugar para poder inyectarlos dentro de la ISR desde el compilador. No va a ser tarea fácil, por ahí como te han recomendado con el MPLAB SIM lo hagas mucho más rápido.

Como le dije a pali, estoy usando MPLAB para hacer todo esto, escribo el codigo en C, y al compilarlo debuggeo el ASM que genera. Entonces tendre que modificar ese ASM generado, no? No puedo hacer los cambios directamente desde C supongo...  :?

Sigo mirando el codigo y hay otras cosas que no entiendo....
*Por que en la linea 20 da la instruccion de pasar al Register Bank 0, si ya comprueba que esta en el banco 0 en la linea 4, y desde entonces no hay ninguna instruccion que cambie de banco. ¿?
*En la linea 12 pone a 0 el bit IRP de Status. Pero en el datasheet dice que no toquemos ese bit. Para que sirve?
*No entiendo muy bien que funcion cumplen las lineas 23 y 29? Segun el datasheet leer indirectamente el registro INDF devolvera 00h... ¿leer indirectamente?

Lamento tantas preguntas, tal vez deberia dirigirme al foro de ASM para resolverlas...
Un saludo y gracias a todos!
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 05 de Noviembre de 2008, 06:14:44
Hola!

y en vez de usar la instruccion SWAPF, no se podria usar la instruccion MOVELW? Tampoco afecta al registro Z.

Supongo que te referirás a la instrucción MOVLW. No es posible. La instrucción MOVLW sirve para cargar un LITERAL, es decir un valor pre-establecido. No permite cargar un valor no estático y el contenido de STATUS siempre varía. El movlw carga siempre un valor que tú eliges a la hora de programación. No se puede modificar el valor a cargar en W utilizando la movlw durante la ejecución en el pic(deberías sobrescribir la flash).

Ok, no me habia dado cuenta que al guardar NO hace SWAP, pero lo hace unas instrucciones mas adelante sobre el valor guardado, por eso al recuperar el contexto le vuelve a hacer el SWAP.
Aun asi sigo sin entender que importancia tiene modificar el registro Z, en realidad al guardar los registros del 0x20 al 0x24 lo hace con MOVF y MOVWF, con lo que estan modificando Z.

Lo importante no es NO modificarlo. Lo importante es no modificarlo mientras lo guardás o lo restaurás. Es decir, los registros clave deben valer al retornar de la interr. exáctamente lo mísmo que valían antes de ingresar a la ISR.

Si mi programa no usa esas posiciones de memoria, puedo omitir salvar el contexto de dichas posiciones, y tambien omitir restaurarlas? Me ahorro 10 instrucciones en la entrada y otras 10 en la salida de la interrupcion!

Podés. Siempre y cuando el programa no las use, volalas tranquilo.

Como le dije a pali, estoy usando MPLAB para hacer todo esto, escribo el codigo en C, y al compilarlo debuggeo el ASM que genera. Entonces tendre que modificar ese ASM generado, no? No puedo hacer los cambios directamente desde C supongo...  :?
Y..no veo otra manera, al menos desde lo que conozco. El problema es que no exíste una función en C referida a la ISR como para que puedas al menos inyectar los NOP desde código C. Tal vez usando el #asm y el org 0xXXX puedas hacer algo desde C pero no se si no te pisarás con el compilador...

Sigo mirando el codigo y hay otras cosas que no entiendo....
*Por que en la linea 20 da la instruccion de pasar al Register Bank 0, si ya comprueba que esta en el banco 0 en la linea 4, y desde entonces no hay ninguna instruccion que cambie de banco. ¿?

Está de mas. Podés sacarla tranquilo. Es mas: hay varias que se podrían unir y hacer el código más corto por lo que veo...

*En la linea 12 pone a 0 el bit IRP de Status. Pero en el datasheet dice que no toquemos ese bit. Para que sirve?

El bit IRP sirve sólo en uC que poseen más de 256 registros RAM. Sirve para acceder a los registros superiores de la RAM mediante direccionamiento indirecto(registros FSR e INDF). Como este uC que estás usando no posee más de 256 registros, no deberías tocarlo. Conclusión. Podés eliminar esa línea también.

*No entiendo muy bien que funcion cumplen las lineas 23 y 29? Segun el datasheet leer indirectamente el registro INDF devolvera 00h... ¿leer indirectamente?

Para comprenderlas, debés aprender sobre el direccionamiento indirecto y las lineas previas a las que desconocés su función.

  ...
  021    308C     MOVLW 0x8c
  022    0084     MOVWF 0x4
  023    1C00     BTFSS 0, 0
  024    2827     GOTO 0x27
  025    180C     BTFSC 0xc, 0
  026    2850     GOTO 0x50
  027    308C     MOVLW 0x8c
  028    0084     MOVWF 0x4
  029    1C80     BTFSS 0, 0x1
  ...
Se transforma directamente(con palabras un poco más legibles) en:

  ...
  021    308C     MOVLW PIE1
  022    0084     MOVWF FSR
  023    1C00     BTFSS INDF, 0
  024    2827     GOTO 0x27
  025    180C     BTFSC PIR1, TMR1IF
  026    2850     GOTO 0x50
  027    308C     MOVLW PIE1
  028    0084     MOVWF FSR
  029    1C80     BTFSS INDF,1
  ...

Y ahora yo la paso de assembler a español :mrgreen: :mrgreen: :mrgreen: :mrgreen:


  021    308C     MOVLW PIE1    ;(Cargo en W la dirección a la cual quiero acceder de manera indirecta...es decir, 0x8C)
  022    0084     MOVWF FSR      ;(la copio al registro FSR. Entonces, ahora al leer INDF, hacé de cuenta que estoy leyendo en realidad el registro 0x8C. Esto es básicamente el direccionamiento indirecto)
  023    1C00     BTFSS INDF, 0  ;(esto sería como hacer entonces... btfss PIE1,TMR1IE) = Interrupción de timer1 habilitada?
  024    2827     GOTO 0x27       ;no, ir a 0x27
  025    180C     BTFSC PIR1, TMR1IF ;Si. Ahora, btfsc PIR1,TMR1IF) = La bandera de interrupción del timer1 NO se ha producido?
  026    2850     GOTO 0x50       ;Se ha producido, ir a 0x50
  027    308C     MOVLW PIE1     ;No. El timer1 no ha interrumpido. Mover nuevamente el valor 0x8C a W
  028    0084     MOVWF FSR       ;y nuevamente apunta rindirectamente a él(estas dos podrías sacarse creo)
  029    1C80     BTFSS INDF,1    ;(esto sería como hacer entonces... btfss PIE1,TMR2IE) = Interrupción de timer2 habilitada?
  ...

Y sigue..

Saludos.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 05 de Noviembre de 2008, 06:17:23
Comentario al margen:

Cuanto más mires el código ASM de salida generado de un compilador, más ganas te van a dar ganas de pasarte a ASM si necesitás controlar los tiempos a la perfección. Esa rutina de interrupción deja bastante que desear...

Saludos.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: PalitroqueZ en 05 de Noviembre de 2008, 15:53:05
Comentario al margen:

Cuanto más mires el código ASM de salida generado de un compilador, más ganas te van a dar ganas de pasarte a ASM si necesitás controlar los tiempos a la perfección. Esa rutina de interrupción deja bastante que desear...

Saludos.

si eso es cierto, yo tengo un proyecto estancado, porque me impuse la manía de simplificar el asm generado por el C, casi que mando ese proyecto a freir monos.


Cuando se programa en C, hay que olvidarse un poco de la velocidad y subir la potencia del pic.

Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Leon Pic en 05 de Noviembre de 2008, 17:47:52
El lenguaje C, no es más que subrutinas para cada instrucción del CCS. Es por eso que pone el banco 0 otra vez. Ya que, en la rutina que tiene grabada, empieza poniendo el banco 0 por si antes se ejecutó otra rutina y lo dejó en cualquier banco.

Todo el lenguaje C, son rutinas pregrabadas que se iran uniendo según se valla escribiendo el programa. Al tener rutina pre grabadas, hace que la programación sea más fácil pero sacrificando instrucciones de más y tiempo demás. Lo mismo ocurre en ASM. Yo puedo crear carios tipos de rutinas en librerías y luego ir incluyendola, pero si quiero una buena programación, voy a tener que estar modificando las librerías antes mencionadas.

Además, cada subrutina grabada es generalizada para varios tipos de pic, de esta manera no se hace una subrutina para cada tipo de pic.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 06 de Noviembre de 2008, 02:17:04
Bruno, genial! Simplemente GENIAL!
Que sepas que si te pasas alguna vez por Galicia (España), o si ando por Rosario, te invito unas cervezas, que te las tienes merecidas! :wink:

La verdad me ha quedado todo clarisimo!
Excepto esto:  :mrgreen:

*El direccionamiento indirecto que funcion tiene? Si podemos leer el registro directamente, para que lo vamos a leer de manera indirecta? O es para no tener que cambiar de pagina?
Si uso direccionamiento indirecto, en FSR tengo el PORTA por ej, cuando cambie el PORTA, tambien cambiara FSR?
Por cierto, cuando tengo que cambiar de pagina? Si estoy en el banco 0, y quiero leer o escribir algo del banco 1 primero tengo que cambiar de pagina? En la pregunta siguiente la instruccion MOVLW lee PIE1 del banco 1, estando en el banco 0 ¿?


Citar
La instrucción MOVLW sirve para cargar un LITERAL, es decir un valor pre-establecido. No permite cargar un valor no estático y el contenido de STATUS siempre varía. El movlw carga siempre un valor que tú eliges a la hora de programación. No se puede modificar el valor a cargar en W utilizando la movlw durante la ejecución en el pic(deberías sobrescribir la flash).

Si te fijas, en la linea 21:
Código: ASM
  1. 021    308C     MOVLW PIE1    ;(Cargo en W la dirección a la cual quiero acceder de manera indirecta...es decir, 0x8C)

Aqui estamos cargando en W un valor que no es un "literal". PIE1 se puede modificar en ejecucion o no?

Bueno, llevo un par de dias con ASM y la verdad se pone cada vez mas interesante... Y como estan diciendo TODOS, hay que cambiarse a ASM si quiero tener control total sobre las instrucciones. Mucha razon tienen, pero por ahora lo unico que me da problemas es el ISR, asi que escribire el codigo en C, y modificare el ASM generado. Aun no tengo conocimientos como para hacer todo el programa en ASM.

Pali, lo que no veo muy logico es pasarse a un micro mas potente y quedarse en C. Si tu programa necesita precision de instrucciones, por mas que te pases a un micro mas rapido, las instrucciones que genera "de mas" el CCS, y las rutinas poco eficientes siguen estando ahi, y aunque se ejecuten mas rapido, sigues teniendo una imprecision que no puedes controlar.

Creo que va siendo hora que me busque un manual de ASM, porque aprender del datasheet del PIC y del codigo generado de mi programa esta dejandome con demasiadas dudas  :-)
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: jacrmr en 06 de Noviembre de 2008, 02:36:28
Citar
*El direccionamiento indirecto que funcion tiene? Si podemos leer el registro directamente, para que lo vamos a leer de manera indirecta?

Precisamente su función e importancia es el no tener que hacerlo directamente, aunque parezca algo confuso. Si quieres abordar un autobús en la central de autobuses es más lógico y práctico que vayas al tablero de salidas (direccionamiento indirecto) y conozcas la hora de salida de tu autobús, que ir directamente con el piloto o chofer del mismo a preguntarle a él (que además no te lo permitirían tal vez).

Respecto a ésta instrucción "MOVLW PIE1", en realidad no es correcta en la arquitectura 16F, pero verás que el ASM la toma como si lo fuera. Hay una razón muy sencilla. PIE1 en éste caso (aunque sabemos que es el registro PIE1) para el ASM simplemente tiene un valor numérico que es la dirección de dicho registro. Así que el ASM entiende en ésta instrucción lo siguiente:
MOVLW 0x0C, sin saber que te refieres a un registro. Esto es porque en el include se le dió dicho valor a PIE1.
 
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 06 de Noviembre de 2008, 03:11:10
La verdad que si que es un poco confuso lo del direccionamiento indirecto... Y sobre todo, cuando debo o no cambiar de pagina  :z)

Respecto a ésta instrucción "MOVLW PIE1", en realidad no es correcta en la arquitectura 16F, pero verás que el ASM la toma como si lo fuera. Hay una razón muy sencilla. PIE1 en éste caso (aunque sabemos que es el registro PIE1) para el ASM simplemente tiene un valor numérico que es la dirección de dicho registro. Así que el ASM entiende en ésta instrucción lo siguiente:
MOVLW 0x0C, sin saber que te refieres a un registro. Esto es porque en el include se le dió dicho valor a PIE1.

Cuando dices que el include le da el valor 0x0C a PIE1, que significa? o se te "chispoteo" y querias decir 0x8C?
Si es asi, que diferencia hay con usar MOVLW con valores que no son constantes si el compilador los entiende igual?
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 06 de Noviembre de 2008, 03:37:18
Bruno, genial! Simplemente GENIAL!
Que sepas que si te pasas alguna vez por Galicia (España), o si ando por Rosario, te invito unas cervezas, que te las tienes merecidas! :wink:

Me alegro que te pueda ayudar. Obviamente nunca rechazo unas cervezas ;) :D :D  :D

La verdad me ha quedado todo clarisimo!
Excepto esto:  :mrgreen:

*El direccionamiento indirecto que funcion tiene? Si podemos leer el registro directamente, para que lo vamos a leer de manera indirecta? O es para no tener que cambiar de pagina?

Bueno, ya jacrmr ha respondido de una manera bastante peculiar y buena a tus preguntas. Yo voy a intentar hacerte ver para qué serviría en la práctica el direccionamiento indirecto.
Para poder acceder a un registro de manera indirecta, posees 2 registros:
El registro FSR, que es un registro puntero. Es decir, "apunta" o contiene el valor de la posición de memoria a la cual deseás acceder;
Y el registro INDF que contiene el valor del registro al cual FSR apunta en ese momento.

Entonces, supongamos que quiero poner a cero todas la memoria RAM comprendida entre 0x20 y 0x4F.
Si no existiera el direccionamiento indirecto, tendríamos que hacer algo así:

    clrf    0x20
    clrf    0x21
    clrf    0x22
    clrf    0x23
    .....
    clrf    0x4d
    clrf    0x4e
    clrf    0x4f


Lo que sería un verdadero despilfarro de memoria, no?

Ahora, utilizando direccionamiento indirecto, la cosa se torna más sencilla.

         movlw 0x20       ;comienzo desde el registro 0x20
         movwf FSR        ;apunto a dicho registro(ahora, INDF contiene valor del registro 0x20. Todas las operaciones de lectura/escritura sobre el INDF afectarán al registro como si estuviese accediendo directamente a él)
prox  clrf      INDF      ;pongo a cero la posición de memoria a la cual FSR apunta en este momento
         incf     FSR,F     ;indico que quiero acceder a la proxima posicion de memoria
         movf   FSR,w    ;copio el valor de FSR a W
         xorlw  0x50      ;y aplico una XOR para ver si ya he terminado con todos los registros que deseaba limpiar
         btfss   STATUS,Z ;si se cumple, he terminado
         goto    prox         ;no, entonces próximo registro
      
         nop                  ;listo!

Si uso direccionamiento indirecto, en FSR tengo el PORTA por ej, cuando cambie el PORTA, tambien cambiara FSR?

Bueno, supongamos que "en FSR tengo el PORTA": Esto es lo mísmo que decir(en esta familia de PICs) que FSR = 0x05. O sea, que en el registro FSR has cargado el valor 0x05 que corresponde al PORTA. Ahora, si cambiás el valor del PORTA, también cambiará el valor contenido en el registro INDF. No el FSR. El FSR sólo indica el registro al cual acceder. INDF es el que contiene el valor del PORTA, y cambiará si PORTA cambia y viceversa(cambiar el valor del INDF también cambiará el valor del registro 0x05(PORTA)).
¿Se entendió?

Vamos con un ejemplo:
;Supongo que configuré a PORTB todo como salidas y ahora:

     clrf      PORTB      ;ahora, PORTB=0
     movlw 0x06         ;cargo en W la dirección del PORTB(podría haber hecho movlw PORTB)
     movwf FSR          ;ahora, copio el valor de W en el registro FSR. Como W vale 0x06, al cargarlo en el FSR ahora estoy accediendo indirectamente al PORTB.
     bsf    INDF,0        ;ahora, indico que pongo a uno el bit0 del registro INDF. Como INDF contiene el valor del registro PORTB porque FSR apunta a el, ahora el registro PORTB también valdrá 0x01
     clrf     PORTB       ;vuelvo a limpiar el registro PORTB, por lo que INDF también ahora se verá afectado y valdrá 0x00

Es decir que ambos se afectan mutuamente y se comportan como uno sólo(en realidad lo son :D)

Por cierto, cuando tengo que cambiar de pagina? Si estoy en el banco 0, y quiero leer o escribir algo del banco 1 primero tengo que cambiar de pagina? En la pregunta siguiente la instruccion MOVLW lee PIE1 del banco 1, estando en el banco 0 ¿?

Bueno. Esto tiene que ver con la arquitectura de esta familia de microcontroladores. El direccionamiento indirecto posee una ventaja frente al directo. El directo está dividido en bancos de 128 registros cada uno. Esto es por un tema un poco más profundo que no quiero explayar para no marearte.
Lo importante es que mediante el direccionamiento indirecto, podes acceder a cualquiera de los primeros 256 registros sin tener que cambiarlo de banco. Si necesitás acceder a un registro más allá del 0xFF mediante direccionamiento indirecto entonces necesitás setear el bit IRP que mencionaste anteriormente y en este uC no tiene sentido por lo que ya mencionamos.
En definitiva, en este uC que estás usando, podés acceder a toda la RAM sin necesidad de tener precauciones de cambio de banco siempre y cuando lo hagas mediante direccionamiento indirecto. Si usás direccionamento directo, que es más común, necesitás asegurarte que el uC se encuentre en el banco correcto antes de trabajar sobre dicho registro.
Si mirás en las intrucciones en el datasheet vas a ver que en las instrucciones movf, movwf,xorwf, y muchas otras, el registro f debe estar entre 0 y 127. Es decir que cada una de esas instrucciones sólo pueden contener 7bits de direccionamiento. Los otros dos bits(de mayor peso) son dados mediante los bits RP1 y RP0.
Resumiendo:
Si quisiese acceder a PIE1 mediante direccionamiento indirecto sólo me bastaría con hacer:
   movlw  PIE1
   movwf  FSR
   clrf       INDF   ;y aqui leer o escribir directamente el registro INDF

en cambio, si quisiese acceder mediante direccionamiento directo y estuviese en el banco 0:
   bsf  STATUS,RP0           ;cambio al banco1
   clrf    PIE1        ;y ahora si podría trabajar sobre el registro

Citar
La instrucción MOVLW sirve para cargar un LITERAL, es decir un valor pre-establecido. No permite cargar un valor no estático y el contenido de STATUS siempre varía. El movlw carga siempre un valor que tú eliges a la hora de programación. No se puede modificar el valor a cargar en W utilizando la movlw durante la ejecución en el pic(deberías sobrescribir la flash).

Si te fijas, en la linea 21:
Código: ASM
  1. 021    308C     MOVLW PIE1    ;(Cargo en W la dirección a la cual quiero acceder de manera indirecta...es decir, 0x8C)

Aqui estamos cargando en W un valor que no es un "literal". PIE1 se puede modificar en ejecucion o no?

Bueno, esto genera siempre mucha confusión. jacrmr te lo ha explicado más que suficientemente bien.
PIE1 se puede modificar en ejecución. Pero no confundamos el contenido del registro PIE1(que es el que puede cambiar en ejecución) con la dirección en la que se encuentra el registro PIE1(que no cambia).

Hacer MOVLW  PIE1 es exáctamente lo mísmo que hacer movlw 0x0C. Porque como el MPASM espera un literal, un valor incambiable, lo buscará en la definición que hayas hecho de PIE1, y si lo buscas dentro del archivo include(.inc) verás que PIE1 ha sido definido como 0x0C. El ensamblador asume que su valor es 0x0C y lo toma.
Esto permite un código un poco más legible. Obviamente todo depende de la instrucción. Esto se usa mucho en las que aceptan literales como argumentos.

Saludos!
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: jacrmr en 06 de Noviembre de 2008, 03:40:34
Citar
Cuando dices que el include le da el valor 0x0C a PIE1, que significa? o se te "chispoteo" y querias decir 0x8C?
Si es asi, que diferencia hay con usar MOVLW con valores que no son constantes si el compilador los entiende igual?

En efecto, quise decir 0x8C, ya que así está especificado en el include. Pero (espero no confundirte con lo que sigue, en realidad es transparente al usuario y no te debe de preocupar) si tú haces MOVWF PIE1, internamente el PIC te considera el registro como si tuviera un valor de 0x0C, y el bit que lo convierte en 0x8C en realidad es el bit RP0 del STATUS. Y esto debería contestar tu pregunta de por qué es necesario cambiar de páginas (o de bancos en este caso). Los bits de las páginas y los bancos son los bits más signifcativos que forman toda la dirección de la memoria o la dirección de los registros.
Por ejemplo si tú haces MOVWF EECON1, el ASM te genera el mismo código máquina que si hicieras MOVWF PIE1. Los bits RP0 y RP1 del STATUS son los que te forman toda la dirección del registro internamente en el PIC. Y esto nos lleva a lo interesante del ASM y a tu pregunta de que qué diferencia hay si de todas formas le da igual. Este por sí mismo no tiene ambiguedades. Nosotros somos los que podemos incurrir en ellas y es nuestra responsabilidad de que ningún bit de código signifique algo que nosotros no queríamos intencionalmente.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 06 de Noviembre de 2008, 03:42:37
Ehh joer, yo también arrastré ese error :D :D
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Leon Pic en 06 de Noviembre de 2008, 10:50:00
Aprovechando que se está tratando el tema de los accesos y escribir en forma indirecta, quiero explicar que para grabar en la EEPROM del PIC para el usuario, se hace también en forma indirecta, más precisamente con los registro EEADR y EEDATA (en algunos PIC, como al 16F877, se agregan dos más que son para la parte alta EEADRH y EEDATAH).

Bien, EEADR significa EE: EEPROM y ADR: Address (dirección)----- EEDATA: EEPROM y DATA: DATA (datos).

Para grabar un dato en una pocición determinada, primero tengo que cargar en EEADR la dirección. Y en EEDATA el valor propiamente dicho para guardar en la pocición designada en EEADR.

Por ejemplo:

Código: ASM
  1. MOVLW       H'23'       ;Cargo a W con el valor H'23'
  2.         MOVWF       EEADR    ;y lo muevo a EEADR para apuntar la pocición H'23'
  3.         MOVLW       H'12'       ;Cargo a W con el valor H'12'
  4.         MOVWF       EEDATA  ;y lo muevo a EEDATA para guardar el valor deseado.

Si logran entender este ejemplo, pasa lo mismo con INDF y FSR. INDF hace el mismo trabajo que EEADR y FSR hace el mismo trabajo que EEDATA.

Todo esto, pronto lo explicaré en ASM desde 0 (http://www.todopic.com.ar/foros/index.php?topic=23623.0)
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 07 de Noviembre de 2008, 01:55:49
Bueno, deje "macerar" mis conocimientos recientemente aprendidos. Dormi, pense en otras cosas, estuve con mi novia, lei, di una vuelta.... Y ahora volvi a leer todo de nuevo para asentar lo aprendido. La verdad creo que ya lo tengo todo MUCHO mas claro! Creo que incluso entiendo el direccionamiento indirecto!  :D

Leo, jacrmr, tambien os mereceis una cervecita! Si quereis probar una "Duff" (la de los simpson) aqui en Galicia las tenemos!

(http://i299.photobucket.com/albums/mm317/Marttyn/photo.jpg)

Bruno, tu comentaste antes que que este codigo de interrupcion deja bastante que desear, y que hay unas cuantas lineas que se pueden "unir" para hacer el codigo mas corto. Podrias indicarme cuales? Esas son las cosas que no vienen en los manuales y que solo se aprenden con la experiencia... o si te las dice otro  :D

Salu2
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 07 de Noviembre de 2008, 03:26:27
Hola!

Te comento cómo lo dejaría yo:

1er paso: Renombrar un poco las cosas para que sea un poco más legible;

Código: ASM
  1. 004    1A83     BTFSC STATUS, RP0
  2.   005    280A     GOTO 0xa
  3.   006    00A5     MOVWF W_AUX           ;0x25
  4.   007    0E03     SWAPF STATUS, W
  5.   008    00A6     MOVWF S_AUX           ;0x26
  6.   009    280F     GOTO 0xf
  7.   00A    1283     BCF STATUS, RP0
  8.   00B    00A5     MOVWF W_AUX
  9.   00C    0E03     SWAPF STATUS, W
  10.   00D    00A6     MOVWF S_AUX
  11.   00E    14A6     BSF S_AUX, 1         
  12.   00F    080A     MOVF PCLATH, W
  13.   010    00AD     MOVWF P_AUX           ;0x2d
  14.   011    018A     CLRF PCLATH
  15.   012    1383     BCF STATUS, IRP
  16.   013    0EA5     SWAPF W_AUX, F
  17.   014    0804     MOVF FSR, W
  18.   015    00A7     MOVWF F_AUX           ;0x27
  19.   016    0820     MOVF REG1, W          ;0x20
  20.   017    00A8     MOVWF R1_AUX          ;0x28
  21.   018    0821     MOVF REG2, W          ;0x21
  22.   019    00A9     MOVWF R2_AUX          ;0x29
  23.   01A    0822     MOVF REG3, W          ;0x22
  24.   01B    00AA     MOVWF R3_AUX          ;0x2a
  25.   01C    0823     MOVF REG4, W          ;0x23
  26.   01D    00AB     MOVWF R4_AUX          ;0x2b
  27.   01E    0824     MOVF REG5, W          ;0x25
  28.   01F    00AC     MOVWF R5_AUX          ;0x2c
  29.   020    1283     BCF STATUS, RP0
  30.   021    308C     MOVLW PIE1
  31.   022    0084     MOVWF FSR
  32.   023    1C00     BTFSS INDF, TMR1IE
  33.   024    2827     GOTO 0x27
  34.   025    180C     BTFSC PIR1, TMR1IF
  35.   026    2850     GOTO 0x50
  36.   027    308C     MOVLW PIE1
  37.   028    0084     MOVWF FSR
  38.   029    1C80     BTFSS INDF, TMR2IE
  39.   02A    282D     GOTO 0x2d
  40.   02B    188C     BTFSC PIR1, TMR2IF
  41.   02C    2857     GOTO 0x57
  42.   02D    1E8B     BTFSS INTCON, TMR0IE
  43.   02E    2831     GOTO 0x31
  44.   02F    190B     BTFSC INTCON, TMR0IF
  45.   030    284C     GOTO 0x4c
  46.   031    308C     MOVLW PIE1
  47.   032    0084     MOVWF FSR
  48.   033    1E80     BTFSS INDF, RCIE
  49.   034    2837     GOTO 0x37
  50.   035    1A8C     BTFSC PIR1, RCIF
  51.   036    285B     GOTO 0x5b
  52.   037    0827     MOVF F_AUX, W
  53.   038    0084     MOVWF FSR
  54.   039    0828     MOVF R1_AUX, W
  55.   03A    00A0     MOVWF REG1
  56.   03B    0829     MOVF R2_AUX, W
  57.   03C    00A1     MOVWF REG2
  58.   03D    082A     MOVF R3_AUX, W
  59.   03E    00A2     MOVWF REG3
  60.   03F    082B     MOVF R4_AUX, W
  61.   040    00A3     MOVWF REG4
  62.   041    082C     MOVF R5_AUX, W
  63.   042    00A4     MOVWF REG5
  64.   043    082D     MOVF P_AUX, W
  65.   044    008A     MOVWF PCLATH
  66.   045    0E26     SWAPF S_AUX, W
  67.   046    0083     MOVWF STATUS
  68.   047    1283     BCF STATUS, RP0
  69.   048    0E25     SWAPF W_AUX, W
  70.   049    18A6     BTFSC S_AUX, 1
  71.   04A    1683     BSF STATUS, RP0
  72.   04B    0009     RETFIE

2do paso: Comentar un poco

Código: ASM
  1. 004    1A83     BTFSC STATUS, RP0               ;Banco 0?
  2.   005    280A     GOTO 0xa                      ;No. Saltar
  3.   006    00A5     MOVWF W_AUX           ;0x25   ;Si. Guardar W
  4.   007    0E03     SWAPF STATUS, W               ;Guardar STATUS
  5.   008    00A6     MOVWF S_AUX           ;0x26
  6.   009    280F     GOTO 0xf                      ;y saltar
  7.   00A    1283     BCF STATUS, RP0               ;Banco 1. Volver a banco 0
  8.   00B    00A5     MOVWF W_AUX                   ;Guardar W
  9.   00C    0E03     SWAPF STATUS, W               ;Guardar STATUS
  10.   00D    00A6     MOVWF S_AUX  
  11.   00E    14A6     BSF S_AUX, 1          ;1      ;RECORDAR QUE ESTABA EN EL BANCO 1!
  12.   00F    080A     MOVF PCLATH, W                ;Guardar PCLATH
  13.   010    00AD     MOVWF P_AUX           ;0x2d
  14.   011    018A     CLRF PCLATH                   ;Limpiar PCLATH
  15.   012    1383     BCF STATUS, IRP               ;Limpiar IRP
  16.   013    0EA5     SWAPF W_AUX, F                ;Swapear W_AUX
  17.   014    0804     MOVF FSR, W                   ;Guardar FSR
  18.   015    00A7     MOVWF F_AUX           ;0x27   ;Y otros registros usados
  19.   016    0820     MOVF REG1, W          ;0x20
  20.   017    00A8     MOVWF R1_AUX          ;0x28
  21.   018    0821     MOVF REG2, W          ;0x21
  22.   019    00A9     MOVWF R2_AUX          ;0x29
  23.   01A    0822     MOVF REG3, W          ;0x22
  24.   01B    00AA     MOVWF R3_AUX          ;0x2a
  25.   01C    0823     MOVF REG4, W          ;0x23
  26.   01D    00AB     MOVWF R4_AUX          ;0x2b
  27.   01E    0824     MOVF REG5, W          ;0x25
  28.   01F    00AC     MOVWF R5_AUX          ;0x2c
  29.   020    1283     BCF STATUS, RP0               ;Banco 0
  30.   021    308C     MOVLW PIE1                    ;Verificacion de si Timer1 interrumpió
  31.   022    0084     MOVWF FSR
  32.   023    1C00     BTFSS INDF, TMR1IE
  33.   024    2827     GOTO 0x27
  34.   025    180C     BTFSC PIR1, TMR1IF
  35.   026    2850     GOTO 0x50
  36.   027    308C     MOVLW PIE1                    ;Verificacion de si Timer1 interrumpió
  37.   028    0084     MOVWF FSR
  38.   029    1C80     BTFSS INDF, TMR2IE
  39.   02A    282D     GOTO 0x2d
  40.   02B    188C     BTFSC PIR1, TMR2IF
  41.   02C    2857     GOTO 0x57
  42.   02D    1E8B     BTFSS INTCON, TMR0IE          ;Verificacion de si Timer0 interrumpió
  43.   02E    2831     GOTO 0x31
  44.   02F    190B     BTFSC INTCON, TMR0IF
  45.   030    284C     GOTO 0x4c
  46.   031    308C     MOVLW PIE1                    ;Verificacion de si USART interrumpió
  47.   032    0084     MOVWF FSR
  48.   033    1E80     BTFSS INDF, RCIE
  49.   034    2837     GOTO 0x37
  50.   035    1A8C     BTFSC PIR1, RCIF
  51.   036    285B     GOTO 0x5b
  52.   037    0827     MOVF F_AUX, W                 ;Restaurar registros...
  53.   038    0084     MOVWF FSR
  54.   039    0828     MOVF R1_AUX, W
  55.   03A    00A0     MOVWF REG1
  56.   03B    0829     MOVF R2_AUX, W
  57.   03C    00A1     MOVWF REG2
  58.   03D    082A     MOVF R3_AUX, W
  59.   03E    00A2     MOVWF REG3
  60.   03F    082B     MOVF R4_AUX, W
  61.   040    00A3     MOVWF REG4
  62.   041    082C     MOVF R5_AUX, W
  63.   042    00A4     MOVWF REG5
  64.   043    082D     MOVF P_AUX, W
  65.   044    008A     MOVWF PCLATH
  66.   045    0E26     SWAPF S_AUX, W
  67.   046    0083     MOVWF STATUS
  68.   047    1283     BCF STATUS, RP0
  69.   048    0E25     SWAPF W_AUX, W
  70.   049    18A6     BTFSC S_AUX, 1
  71.   04A    1683     BSF STATUS, RP0
  72.   04B    0009     RETFIE

3er paso: Optimizarla y reubicarla

Código: ASM
  1. 004      ????     BCF   R1_AUX,0                ;Incicializo indicando que estaba en banco0
  2.   005    1A83     BTFSC STATUS, RP0             ;Banco 0?
  3.   006    ????     BSF   R1_AUX,0                ;No. Entonces guardo que estaba en el banco1
  4.  
  5.   007    ????     CLRF  STATUS                  ;Banco0
  6.   008    00A5     MOVWF W_AUX           ;0x25   ;Guardar W             
  7.   009    0E03     SWAPF STATUS, W               ;Guardar STATUS
  8.   00A    00A6     MOVWF S_AUX           ;0x26
  9.   00B    ????     BTFSC R1_AUX,0                ;Ingreso estando en el banco0?
  10.   00C    14A6     BSF S_AUX, 1                  ;No.Guardar que estaba en el banco1
  11. ;GUARDA OTROS REGISTROS CLAVE
  12.   00D    080A     MOVF PCLATH, W                ;Guardar PCLATH
  13.   00E    00AD     MOVWF P_AUX           ;0x2d
  14.   00F    018A     CLRF PCLATH                   ;Limpiar PCLATH
  15.   010    0804     MOVF FSR, W                   ;Guardar FSR
  16.   011    00A7     MOVWF F_AUX           ;0x27   ;Y otros registros usados
  17.   012    0820     MOVF REG1, W          ;0x20
  18.   013    00A8     MOVWF R1_AUX          ;0x28
  19.   014    0821     MOVF REG2, W          ;0x21
  20.   015    00A9     MOVWF R2_AUX          ;0x29
  21.  
  22. TIMER0
  23.   016    1E8B     BTFSC INTCON, TMR0IE          ;Verificacion de si Timer0 interrumpió
  24.   017    190B     BTFSS INTCON, TMR0IF
  25.   018    284C     GOTO 0x4c                     ;TIMER0 ISR
  26.  
  27.   019    308C     MOVLW PIE1
  28.   01A    0084     MOVWF FSR
  29.  
  30. TIMER1
  31.   01B    1C00     BTFSC INDF, TMR1IE
  32.   01C    180C     BTFSS PIR1, TMR1IF
  33.   01D    2850     GOTO 0x50                     ;TIMER1 ISR
  34.  
  35. TIMER2
  36.   01E    1C80     BTFSC INDF, TMR2IE
  37.   01F    188C     BTFSS PIR1, TMR2IF
  38.   020    2857     GOTO 0x57                     ;TIMER2 ISR
  39.  
  40. USART
  41.   021    1E80     BTFSC INDF, RCIE
  42.   022    1A8C     BTFSS PIR1, RCIF
  43.   023    285B     GOTO 0x5b                     ;USART ISR
  44.  
  45. RESTAURAR
  46.   024    0827     MOVF F_AUX, W                 ;Restaurar registros...
  47.   025    0084     MOVWF FSR
  48.   026    0828     MOVF R1_AUX, W
  49.   027    00A0     MOVWF REG1
  50.   028    0829     MOVF R2_AUX, W
  51.   029    00A1     MOVWF REG2
  52.   02A    082D     MOVF P_AUX, W
  53.   02B    008A     MOVWF PCLATH
  54.   02C    0E26     SWAPF S_AUX, W
  55.   02D    0083     MOVWF STATUS
  56.   02E    1283     BCF STATUS, RP0
  57.   02F    0EA5     SWAPF W_AUX, F                ;Swapear W_AUX
  58.   030    0E25     SWAPF W_AUX, W
  59.   031    18A6     BTFSC S_AUX, 1
  60.   032    1683     BSF STATUS, RP0
  61.   033    0009     RETFIE

4to paso: Segunda optimización(esta requiere que 0x2C no sea usada nunca en el programa! ojo! aprovecho que no se usa para guardar el banco(RP0)

Código: ASM
  1. 004      ????     BCF   0x2C,RP0                ;Incicializo indicando que estaba en banco0
  2.   005    1A83     BTFSC STATUS, RP0             ;Banco 0?
  3.   006    ????     BSF   0x2C,RP0                ;No. Entonces guardo que estaba en el banco1
  4.  
  5.   007    ????     CLRF  STATUS                  ;Banco0
  6.   008    00A5     MOVWF W_AUX           ;0x25   ;Guardar W             
  7.   009    0E03     SWAPF STATUS, W               ;Guardar STATUS
  8.   00A    00A6     MOVWF S_AUX           ;0x26
  9.  
  10. ;GUARDA OTROS REGISTROS CLAVE
  11.   00B    080A     MOVF PCLATH, W                ;Guardar PCLATH
  12.   00C    00AD     MOVWF P_AUX           ;0x2d
  13.   00D    018A     CLRF PCLATH                   ;Limpiar PCLATH
  14.   00E    0804     MOVF FSR, W                   ;Guardar FSR
  15.   00F    00A7     MOVWF F_AUX           ;0x27   ;Y otros registros usados
  16.   010    0820     MOVF REG1, W          ;0x20
  17.   011    00A8     MOVWF R1_AUX          ;0x28
  18.   012    0821     MOVF REG2, W          ;0x21
  19.   013    00A9     MOVWF R2_AUX          ;0x29
  20.  
  21. TIMER0
  22.   014    1E8B     BTFSC INTCON, TMR0IE          ;Verificacion de si Timer0 interrumpió
  23.   015    190B     BTFSS INTCON, TMR0IF
  24.   016    284C     GOTO 0x4c                     ;TIMER0 ISR
  25.  
  26.   017    308C     MOVLW PIE1
  27.   018    0084     MOVWF FSR
  28.  
  29. TIMER1
  30.   019    1C00     BTFSC INDF, TMR1IE
  31.   01A    180C     BTFSS PIR1, TMR1IF
  32.   01B    2850     GOTO 0x50                     ;TIMER1 ISR
  33.  
  34. TIMER2
  35.   01C    1C80     BTFSC INDF, TMR2IE
  36.   01D    188C     BTFSS PIR1, TMR2IF
  37.   01E    2857     GOTO 0x57                     ;TIMER2 ISR
  38.  
  39. USART
  40.   01F    1E80     BTFSC INDF, RCIE
  41.   020    1A8C     BTFSS PIR1, RCIF
  42.   021    285B     GOTO 0x5b                     ;USART ISR
  43.  
  44. RESTAURAR
  45.   022    0827     MOVF F_AUX, W                 ;Restaurar registros...
  46.   023    0084     MOVWF FSR
  47.   024    0828     MOVF R1_AUX, W
  48.   025    00A0     MOVWF REG1
  49.   026    0829     MOVF R2_AUX, W
  50.   027    00A1     MOVWF REG2
  51.   028    082D     MOVF P_AUX, W
  52.   029    008A     MOVWF PCLATH
  53.   02A    0E26     SWAPF S_AUX, W
  54.   02B    0083     MOVWF STATUS
  55.   02C    0EA5     SWAPF W_AUX, F                ;Swapear W_AUX
  56.   02D    0E25     SWAPF W_AUX, W
  57.   02E    18A6     BTFSC 0x2C, RP0
  58.   02F    1683     BSF STATUS, RP0
  59.   030    0009     RETFIE

Saludos.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 08 de Noviembre de 2008, 03:28:49
Hola Bruno! Gracias por ayudarme a optimizar el codigo!
La verdad que tuve que estrujarme un poco los sesos para entender porque haces lo que haces cuando entras en el vector de interrupcion, aunque creo que ya lo cacé.
Solo hay una cosita que no consigo entender, porque la segunda optimizacion ocupa mas instrucciones que la primera? Puede ser que las hayas puesto al reves? Sino tampoco me cuadra lo de no poder usar el registro 0x2C en todo el programa.

Y ahora me dejo de preguntas y me someto a "examen". Aplicando todo lo aprendido sobre direccionamiento directo e indirecto quiero ver si apruebo con el siguiente codigo:

Código: ASM
  1. 004    MOVWF    0x70
  2. 005    SWAPF    STATUS, W
  3. 006    MOVWF    0x71
  4. .
  5. .
  6. .
  7. [Todo el resto]

Sencillo... Jeje... Ahora explico lo que hace, o al menos lo que me gustaria que haga  :D
El codigo original, y el de Bruno hacen una comprobacion para ver en que banco se encuentrar para poder luego ir al banco 0 y salvar el contexto. Este codigo lo que hace es no preocuparse de ver en que banco estamos, aprovechar el direccionamiento directo, que solo son 7 bits y asi grabar en la posicion 70h el contenido de W, y en 71h el contenido de STATUS. No nos importa en que banco estemos porque si estamos en el banco 1, y grabamos en el registro 70h, estaremos grabando en realidad en el registro F0h (esto lo aprendi de jacrmr  :mrgreen:). Y si estamos en el banco 0, y grabamos en el registro 70h, estaremos grabando exactamente en ese registro (obvio). Lo bonito de esto es que los registros del F0h al FFh acceden directamente a los registros 70h al 7Fh, por lo que siempre estaremos grabando en el banco 0, aunque nos encontremos en el banco 1. De esta manera nos ahorramos la comprobacion del principio y usar mas memoria de la necesaria... Y lo mas interesante para tener los tiempos controlados es evitar que el programa se bifurque consumiendo 1 o 2 ciclos dependiendo de algunas cosas.
Que opinas? Estoy aprobado? o la teoria es muy bonita pero estoy dando palos de ciego?  :D

PS: por cierto, al compilar en C, se genera algun archivo en ASM que pueda cargar y modificar directamente desde MPASM? Porque el .lst no se si sera "apto".
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: jacrmr en 08 de Noviembre de 2008, 04:00:17
Supongo que ya lo sabes de antemano, pero en "Archivos de Programa\Microchip\MPASM Suite\Template\Code" se encuentran todos los templates para cada microcontrolador. Ahí puedes observar como Microchip recomienda e implementa la entrada y salida de las interrupciones y el porqué de usar los registros arriba de 0x70. No hay necesidad de saber en qué banco te encuentras cuando entras a salvar el contexto del programa. La hay cuando ya salvaste el contexto y empiezas a hacer tu rutina de interrupción.

Código: ASM
  1. ;**********************************************************************
  2. ;   This file is a basic code template for assembly code generation   *
  3. ;   on the PICmicro PIC16F877A. This file contains the basic code     *
  4. ;   building blocks to build upon.                                    *  
  5. ;                                                                     *
  6. ;   If interrupts are not used all code presented between the ORG     *
  7. ;   0x004 directive and the label main can be removed. In addition    *
  8. ;   the variable assignments for 'w_temp' and 'status_temp' can       *
  9. ;   be removed.                                                       *                        
  10. ;                                                                     *
  11. ;   Refer to the MPASM User's Guide for additional information on     *
  12. ;   features of the assembler (Document DS33014).                     *
  13. ;                                                                     *
  14. ;   Refer to the respective PICmicro data sheet for additional        *
  15. ;   information on the instruction set.                               *
  16. ;                                                                     *
  17. ;**********************************************************************
  18. ;                                                                     *
  19. ;    Filename:      xxx.asm                                           *
  20. ;    Date:                                                            *
  21. ;    File Version:                                                    *
  22. ;                                                                     *
  23. ;    Author:                                                          *
  24. ;    Company:                                                         *
  25. ;                                                                     *
  26. ;                                                                     *
  27. ;**********************************************************************
  28. ;                                                                     *
  29. ;    Files required:                                                  *
  30. ;                                                                     *
  31. ;                                                                     *
  32. ;                                                                     *
  33. ;**********************************************************************
  34. ;                                                                     *
  35. ;    Notes:                                                           *
  36. ;                                                                     *
  37. ;                                                                     *
  38. ;                                                                     *
  39. ;                                                                     *
  40. ;**********************************************************************
  41.  
  42.  
  43.         list            p=16f877A       ; list directive to define processor
  44.         #include        <p16f877A.inc; processor specific variable definitions
  45.        
  46.         __CONFIG _CP_OFF & _WDT_OFF & _BODEN_OFF & _PWRTE_ON & _RC_OSC & _WRT_OFF & _LVP_ON & _CPD_OFF
  47.  
  48. ; '__CONFIG' directive is used to embed configuration data within .asm file.
  49. ; The lables following the directive are located in the respective .inc file.
  50. ; See respective data sheet for additional information on configuration word.
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57. ;***** VARIABLE DEFINITIONS
  58. w_temp          EQU     0x71            ; variable used for context saving
  59. status_temp     EQU     0x72            ; variable used for context saving
  60. pclath_temp     EQU     0x73            ; variable used for context saving                     
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67. ;**********************************************************************
  68.         ORG     0x000             ; processor reset vector
  69.  
  70.         nop                       ; nop required for icd
  71.         goto    main              ; go to beginning of program
  72.  
  73.  
  74.         ORG     0x004             ; interrupt vector location
  75.  
  76.         movwf   w_temp            ; save off current W register contents
  77.         movf    STATUS,w          ; move status register into W register
  78.         movwf   status_temp       ; save off contents of STATUS register
  79.         movf    PCLATH,w          ; move pclath register into w register
  80.         movwf   pclath_temp       ; save off contents of PCLATH register
  81.  
  82. ; isr code can go here or be located as a call subroutine elsewhere
  83.  
  84.         movf    pclath_temp,w     ; retrieve copy of PCLATH register
  85.         movwf   PCLATH            ; restore pre-isr PCLATH register contents
  86.         movf    status_temp,w     ; retrieve copy of STATUS register
  87.         movwf   STATUS            ; restore pre-isr STATUS register contents
  88.         swapf   w_temp,f
  89.         swapf   w_temp,w          ; restore pre-isr W register contents
  90.         retfie                    ; return from interrupt
  91.  
  92.  
  93.  
  94. main
  95.  
  96. ; remaining code goes here
  97.  
  98.  
  99.  
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.         END                       ; directive 'end of program'

Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 08 de Noviembre de 2008, 04:08:13
Supongo que ya lo sabes de antemano, pero en "Archivos de Programa\Microchip\MPASM Suite\Template\Code" se encuentran todos los templates para cada microcontrolador. Ahí puedes observar como Microchip recomienda e implementa la entrada y salida de las interrupciones y el porqué de usar los registros arriba de 0x70.

 :shock: :shock: :shock:
 :5] :5] :5]
Yo creia que se me habia ocurrido algo GENIAL... Llevo HORAS tratando de ingeniarmelas para esquivar los BTF
:8} :8} :8}

Bueno... no se puede reinventar la rueda... pero al menos me queda el consuelo de saber que lo descubri solito   :P
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 08 de Noviembre de 2008, 08:59:35
Buenas

Bueno, yo también ya sabía eso, pero pensé que la idea tampoco era
Solo hay una cosita que no consigo entender, porque la segunda optimizacion ocupa mas instrucciones que la primera? Puede ser que las hayas puesto al reves?

Hmm...según lo que yo veo, la 2da ocupa 3 instrucciones menos que la 1era, o estaré loco?

Sino tampoco me cuadra lo de no poder usar el registro 0x2C en todo el programa.

El 0x2C lo usé como bit auxiliar para recordar el banco al ingresar a la ISR. Si el compilador usara ese registro, se destruiría dentro de la ISR desde qué banco ingresó. :)

Y ahora me dejo de preguntas y me someto a "examen". Aplicando todo lo aprendido sobre direccionamiento directo e indirecto quiero ver si apruebo con el siguiente codigo:

Código: ASM
  1. 004    MOVWF    0x70
  2. 005    SWAPF    STATUS, W
  3. 006    MOVWF    0x71
  4. .
  5. .
  6. .
  7. [Todo el resto]

Sencillo... Jeje... Ahora explico lo que hace, o al menos lo que me gustaria que haga  :D
El codigo original, y el de Bruno hacen una comprobacion para ver en que banco se encuentrar para poder luego ir al banco 0 y salvar el contexto. Este codigo lo que hace es no preocuparse de ver en que banco estamos, aprovechar el direccionamiento directo, que solo son 7 bits y asi grabar en la posicion 70h el contenido de W, y en 71h el contenido de STATUS. No nos importa en que banco estemos porque si estamos en el banco 1, y grabamos en el registro 70h, estaremos grabando en realidad en el registro F0h (esto lo aprendi de jacrmr  :mrgreen:). Y si estamos en el banco 0, y grabamos en el registro 70h, estaremos grabando exactamente en ese registro (obvio). Lo bonito de esto es que los registros del F0h al FFh acceden directamente a los registros 70h al 7Fh, por lo que siempre estaremos grabando en el banco 0, aunque nos encontremos en el banco 1. De esta manera nos ahorramos la comprobacion del principio y usar mas memoria de la necesaria... Y lo mas interesante para tener los tiempos controlados es evitar que el programa se bifurque consumiendo 1 o 2 ciclos dependiendo de algunas cosas.
Que opinas? Estoy aprobado? o la teoria es muy bonita pero estoy dando palos de ciego?  :D

PS: por cierto, al compilar en C, se genera algun archivo en ASM que pueda cargar y modificar directamente desde MPASM? Porque el .lst no se si sera "apto".

Ja ja. No hombre, muy bien! Creeme que cuando yo había empezado con ASM no se me hubiese ocurrido. Si, los 16 registros son muy útiles para lograr lo que querés. Yo no me fui fuera de lo que el  compilador pretendía. Pensé que no querías tocar esos registros ni ningúno fuera de los que el CCS ya utilizaba. Obviamente que vale siempre y cuando no esté el CCS usandolos a dichos registros(los que elijas entre los 16 que hay).

Y jacrmr, no seas tan duro con el chico, eh? :P :D

Saludos

Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: jacrmr en 08 de Noviembre de 2008, 13:51:53
Citar
Y jacrmr, no seas tan duro con el chico, eh? 


No, para nada. Al contrario, me entusiasma mucho cuando alguien le toma interés al ASM.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 08 de Noviembre de 2008, 16:07:34
jacrmr, no seas tan duro conmigo, eh!  :D :D :D

Disculpa bruno, tienes razon, el 4º codigo esta mas optimizado que el tercero... lo que paso fue que al imprimirlos para analizarlos los mezcle y les puse el titulo intercambiado. Por eso mismo tampoco me cuadraba lo del registro auxiliar 0x2C  :oops:

Gracias a todos por la ayuda prestada! Creo que a estas alturas ya puedo armar mi propia rutina de ISR  :-/
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 10 de Noviembre de 2008, 00:02:50
Hola otra vez! 
ESTOY FELIZ :mrgreen:
Mirad lo que encontre en la ayuda del CCS:
Citar
Syntax:
 #int_global
 
Elements:
 None
 
Purpose:
 This directive causes the following function to replace the compiler interrupt dispatcher.  The function is normally not required and should be used with great caution.  When used, the compiler does not generate start-up code or clean-up code, and does not save the registers.
 
Examples:
 
Código: C
  1. #int_global
  2. isr() {     // Will be located at location 4 for PIC16 chips.
  3.    #asm
  4.    bsf   isr_flag
  5.    retfie
  6.    #endasm
  7. }

Es lo que creo que es, no?
Si es asi me ahorro el tener que andar compilando el programa en C, y luego modificar el ASM generado cada vez que quiero hacer una prueba!
Eso si, la ISR la escribire en ASM igualmente, ya que de lo que trataba todo esto era de que lSR "midiera" exactamente lo que yo necesito.
Salu2!
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 10 de Noviembre de 2008, 01:11:34
Así es..Congratulations! yo nunca supe de su existencia :D

Saludos
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 10 de Noviembre de 2008, 04:27:10
 :?
Mi alegria no podia ser total y absoluta...
Segun estuve mirando, si se usa #int_global, no se pueden usar las demas #int_xxx. Esto implica que el int_global se tiene que encargar de TODO. Ademas de salvar el contexto y comprobar que interrupcion salto, tambien debemos incluir el codigo que queramos ejecutar para cada int, dentro del mismo int_global. Queda todo demasiado condensado para mi gusto... pero aun asi, es un gran descubrimiento poder encargarme del ISR  :mrgreen:

Bruno, una consulta. En los codigos que optimizaste utilizas la siguiente estructura para comprobar si salto la interrupcion:
Código: ASM
  1. BTFSC INDF, TMR1IE
  2. BTFSS PIR1, TMR1IF
  3. GOTO 0x50    ;TIMER1 ISR

y segun entiendo, si esta deshabilitada TMR1IE salta una instruccion, con lo cual llega al GOTO y entra a la interrupcion, pero no deberia
en el otro caso, si TMR1IE esta habilitada, sigue con la siguiente instruccion, que si esta habilitado el flag TMR1IF salta una instruccion, por lo que no entra, aunque deberia.

La verdad me son un poco complicados de seguir los BTF, y tal vez los este interpretando mal  :?
Que opinas?
Salu2
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: BrunoF en 10 de Noviembre de 2008, 11:07:39
 :shock: :shock: :shock:

Tenés razón. Cuando yo cometo un error así,es para ver si la persona estaba atenta a mi explicación  :mrgreen:  :lol: :D

Nah, mentira. Me equivoqué. No se por que se me chispoteó y las hice al revés, negadas.

Saludos.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 10 de Noviembre de 2008, 13:05:00
Me parece genial que me pongas "equivocaciones" trampa para ver si estoy atento  :mrgreen:
Gracias a ti y los compañeros que me ayudaron en este hilo ya "se" lo minimo de ASM!!  :-/

Lo que comentas del codigo, aunque esten al reves, negadas, puede ser que le falte un GOTO entre los BTF? sino no veo la manera de que funcione.
Yo lo resolvi asi:

Código: C
  1. TIMER1: //--------------------
  2.         BTFSS    INDF, TMR1IE   //si esta habilitada la int, salta...
  3.         GOTO     CCP1           //...sino continua hacia la siguiente int a comprobar
  4.         BTFSC    PIR1, TMR1IF   //si esta desactivado el flag, salta...
  5.         GOTO     TMR1_INT       //...sino ejecuta la interrupcion

Ese codigo funciona. De hecho, todo el #int_global funciona!  :-/
Si alguien quiere aprovecharlo me quedo asi:

Código: C
  1. //reserva posiciones de memoria para salvar contexto
  2. #reserve 0x70, 0x71, 0x72, 0x73
  3.  
  4. //Constantes ASM
  5. #define W               0
  6. #define F               1
  7.  
  8. #define INDF    0x00
  9. #define STATUS  0x03
  10. #define PCLATH  0x0A
  11. #define FSR             0x04
  12. #define PIR1    0x0C
  13. #define PIE1    0x8C
  14.  
  15. #define TMR1IF  0
  16. #define CCP1IF  5
  17.  
  18. #define TMR1IE  0
  19. #define CCP1IE  5
  20.  
  21. #define W_AUX   0x70    //W
  22. #define S_AUX   0x71    //STATUS
  23. #define P_AUX   0x72    //PCLATH
  24. #define F_AUX   0x73    //FSR
  25.  
  26. #int_GLOBAL
  27. void ISR(void){
  28.         #asm
  29.         //Guardar contexto
  30.         MOVWF   W_AUX           //guardo el contenido de W
  31.         SWAPF   W_AUX, F        //swap a W
  32.  
  33.         SWAPF   STATUS, W       //cargo W con STATUS
  34.         MOVWF   S_AUX           //guardo STATUS en 0x71
  35.  
  36.         MOVF    PCLATH, W       //cargo W con PCLATH
  37.         MOVWF   P_AUX           //guardo PCLATH en 0x72
  38.         CLRF    PCLATH          //borro PCLATH
  39.  
  40.         MOVF    FSR, W          //cargo W con FSR
  41.         MOVWF   F_AUX           //guardo FSR en 0x73
  42.        
  43.         MOVLW   PIE1            //puntero de PIE1...
  44.         MOVWF   FSR                     //...en FSR
  45.        
  46. TIMER1: //--------------------
  47.         BTFSS   INDF, TMR1IE    //si esta habilitada la int, salta...
  48.         GOTO    CCP1                    //...sino continua hacia la siguiente int a comprobar
  49.         BTFSC   PIR1, TMR1IF    //si esta desactivado el flag, salta...
  50.         GOTO    TMR1_INT                //...sino ejecuta la interrupcion
  51.        
  52. CCP1:   //--------------------
  53.         BTFSS   INDF, CCP1IE    //si esta habilitada la int, salta...
  54.         GOTO    RESTAURAR               //...sino va a restaurar contexto y sale del ISR
  55.         BTFSC   PIR1, CCP1IF    //si esta desactivado el flag, salta...
  56.         GOTO    CCP1_INT                //...sino ejecuta la interrupcion
  57.         GOTO    RESTAURAR               //sale del ISR
  58.        
  59. TMR1_INT:
  60.         //codigo de INT_TIMER1
  61.         //......
  62.  
  63.         BCF             PIR1, TMR1IF//resetea el flag
  64.         BCF             PCLATH, 3       //
  65.         GOTO    RESTAURAR       //restaura el contexto
  66.  
  67. CCP1_INT:
  68.         //codigo de INT_CCP1
  69.         //......
  70.  
  71.         BCF     PIR1, CCP1IF    //resetea el flag
  72.         BCF     PCLATH, 3
  73.         GOTO RESTAURAR          //restaura el contexto
  74.  
  75. RESTAURAR:      //Restaurar contexto
  76.         MOVF    F_AUX, W        //cargo W con F_AUX
  77.         MOVWF   FSR                     //restauro valor de FSR
  78.  
  79.         MOVF    P_AUX, W        //cargo W con P_AUX
  80.         MOVWF   PCLATH          //restauro valor de PCLATH
  81.  
  82.         SWAPF   S_AUX, W        //cargo W con S_AUX
  83.         MOVWF   STATUS          //restauro valor de STATUS
  84.  
  85.         SWAPF   W_AUX, W        //restauro valor de W
  86.         #endasm
  87. }

Modificandolo un poquito se puede adaptar a otras interrupciones.
las instrucciones "BCF PCLATH, 3" que estan en la linea 39 y 47 no se para que sirven, vienen por defecto cuando sales de una INT en CCS. Probablemente se puedan omitir.

Ahora mis servos no se adelantan ni se retrasan ni 1uS!!  :-)
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: jacrmr en 11 de Noviembre de 2008, 19:46:36
Seguramente te benficiará el nuevo cambio de arquitectura de Microchip en toda su línea Mid-Range PIC12 y PIC16 que saldrá empezando el 2009. En estos dispositivos (que serán compatibles con los actuales) el contexto de la interrupción se guardará por hardware y no con software como se ha estado haciendo.
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Marttyn en 11 de Noviembre de 2008, 22:15:09
Seguramente te benficiará el nuevo cambio de arquitectura de Microchip en toda su línea Mid-Range PIC12 y PIC16 que saldrá empezando el 2009. En estos dispositivos (que serán compatibles con los actuales) el contexto de la interrupción se guardará por hardware y no con software como se ha estado haciendo.

Estuve mirando un poco y la verdad tienen muy buena pinta! Ademas de salvar el contexto automaticamente tambien cuenta con 2 registros INDF, aumentan a 49 el numero de intrucciones, stack de 16 niveles...
http://www.microchip.com/stellent/idcplg?IdcService=SS_GET_PAGE&nodeId=2692&redirects=enhanced

Espero que levanten la restriccion de los samples para probar estos micros nuevos  :mrgreen:
Título: Re: Entrar a interrupcion en ASM, en entorno C
Publicado por: Mario en 20 de Febrero de 2009, 19:54:16
Espero que levanten la restriccion de los samples para probar estos micros nuevos  :mrgreen:


Pues yo tuve que pagar los 7.50 para que me llegarán unos 24H y 24F que se pidieron en Diciembre  del 2008, no creo que lo levanten.