Estoy migrando esta pregunta de StackOverflow a este foro porque creo que es más adecuada.
Estoy escribiendo una rutina de esclavo I2C para PIC18F25K80 y estoy atrapado en un problema extraño.
Esta es mi rutina: (EDITADO CON LA VERSIÓN MÁS ACTUAL BASADA EN LOS COMENTARIOS, AÚN MISMO PROBLEMA)
void interrupt interruption_handler() {
INTCON1bits.GIE = 0; // Disable Master Synchronous Serial Port Interrupt
if (PIR1bits.ADIF == 1) {
//This is a A/D interruption
PIR1bits.ADIF = 0;
INTCON1bits.GIE = 1; // Enable Master Synchronous Serial Port Interrupt
return;
} else
if (PIR1bits.SSPIF == 1) {
//This is a I2C interruption
PIR1bits.SSPIF = 0;
//Treat overflow
if ((SSPCON1bits.SSPOV) || (SSPCON1bits.WCOL)) {
dummy = SSPBUF; // Read the previous value to clear the buffer
SSPCON1bits.SSPOV = 0; // Clear the overflow flag
SSPCON1bits.WCOL = 0; // Clear the collision bit
SSPCON1bits.CKP = 1;
board_state = BOARD_STATE_ERROR;
} else {
if (!SSPSTATbits.D_NOT_A) {
//Slave address
debug(0, ON);
//Read address (A/D number)
address = SSPBUF; //Clear BF
while (BF); //Wait until completion
if (SSPSTATbits.R_NOT_W) {
SSPCON1bits.WCOL = 0;
unsigned char a = 0x01;
SSPBUF = a; //0x01; //a+1; //Deliver first byte
}
} else {
if (SSPSTATbits.BF) {
dummy = SSPBUF; // Clear BF (just in case)
while (BF);
}
if (SSPSTATbits.R_NOT_W) {
//Multi-byte read
debug(1, ON);
SSPCON1bits.WCOL = 0;
SSPBUF = 0x02; //Deliver second byte
} else {
//WRITE
debug(2, ON);
}
}
transmitted = TRUE;
SSPCON1bits.CKP = 1;
PIR1bits.SSPIF = 0; //Clear again just in case
INTCON1bits.GIE = 1; // Enable Master Synchronous Serial Port Interrupt
}
} else
PIR1 = 0x00; //Just in case
}
Funciona como un encanto si configuro valores constantes en SSPBUF. Por ejemplo, si lo hace:
SSPBUF = 0x01;
(...)
SSPBUF = 0x02;
Obtengo los dos bytes en el master. Incluso puedo ver las formas de onda de los bytes que se transmiten en el osciloscopio. Muy divertido!
Pero cuando intento establecer SSPBUF usando una variable como:
unsigned char a = 0x01;
SSPBUF = a;
Tengo cero en el maestro.
Me está volviendo loco.
Algunas hipótesis que he descartado:
- El temporizador de vigilancia está desordenando la interrupción en medio del protocolo: no lo está. Está deshabilitado y el problema ocurre en ambas asignaciones SSPBUF
- Necesito esperar hasta que BF baje para continuar: no lo hago. AFAIK, usted configura el SSPBUF, borra el SSPIF, configura el CKP y regresa de la interrupción para cuidar la vida en 4Mhz mientras que el hardware envía datos en pocos Khz. Te interrumpirá de nuevo cuando termine.
No tiene sentido para mí. ¿Qué tan bueno es si no puede definir un valor arbitrario usando una variable?
Por favor, gurús, ilumina a este pobre programador.
Gracias de antemano.