Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

[PIC] PIC18F2580 [SPI]- Problem with communication to ADT7310 temperature sensor via SPI

Status
Not open for further replies.

flukeco

Junior Member level 1
Joined
Apr 25, 2014
Messages
16
Helped
0
Reputation
0
Reaction score
0
Trophy points
1
Activity points
180
Hi everyone,

First of all I want to apologize in advance for my bad English. I'm not a native speaker, but I'll try my best to explain the problem I have.

Now I'm trying to communicate with temperature sensor (ADT7310) via SPI bus.

I'm using PIC18F2580, 10Mhz internal oscillator with PLL enabled (so the clock frequency is 40Mhz), and ADT7310 temperature.
For the compiler, I'm using MPLAB IDE and XC8 compiler.

First, I tried to read the temperature values, but I'm receiving some meaningless values, so I suspected that my SPI settings might be wrong.

Since the code for my temperature reading is quite long, and I only need to know whether my SPI settings is correct or not, I rewrite my code to only read the device status register (register address 0x00). If my settings is correct, I should receive 0x80 as stated in the datasheet.

Unfortunately, instead of receiving 0x80, I received some 8-bit junk. However, that 8-bit junk is consistent all the time (0x47 to be more specific).

I neither have access to oscilloscope nor the logic analyzer, so I have no idea why this goes wrong.

I've read ADT7310's datasheet many times and found some articles which contain working code. So I'm pretty sure that I set clock polarity (CKP), clock edge selection (CKE), and sampling phase (SMP) bits to communicates with ADT7310 correctly via SPI.

Also PIC18F2580's datasheet states that using Fosc/4 at 40 Mhz will give the maximum data rate of 10.00 Mbps, so I'm also pretty sure that I'm on the right track.

I also have 1 more problem. When I debug my program by setting breakpoint and then use "Step Into", the variable that I'm using to store SSPBUF will contain a value (even if it's not what I expected). However, if I set breakpoint and then "Run", when the breakpoint is hit, the variable that I'm using to store SSPBUF is zero all the time. For example:

Code:
    while (1) {
        PORTAbits.SS = 0;           /* enable SPI */

        SSPBUF = 0b01000000;     /* read register 0x00 (status register)*/
        while(!PIR1bits.SSPIF);     /* wait for transmission to completed */
        value = SSPBUF;             /* receive 8-bit value */

        PIR1bits.SSPIF = 0;         /* clear SSP interrupt flag */   <-- breakpoint here, if I use "step into" until come to this line again, value is 0x47
                                                                   however, if I click "Continue", when the breakpoint is hit next time value contains 0x00

        PORTAbits.SS = 1;           /* disable SPI*/
    }

The following is my completed code. If you find something wrong or have any suggestions, please tell me. your help would be highly appreciated.

Thank you in advance for your help, and again, sorry for my bad English.

Pat

Code:
int main(void) {
    unsigned char value = 0;

    ADCON1 = 0x0F;     /* set all port A pins, including SS (RA5), as digital I/O */

    TRISCbits.RC3 = 0;  /* set SCK as output pin */
    TRISCbits.RC4 = 1;  /* set SDI as input pin */
    TRISCbits.RC5 = 0;  /* set SDO as output pin */
    TRISAbits.RA5 = 0;  /* set SS as output pin */

    SSPCON1 = 0b0000;           /* master mode, Fosc/4 */

    SSPSTATbits.SMP = 0;        /* input data sampled at middle of data output time */
    SSPSTATbits.CKE = 1;        /* transmit on transition from active to idle clock state */

    SSPCON1bits.CKP = 1;        /* clock idle state is high, active is low */

    PORTAbits.SS = 1;       /* disable SPI*/
    SSPCON1bits.WCOL = 0;   /* clear write collision */
    SSPCON1bits.SSPOV = 0;  /* clear receive overflow */

    SSPCON1bits.SSPEN = 1;      /* enable serial port (SCK, SDO, SDI, SS pins) */

    while (1) {
        PORTAbits.SS = 0;           /* enable SPI */

        /* ADT7310's command byte format: */
        /* bit 7 must be 0, bit 6 is R/W bits (0 for write, 1 for read), bits<5:3> = register address */
        /* bit 2 is continuous read mode (for reading temperature value register (address 0x02) only */
        /* bits<1:0> must be 0 */
        SSPBUF = 0b01000000;     /* read register 0x00 (status register)*/
        while(!PIR1bits.SSPIF);     /* wait for transmission to completed */
        value = SSPBUF;             /* receive 8-bit value */
        PIR1bits.SSPIF = 0;         /* clear SSP interrupt flag */

        PORTAbits.SS = 1;           /* disable SPI*/
    }

    return (EXIT_SUCCESS);
}
 

The code can't work. The data transmission takes 2 byte cycles, as you can clearly see from the datasheet. To continue SPI clocking for the second byte, send a dummy byte to SSPBUF, e.g. 0xff or 0x00.

- - - Updated - - -

Secondly the mode programming is wrong. The chip uses SPI mode 3 (clock idle state high, data sampled on risisng edge), the respective setting is CKP =1, CKE = 0). SMP = 0 is correct.
 
Hi FvM,

First of all, thank you very much for your suggestions. I really appreciate your help.
Since I don't have the board with me right now, I'll definitely try it tomorrow and tell you the result.

However, I still have something to be clarified.
1. Do I need to read SSPBUF after the first transmission is completed (i.e. before sending the dummy byte)?
2. After the dummy byte is sent, SSPBUF will contains the value I need. Is that correct?

To sum it up, does this code correct based on your suggestions? (beside the wrong setting of SPI mode)

Code:
    while (1) {
        PORTAbits.SS = 0;           /* enable SPI */


        SSPBUF = 0b01000000;        /* read register 0x00 (status register)*/
        while(!PIR1bits.SSPIF);     /* wait for transmission to completed */
        junk = SSPBUF;              /* clock out whatever byte currently store in SSPBUF */
        PIR1bits.SSPIF = 0;         /* clear SSP interrupt flag */
        
        SSPBUF = 0xFF;              /* transmit the dummy byte */
        while(!PIR1bits.SSPIF);     /* wait for transmission to completed */
        value = SSPBUF;             /* receive 8-bit value */
        PIR1bits.SSPIF = 0;         /* clear SSP interrupt flag */

        PORTAbits.SS = 1;           /* disable SPI*/
    }

For the wrong CKE, CKP, and SMP settings that you mentioned, I came upon one Japanese article in which the author claims that the code is working. In the code, he set CKE and CKP to 1 and SMP to 0. That's why I came up with this settings. The link to the article is https://sfukuda.at.webry.info/201311/article_10.html

Does the ADT7310's datasheet says about the correct SPI mode setting or you just figure it out by looking at the timing diagram yourself? The reason I'm asking this is because I'm very new to embedded system programming especially PIC, so it's very difficult, if not impossible, for me to make sense of the timing diagram provided in the datasheet.

Also example code in the Japanese article I mentioned above contains many delays in various states (such as after sending the first byte and before beginning of next data transmission). Does these delays necessary to get the code to work in your opinion?

Again thank you very much for your help. I'll let you know tomorrow whether the code is working or not.

Pat
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top