I'm trying to configure the MSSP module of a PIC18F25K22 into SPI master mode. I'm looking at the timing and the clock doesn't remain steady through the whole transmission. A picture shows it better than words. SPI Timing Diagram

After a bit is sent, the clock shortens, and not by the same amount each time. I've not worked with SPI before, but the diagrams I've found on Wikipedia and other resources don't ever show this. I also hooked up an Arduino and did not see this behavior. My code is:

    #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;
    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);

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

(also https://gist.github.com/stumpylog/5095250 )

Has anyone encountered this or have suggestions as to the cause?

What I Did

In the end, I was unable to get the MSSP1 module working. However, changing it to the MSSP2 module, exact same code, did not exhibit this behavior. I can't explain it, but this solved the problem.

  • \$\begingroup\$ Can you show your code for using the SPI? \$\endgroup\$ – Gustavo Litovsky Mar 5 '13 at 23:51
  • 1
    \$\begingroup\$ Generally, SPI (and I2C too) would work with non-uniform clock. SPI is synchronous. At the same time, it seems odd that a hardware MSSP generates a non-uniform clock. When the data line (green) is low, your clocks are uniform. When the data line is high, your clocks are shorter. Just in case, check the errata for your PIC. \$\endgroup\$ – Nick Alexeev Mar 5 '13 at 23:52
  • \$\begingroup\$ @GustavoLitovsky I've added the code directly to the question now. \$\endgroup\$ – Trenton Holmes Mar 6 '13 at 0:01
  • \$\begingroup\$ @NickAlexeev Thanks, I had a look at it. Nothing mentioned about the MSSP module. I'll have to check if my slave can handle the timing as is. \$\endgroup\$ – Trenton Holmes Mar 6 '13 at 0:15
  • \$\begingroup\$ Probably unrelated to your problem, but I don't see code for clearing the ANSEL bits for your ports. Microchip has made the annoying choice of having the pins be analog inputs by default instead of digital. \$\endgroup\$ – apalopohapa Mar 9 '13 at 1:08

This is a guess, but you are probably resetting something you shouldn't be each byte. Things like the bit rate generator and the general peripheral configuration should only be set once.


You now say that you couldn't get MSSP1 to work but did get MSSP2 working. That hints that you have a bug elsewhere in the code that is doing unintended writes. It happens to be hitting some MSSP1 state, which is why it acts strangely and why MSSP2 works.

Don't just let this go. Moving to MSSP2 may appear to have fixed the problem, but at best you have worked around it, probably temporarily. Next time you link with things in different places, different memory may get scribbled on. If you don't find and really fix this, this firmware will be forever flaky. The worst case is when there are no obvious symptoms doing you the favor to making it clear there is a problem. The problem will then appear a year later when just the right data is encountered, only a customer sites, after 1000 are in the field. FIX THIS THE RIGHT WAY NOW.


It looks like you may have signal integrity issues - on the LA shot, it appears the clock line glitches when the data line falls. Try making sure the two are well isolated, and the trace or wiring is not too long. You also try slowing the clock rate down or adding a small RC filter on the lines (if the lines are long, just a series resistor of say 220Ω may help)

If you have an oscilloscope, check the lines with this to make sure the signal integrity is good. If it's not, try the suggestions above and adjust things until you have good quality signals.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.