TODOPIC
Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: Robert76 en 11 de Abril de 2021, 20:38:31
-
Buenas a la comunidad, estuve buscando en el foro, algún tema relacionado pero no encontré algo preciso.
Comento el asunto.
Estoy Armando un código en CCS, que utiliza varias interrupciones, entre ellas uso TMR0, TMR1 y TMR2.
El punto está en que hay una parte del código que no se ejecuta cuándo debe(condición IF) o lo hace de forma aleatoria. He puesto marcas dentro del bucle para debuguear y efectivamente NO entra en esa condición a pesar que se dan las condiciones.
Lo que he notado es que si desactivo las interrupciones, el programa corre de maravillas.
Las he desactivado de a una para ir acercándome al problema, pero no, el problema desaparece cuándo no hay interrupciones en proceso.
Ahora viene la pregunta, será un problema del compilador?
El PIC utilizado es un 18F2550, también probé un 16F819 con los mismos resultados.
-
Es difícil imaginar qué puede estar pasando, la mayoría de las causas de errores insólitos son insólitas.
Subí un bloque de código que pueda compilarse para ver qué puede ser.
-
Intenta recrearlo con lo minimo posible, un cambio de salidas en la interrupciones. Y ese if...
Puede ser el compilador y su efecto de optimizar el código. Si estas usando alguna variable que se comparte, proba ponerle ponerle el "volatile" a las variables que se usen en la interrupción y en el programa, tal ves eso haga cambiar la decisión del compilador de quitarla.
Si podes recrearlo con lo minimo, luego se puede llegar a ver el ASM resultante para ver que paso con esa parte del codigo.
-
El if que no se ejecuta, ¿está dentro del handler de interrupción?.
¿Depende de alguna variable local?..
Prueba desactivando las optimizaciones para intentar descartar que sea por lo que dice KillerJC.
-
Gracias por las respuestas, apenas pueda subo el código que es muy simple.
El IF está en la función principal.
Creo que el tema viene por el lado variables. Cómo la memoria de los PICs viene fragmentada, me parece que hay algunas solapadas por error del compilador.
Ya que un array según el tamaño que se lo defina, por ejem a var[64] aparece otro comportamiento errático en otra variable, que se vuelve cero, y en ningún momento le asigno ese valor. Ahora sí lo defino más pequeño, digamos var[16] no ocurre ese detalle.
-
Aquí les comparto parte del código.
El problema se da en la condición IF en dónde compara la variable rebot==200, la variable se incrementa aparentemente pero por algún motivo, NO llega al valor 200 o bien lo saltea!
#include <18F2550.h>
//#device adc=10
#fuses NOWDT, HSPLL, NOPUT, PROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT, CPUDIV1, PLL3, NOMCLR, NOVREGEN, RESERVED
#use delay (clock=12000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#zero_ram
///////////////////////////////////////////////////////////////////////////////
static int bufl[1950];
static int ptc=1;
static long rebot, x, y, pitch=130;
void main(void)
{
set_tris_a(0b11111111);
set_tris_b(0b00000000);
set_tris_c(0b00000011);
output_b(0);
///////////////////////////////////////////////////////////////////////////////
setup_adc( ADC_CLOCK_DIV_2);
setup_adc_ports(AN0|VREF_VREF); // VRef_min=A2 Vref_max=A3
set_adc_channel(0); // Habilita A0= ent Analog
read_adc(ADC_START_ONLY);
//ADFM=1;
///////////////////////////////////////////////////////////////////////////////
setup_timer_2(T2_DIV_BY_1,255,1);
setup_ccp1(CCP_PWM);
//CCP1CON=0b00001100;
///////////////////////////////////////////////////////////////////////////////
setup_timer_0(T0_INTERNAL|T0_8_BIT|T0_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
//setup_timer_2(T2_DIV_BY_1,1,1);
///////////////////////////////////////////////////////////////////////////////
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
disable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(true)
{
if(!RC0||!RC1) // Lee botón (A4=-) (A4=+)
{
if(rebot==200) // ===> La variable rebot no se incrementa cuándo debe
{
...
}
if(rebot<500)rebot++;
}
else rebot=0;
}
}
#INT_GLOBAL
void isr_global()
{
if(TMR0IF)
{
TMR0IF=0; // Resetea bit interrup
...
}
if(TMR1IF)
{
TMR1IF=0; // Resetea bit interrup
...
}
}
-
Aquí les comparto parte del código.
El problema se da en la condición IF en dónde compara la variable rebot==200, la variable se incrementa aparentemente pero por algún motivo, NO llega al valor 200 o bien lo saltea!
#include <18F2550.h>
//#device adc=10
#fuses NOWDT, HSPLL, NOPUT, PROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT, CPUDIV1, PLL3, NOMCLR, NOVREGEN, RESERVED
#use delay (clock=12000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#zero_ram
///////////////////////////////////////////////////////////////////////////////
static int bufl[1950];
static int ptc=1;
static long rebot, x, y, pitch=130;
void main(void)
{
set_tris_a(0b11111111);
set_tris_b(0b00000000);
set_tris_c(0b00000011);
output_b(0);
///////////////////////////////////////////////////////////////////////////////
setup_adc( ADC_CLOCK_DIV_2);
setup_adc_ports(AN0|VREF_VREF); // VRef_min=A2 Vref_max=A3
set_adc_channel(0); // Habilita A0= ent Analog
read_adc(ADC_START_ONLY);
//ADFM=1;
///////////////////////////////////////////////////////////////////////////////
setup_timer_2(T2_DIV_BY_1,255,1);
setup_ccp1(CCP_PWM);
//CCP1CON=0b00001100;
///////////////////////////////////////////////////////////////////////////////
setup_timer_0(T0_INTERNAL|T0_8_BIT|T0_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
//setup_timer_2(T2_DIV_BY_1,1,1);
///////////////////////////////////////////////////////////////////////////////
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
disable_interrupts(INT_TIMER2);
enable_interrupts(GLOBAL);
while(true)
{
if(!RC0||!RC1) // Lee botón (A4=-) (A4=+)
{
if(rebot==200) // ===> La variable rebot no se incrementa cuándo debe
{
...
}
if(rebot<500)rebot++;
}
else rebot=0;
}
}
#INT_GLOBAL
void isr_global()
{
if(TMR0IF)
{
TMR0IF=0; // Resetea bit interrup
...
}
if(TMR1IF)
{
TMR1IF=0; // Resetea bit interrup
...
}
}
¿Y no puede pasar que llegues tarde al if??.
Si rebot se incrementa por ejemplo en la interrupción puede estar pasando que ya esté a 201 cuando pasas por el if. En tal caso, ¿te viene mal poner if(rebot>=200) ? Para que tenga en cuenta no solo que llegue a 200, sino que se pase...
-
A ese código le agregué unas definiciones para que me compile
#bit TMR0IF=GETENV("SFR:INTCON").2
#bit TMR1IF=GETENV("SFR:PIR1").0
#bit RC0=GETENV("SFR:PORTC").0
#bit RC1=GETENV("SFR:PORTC").1
y el cambio en un pin para comprobar si pasa.
if(rebot==200) // ===> La variable rebot no se incrementa cuándo debe
{
output_toggle(PIN_B0);
while(!RC0||!RC1) ;
}
Con este circuito de prueba anda lo mas bien...
- Tienes que ingresar para ver archivos adjuntos -
??????
-
Respondiendo a REMI04, lo que comentas sobre que la interrupción evita que justo cuándo cuándo cuenta de 200 a 201 llegue tarde, así que reduje la velocidad del timer para hacer las interrupciones más espaciadas, y nada... la cosa sigue igual.
Además una interrupción sólo interrumpe un proceso, NO puede hacer que el programa principal se saltee acciones.
Sólo puedo usar la comparación ==200 ya que debe entrar sólo una vez al IF.
Por otro lado, desde que uso interrupciones, es la 1ra. vez que tengo un problema así.
Voy a analizar el trabajo que te tomaste EDUARDO2, muchas gracias. Luego comentaré. ((:-))
Sospecho en que hay problemas con la versión del compilador, creo tener la 4.02 o algo así.
-
Edito lo que estuve escribiendo porque hay cosas que no van :(
------------Va de nuevo -------------------
La interrupción global debe ser declarada como #INT_GLOBAL FAST para que te salve el estado, pero antes tenes que habilitarlas al principio con #DEVICE HIGH_INTS=TRUE
De lo contrario te vuelve de la interrupción con un RETFIE 0 (no recupera estado) en lugar de un RETFIE 1 (recupera estado)
-
Voy a ver ésto que mencionas.
Ya que es la 1ra. Vez que uso una función global de interrupciones y discrimo cuál se disparó dentro de dicha función.
Gracias Eduardo2.
-
Ojo que la opción #INT_GLOBAL FAST es para los 18F, en los 16F hay que salvar y recuperar el estado a mano.
-
Hola, estuve chequeando sobre tu recomendación, y el resultado es el mismo.
Estoy simulando y probando en protoboard un 18F.
Probé en otro compilador y la cosa sigue igual.
Eliminé la función GLOBAL, y me remití a usar cada interrupción con su función individual, y el problema persiste.
Así que eliminé todo lo que hay en la función principal y coloqué la sig línea, que no es más que reflejar el estado de B0 en B7.
Increíble tener que llegar a ésto :(
botons=input_b()&1;
if(botons!=1)output_high(pin_B7); else output_low(pin_B7);
Y el programa NO lee el puerto y si lo hace NO provoca cambios. en el puerto B7.
Honestamente he probado casi todo sin resultados favorables.
Pero si desactivo la habilitación de interrupciones globales. La línea de programa trabaja cómo debe.
-
Así que eliminé todo lo que hay en la función principal y coloqué la sig línea, que no es más que reflejar el estado de B0 en B7.
Mientras menos tenga el programa, mejor, pero me gustaria si es posible que me pases el .hex del programa mas sencillo que puedas hacer (con la menor cantidad de lineas de programacion) y que presente ese error
Y luego otro hex, con lo mismo, pero deshabilitando la interrupcion.
-
Creo que acabo de arrimarme al problema.
Me doy cuenta que en principio NO sería culpa de las interrupciones.
Lo que hice fue desactivar el almacenamiento de datos de un array que tiene 512 elementos dentro de una función de interrupción.
Y ahora lee el puerto.
Pero... entonces?
Seguramente estoy pisando datos en posiciones de memoria que usa el programa?
Cómo puedo saber que región usar de memoria para datos del programa huésped?
Apenas pueda KILLER te comparto un .hex del problema es cuestión. Ahora estoy escribiendo desde el celular.
-
Creo que acabo de arrimarme al problema.
Me doy cuenta que en principio NO sería culpa de las interrupciones.
Lo que hice fue desactivar el almacenamiento de datos de un array que tiene 512 elementos dentro de una función de interrupción.
Y ahora lee el puerto.
Pero... entonces?
Seguramente estoy pisando datos en posiciones de memoria que usa el programa?
Cómo puedo saber que región usar de memoria para datos del programa huésped?
Apenas pueda KILLER te comparto un .hex del problema es cuestión. Ahora estoy escribiendo desde el celular.
Mas que el .hex convendría el fuente, pero uno que haga la falla. Lo que subiste antes tenía la interrupcion vacía.
-
Por eso a tí te funcionó en la simulación, porque no escribía ningún dato en la RAM.
Estoy investigando cómo poder reservar y usar RAM sin que solape con registros de uso interno.
Porque ahí está el tema.
-
Por esas casualidades... Cuando escribís la RAM lo hacés antes o después de resetear TMR0IF ?
-
Lo intenté de ambas maneras. Es decir al principio de la función y también antes de salir.
Pero no hubo cambios.
El programa lo que hace es muestrear audio, y almacenarlo en un buffer de 512 bytes.
Pero luego de reproducirlo, veo que aparecen pequeños picos en el audio reproducido.
Y probando de usar un buffer más chico, por ejem. la mitad, esos picos desaparecen.
Por lo que también me lleva a pensar que el buffer que almacena los datos está usando registros del programa, y ahí se arma la tosca!
La solución a todos esos males, es buscar la manera de organizar la RAM para evitar esos conflictos,(que por cierto en muchas oportunidades he tenido problemas anómalos, y veo que todo tiene que ver con eso)
Estoy investigando sobre la organización de la RAM, hay una directiva llamada #reserved, que nunca usé. Voy a ver que hace exactamente.
-
Mas que el .hex convendría el fuente, pero uno que haga la falla. Lo que subiste antes tenía la interrupcion vacía.
Es que no poseo el compilador CCS, y siendo muy sencillo el programa, deberia ser facil localizar la variable que se compara con 200 o un valor fijo
-
Que tal KILLER? Paso a contar sobre el detalle.
Después de tantos intentos, el problema viene por la forma en que el compilador asigna el espacio de RAM a los arrays del programa.
Ayer comencé a desactivar uno a uno, hasta que de repente, el programa lee los dos puertos que tiene asignado a un botón cada uno.
Leyendo un poco encontré info. cómo manipular la RAM.
Y encuentro la directiva #reserve, pero sólo sirve para asignar locaciones para uso exclusivo del compilador, listo eso terminó ahí.
Continué buscando el problema y veo que según el tamaño que asigne a los arrays el problema se daba o no.
Entonces empecé a dimensionar los arrays con valores múltiplos de 2, más específicamente de 256 en 256, de esa manera no hubo problemas, por ejem. 1023, 1535 o 1791.
Luego he intentado provocar la falla, y no lo he conseguido, probé con los valores cercanos a los que usé, y no hubo forma, desconcertándome aún más :shock: :shock:
En conclusión, al asignar un array tipo short var[1500] o similar, me apareció el problema. Estimo que el array estaba pisando algún valor de algún registro de uso interno cómo lo mencioné antes.
Además añadiendo la línea
#DEVICE HIGH_INTS=TRUE ,( muy bien sugerida por Eduardo2), el programa trabaja estable.
Espero le sirva a alguien más, aunque NO encontré el problema en si, pero funciona cómo debe. Veo que muchos han tenido problemas similares al mío, al trabajar con arrays de gran tamaño en los pic 18F.
Gracias por la colaboración!!!👏👏👏
-
Hola gente, bueno, les comparto parte del código (sólo por curiosidad, ya que pude hacerlo funcionar)en dónde manifiesta error en los puertos, según el tamaño del array llamado
bufl[].
Si dicho array tiene 100 elementos por ejem. todo funciona cómo debe, ahora si lo dimensionamos a 300 elementos, aparecen la falla de que no actualiza los puertos de salida, o no lee un pin de entrada etc.
La única prueba que me quedó pendiente de hacer fue, escribir los datos del array, por referencia a la función, aún así debería funcionar de cualquier modo.
#include <18F2550.h>
#device HIGH_INTS = TRUE
#device adc=10
#fuses NOWDT, HSPLL, NOPUT, PROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT, CPUDIV1, PLL3, NOMCLR, NOVREGEN, RESERVED
#use delay (clock=12000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#zero_ram
#byte ADRESH = 0xFC4 // Registro Almacenamiento valor ADC0
#byte CCPR1L = 0xFBE
#byte CCPR1H = 0xFBF
#byte CCP1CON = 0xFBD
#byte TMR0L = 0xFD6
#byte TMR0H = 0xFD7
#byte TMR1L = 0xFCE
#byte TMR1H = 0xFCF
#bit TMR0IF = 0xFF2.2
#bit TMR1IF = 0xF9E.0
#bit ADFM = 0xFC0.7
#bit RB4 = 0xF81.4
#bit RB5 = 0xF81.5
///////////////////////////////////////////////////////////////////////////////
static int bufl[300]; //==============================================> Genera en puerto RC error según tamaño del array
static int ptc=1;
static long rebot[5], x, y, pitch=130;
void main(void)
{
set_tris_a(0b11111111);
set_tris_b(0b00110000);
set_tris_c(0b00000000);
output_b(0);
///////////////////////////////////////////////////////////////////////////////
setup_adc( ADC_CLOCK_DIV_2);
setup_adc_ports(AN0_TO_AN3|VSS_VDD);
set_adc_channel(2);
read_adc(ADC_START_ONLY);
ADFM=0;
///////////////////////////////////////////////////////////////////////////////
setup_timer_2(T2_DIV_BY_1,255,1);
setup_ccp1(CCP_PWM);
CCP1CON=0b00001100;
///////////////////////////////////////////////////////////////////////////////
setup_timer_0(T0_INTERNAL|T0_8_BIT|T0_DIV_2);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);
///////////////////////////////////////////////////////////////////////////////
enable_interrupts(INT_TIMER0);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);
while(true)
{
if(!RB4||!RB5)
{
if(rebot[2]==200)
{
if(!RB4)if(ptc>0)ptc--;
if(!RB5)if(ptc<2)ptc++;
output_c(ptc);
switch(ptc)
{
case 0:pitch=2;break; case 1:pitch=130;break; case 2 :pitch=200;break;
}
}
if(rebot[2]<500)rebot[2]++;
}
else rebot[2]=0;
}
}
#INT_GLOBAL
void isr_global()
{
if(TMR0IF)
{
TMR0IF=0;
}
if(TMR1IF)
{
TMR1L=130;
TMR1H=255;
bufl[x]=ADRESH;
read_adc(ADC_START_ONLY);
if(x<99)x++;else x=0;
TMR1IF=0;
}
}
-
Hola gente, bueno, les comparto parte del código (sólo por curiosidad, ya que pude hacerlo funcionar)en dónde manifiesta error en los puertos, según el tamaño del array llamado
bufl[].
Si dicho array tiene 100 elementos por ejem. todo funciona cómo debe, ahora si lo dimensionamos a 300 elementos, aparecen la falla de que no actualiza los puertos de salida, o no lee un pin de entrada etc.
...
Te había comentado que debe declararse #DEVICE HIGH_INTS=TRUE al principio e #INT_GLOBAL FAST para que termine la interrupción con un RETFIE 1 , de lo contrario lo hace con RETFIE 0 y no recupera el estado.
Agregando el FAST lo pruebo con 2000 elementos y anda todo bien (al menos en el Proteus :) )
-
Bueno, faltó aclarar ese detalle. Tuve que quitar el FAST, porque la versión que tengo 4.012(creo) daba error al compilar.
En otra PC, tengo una versión más reciente y soporta el argumento FAST, pero aún así no funcionaba.
Lo que me deja con la espina es que, sin argumento FAST, debería fallar de cualquier forma. Y no porque según el tamaño del arrays dependa el funcionamiento.
De todos modos tu aporte me sirvió para definir las cosas cómo debe hacerse.
Gracias por tu ayuda! Quedó todo ok ((:-)) ((:-))
-
El atributo FAST te da error si no lo habilitaste antes con #DEVICE HIGH_INTS=TRUE
Puede que sea un bug de esa versión, yo uso la 5.091.
Podés probar con el salvado de estado "a mano" que propone Microchip
#byte STATUS = getenv("SFR:STATUS") ;
#byte BSR = getenv("SFR:BSR") ;
byte W_TEMP,STATUS_TEMP,BSR_TEMP ;
//EXAMPLE 9-1: SAVING STATUS, WREG AND BSR REGISTERS IN RAM
#ASM
MOVWF W_TEMP ; W_TEMP is in virtual bank
MOVFF STATUS, STATUS_TEMP ; STATUS_TEMP located anywhere
MOVFF BSR, BSR_TEMP ; BSR_TMEP located anywhere
#ENDASM
//
// USER ISR CODE
//
#ASM
MOVFF BSR_TEMP, BSR ; Restore BSR
MOVF W_TEMP, W ; Restore WREG
MOVFF STATUS_TEMP, STATUS ; Restore STATUS
#ENDASM
El problema que aparentemente tenés es que la interrupción te cambia el banco de memoria (el registro BSR) y no se restaura.
-
Excelente!!! Gracias por el dato. :-/
Estuve haciendo más pruebas en la versión 5.0XX de CCS, que si soporta el argumento FAST.
Y vuelve a fallar al leer o accionar puertos, cuándo declaro una variable short de 1700 elementos.
-
Resumen: Problema del compilador :D
-
No queda otra que aprender a vivir con Bugs.
Peor es casarse me dijeron. :P