spi communication with scp 1000 d01 pressure/temperature

General discussion on mikroC.
Post Reply
Author
Message
pic_on_me
Posts: 22
Joined: 21 Feb 2010 22:30

spi communication with scp 1000 d01 pressure/temperature

#1 Post by pic_on_me » 18 Jul 2010 19:38

I am trying to get a pic18f4550 to read the temperature and pressure from an scp 1000 d01 temperature/pressure sensor. All of the examples I have found so far use a functions like:

write_register(place, thing)//Configure SCP1000 with low noise configuration
temp_data = read_register16(0x21); //Read the temperature data

How do I do this using spi_read(), and spi_write()

My guess is that I need to write some long binary number that is made up of the register to which I am writing and the contents of that write. I will look this up in the data sheet for the device.

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

Re: spi communication with scp 1000 d01 pressure/temperature

#2 Post by Sobrietytest » 19 Jul 2010 00:01

It shouldn't be that difficult; normally you send the register address which will include one bit that tells the slave device whether you are reading or writing, in the next byte you either write or read data...

To write data...
Spi_Write(0xXX); //control byte containing write bit and register address
Spi_Write(0xXX); //data byte that you want to write to the device


To read data...
Spi_Write(0xXX); //control byte containing read bit and register address
SPIdata = Spi_Read(buffer); the PIC will send 8 clock cycles and the slave responds simultaneously with the data in the register


SPI comms is really quite simple, all you have to do is make sure that your control byte is correct, within the SPI library you can send this as decimal, binary or hex.

ST.

pic_on_me
Posts: 22
Joined: 21 Feb 2010 22:30

Re: spi communication with scp 1000 d01 pressure/temperature

#3 Post by pic_on_me » 19 Jul 2010 01:38

Thanks for the advice. To select mode on the sensor I have to write 0x09 to the memory location 0x03.

The data sheet gives the following instructions in the spi section
Each SPI communication frame contains two or three 8 bit words: the first word defines the register address (6 bits wide, bits [A5:A0] in Figure 9) followed by the type of access (‘0’ = Read or ‘1’ = Write) and one zero bit (bit 0, LSB). The following word(s) contain the data being read or written. The MSB of the words are sent first. Bits from MOSI line are sampled in on the rising edge of SCK and bits to MISO line are latched out on falling edge of SCK.

the address is 000011
write is 1
zero bit is 0
data is 00001001

all together that means I use
spi_write(0b0000111000001001)

to read from register 0x1f I use
spi_write(0b01111100);
pressure=spi_read(buffer);

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

Re: spi communication with scp 1000 d01 pressure/temperature

#4 Post by Sobrietytest » 19 Jul 2010 10:30

No, not quite. Remember that each SPI read/write command will only communicate 1 byte, so...

All together you should use
spi_write(0b00001110)
spi_write(0b00001001)

spi_write(0b01111100);
pressure=spi_read(buffer);


Also, if the data that you want to read is greater than one byte you would have to do multiple reads...

spi_write(0b01111100);
pressureL = spi_read(buffer);
pressureH = spi_read(buffer);

pic_on_me
Posts: 22
Joined: 21 Feb 2010 22:30

Re: spi communication with scp 1000 d01 pressure/temperature

#5 Post by pic_on_me » 22 Jul 2010 03:42

Thanks for the help so far. I am still having trouble, so maybe if anyone sees a problem with my code, they could mention it.

The wiring is as follows
______PIC______//___SD______
RB0 = SDI(MISO) --> SDO(MOSI)
RB1 = SLK -----------> SLK
RC7 = SDI(MOSI) --> SDO(MISO)
RD1 = CS ------------> CS
RA5 ------------------> Data Ready

The signals that go to the sensor are connected through a voltage divider just like I use when connecting a MMC. The signals that go from the sensor to the PIC are connected through a logic level converter to bring them from 3.3V to 5V. The sensor is powered at 3.3V and I have checked that voltage with a digital multi meter.

When I run the following program the LCD screen does not display that inside loop statement.

Code: Select all

void main(){

unsigned char out[20];
int buffer,pressure2,pressure=9999;

ADCON1=0b00000111;
TRISA=0b11111111;
intcon=0;

Lcd_Init(&PORTD);
Lcd_Cmd(LCD_CLEAR);
Spi_Init_Advanced(Master_OSC_div64, DATA_SAMPLE_END, CLK_Idle_HIGH, LOW_2_HIGH);
//SPI settings were determined based on the following like from the datasheet
//The MSB of the words are sent first. Bits from MOSI line are sampled in
//on the rising edge of SCK and bits to MISO line are latched out on falling
//edge of SCK

spi_write(0b00100110);// location:1001, 1 for write, 0 added to end
spi_write(0b00000011);// data to be written to location 1001

delay_ms(150);

while(1){
         while(PORTA.F5){// A5 is the data ready connection to the sensor
              spi_write(0b10000000); //location 100000, 0 for read, 0 added to end
              pressure2=spi_read(buffer);//read first 8 bits
              pressure=spi_read(buffer);//read last 8 bits
              IntToStr(pressure2,out);
              Lcd_Out(1,1,out);
              Lcd_Out(2,1,"inside loop");
              delay_ms(100);
              Lcd_Cmd(Lcd_Clear);
                         }
        }

}

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

Re: spi communication with scp 1000 d01 pressure/temperature

#6 Post by Sobrietytest » 22 Jul 2010 12:16

Have a look at my notes in your code...

Code: Select all

void main(){

unsigned char out[20]; //THIS ARRAY IS TOO LARGE, IN YOUR IntToStr CONVERSION YOU ARE ONLY CONVERTING
ONE BYTE THEREFORE THE RESULT CAN ONLY APPEAR IN THE LAST THREE ELEMENTS OF THE ARRAY (RIGHT jUSTIFIED).
CONSEQUENTLY THE RESULT WILL BE OFF-SCREEN ON THE LCD. CHANGE TO out[7].

int buffer, pressure;
short pressure2, pressure1; //THESE ONLY NEED TO BE ONE BYTE WIDE, WHY DID YOU SET pressure TO 9999 ???

ADCON1=0b00000111;
TRISA=0b11111111;
intcon=0;

Lcd_Init(&PORTD);
Lcd_Cmd(LCD_CLEAR);
Spi_Init_Advanced(Master_OSC_div64, DATA_SAMPLE_END, CLK_Idle_HIGH, LOW_2_HIGH);
//SPI settings were determined based on the following like from the datasheet
//The MSB of the words are sent first. Bits from MOSI line are sampled in
//on the rising edge of SCK and bits to MISO line are latched out on falling
//edge of SCK
//I'M ASSUMING THESE SETTINGS ARE CORRECT

spi_write(0b00100110);// location:1001, 1 for write, 0 added to end
spi_write(0b00000011);// data to be written to location 1001

delay_ms(150);

while(1){
         while(PORTA.F5){// A5 is the data ready connection to the sensor
              spi_write(0b10000000); //location 100000, 0 for read, 0 added to end
              pressure2=spi_read(buffer);//read first 8 bits
              pressure1=spi_read(buffer);//read last 8 bits //CHANGED
              pressure = pressure1 + pressure2; //ADD THIS LINE
              IntToStr(pressure,out);
              Lcd_Out(1,1,out);
              Lcd_Out(2,1,"inside loop");
              delay_ms(100);
              Lcd_Cmd(Lcd_Clear);
                         }
        }



I don't know whether this will fix your problem but it will help the program work better. However, I cannot see anywhere in your software that assigns or controls the CS line.

pic_on_me
Posts: 22
Joined: 21 Feb 2010 22:30

Re: spi communication with scp 1000 d01 pressure/temperature

#7 Post by pic_on_me » 22 Jul 2010 18:49

I have added the CS changes. I didn't think I had too, as I am used to using the MMC library. The loop still does not get entered. If the CS changes are correct, I am going to start changing clock frequencies. Can I wire the CS directly to the ground as it is the only chip being used by the SPI?

Code: Select all

void main(){

unsigned char out[7];
int buffer,pressure;
short pressure2,pressure1;
TRISD=0x00;
ADCON1=0b00000111;
TRISA=0b11111111;
intcon=0;

portd.f1=1; // CS = 1
Lcd_Init(&PORTD);
Lcd_Cmd(LCD_CLEAR);
Spi_Init_Advanced(Master_OSC_div64, DATA_SAMPLE_END, CLK_Idle_HIGH, LOW_2_HIGH);

portd.f1=0; // CS = 0
spi_write(0b00100110);// location:1001, 1 for write, 0 added to end
spi_write(0b00000011);// data to be written to location 1001
portd.f1=1; // CS = 1

delay_ms(150);

while(1){
         if(PORTA.F5){
              portd.f1=0; // CS = 0
              spi_write(0b10000000); //location 100000, 0 for read, 0 added to end
              pressure2=spi_read(buffer);//read first 8 bits
              pressure1=spi_read(buffer);//read last 8 bits
              portd.f1=1; // CS = 1
              pressure=pressure2+pressure1;
              IntToStr(pressure,out);
              Lcd_Out(1,1,out);
              Lcd_Out(2,1,"inside loop");
              delay_ms(100);
              Lcd_Cmd(Lcd_Clear);
                         }
        }

}

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

Re: spi communication with scp 1000 d01 pressure/temperature

#8 Post by Sobrietytest » 24 Jul 2010 11:53

Yeah, my mistake; if you're using the dedicated CS pin of the SPI port 'manually' switching the CS line shouldn't be necessary. This was legacy from when I used a different pin for CS. You could try tieing the CS line to ground but if the slave device uses CS framing then this might be a problem. I had a similar problem using an Analog Devices chip which used 16-bit CS framing and this is why it was necessary to use a different pin for CS and switch it for each 16 bits, whereas the ME SPI library automatically frames at 8 bits.

If the program is not entering the while loop then you need to confirm that the circuit is providing the right conditions to do so, i.e. is the Data Ready signal working? The best way to solve problems with SPI is to use an oscilloscope, then you can see exactly what is happening.

Can you give me a link to the sensor's datasheet? I can only find a basic one that doesn't show the SPI timing diagrams or the register addresses.

pic_on_me
Posts: 22
Joined: 21 Feb 2010 22:30

Re: spi communication with scp 1000 d01 pressure/temperature

#9 Post by pic_on_me » 25 Jul 2010 01:56

Hi Sobrietytest, I really appreciate your help. Here is what my circuit tests have shown, and here are the links to the product page and data sheet. I believe the data sheet says the CS has to change from 1 to 0 for SPI communication, so your original recommendation was correct.

http://www.sparkfun.com/commerce/produc ... ts_id=8161

http://www.sparkfun.com/datasheets/Comp ... 00-D01.pdf

-voltage across the GND and 3.3V is a constant 3.297
-connecting the DRDY wire to either +3.3V or +5V enters the loop
-connecting the DRDY wire, and the MISO wire to +ve voltage displays -1 which makes sense because the numbers are formated in 2's complement and I am only printing the first two bits.
-connecting the MOSI to an LED and running an infinite loop of spi_write(0b11111111) causes the LED to turn on forever
-SCK frequency as measured with the multi meter is between 176 KHz and 276 KHz depending on the advanced configuration settings of the SPI
-Writing an infinite loop of spi_write(0b11111111) with the MOSI wire connected to the sensor causes the port on the sensor to have a voltage of 2.697V
-Programming CS to be 1 causes the CS voltage on the sensor to be 2.696V. Programming CS to be 0 causes the CS voltage on the sensor to be -.004V

Sobrietytest
Posts: 619
Joined: 05 Jul 2008 06:05
Location: Thailand

Re: spi communication with scp 1000 d01 pressure/temperature

#10 Post by Sobrietytest » 26 Jul 2010 13:50

It looks to me like the DRDY could be a pulse output rather than a fixed voltage level, therefore your program will miss it - you have confirmed this in your tests by forcing the DRDY wire +ve. Maybe you could think about using the DRDY as an interrupt input (e.g. RB0 Interrupt On Change) then write an ISR to read the data.

pic_on_me
Posts: 22
Joined: 21 Feb 2010 22:30

Re: spi communication with scp 1000 d01 pressure/temperature

#11 Post by pic_on_me » 28 Jul 2010 04:24

I got the program to work. It turns out my problem was the first two spi_write commands were backwards. I miss read the data sheet and ended up writing the address to the data.

Sobrietytest, I really appreciate your help on this.

Here is the working code for others to use.

Code: Select all

unsigned char out[20];
int buffer,temperature,temperature1,temperature2,pressure1,pressure2;
long pressure3, pressure;

void main(){

TRISB=0b11111100;
TRISC=0b00000000;
TRISD=0b00000001;
ADCON1=0b00000111;

Lcd_Init(&PORTD);
Lcd_Cmd(Lcd_CURSOR_OFF);

portd.f1=1; // CS = 1

Spi_Init_Advanced(MASTER_OSC_DIV4, DATA_SAMPLE_END, CLK_Idle_HIGH, LOW_2_HIGH);

portd.f1=0; // CS = 0
spi_write(0b00001110);// location 0x03, 1 for write, extra 0
spi_write(0b00001001);//
portd.f1=1; // CS = 1

while(1){
        if(PORTB.F4){
              portd.f1=0; // CS = 0
              spi_write(0b10000100);
              temperature2=spi_read(buffer);//read temperature MSB
              temperature1=spi_read(buffer);//read temperature LSB
              spi_write(0b01111100); //read pressure MSB
              pressure3=spi_read(buffer);
              spi_write(0b010000000); //read pressure LSB
              pressure2=spi_read(buffer);
              pressure1=spi_read(buffer);
              portd.f1=1; // CS = 1
              temperature=(temperature2<<8)+(temperature1); //this is actual temperature times 20
              pressure=(pressure3<<16)+(pressure2<<8)+pressure1;
              pressure=pressure/400; //convert to kPa

              longToStr(pressure,out);
              Lcd_Out(2,1,out);
              longToStr(temperature,out);
              Lcd_Out(1,1,out);

              delay_ms(500);
              Lcd_Cmd(LCD_CLEAR);
                   }
          }
}

Post Reply

Return to “mikroC General”