Go Down

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

yennifs

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

quiensoy

Ok,  thanks very much,
I'll look at that link now, thanks

Nudeln

#47
Mar 31, 2010, 12:19 pm Last 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 up
Temprature (C/F): 51.15 / 124.07
Pressure (hPa): 494.0775146484
---------------------------------
Temprature (C/F): 51.15 / 124.07
Pressure (hPa): 494.0775146484
---------------------------------
Temprature (C/F): 51.15 / 124.07
Pressure (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 constants
const byte DataOutPin = 50;
const byte DataInPin = 51;
const byte SPIClockPin = 52;

// Select master/slave pin
const byte _selectPin = 53;

// Register Addresses
const byte REVID = 0x00;            // ASIC Revision Number
const byte OPREG = 0x03;            // Operation Register
const byte OPSTATUS = 0x04;            // Operation Status
const byte STATUS = 0x07;            // ASIC Status
const byte PRESSURE = 0x1F;            // Pressure 3 MSB
const byte PRESSURE_LSB = 0x20;              // Pressure 16 LSB
const byte TEMP = 0x21;                  // 16 bit temp
const byte RSTR = 0x06;                  // Soft Reset register

// Mode values
const byte HiResMode = 0x0A;      // Hi Resolution, Constant Readings
const byte StandbyMode = 0x00;      // No operation

// Values
float TempC;      // DegC
float 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.

Thanks in advance.

itsthemedication

#48
May 31, 2010, 04:41 am Last 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 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 using 10K resistor
8   MOSI              pin 11 using 10K resistor
9   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 temp

char 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

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.

itsthemedication

#50
May 31, 2010, 04:18 pm Last 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 Mega
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      ArduinoD/ArduinoMega      
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
*/

// 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 temp

char 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 pm Last 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

Mike Mc

Anybody know how I can get in touch with Conor? He was last seen on the forum in 2008.

Mike Mc

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