• Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC SPI bus not receiving data

simonbramble

Active Member
I am having a problem with a new PIC micro. In the past I have always coded my own SPI routines. Now I thought I would use the peripheral. The part is the 16F15355:
http://ww1.microchip.com/downloads/en/DeviceDoc/PIC16(L)F15354_55 Data Sheet 40001853C.pdf

I am using PortB as the SPI bus with
RB0 as CS
RB1 as SCLK
RB2 as DIN
RB3 as DOUT

I am sending data fine (it is appearing on the scope), and I can see data coming back on the DI pin. However, the SSP1BUF is empty.

Here is how I am configuring Port B:

Code:
    /* PORT B */

    TRISB = 0b00000100;                           /* RB2 = SPI DIN */
    PORTB = 0b00000001;                         /* set CS high */   
    WPUB = 0b00000100;                          /* this speed up SPI DI line */
    ANSELB = 0x00;
    INLVLB = 0x00;                                       /* TTL input logic levels */
    SLRCONB = 0b11111111;                       /* slew rate is ON */
The following code sets up the rest of the SPI bus:

Code:
    /* set up SPI 1 */
    SSP1STAT = 0b01000000;                   /* SMP = 0, CKE = 1 */
    SSP1CON1 = 0b00101010;                    /* CKP = 0 */
    SSP1ADD = 0x4F;                                  /* baud rate = 100kHz */ 
    //SSP1ADD = 0x13;                                 /* baud rate = 400kHz */ 
    RB1PPS = 0x15;                                      /* RB1 = SPI SCLK */
    SSP1DATPPS = 0x0A;                          /* RB2 = SPI DIN */
    RB3PPS = 0x16;                                    /* RB3 = SPI DOUT */
I am controlling the CS line just by toggling the port pin manually, so I can do higher than 8 bit transactions in one go.

Here is the SPI function call:
Code:
void write_spi(unsigned char data)              /* write one byte via SPI */
{       
    SSP1BUF = data;
    while(!(checkbit(PIR3, 0)))
    { 
    }
    clearbit(PIR3, 0);
}
And here is the main code:
Code:
        clearbit(PORTB, CS); 
        write_spi(0x00);                /* write null to SPI */
        setbit(PORTB, CS);
        
        data = SSP1BUF;
As I said, data is appearing on RB2, but the buffer is empty. (I have another port pin that toggles high or low for 1 second as it reads through 'data', MSB first

What am I doing wrong??

If anyone can help, I am all ears.

Thanks

Simon
 

Pommie

Well-Known Member
Most Helpful Member
Don't know what your problem is, but you've turned the slew rate ON which slows down the port. And, what's with the checkbit and clearbit? Why not while(!SSP1IF); and SSP1IF=0;? I had a similar problem a while ago and used the 8 channel $5 logic analyser to work out what was wrong - can't remember what it was.

Mike.
 

atferrari

Well-Known Member
Just in case Simon, have you verified the errata for that chip? Saved my life some time ago.
 

simonbramble

Active Member
Hi Both

Thanks for the quick feedback. About the checkbit/clearbit... this is always the way I have written my code. I guess it is time to change! I turned the slew rate limit on as I have long test leads going to my slave (about 4") and the slave was changing its data on the wrong edge of SCLK which was caused by ringing on the SLCK. SR limiting fixed this. I have a scope probe up against the PIC pins, so I know for sure the data is valid at the port pins, so it is not SR limiting causing the problem

I will have a look at the errata of the datasheet - I had not thought of that.

More worryingly, I mapped the SPI DIN to another pin and get different results (all 1's instead of all 0's).

The truth is out there...

Simon
 

simonbramble

Active Member
OK, it now works.

I changed the SMP bit in the SSP1STAT register from '0' to '1' thus telling the part to sample the incoming data on the *falling* edge of the SCLK instead of the rising edge.

I actually need it to sample on the *rising* edge of the SCLK (and my scope says this is when the DIN is 'mid pulse'), but this clearly does not work.

There is more head scratching to do as to why this change causes everything to work, but I thought I would report back for anyone who stumbles across this post in the future.

(For reference, other settings are: CKP = 0, CKE = 1. ) I'll let you know if I get to the bottom of why this fix works

Thanks for listening

Simon
 

Nigel Goodwin

Super Moderator
Most Helpful Member
OK, it now works.

I changed the SMP bit in the SSP1STAT register from '0' to '1' thus telling the part to sample the incoming data on the *falling* edge of the SCLK instead of the rising edge.

I actually need it to sample on the *rising* edge of the SCLK (and my scope says this is when the DIN is 'mid pulse'), but this clearly does not work.
Presumably you don't? - as it working now you've changed SPI mode, then the other end is presumably set to that mode?.

Must admit, I've send ages trying to sort SPI problems in the past, only to eventually find the mode was set wrong :rolleyes:

One quick tip - the slew rate limiting - this severely restricts your SPI speed, and makes driving TFT's useless (as it has to be run far too slow). Your 4 inch leads don't sound 'long' to me - I would suggest turning the slew rate limiting OFF to see if it works now you're sorted the mode issue out (the limiting 'might' have been hiding the real problem).
 
Last edited:

simonbramble

Active Member
Presumably you don't?
. I see what you mean... however... look at the attached scope plot (pdf file attached). The yellow is CS, the blue is SCLK and the pink is SDI (displaying a byte of 10100100). I have put the pink vertical cursor on the rising edge of one of the clock pulses and you can see this is when the incoming data is at its most stable, so I would have thought this is where I need my PIC to sample the data.

From the datasheet extract, I have CKP = 0, CKE = 1 so am on the line indicated by the first red arrow:datasheet.png

I would have thought I need my sampling to be SMP = 0 (the second red arrow) on the rising edge of the SCLK. This does not work. Setting SMP = 1 seems to work, but I dont know why.

That was the point I was making.

With the settings above (and SMP = 0), the data changes on the falling edge of SCLK. Without slew rate limiting I see it changes on both the rising and falling edges.

Thanks for your help and keep the comments comin'

- Simon
 

Attachments

rjenkinsgb

Well-Known Member
Most Helpful Member
With a lot of synchronous logic, the same edge that is used to clock data is used to capture the level.

Think of a typical synchronous shift register as an example:


The clock rising edge both captures the data and changes it; that gives the longest possible time for the new data to propagate through the preceding device output before the next capture, so allows highest speed and best stability.
 

Latest threads

EE World Online Articles

Loading
Top