Go Down

### Topic: n00b SPI problem (Read 29398 times)previous topic - next topic

#### yennifs

#45
##### Mar 16, 2010, 03:33 pm
Here is what SparkFun says:

Four user selectable measuring modes combine 17-bit resolution (9cm of air column) with low or ultra-low power consumption, or alternatively 15-bit resolution (18cm of air column) with high speed data read (9Hz) or less than 5uA and power consumption. For example, at Low Power mode, the SCP1000 has an overall resolution of 2 Pa (15cm of air column) and a power consumption of 3.5uA.

I did not review the code from #33, but your values are not far from the 15cm column of air accuracy that SparkFun describes.

The code I linked to a few posts back is very well documented, and you could run it in any mode (high accuracy, low power, etc) so you could easily validate against the specs.

Sam

#46
##### Mar 16, 2010, 07:18 pm
Ok,  thanks very much,
I'll look at that link now, thanks

#### Nudeln

#47
##### Mar 31, 2010, 12:19 pmLast Edit: Mar 31, 2010, 12:21 pm by Nudeln Reason: 1
We have problems getting our Arduino Mega to work with a SPC1000-D01. We have tryed both Dave's code as listed in post #33, with the exception of editing the pins (of course) to :

Code: [Select]
`#define CSB 53 //  SLAVESELECT#define SPICLOCK 52  // SCK#define DATAOUT 50      //MOSI#define DATAIN 51       //MISO`
...and the result is:
Code: [Select]
`Initialize High Speed Constant Reading Mode P = 53907, T x 10 = 511 C P = 53907, T x 10 = 511 C P = 53907, T x 10 = 511 C P = 53907, T x 10 = 511 C`
We also tryed the libary posted at this: arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236443720/8, but making just functions (and not objects and libaries) as dilbert98122 post #14.

... and the result is:
Code: [Select]
`Starting upTemprature (C/F): 51.15 / 124.07Pressure (hPa): 494.0775146484---------------------------------Temprature (C/F): 51.15 / 124.07Pressure (hPa): 494.0775146484---------------------------------Temprature (C/F): 51.15 / 124.07Pressure (hPa): 494.0775146484...`

As you can see our values don't varries. Is there any logical explanation for this (I suppose YES)? Do we need to do something with the registers at the SCP1000-D01?

We're stuck. The code that we would like to work looks like:
Code: [Select]
`#include "WProgram.h"// Class global constantsconst byte DataOutPin = 50;const byte DataInPin = 51;const byte SPIClockPin = 52;// Select master/slave pinconst byte _selectPin = 53;// Register Addressesconst byte REVID = 0x00;            // ASIC Revision Numberconst byte OPREG = 0x03;            // Operation Registerconst byte OPSTATUS = 0x04;            // Operation Statusconst byte STATUS = 0x07;            // ASIC Statusconst byte PRESSURE = 0x1F;            // Pressure 3 MSBconst byte PRESSURE_LSB = 0x20;              // Pressure 16 LSBconst byte TEMP = 0x21;                  // 16 bit tempconst byte RSTR = 0x06;                  // Soft Reset register// Mode valuesconst byte HiResMode = 0x0A;      // Hi Resolution, Constant Readingsconst byte StandbyMode = 0x00;      // No operation// Valuesfloat TempC;      // DegCfloat BaroP;      // in hPa (mbar)void setup() {        Serial.begin(57600); // Open serial connection to report values to host        Serial.println("Starting up");        // Set Pin directions      pinMode(DataOutPin, OUTPUT);      pinMode(DataInPin, INPUT);      pinMode(SPIClockPin, OUTPUT);      pinMode(_selectPin, OUTPUT);      digitalWrite(_selectPin, HIGH); //disable device        // Set SPI control register      // SPIE = 0      no interupt      // SPE = 1      SPI enabled      // DORD = 0      (MSB first)      // MSTR = 1 (master)      // CPOL = 0 (clock idle when low)      // CPHA = 0 (samples MOSI on rising edge)      // SPR1 = 1 & SPR0 = 1 (125kHz)      SPCR = 0b01010011;      SPSR = 0b00000000;      delay(100);            // Allow SCP1000 to complete initialization                write_register(OPREG, HiResMode);}void loop() {        readTemperature();      readPressure();        Serial.print("Temprature (C/F): ");        Serial.print(TempC);        Serial.print(" / ");        Serial.println( (1.8*TempC + 32) );        Serial.print("Pressure (hPa): ");        Serial.println(BaroP, 10);        Serial.println("---------------------------------");        delay(1000);}void write_register(byte register_name, byte data) {      //SCP1000 command format is 6-bit address, 1-bit R/W, and 1-bit "0"      register_name <<= 2;                  // Shift register address to upper bits      register_name |= 0b00000010;            // Write command      digitalWrite(_selectPin, LOW);      // Select SPI device      spi_transfer(register_name);      // Send register location      spi_transfer(data);            // Send value to record into register      digitalWrite(_selectPin, HIGH);      // End Communication}void readPressure(){      unsigned long pressure;      // Pressure value is in 19-bit unsigned format      // Value = Pa * 4      pressure = read_register(PRESSURE, 1);  // Read MSB      pressure &= 0b00000111;                              // mask unused bits      pressure <<= 16;                                    // shift into upper word      pressure  |= read_register(PRESSURE_LSB, 2); // read low word      // Convert to real pressure in hPa      BaroP = pressure / 400.0;}void readTemperature(){      int temp_in;      // Temperature word is 14-bit signed int = (DegC * 20)      temp_in = read_register(TEMP, 2);      // Shift sign bit (bit 13) to proper position for signed int (bit 15)      // This is equivalent to multiplying by 4, so now temp_in = DegC * 80      temp_in <<= 2;      TempC = temp_in / 80.0;            // Convert to real DegC}unsigned int read_register(byte register_name, byte numBytes){      unsigned int in_word;      // SCP1000 registers are either 1 or 2 bytes long      numBytes = (numBytes > 2) ? 2 : numBytes;  // ensure # of bytes is 0..2      // SCP1000 command format is 6-bit address, 1-bit R/W, and 1-bit "0"      register_name <<= 2;            // Shift register address to upper bits      register_name &= 0b11111100;      //Read command      digitalWrite(_selectPin,LOW);      // Select SPI Device      spi_transfer(register_name);      // Send register address to device      for(; numBytes > 0; --numBytes) {            in_word <<= 8;                              // move existing bits up by one byte            in_word |= spi_transfer(0x00);      // add next byte      }      digitalWrite(_selectPin,HIGH);      // End Communiction      return(in_word);}byte spi_transfer(volatile byte data){      SPDR = data;                              // Start the transmission      while (!(SPSR & (1<<SPIF)))                    // Wait for the end of the transmission      {};      return SPDR;                              // return the received byte}`

dilbert98122s code, though edited as explained above.

#### itsthemedication

#48
##### May 31, 2010, 04:41 amLast Edit: May 31, 2010, 05:06 pm by itsthemedication Reason: 1
Here is a compilation of code and code fixes from this thread that seems to be working for me.  There is code for the Duemilanove.  You'll find code for the Mega in the next post.

First, use this Sparkfun page to hook the 3.3 volt board to the 5 volt Arduino:

http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=65

Here is a cheatsheet:

Parallax SCP1000   Arduino      Deumilanova/Mega
1      VSS/GND       gnd
2      AVDD             3.3 v
3      TRIG             Connect to gnd if not used
4      DRDY (Int)     n/a
5      DVDD            3.3 V
6      PD                 connect to gnd if not used
7      SCLK                   pin 13/52 using 10K resistor
8      MOSI             pin 11/51 using 10K resistor
9      MISO                 pin 12/50 straight through (no resistor needed)
10      CSB             pin 10/53 using 1K with 10K 3.3v pull up from
sensor side of 1K

Here is the Adruno Duemilanove code (nothing new, just has fixes discussed) works in 018.  Dividing temp by 19 instead of 20 (seemed more accurate for my board at least), and outputed pressure in atmospheres (because I get that).

Code: [Select]
`/*SCP1000 (parallax board on 5v arduino duelilanova)code from Conor with fixes by BLP from thread:( http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213217330/5#5 )uses pins 10, 11, 12 ,13 Must use resistors with 5volt Arduino talking to this 3.3 volt SPI sensor. See:(http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=65)Parallax SCP1000      Arduino      1   VSS/GND           gnd      2   AVDD              3.3 v3   TRIG              Connect to gnd if not used      4   DRDY (Int)        n/a      5   DVDD              3.3 V      6   PD                connect to gnd if not used      7   SCLK              pin 13 using 10K resistor8   MOSI              pin 11 using 10K resistor9   MISO              pin 12 straight through (no resistor needed)10  CSB               pin 10 using 1K with 10K 3.3v pull up from                        sensor side of 1K */// define spi bus pins#define SLAVESELECT 10#define SPICLOCK 13#define DATAOUT 11      //MOSI#define DATAIN 12       //MISO#define UBLB(a,b)  ( ( (a) << 8) | (b) )#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )//Addresses#define REVID 0x00      //ASIC Revision Number#define OPSTATUS 0x04   //Operation Status#define STATUS 0x07     //ASIC Status#define START 0x0A      //Constant Readings#define PRESSURE 0x1F   //Pressure 3 MSB#define PRESSURE_LSB 0x20 //Pressure 16 LSB#define TEMP 0x21       //16 bit tempchar rev_in_byte;          int temp_in;unsigned long pressure_lsb;unsigned long pressure_msb;unsigned long temp_pressure;unsigned long pressure;void setup(){  byte clr;  pinMode(DATAOUT, OUTPUT);  pinMode(DATAIN, INPUT);  pinMode(SPICLOCK,OUTPUT);  pinMode(SLAVESELECT,OUTPUT);  digitalWrite(SLAVESELECT,HIGH); //disable device      SPCR = B01010011; //MPIE=0, SPE=1 (on), DORD=0 (MSB first), MSTR=1 (master), CPOL=0 (clock idle when low), CPHA=0 (samples MOSI on rising edge), SPR1=0 & SPR0=0 (500kHz)  clr=SPSR;  clr=SPDR;  delay(10);  Serial.begin(9600);  delay(500);  Serial.println("Initialize High Speed Constant Reading Mode");  write_register(0x03,0x09);}void loop(){    rev_in_byte = read_register(REVID);    pressure_msb = read_register(PRESSURE);  pressure_msb &= B00000111;  pressure_lsb = read_register16(PRESSURE_LSB);  pressure_lsb &= 0x0000FFFF;  // this is BLP's fix  pressure = UBLB19(pressure_msb, pressure_lsb);  pressure /= 4;    Serial.print("PRESSURE (Pa)[");  Serial.print(pressure, DEC);  Serial.println("]");    Serial.print("PRESSURE (Atm)[");  float pAtm=float(pressure)/101325.0;  Serial.print(pAtm, 3);  Serial.println("]");    temp_in = read_register16(TEMP);  float tempC = float(temp_in)/19.0; // use 20 by the spec sheet - my board seems closer to 19  Serial.print("TEMP C [");  Serial.print(tempC , 0);  Serial.println("]");  float tempF = tempC*1.8 + 32;  Serial.print("TEMP F [");  Serial.print(tempF , 0);  Serial.println("]");  Serial.println("--------------------------");  delay(2500);  }char spi_transfer(volatile char data){  SPDR = data;                    // Start the transmission  while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission  {  };  return SPDR;                    // return the received byte}char read_register(char register_name){    char in_byte;    register_name <<= 2;    register_name &= B11111100; //Read command      digitalWrite(SLAVESELECT,LOW); //Select SPI Device    spi_transfer(register_name); //Write byte to device    in_byte = spi_transfer(0x00); //Send nothing, but we should get back the register value    digitalWrite(SLAVESELECT,HIGH);    delay(10);    return(in_byte);  }unsigned long read_register16(char register_name){    byte in_byte1;    byte in_byte2;    float in_word;        register_name <<= 2;    register_name &= B11111100; //Read command    digitalWrite(SLAVESELECT,LOW); //Select SPI Device    spi_transfer(register_name); //Write byte to device    in_byte1 = spi_transfer(0x00);        in_byte2 = spi_transfer(0x00);    digitalWrite(SLAVESELECT,HIGH);    in_word = UBLB(in_byte1,in_byte2);    return(in_word);}void write_register(char register_name, char register_value){    register_name <<= 2;    register_name |= B00000010; //Write command    digitalWrite(SLAVESELECT,LOW); //Select SPI device    spi_transfer(register_name); //Send register location    spi_transfer(register_value); //Send value to record into register    digitalWrite(SLAVESELECT,HIGH);} `

#### PaulS

#49
##### May 31, 2010, 12:34 pm
Notice how difficult that code is to read. It looks like you used the "Copy for forum" option on the Edit menu of the Arduino IDE.

When copying code for the forum, please don't use that option. It is meant to prepare the code for pasting as a quote, not as code.

The preferred method is to copy the code using Select All and Copy. Then, use the Code button (with the # symbol) and paste the code.

I wish that they would remove the Copy for Forum option from the Edit menu.
The art of getting good answers lies in asking good questions.

#### itsthemedication

#50
##### May 31, 2010, 04:18 pmLast Edit: Jun 01, 2010, 01:55 pm by itsthemedication Reason: 1
Thanks for the catch.  Yes I did stupidly use the seemingly appropriately named "copy for forum."  Sorry.  It's fixed now.  Here is scp1000 code for the MEGA (tested) Thanks for everyone that contributed in this thread.

Mega code - remember the resistors and that the last two ports at the end of the row on the MEga are not 52 and 53, they are gnd ports!!!!
Code: [Select]
`/*SCP1000 (parallax board on 5v arduino mega)code from Conor with fixes by BLP from thread:( http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1213217330/5#5 )uses pins 10, 11, 12 ,13  for Duemilanove or 53, 51, 50, 52 for Arduino MegaMust use resistors with 5volt Arduino talking to this 3.3 volt SPI sensor. See:(http://www.sparkfun.com/commerce/tutorial_info.php?tutorials_id=65)Parallax SCP1000      ArduinoD/ArduinoMega      1   VSS/GND           gnd      2   AVDD              3.3 v3   TRIG              Connect to gnd if not used      4   DRDY (Int)        n/a      5   DVDD              3.3 V      6   PD                connect to gnd if not used      7   SCLK              pin 13/52 using 10K resistor8   MOSI              pin 11/51 using 10K resistor9   MISO              pin 12/50 straight through (no resistor needed)10  CSB               pin 10/53 using 1K with 10K 3.3v pull up from                        sensor side of 1K */// define spi bus pins#define SLAVESELECT 53   // CS/SS pin 10 or 53#define SPICLOCK 52      // clk pin 13 or 52#define DATAOUT 51       //MOSI pin 11 or 51#define DATAIN 50       //MISO pin 12 or 50#define UBLB(a,b)  ( ( (a) << 8) | (b) )#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )//Addresses#define REVID 0x00      //ASIC Revision Number#define OPSTATUS 0x04   //Operation Status#define STATUS 0x07     //ASIC Status#define START 0x0A      //Constant Readings#define PRESSURE 0x1F   //Pressure 3 MSB#define PRESSURE_LSB 0x20 //Pressure 16 LSB#define TEMP 0x21       //16 bit tempchar rev_in_byte;          int temp_in;unsigned long pressure_lsb;unsigned long pressure_msb;unsigned long temp_pressure;unsigned long pressure;void setup(){  byte clr;  pinMode(DATAOUT, OUTPUT);  pinMode(DATAIN, INPUT);  pinMode(SPICLOCK,OUTPUT);  pinMode(SLAVESELECT,OUTPUT);  digitalWrite(SLAVESELECT,HIGH); //disable device      SPCR = B01010011; //MPIE=0, SPE=1 (on), DORD=0 (MSB first), MSTR=1 (master), CPOL=0 (clock idle when low), CPHA=0 (samples MOSI on rising edge), SPR1=0 & SPR0=0 (500kHz)  clr=SPSR;  clr=SPDR;  delay(10);  Serial.begin(9600);  delay(500);  Serial.println("Initialize High Speed Constant Reading Mode");  write_register(0x03,0x09);}void loop(){    rev_in_byte = read_register(REVID);    pressure_msb = read_register(PRESSURE);  pressure_msb &= B00000111;  pressure_lsb = read_register16(PRESSURE_LSB);  pressure_lsb &= 0x0000FFFF;  // this is BLP's fix  pressure = UBLB19(pressure_msb, pressure_lsb);  pressure /= 4;    Serial.print("PRESSURE (Pa)[");  Serial.print(pressure, DEC);  Serial.println("]");    Serial.print("PRESSURE (Atm)[");  float pAtm=float(pressure)/101325.0;  Serial.print(pAtm, 3);  Serial.println("]");    temp_in = read_register16(TEMP);  float tempC = float(temp_in)/19.0; // use 20 by the spec sheet - my board seems closer to 19  Serial.print("TEMP C [");  Serial.print(tempC , 0);  Serial.println("]");  float tempF = tempC*1.8 + 32;  Serial.print("TEMP F [");  Serial.print(tempF , 0);  Serial.println("]");  Serial.println("--------------------------");  delay(2500);  }char spi_transfer(volatile char data){  SPDR = data;                    // Start the transmission  while (!(SPSR & (1<<SPIF)))     // Wait for the end of the transmission  {  };  return SPDR;                    // return the received byte}char read_register(char register_name){    char in_byte;    register_name <<= 2;    register_name &= B11111100; //Read command      digitalWrite(SLAVESELECT,LOW); //Select SPI Device    spi_transfer(register_name); //Write byte to device    in_byte = spi_transfer(0x00); //Send nothing, but we should get back the register value    digitalWrite(SLAVESELECT,HIGH);    delay(10);    return(in_byte);  }unsigned long read_register16(char register_name){    byte in_byte1;    byte in_byte2;    float in_word;        register_name <<= 2;    register_name &= B11111100; //Read command    digitalWrite(SLAVESELECT,LOW); //Select SPI Device    spi_transfer(register_name); //Write byte to device    in_byte1 = spi_transfer(0x00);        in_byte2 = spi_transfer(0x00);    digitalWrite(SLAVESELECT,HIGH);    in_word = UBLB(in_byte1,in_byte2);    return(in_word);}void write_register(char register_name, char register_value){    register_name <<= 2;    register_name |= B00000010; //Write command    digitalWrite(SLAVESELECT,LOW); //Select SPI device    spi_transfer(register_name); //Send register location    spi_transfer(register_value); //Send value to record into register    digitalWrite(SLAVESELECT,HIGH);} `

#### sbod

#51
##### Jun 22, 2010, 05:19 pmLast Edit: Jun 22, 2010, 05:20 pm by sbod Reason: 1
hi,

im using the openLog board, this is also arduino compatibel , but much smaller.

I get with the "conor" code correct pressure datas, but im little confused about the pins, because i think the pin definition is not the same as at the normal arduino board
Code: [Select]
`// define spi bus pins#define SLAVESELECT 10#define SPICLOCK 17  //SCK 13 #define DATAOUT 11      //MOSI 11 , atmega spec 15#define DATAIN 12       //MISO 12, atmega spec 16#define UBLB(a,b)  ( ( (a) << 8) | (b) )#define UBLB19(a,b) ( ( (a) << 16 ) | (b) )`

the pin definition have i read from the atmega 328p spec is in my opinion different, so the slaveselectpin  is not clear and MOSI, MISO are also different pins.

did anyone here also use this openLog Board together with the SCP 1000 over SPI ?

have anyone here a method to calculate the heigth from the pressuredata ?

Greetings

Steffen

#### zooto68

#52
##### Aug 20, 2010, 10:44 am
Anybody know how I can get in touch with Conor? He was last seen on the forum in 2008.

#### zooto68

#53
##### Aug 23, 2010, 04:36 pm
Can anyone explain why these commands are necessary?

Code: [Select]
`{    char in_byte;    register_name <<= 2;    register_name &= B11111100; //Read command`

I've read the SCP1000 datasheet and it makes no sense to me. Also, the AND function doesn't change the number so it is irrelevant as far as I can see.

Can anyone explain?

Go Up