I am using the MSSP module of a PIC 18F25K22 (datasheet) for SPI. This works successfully except for when I try to use the maximum SPI clock rate of 16Mhz.

The target device is an SD card and the symptoms described below happen with a selection of different cards, tested with 6 cards from different manufacturers.

The microcontroller clock is the internal 16Mhz oscillator with 4x PLL, setup as shown below.

// Internal 64Mhz oscillator
IRCF2 = 1;
IRCF1 = 1;
IRCF0 = 1;
PLLEN = 1;

Circuit diagram

The relevant portion of the circuit is shown below, connections go directly to the PIC (note I used 47k resistors when assembling the PCB).

Circuit diagram

There are some right angles on the PCB where I broke out the SPI pins for debugging. On the top layer the traces go to the debug header, on the bottom to the PIC. I include this in case signal integrity might be relevant.

PCB top layer

PCB bottom layer

What works

Any speed below the theoretical maximum works successfully.

The following setup should produce an 8Mhz SPI clock from the formula 64000000 / (4 * 2).

// SPI clock = Fosc / (4 * (SSPADD + 1))
SSPCON1bits.SSPM = 0b1010; 
SSP1ADD = 1;
SSPSTATbits.CKE = 1; // Work around known silicon bug, see errata
SSPCON1bits.SSPEN = 1;

Data is written using the most basic method, no interrupts are used:

unsigned char spi_byte(uint8_t data) {
    SSPBUF = data;
    // Wait for the buffer to fill with incoming data
    while (!SSPSTATbits.BF);

    data = SSPBUF;
    return data;

When tested with a logic analyser there's a decent 8Mhz clock and my code works fine:

enter image description here

What doesn't work

I'd like to use the fastest clock possible, the datasheet shows two ways to do this:

enter image description here

I should be able to:

  • Set the clock rate directly to Fosc / 4
  • Set SSPxADD = 0 for the same effect - Fosc / (4 * (SSPxADD + 1)) = Fosc / 4 * 1

With my 64Mhz clock this should give a theoretical SPI clock speed of 16Mhz from the MSSP module.

SD initialisation requires a slow speed, below this can be seen marked by the red "1".

Overview at highest speed

This phase is successful. Therefore I should be able to speed up, so I tested with SSP1ADD set to zero (this happens around marker "A1"). The faster clock should be present in the period marked by a red "2".

SSPCON1bits.SSPEN = 0;
SSP1ADD = 0; // BUG: Set to 1 to make this work, 0 gives unstable clock?
SSPCON1bits.SSPEN = 1; 

However this does not work and produces a very unstable clock of about 82Khz, shown below (this is a zoom of the period marked "2" above).

Zoom of unstable SPI clock at highest speed

The first three bytes here have a slightly faster clock but it's still only ~400Khz (far below 16Mhz) and the duty cycle is nowhere near 50%. Then the clock rate mysteriously changes to ~82Khz during the fourth byte and is more like a series of pulses than a clock.

The 18F25K22 does have slew rate control, which has an impact. The above traces were taken with the default settings, slew rate control enabled. When disabled the above settings give a SPI clock of 400Khz (which is more stable and does work), but is far slower what it should be.


  • There is nothing relevant in the Microchip errata (I have a revision 5 chip)
  • I work around the one MSSP bug which still affects revision 5 by setting CKE = 1, though this isn't relevant to the problem here.
  • I can take scope traces if required, but don't have it with me right now.
  • I found this unanswered question which is similar, but I can't switch to MSSP2.


Does anybody know if I should be able to use an SPI clock of 16Mhz, or am I missing something from the datasheet?

  • \$\begingroup\$ If you could take some scopeshot (not logic analyzer) there's a slim chance that would help. But it seems to me this is not about external components, plus 16MHz is not that fast. \$\endgroup\$ Nov 8, 2015 at 22:18
  • \$\begingroup\$ Unfortunately I'm travelling and won't have access to a scope for a few days, but I can do this later in the week. I do not think this is external components, I think it's likely an unusual problem with the MSSP baud rate generator OR I've missed something important in the datasheet. \$\endgroup\$
    – David
    Nov 8, 2015 at 22:32
  • \$\begingroup\$ "I should be able to: Set the clock rate directly to Fosc / 4" - did you try this, and if so what was the result? \$\endgroup\$ Nov 8, 2015 at 23:48
  • \$\begingroup\$ @BruceAbbott yes I also tried setting SSP1M=0 and it either produces the same result as the alternative or occasionally locks the uC up (no further SPI activity, requires a reset). Because random lock ups are harder to debug I focussed on the alternative. Note the lock up is possibly while (!SSPSTATbits.BF) but I have not debugged this. \$\endgroup\$
    – David
    Nov 8, 2015 at 23:51

3 Answers 3


LOOK AT THE SLRCONX REGISTER, WHERE X IS PORT A, B OR C. Default bits are set, which limits slew rate to 25nSec, too slow for 16MHz SCK! Reset the bits corresponding to the port and pins you are using for SPI clock and data and it will work great. I got bit the same way, found the solution on another forum.

  • \$\begingroup\$ This, indeed, solves the issue with 16MHz SPI. It's clearly a bug in the datasheet, they should've mentioned it. Thanks. \$\endgroup\$
    – jackhab
    Sep 8, 2020 at 11:18

Maybe this is unrelated, but in the PIC16F145X datasheet a fifth note is added for SSPM bits for SPI mode.

enter image description here

So in this other PIC you cannot use SSPADD with 0 and have Fosc/4 when using SSPM = 1010. I think the SPI module may have the same rules as in your PIC18F25K22, but somehow that may not be shown in the datasheet.

  • \$\begingroup\$ I don't think this explains why SSPM set to 0000 doesn't work either. I still think this is likely another bug. \$\endgroup\$
    – David
    Sep 8, 2017 at 22:38
  • \$\begingroup\$ Try sending your bug report to Microchip. If it's a sillicon problem they must release an errata for it. \$\endgroup\$ Sep 13, 2017 at 19:27

In the datasheet : Datasheet

you see that it begins count down, and when the value is 0 or 1 this is very difficult to do by the micro. In other datasheet(dspic30F3012) they said that clearly in I2C:

enter image description here

The use of 0 or 1 is illegal . so use greater PLL or greater crystal.

  • \$\begingroup\$ A similar note is in the datasheet image in the question, but this applies to I2C mode not SPI master mode. This also doesn't explain why Fosc/4 mode doesn't work. \$\endgroup\$
    – David
    Nov 11, 2015 at 13:27
  • \$\begingroup\$ The first image is for SPI, how does the pic can begin counting down from zero ?? \$\endgroup\$
    – Zara Zara
    Nov 11, 2015 at 14:12
  • \$\begingroup\$ Whilst this is an interesting observation it is not supported by other documented restrictions in the datasheet. It doesn't explain why Fosc/4 doesn't work, or why switching to MSSP2 module works for another individual. \$\endgroup\$
    – David
    Nov 11, 2015 at 14:16
  • \$\begingroup\$ And the answer to "how can you count down" could be the same as timers, they interrupt / act on underflow on decrement from zero. We simply cannot know because the datasheet does not specify this, nor does it tell us that zero is an illegal value for SPI master mode. \$\endgroup\$
    – David
    Nov 11, 2015 at 15:47
  • \$\begingroup\$ you can save time and try what I said about the increasing the frequency or the PLL factor . or you can wait another response , I wish that . \$\endgroup\$
    – Zara Zara
    Nov 12, 2015 at 8:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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