Interrupciones de dsPIC33, esclavo SPI y Timer1. ¿Lo que sucede?

Tengo un problema interesante con el dsPIC33FJ128GP802 .

Lo tengo configurado como un dispositivo SPI esclavo conectado a un Arduino que actúa como maestro.

Timer1 está configurado para activar una interrupción en momentos específicos en una secuencia determinada.

Una de las secuencias de interrupciones tarda unos 50 µs en ejecutarse. Sí, sé que no es una "buena práctica" tener una rutina de interrupción que dure tanto tiempo, pero solo se usa una interrupción en el sistema, y ​​las restricciones de tiempo significan que tiene que tomar ese tiempo.

Ahora, todo funciona: el SPI se está ejecutando y recibe comandos del Arduino. El Timer1 activa la interrupción en el momento justo y todo se ve bien.

Excepto que veo corrupción en el SPI. Solo puedo suponer que se debe a la interrupción del disparo del Timer1 durante la transferencia SPI. Si desactivo el temporizador y su interrupción, no tengo ningún problema con la transferencia SPI.

Por lo que entiendo de las interrupciones, se supone que todos los registros, etc., están exactamente en el mismo estado cuando el ISR regresa como estaban cuando se activó la interrupción. Eso es ciertamente lo que afirma el manual de usuario del C30.

Intenté volver a escribir mi código C para la recepción de SPI en ensamblador, pero el problema persiste.

Aquí hay un fragmento de mi código C:

while(PORTAbits.RA3==1);     // Wait for a transfer to be requested     
SPI1STATbits.SPIEN=1;        // Enable the SPI module     
SPI1BUF=0x0;                 // Prime the buffer to start a transfer     
LATAbits.LATA1=0;            // Signal to the master it may transfer     
while(PORTAbits.RA3==0);     // Wait for the master to signal it has transferred   
in = SPI1BUF;                // Store the resultant word     
SPI1STATbits.SPIEN=0;        // Turn off the SPI module     
               ... perform operations depending on SPI command received ...     
LATAbits.LATA1=1;            // Signal to the master the command has finished and it may transfer again.
  • RA3 es el pin Slave Select para el SPI
  • LATA4 es un protocolo de enlace inverso del esclavo al maestro

Ambos son activos-bajos.

Como puede ver, estoy usando más protocolo de enlace que el SPI normal, ya que necesito retroalimentación del esclavo al maestro cuando es seguro comenzar a transferir otro comando SPI.

Mi ISR ​​se define como:

void __attribute__((__interrupt__,no_auto_psv)) _T1Interrupt(void)   

He intentado agregar el __shadow__atributo para usar los registros de sombra, pero no ha tenido efecto.

Entonces, ¿qué sucede realmente con el SPI en este chip cuando se activa una interrupción del temporizador? Como tiene un reloj independiente de la CPU principal, y solo cambia los bits dentro/fuera de un registro de desplazamiento, seguramente no debería verse afectado por las interrupciones.

Me está volviendo loco, por lo que cualquier sugerencia será bienvenida.

Respuestas (1)

Normalmente configuraría el periférico SPI una vez y luego lo dejaría encendido. El apretón de manos adicional que está haciendo le impide usar el hardware a su máxima capacidad. También hacer una espera ocupada para que el maestro afirme la selección de esclavo es una mala idea si alguna vez desea que el procesador haga otra cosa.

Dado que está transfiriendo 16 bits menos por mensaje, dejaría que el hardware se encargara de ello. Luego puede monitorear el indicador de interrupción SPI para determinar cuándo se han recibido nuevos datos del maestro. Si necesita reducir la velocidad del maestro por razones de control de flujo, lo haría fuera del mensaje SPI. Sospecho que la interrupción está agregando latencia a su esquema de protocolo de enlace local, y algo en alguna parte no está del todo bien y no puede tolerar esa latencia. Eso suponiendo, por supuesto, que la interrupción no intente tocar el hardware SPI o cualquiera de sus líneas de E/S.

Desafortunadamente, no me es posible usar el manejo de SS del hardware. En este chip, se comparte con uno de los pines PORTB, y la hoja de datos indica que "Conducir el pin alto aborta la transferencia", y tengo que usar todo el PORTB para este sistema (actúa como un registro de desplazamiento). Así que tengo que usar manualmente un pin PORTA como señal SS. El procesador nunca querrá hacer nada más durante las esperas ocupadas. Hay 2 operaciones básicas. La lectura SPI y la interrupción del temporizador. Eso es todo lo que está sucediendo, y todo lo que alguna vez sucederá.
La interrupción manipula PORTB y la funcionalidad SPI se comparte con algunos de los pines PORTB. Sin embargo, la función de reasignación de dsPIC desactiva la funcionalidad de PUERTO de esos pines cuando el SPI está habilitado en ellos. La interrupción no manipula SPI de ninguna manera.
Lo he reescrito todo para que sea 100% controlado por interrupciones. Al jugar con los niveles de interrupción en este chip, conseguí que funcionara correctamente. Gracias por los consejos.