Autor Tema: Interrupciones deshabilitadas para evitar la reentrada  (Leído 3293 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado franda2005

  • PIC10
  • *
  • Mensajes: 12
Interrupciones deshabilitadas para evitar la reentrada
« en: 14 de Febrero de 2017, 08:12:41 »
Buenos dias.

Tengo una duda con este programa de prueba:

Código: [Seleccionar]
include <16f876a.h>
#fuses XT,NOWDT,NOPROTECT,PUT,NOBROWNOUT,NODEBUG,NOLVP,NOCPD
#use delay(clock=4000000)   
#use fast_io(A)
#use fast_io(B)


//#use delay(clock=4000000)
#INT_EXT                     
void interrupcionRB0()       
{
   delay_ms(4000);               
   output_toggle(pin_a5);       
}

//#use delay(clock=4000000)
void main()
{
   set_tris_a(0x00);
   set_tris_b(0xFF);

   ext_int_edge(L_TO_H);         

   enable_interrupts(GLOBAL);   

   enable_interrupts(INT_EXT);   

   output_a(0x00);             

   while (true)
   {
      output_toggle(pin_a0);   
      delay_ms(1000);         
   }
}

Cuando se compila aparece el warning "Interrupts disabled to prevent re-entrancy [delay_ms1]", que a mi entender significa que mientras se este ejecutando el delay_ms(1000);  del while el compilador, deshabilita las interrupciones para que no se entre a la interrupcion externa a ejecutar la misma funcion delay_ms (recursividad).

Esto sin embargo no sucede, cuando esta en el delay_ms(1000);  del while si que entra en la interrupcion y ejecuta el delay_ms(4000);  de su interior ???. Probado fisicamente y con PROTEUS.

Por que pasa esto y no deshabilita la interrupcion?

PD. Solo es un programa de prueba

« Última modificación: 14 de Febrero de 2017, 14:14:48 por franda2005 »

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5552
    • Picmania by Redraven
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #1 en: 14 de Febrero de 2017, 11:20:13 »
No estoy seguro del todo, igual algún compañero me corrige o amplía la información, pero el CCS me tira esta misma advertencia cada vez que DENTRO de una interrupción hago una llamada a una función externa, en el caso de tu ejemplo el delay_ms(4000); Prueba a comentar esa línea y compilar, creo que desaparece el  warning "Interrupts disabled to prevent re-entrancy [delay_ms]"
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado franda2005

  • PIC10
  • *
  • Mensajes: 12
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #2 en: 14 de Febrero de 2017, 14:23:31 »
Si eso esta claro, si quitas el delay_ms(4000) desaparece el warning al desaparecer la recursividad (llamar a la funcion delay_ms desde dentro de otra delay_ms).

La duda es si mantenemos los dos delay_ms porque se ejecuta el codigo de la interrupcion si se supone que el compilador ha deshabilitado las interrupciones.

O las deshabilita cuando le da la gana?  :shock:

Desconectado colotron

  • PIC12
  • **
  • Mensajes: 73
    • Canal de YouTube
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #3 en: 15 de Febrero de 2017, 11:39:27 »
Si eso esta claro, si quitas el delay_ms(4000) desaparece el warning al desaparecer la recursividad (llamar a la funcion delay_ms desde dentro de otra delay_ms).

La duda es si mantenemos los dos delay_ms porque se ejecuta el codigo de la interrupcion si se supone que el compilador ha deshabilitado las interrupciones.

O las deshabilita cuando le da la gana?  :shock:

Yo creería que las deshabilita al momento de llamar a la función (justo antes o después de poner los parámetros de la función en la pila) y las vuelve a habilitar luego de retornar de la función.
Es decir: las interrupciones están deshabilitadas solo cuando se ejecuta la función delay().

¿Pero antes mencionabas que la interrupción salta mientras se está ejecutando el delay o entendí mal?.
¿Como verificaste eso? (breakpoint dentro de rutina de interrupción?).

De todas formas no es aconsejable usar un retardo de 4 segundos dentro de una interrupción porque el programa se va a quedar "clavado" ahí y no va a tener respuesta a cualquier estímulo externo en ese estado, pero siendo un programa de pruebas.

Para aclarar términos: reentrada no se refiere a lo mismo que recursividad. En C para micros la recursividad no está en general soportada porque la pila se llenaría al hacer un número indeterminado de llamadas a función anidadas. Hay excepciones (llamada a función recursiva como última instrucción de la función recursiva para reutilizar la pila) pero no es nada frecuente verlo.

Reentrada se refiere a qué pasa cuando una función se llama desde 2 o más hilos/tareas/threads a la misma vez. Llevado al caso de los micros sin usar RTOS ni ninguna de esas yerbas, solo hay 2 hilos posibles: el código normalito del main, y el código de interrupción.
Bueno... creo que algunos pics tienen interrupción de alta prioridad y baja prioridad y que la de alta puede interrumpir a la de baja... ahí sería 3 hilos.

Entonces, si una función escribe variables globales (variables del programa, puertos, periféricos) muy probablemente no sea re-entrante, y por eso el compilador - dado que el posible conflicto solo es entre código de interrupción y código normal - introduce la deshabilitación de interrupción antes de llamarla y habilitación luego de retornar como forma básica de evitar problemas de reentrada para este caso particular de microcontrolador sin ningún sistema operativo (la función siempre se ejecuta de un tirón sin ser interrumpida por nadie).

Conclusión: creo que el compilador deshabilita interrupciones antes de llamar a delay() y las vuelve a habilitar luego del retorno de delay(). Introduce ese código en el prólogo (deshabilitar) y epílogo (habilitar) de la función.

Como probar si la rutina delay está siendo interrumpida?, con alguna trampa de prueba como:

volatile unsigned int delayActivo = 0;

void MiDelay(unsigned long cuentas) {
   if(delayActivo) {
      //poner un punto de interrupción o while(1) para colgar a propósito el programa
      //esto significaría que se llamó a MiDelay() desde la interrupción cuando
      //se estaba ejecutando el MiDelay del while(1)
      //Si el compilador hizo bien su trabajo este punto nunca debería alcanzarse.
   } else {
      delayActivo = 1;
      delay(cuentas);
   }
}

void main(void) {

//...

   while(1) {
      //...
      MiDelay(blabla);
   }
}


void Interrupcion(void){
   //...
   MiDelay(blabla2);
}

Desconectado franda2005

  • PIC10
  • *
  • Mensajes: 12
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #4 en: 15 de Febrero de 2017, 14:07:33 »
El programa en concreto tiene dos temporizaciones, una de 1s en el while y otra de 4s en la interrupcion. Si cuando esta temporizando en mitad del delay_ms(1000) del while pulsamos en RB0 salta la interrupcion y temporiza el delay_ms(4000) de la interrupcion para luego volver y acabar los ms que le restasen ... y esto creo que entra en conflicto con el warning "Interrupts disabled to prevent re-entrancy [delay_ms1]".

Lo he comprobado fisicamente.

Desconectado colotron

  • PIC12
  • **
  • Mensajes: 73
    • Canal de YouTube
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #5 en: 15 de Febrero de 2017, 18:49:42 »
El programa en concreto tiene dos temporizaciones, una de 1s en el while y otra de 4s en la interrupcion. Si cuando esta temporizando en mitad del delay_ms(1000) del while pulsamos en RB0 salta la interrupcion y temporiza el delay_ms(4000) de la interrupcion para luego volver y acabar los ms que le restasen ... y esto creo que entra en conflicto con el warning "Interrupts disabled to prevent re-entrancy [delay_ms1]".

Lo he comprobado fisicamente.

Ah ok, entonces se ve que el compilador no está haciendo lo que yo decía...
Si querés lo podés hacer manualmente con:

void MiDelay_ms(unsigned int ms) {
  disable_interrupts(GLOBAL);
  delay_ms(ms);
  enable_interrupts(GLOBAL);
}
 

Desconectado franda2005

  • PIC10
  • *
  • Mensajes: 12
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #6 en: 16 de Febrero de 2017, 04:15:45 »
Gracias colotron, no es problema de funcionamiento. Es averiguar porque el compilador dice que deshabilita las interrupciones cuando en realidad no lo esta haciendo.

Por cierto el warning desaparece si delante del main metemos #use delay(clock=4000000), pero eso no me interesa, me interesa saber porque el puñetero del compilador promete una cosa y no la cumple.

Desconectado franda2005

  • PIC10
  • *
  • Mensajes: 12
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #7 en: 16 de Febrero de 2017, 16:11:57 »
Creo que tengo la respuesta. Lo he sacado mirando el archivo .lst

Código: [Seleccionar]
....................    while (true)
....................    {
....................       output_toggle(pin_a0);     
0066:  MOVLW  01
0067:  XORWF  05,F
....................       delay_ms(1000);           
0068:  MOVLW  04
0069:  MOVWF  28
006A:  CLRF   27
006B:  BTFSC  0B.7
006C:  BSF    27.7
006D:  BCF    0B.7                   <----------------- bit GIE=0 (lo inhabilita)
006E:  MOVLW  FA
006F:  MOVWF  2B
0070:  CALL   02F                    Esto va al trozo de codigo del #use delay(clock=4000000)
0071:  BTFSC  27.7
0072:  BSF    0B.7                    < --------------- bit GIE=1 (lo vuelve a habilitar)
0073:  DECFSZ 28,F
0074:  GOTO   06A
....................    }
0075:  GOTO   066
.................... }


Si cuando esta temporizando 1s llega la interrupcion el bit parcial INTE=1 y cuando llegue la linea BSF    0B.7 saltara la interrupcion con lo cual deja la temporizacion de 1s y se mete en la interrupcion para hacer la temporizacion de 4s.

Estoy en lo cierto o estoy metiendo la gamba?

Desconectado franda2005

  • PIC10
  • *
  • Mensajes: 12
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #8 en: 16 de Febrero de 2017, 16:33:00 »
Creo que ya todo va teniendo sentido. El mensaje exacto del warning del compilador es:  "Interrupts disabled during call to prevent re-entrancy [delay_ms1]", es decir que deshabilita las interrupciones durante la llamada (call) y permanencia en la subrutina, pero cuando sale de ella las vuelve a habilitar con el BSF    0B.7 para de nuevo hacer otro call ...

Con lo cual si entre llamada y llamada INTE=1 salta a la interrupcion sin terminar de temporizar.

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:Interrupciones deshabilitadas para evitar la reentrada
« Respuesta #9 en: 23 de Febrero de 2017, 15:13:36 »
Tal ves lo hace por que debe anidar varios delays, y por miedo a que se le termine el Stack que posee el PIC de llamadas, ya que una entrada a la interrupcion es otra llamada mas.


 

anything