Pages: 1 2 3 [4]   Go Down
Author Topic: n00b SPI problem  (Read 13072 times)
0 Members and 1 Guest are viewing this topic.
0
Offline Offline
Newbie
*
Karma: 0
Posts: 10
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 6
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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

0
Offline Offline
Newbie
*
Karma: 0
Posts: 1
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
#define CSB 53 //  SLAVESELECT
#define SPICLOCK 52  // SCK
#define DATAOUT 50      //MOSI
#define DATAIN 51       //MISO
...and the result is:
Code:
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:
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:
#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.
« Last Edit: March 31, 2010, 05:21:22 am by Nudeln » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
/*
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);
}

« Last Edit: May 31, 2010, 10:06:26 am by itsthemedication » Logged

Seattle, WA USA
Offline Offline
Brattain Member
*****
Karma: 642
Posts: 50366
Seattle, WA USA
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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.
Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 17
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
/*
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);
}
« Last Edit: June 01, 2010, 06:55:11 am by itsthemedication » Logged

0
Offline Offline
Newbie
*
Karma: 0
Posts: 3
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
// 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
« Last Edit: June 22, 2010, 10:20:50 am by sbod » Logged

London, England
Offline Offline
Edison Member
*
Karma: 4
Posts: 1026
Go! Go! Arduinoooo !!!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

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

London, England
Offline Offline
Edison Member
*
Karma: 4
Posts: 1026
Go! Go! Arduinoooo !!!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Can anyone explain why these commands are necessary?

Code:
{
    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?
Logged

Pages: 1 2 3 [4]   Go Up
Jump to: