¿Qué está mal con esta detección de cambio de pin de PIC?

6

Tengo dos PIC18F4620 conectados a través de SPI + Slave Select + línea IRQ adicional. Ambos controladores se controlan desde el mismo oscilador de cristal utilizando los mismos ajustes de reloj. El maestro envía un byte y luego espera hasta que el esclavo alterne esa línea IRQ adicional. La duración de la conmutación es de 4 ciclos de instrucción. Todos los bordes se ven bien en el alcance y la comunicación SPI funciona correctamente, a excepción de la detección de conmutación ( while(!PORTBbits.RB1); ).

Este es mi código de envío SPI:

    while (spi_out_msg_buffer.write_cursor > spi_out_msg_buffer.read_cursor)
    {
        DisableInterrupts;
        SSPBUF = spi_out_msg_buffer.data[spi_out_msg_buffer.read_cursor];
        LATBbits.LATB0 = 1;
        while(!PORTBbits.RB1); // wait for toggle on IRQ line
        LATBbits.LATB0 = 0;
        EnableInterrupts;
        spi_out_msg_buffer.read_cursor++;
    }

El while(!PORTBbits.RB1); se traduce en dos instrucciones:

BTFSS PORTB, 1, ACCESS
BRA 0x188

Instalé esa línea B0 para propósitos de depuración, puedes verla al final de este diagrama de tiempo:

PuedeverelcambiodelalíneaIRQ(segundodesdelaparteinferior)ycómonosedetecta,porquelalíneadedepuraciónB0semantienealta.CuandodetengolaejecuciónatravésdeICD,secuelgadentrodewhile.Valelapenamencionarquegeneralmentefuncionaparaunospocosbytesyluegosedetiene,comopuedeveraquí:

Medí que el pulso es en realidad 4 ciclos de instrucción (= 16 ciclos PLL = 4 ciclos de reloj) largos:

Creoquedeberíasersuficienteparaquesedetecteelpulso.InclusosielprimerBTFSSlopierdeporqueelpuertosemuestreaalcomienzodelciclodeinstrucciones,entonceselsegundodeberíaobtenerlo:

10 MHz - > PLL - > 40 MHz - > 10 M instrucciones por segundo - > 100 ns por instrucción.

¿No debería ser eso lo suficientemente largo para salir de while ?

    
pregunta AndreKR

3 respuestas

2

La razón real era que yo era un idiota. Mi macro DisableInterrupts hizo INTCONbits.GIE=1 .

Encontré esto al cambiar un pin durante la espera ocupada:

while(!PORTBbits.RB1)
{
    LATBbits.LATB0 = 0;
    LATBbits.LATB0 = 1;
}

Noté que la conmutación se detuvo en intervalos regulares y cuando el pulso de notificación cae en una de estas ventanas, pasa desapercibido.

    
respondido por el AndreKR
6

Estás usando un compilador, por lo que no tienes idea de cuántos ciclos toma el ciclo de sondeo. En el ensamblador, puedes reducirlo a 3 ciclos, pero renunciaste al derecho de contar ciclos cuando escribiste el código en un lenguaje de alto nivel.

Sin embargo, el problema real es el enfoque general. Pedir el código para detectar un pequeño fallo no es una buena idea. Incluso si pudiera garantizar que el tiempo de bucle es menor que el tiempo de falla, ahora no puede activar las interrupciones durante la espera. Esto puede presentar problemas arquitectónicos más adelante.

Una idea mucho mejor es utilizar el hardware que ya tiene para detectar el problema, y luego hacer que el firmware verifique ese hardware. Lo más simple sería conectar el fallo a una de las líneas INTx, luego buscar el indicador INTxIF. Los pines de detección de cambios también funcionarán, pero ten en cuenta que la marca se establece en ambos bordes y debes eliminar la falta de coincidencia para eliminar la condición.

    
respondido por el Olin Lathrop
5

La última instrucción es una rama incondicional, ¿verdad? Por lo general, las sucursales y los accesos a la memoria (realizados en la primera instrucción, ¿no?) Toman aproximadamente 2-3 veces más tiempo de ejecución, por lo que en su caso, esas instrucciones podrían demorar alrededor de 16 ciclos, lo que equivale a 400 ns (en el mejor de los casos) ).

    
respondido por el rnunes

Lea otras preguntas en las etiquetas