Reloj SPI en PIC inestable

Estoy tratando de configurar el módulo MSSP de un PIC18F25K22 en modo maestro SPI. Estoy mirando el tiempo y el reloj no se mantiene estable durante toda la transmisión. Una imagen lo muestra mejor que las palabras.Diagrama de tiempo SPI

Después de enviar un bit, el reloj se acorta, y no por la misma cantidad cada vez. No he trabajado con SPI antes, pero los diagramas que he encontrado en Wikipedia y otros recursos nunca muestran esto. También conecté un Arduino y no vi este comportamiento. mi código es:

    #pragma config FOSC = INTIO67   // Oscillator Selection bits (Internal oscillator block)
#pragma config PLLCFG = OFF     // 4X PLL Enable (Oscillator used directly)
#pragma config BOREN = OFF      // Brown-out Reset Enable bits (Brown-out Reset disabled in hardware and software)
#pragma config WDTEN = OFF      // Watchdog Timer Enable bits (Watch dog timer is always disabled. SWDTEN has no effect.)
#pragma config MCLRE = EXTMCLR  // MCLR Pin Enable bit (MCLR pin enabled, RE3 input pin disabled)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

void main(void)
{
    OSCCON = 0b11100110;
    spi_setup();
    __delay_ms(10);
    byte temp;
    while (TRUE)
    {
        temp = spi_transfer(0x00);
        temp = spi_transfer(0x01);
        temp = spi_transfer(0x02);
        temp = spi_transfer(0x03);
        temp = spi_transfer(0x04);
        temp = spi_transfer(0x05);
        __delay_us(1);
    }
}

void spi_setup(void)
{
    SSP1STAT = 0b00000000;
    SSP1STATbits.CKE = HIGH; // data transmitted on rising edge
    SSP1CON1 = 0b00000000; // enable Master SPI mode
    SSP1CON1bits.CKP1 = LOW; //clock idle state is low
    //i2c bits, all don't matters for SPI, cleared just in case
    SSP1CON3 = 0;
    // baud rate generation
    SSP1ADD = 0; //FCLOCK = 8Mhz /2 = 2Mhz
    // configure pins for output/input as needed 
    SDI1 = INPUT;
    SDO1 = OUTPUT;
    SCK1 = OUTPUT;
    SS1 = OUTPUT;
    SSP1CON1bits.SSPEN1 = HIGH; // enable pins for serial mode
}

unsigned char spi_transfer(unsigned char data)
{
    SS1_LAT = LOW; // select slave
    PIR1bits.SSPIF = LOW;
    SSP1BUF = data;
    //while (!SSP1STATbits.BF); //wait for receive to complete
    while( !PIR1bits.SSPIF );
    SS1_LAT = HIGH; // deselect slave
    PIR1bits.SSPIF = LOW;   // clear interrupt
    return SSP1BUF; //return data from the slave
}

(también https://gist.github.com/stumpylog/5095250 )

¿Alguien ha encontrado esto o tiene sugerencias sobre la causa?

Lo que hice

Al final, no pude hacer funcionar el módulo MSSP1. Sin embargo, cambiarlo al módulo MSSP2, exactamente el mismo código, no mostró este comportamiento. No puedo explicarlo, pero esto resolvió el problema.

¿Puedes mostrar tu código para usar el SPI?
En general, SPI (y también I2C) funcionaría con un reloj no uniforme. SPI es síncrono. Al mismo tiempo, parece extraño que un MSSP de hardware genere un reloj no uniforme. Cuando la línea de datos (verde) está baja, sus relojes son uniformes. Cuando la línea de datos es alta, sus relojes son más cortos. Por si acaso, revisa la errata de tu PIC.
@GustavoLitovsky He agregado el código directamente a la pregunta ahora.
@NickAlexeev Gracias, lo eché un vistazo. Nada mencionado sobre el módulo MSSP. Tendré que comprobar si mi esclavo puede manejar el tiempo como está.
Probablemente no esté relacionado con su problema, pero no veo el código para borrar los bits ANSEL de sus puertos. Microchip ha tomado la molesta decisión de que los pines sean entradas analógicas por defecto en lugar de digitales.
¿Cómo publicaste tu código en la pregunta de esa manera? ¿Estaba tratando de lograr un resultado similar con mi propia pregunta?
@OsagieIgbeare: pega su código en su pregunta, resalta todo y luego presiona control-K, que coloca cuatro espacios delante de cada línea, invocando el formateador de bloque de código. O simplemente puede colocar cuatro espacios delante de cada línea antes de pegarla.

Respuestas (2)

Esto es una suposición, pero probablemente esté reiniciando algo que no debería ser cada byte. Cosas como el generador de tasa de bits y la configuración periférica general solo deben configurarse una vez.

Agregado:

Ahora dice que no pudo hacer que MSSP1 funcionara, pero sí hizo que MSSP2 funcionara. Eso sugiere que tiene un error en otra parte del código que está haciendo escrituras no deseadas. Sucede que está alcanzando algún estado de MSSP1, por lo que actúa de manera extraña y por lo que funciona MSSP2.

No dejes pasar esto. Puede parecer que cambiar a MSSP2 solucionó el problema, pero en el mejor de los casos lo solucionó, probablemente temporalmente. La próxima vez que se vincule con cosas en diferentes lugares, es posible que se garabateen recuerdos diferentes. Si no encuentra y realmente soluciona esto, este firmware será escamoso para siempre. El peor de los casos es cuando no hay síntomas obvios que le hagan el favor de dejar en claro que hay un problema. El problema aparecerá un año más tarde cuando se encuentren los datos correctos, solo los sitios de un cliente, después de que 1000 estén en el campo. SOLUCIONE ESTO DE LA MANERA CORRECTA AHORA.

Parece que puede tener problemas de integridad de la señal: en la toma de LA, parece que la línea del reloj falla cuando cae la línea de datos. Intente asegurarse de que los dos estén bien aislados y que la pista o el cableado no sea demasiado largo. También intente reducir la velocidad del reloj o agregar un pequeño filtro RC en las líneas (si las líneas son largas, solo una resistencia en serie de, digamos, 220 Ω puede ayudar)

Si tiene un osciloscopio, verifique las líneas con este para asegurarse de que la integridad de la señal sea buena. Si no es así, pruebe las sugerencias anteriores y ajuste las cosas hasta que tenga señales de buena calidad.