# PIC 18F4520 MSSP (SPI mode) question/issue

#### agroom

Joined Oct 15, 2010
60
This is my first time using the MSSP module on a PIC chip, though I've got some intermediate experience using other other modules. Because this is my first attempt, I just wrote a simple test program that outputs 1010... to see with the timing and just make sure it's working correctly.

The 18F4520 is on a custom prototype board called a Boogie Board we made in school. I have a Saleae Logic Analyzer channel 0 and 1 hooked up to the SPI (RC5) and CLK(RC3) pins, respectively, and grounded to the BB's ground. Here's my sample program:

Rich (BB code):
#include <18F4520.h>
#use delay (clock = 20000000)
#fuses HS, NOWDT, NOLVP
#include "library\registers.h" // register lib file

main(){

*TRISC = 0x00;         // SDO, CLK output (ignoring input)
*SSPSTAT &= 0xBF;   // transition idle->active
*SSPCON1 &= 0x20;   // Idle low, SPI Master, clk = Fosc/4
*SSPCON1 |= 0x20;   // Enable

while(1){
*SSPBUF = 0xAA;  // output 1010 1010
//while(*SSPSTAT & 0x01);
}
}
Note: Not sure if I need the while(*SSPSTAT & 0x01); but I get the same output either way. Here I'm just waiting for the buffer full flag bit to clear before sending the next value.

Attached are two Saleae screeshots, one zoomed in and the other zoomed out. The 0xAA output is working correctly based on the clock signal, but the clock looks like it's outputting in bursts. I guess this is where I'm stuck because I wouldn't think that's correct. Is this how SPI works or more likely what am I doing wrong?

#### Attachments

• 95.2 KB Views: 37
• 96.1 KB Views: 35

#### JohnInTX

Joined Jun 26, 2012
4,337
Its not unusual to see some gap between transmissions since there is some overhead associated with reloading SSPBUF with new data.

You do need to poll/use an interrupt with BF/ SSPIF to avoid write collisions. You only have one level of buffering. Maybe you are getting away with it here since your data is the same each time. You won't when you are sending different data.

You really should be
1)Polling BF verify that any previous byte has been sent and SSPBUF is available.
2)Read SSPBUF. Discard the value if transmitting only. This clears BF and avoids WCOL.
3)Write new data to SSPBUF
4) repeat for each new byte of data

Section 17.3.2 in rev E of DS39631 (the 4520 datasheet) has sample code and the recommended (read required) way to use the SPI.

Finally, be SURE to read the errata for your particular silicon version of the chip. The 4520 has had more than its share of errata issues over the years and MSSP accounts for a lot of them. Also, check the notes in MPLAB help for the debugger you are using. Many of these had problems with BF in the past.

BTW: What compiler are you using? *SSPBUF = xxx implies that SSPBUF is a pointer rather than a target register. OK if that's what it set up for but unusual..

Last edited:

#### agroom

Joined Oct 15, 2010
60
Its not unusual to see some gap between transmissions since there is some overhead associated with reloading SSPBUF with new data.
It's not really the transmission that has me questioning this, but the clock signal. Should it also have gaps like that?

You do need to poll/use an interrupt with BF/ SSPIF to avoid write collisions. You only have one level of buffering. Maybe you are getting away with it here since your data is the same each time. You won't when you are sending different data.

You really should be
1)Polling BF verify that any previous byte has been sent and SSPBUF is available.
2)Read SSPBUF. Discard the value if transmitting only. This clears BF and avoids WCOL.
3)Write new data to SSPBUF
4) repeat for each new byte of data
I'd tried something like this initially and was either getting sporadic outputs or nothing (I forget). I forget what I was doing exactly, but if I remember correctly I had the interrupt read/clear SSPBUF and included the while loop that watches BF. The above code was the best result I was able to achieve; however, I wouldn't rule out that I was just doing something wrong.

Let me hook it up and try it again and see what happens.

On another note, is there any way via SPI or other protocol that I can get the output to run in a more continuous stream? The project I'm working on is creating a driver for an LED strip using the WS2811 LED driver. It's a 1-wire protocol that uses 5-bit packets (start/stop bit w/ 3 middle bits containing the data), so one WS2811 byte consists of a 40-bit sequence. If I get breaks like this in the data stream, it assumed I'm done sending data and outputs to the LEDs.

#### agroom

Joined Oct 15, 2010
60
Section 17.3.2 in rev E of DS39631 (the 4520 datasheet) has sample code and the recommended (read required) way to use the SPI.
I took an intro assembly class ~14 years ago, so it pretty much looks like gibberish Though I've read through chap 17 2-3x, and did see SSPBUF should be read from/cleared, I wasn't sure if this only pertained to receiving.

Finally, be SURE to read the errata for your particular silicon version of the chip. The 4520 has had more than its share of errata issues over the years and MSSP accounts for a lot of them. Also, check the notes in MPLAB help for the debugger you are using. Many of these had problems with BF in the past.
I did not know these existed, thanks!

BTW: What compiler are you using? *SSPBUF = xxx implies that SSPBUF is a pointer rather than a target register. OK if that's what it set up for but unusual..
PCWH - The "registers.h" library file has pointers to the registers (example: int *SSPBUF = 0xFC9; ). We were taught to use this method over some of the compiler's built-in functions to make it easier to move between compilers.

#### JohnInTX

Joined Jun 26, 2012
4,337
It's not really the transmission that has me questioning this, but the clock signal. Should it also have gaps like that?
Actually, it IS the transmission that accounts for it. SPI only runs the clock when it has something to send. If there is a delay between the last bit sent and reading SSPBUF then writing the next byte, there will be a gap in the clock.
On another note, is there any way via SPI or other protocol that I can get the output to run in a more continuous stream?
Probably the best you can do is use SSPIF in a high priority interrupt with the next byte to send pre-fetched into some easily accessible register. On the interrupt, read SSPBUF then move the pre-fetched byte to SSPBUF to kick off the next transmission. I don't know for sure if you can get away completely from a bit of a gap. Run the processor as fast as you can vs. the SPI clock. As for another protocol, take a look at the USART in synchronous mode.

I took an intro assembly class ~14 years ago, so it pretty much looks like gibberish Though I've read through chap 17 2-3x, and did see SSPBUF should be read from/cleared, I wasn't sure if this only pertained to receiving.
C is OK if the compiler is good. The XC8 in the PRO mode is really tight for most of the things I've tried. That said, some inline #asm can be a help. As for the second point, keep in mind that SPI is always receives a byte while sending one. The PIC MSSP assumes this so you have to deal with it. I suppose you could experiment to see what you can get away with but.. I wouldn't.

PCWH - The "registers.h" library file has pointers to the registers (example: int *SSPBUF = 0xFC9; ). We were taught to use this method over some of the compiler's built-in functions to make it easier to move between compilers.
Interesting. It's valid but its different than you'd use with HiTechC or XC8, at least with the standard processor includes. You would have some serious source compatibility issues migrating to these if you used the standard processor .h files.

Errata: you're welcome. The DataBook giveth, the Errata taketh away. There are at least 5 silicon revs for the 4520, all with different errata. If you buy from a franchised distributor or Microchip Direct you'll get up to date silicon. Avoid Ebay and secondary markets. Many times they're selling old, buggy revs.

And finally, not all of the bugs make it to errata in a timely manner, some not at all. If you have something that you are sure should work but just doesn't, ask Microchip support. I use the 4520 a lot and have discovered a few things all by my own self.