Pages: 1 [2] 3   Go Down
Author Topic: SPI read write for 32bits data  (Read 6115 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jay,

            You also working on the same IC? Any luck? What hardware connection are you using? Any schematic to show? Thanks
Logged

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1726
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

@Jay

You are correct about the changes from byte to char in the for loops, that was a typo on my end. Also setting SS high at the beginning is necessary (though setting it to an output is done by the SPI library).

One thing I have noticed is that you are trying to use SPI mode 0, and I believe the IC to be SPI mode 3 (data is read on the first rising edge after a falling one according to the timing diagrams).


@Paradigm

The union works by placing an array of 4 bytes in the same memory location as the struct. The struct contains a 24bit variable and a byte variable.
 Due to the way unions work this basically means that the byte variable 'command' is stored at the same place as the element 3 in the array. Similarly the variable 'value' is stored in the same memory space as the three other bytes in the array (elements 0,1,2).
Basically what this means is that you can convert between the array and the struct without doing any calculations, making it a very efficient method.

I will have a play with the code to see if I can find anything which may be causing a problem.
Logged

~Tom~

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1726
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

Right, all of the code appears to be doing what is expected, however I have just had it up on the oscilloscope and the default SCLK rate (8MHz) is far far faster than the chips absolute maximum SCLK rate (2MHz).

Also, it is definitely MODE_3. The datasheet talks about the SDI setup time before rising edge which is indicative of MODE_3 which the timing diagrams confirm.

Try this:
Code:
#include <SPI.h>

union FourByte{
    struct {
      unsigned long value:24; //24bit register values go in here
      byte command:8; //8bit command goes in here.
    };
    byte bit8[4]; //this is just used for efficient conversion of the above into 4 bytes.
};

void setup(){
  SPI.begin();
  SPI.setBitOrder(MSBFIRST);
  SPI.setDataMode(SPI_MODE3); //I believe it to be Mode3
  SPI.setClockDivider(SPI_CLOCK_DIV16);
  pinMode(SS, OUTPUT); //not really necessary as it is done by the SPI library.
  digitalWrite(SS, HIGH);
  //Page
  //example of reading data
  unsigned long voltage = SPI_read(4);//Instantaneous Voltage Channel 1
  
  //example of writing data
  union FourByte data;
  data.command = 0b01000000; //Write to config register
  data.value = 1; //This is the default value from datasheet, just using it as an example.
  SPI_write(data);
}

void loop(){
  
}

void SPI_write(union FourByte data) {
  digitalWrite(SS,LOW); //Using CS pin, so sync1/sync0 bytes not needed
  for(char i = 3; i >= 0; i--){
    SPI.transfer(data.bit8[i]); //transfer all 4 bytes of data - command first, then Big Endian transfer of the 24bit value.
  }
  digitalWrite(SS,HIGH);
}

unsigned long SPI_read(byte command){
  digitalWrite(SS,LOW); //SS goes low to mark start of transmission
  union FourByte data = {0xFEFEFE,command}; //generate the data to be sent, i.e. your command plus the Sync bytes.
  for(char i = 3; i >= 0; i--){
    data.bit8[i] = SPI.transfer(data.bit8[i]); //send the data whilst reading in the result
  }
  digitalWrite(SS,HIGH); //SS goes high to mark end of transmission
  return data.value; //return the 24bit value recieved.
}
Logged

~Tom~

Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Tom, I saw that the chip can run at 4MHz. Where you found the 2MHz? Because from the breakout board supplied by my vendor, the crystal connected to my IC is a 4MHz IC. My Uno is using 16MHz so I have to use the default value of 4 to get it to 4Mhz? Or must I still write SPI.setClockDivider(SPI_CLOCK_DIV4);

Or maybe I can try on different clock speed :-)
Logged

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1726
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

You are correct that the clock for the IC should be 4MHz. However at 4MHz, the serial clock frequency for its SPI interface is limited to a maximum of 2MHz, which is specified on page 11 of the datasheet.

As the Uno runs at 16MHz, then
SPI_CLOCK_DIV2 = 8MHz,
SPI_CLOCK_DIV4 = 4MHz,
SPI_CLOCK_DIV8 = 2MHz,
SPI_CLOCK_DIV16 = 1MHz.

As such you will see this line in the code in my last post:
  SPI.setClockDivider(SPI_CLOCK_DIV16);

So that the SPI interface will run at 1MHz. It is usually best to run below the maximum value which is why I suggest using 1MHz not 2MHz.
Logged

~Tom~

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

@Paradigm yes,I'm on the same boat as you.  smiley and I used Energy IC diagram as in the data sheet page 42 to join the Arduino Uno....working out on the program..

@Tom  Thanks for the correction.. How can I print the voltage?I mean when I print out,the voltage value remains at 0.Should this line be in the loop?
Code:
unsigned long voltage = SPI_read(4);//Instantaneous Voltage Channel 1
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jaay, did you fabricate the circuit yourself or bought it from vendor? How you come out with all the values and rating of the components? Hope you can help me also. As the breakout board that I had is from a vendor. Wish to fabricate it myself
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Tom,

From your code
Code:
//example of writing data
  union FourByte data;
  data.command = 0b01000000; //Write to config register
  data.value = 1; //This is the default value from datasheet, just using it as an example.
  SPI_write(data);
}

The data.value = 1; and you said its a default value from datasheet. Can I ask where you find this statement? Can you kindly advise? Thanks a lot. Because I always thought the data.value should be the sync0 or sync1 value example: data.value = 0xFEFFFE; is it? Thanks a lot for your help
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 12
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I also got it from vendor smiley.All I do is read the data sheet and managing for the code based on the data sheet.But I'm also still on the way so we can help each other out.

@Tom BTW What's this line also...Thanks a lot

Code:
data.value = 1; //This is the default value from datasheet, just using it as an example.
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Jaay,

           Too bad, I thought I can replicate the vendor breakout board. Its ok. As long as I can start reading from the board, I can always buy more from the vendor. Hahaha
Logged

Miramar Beach, Florida
Online Online
Faraday Member
**
Karma: 144
Posts: 5985
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Also, it is definitely MODE_3. The datasheet talks about the SDI setup time before rising edge which is indicative of MODE_3 which the timing diagrams confirm.
How do you figure that? The way I see it, the timing diagram shows the capture is on the first rising edge after the CS goes LOW. That timing specification is marked (on the write timing) as "t3" (time required between the CS Falling and SCLK Rising) (edit: and "t6" on the read timing).

The read timing shows this best. SCLK is idle LOW with clock pulses going HIGH. That is SPI Mode 0.
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

Are we having fun yet?  smiley
« Last Edit: November 22, 2012, 09:56:54 am by SurferTim » Logged

Miramar Beach, Florida
Online Online
Faraday Member
**
Karma: 144
Posts: 5985
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

This is the test code I would use to test read. It reads the same register every second.
Code:
#include <SPI.h>

// change this to your SS pin
#define CS5464 8

void setup() {
  Serial.begin(9600);

  // disable CS5464 SPI
  pinMode(CS5464,OUTPUT);
  digitalWrite(CS5464,HIGH);

  SPI.begin();
  SPI.setClockDivider(SPI_CLOCK_DIV8);

  Serial.println("Setup complete"); 
}

void loop() {
  delay(1000);
  long testVal = readMeter(4);
  Serial.println(testVal);
}

long readMeter(byte meterCommand) {
  long lBuffer = 0;
  byte rtnVal[3];
 
  // enable CS5464 SPI
  digitalWrite(CS5464,LOW);

  // delay 1us after CS LOW
  delayMicroseconds(1);

  // send your command
  SPI.transfer(meterCommand);

  // read the 3 bytes
  // you could use a for loop here
  rtnVal[0] = SPI.transfer(0xFF);
  rtnVal[1] = SPI.transfer(0xFF);
  rtnVal[2] = SPI.transfer(0xFF);

  // disable CS5464 SPI
  digitalWrite(CS5464,HIGH); 

  // assemble into long type
  lBuffer = lBuffer | rtnVal[0];
  lBuffer = lBuffer << 8;
  lBuffer = lBuffer | rtnVal[1];
  lBuffer = lBuffer << 8;
  lBuffer = lBuffer | rtnVal[2];
 
  return lBuffer;
}
Logged

Leeds, UK
Offline Offline
Edison Member
*
Karma: 80
Posts: 1726
Once the magic blue smoke is released, it won't go back in!
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

I also got it from vendor smiley.All I do is read the data sheet and managing for the code based on the data sheet.But I'm also still on the way so we can help each other out.

@Tom BTW What's this line also...Thanks a lot

Code:
data.value = 1; //This is the default value from datasheet, just using it as an example.

Basically that is setting the value you want to write to a register.

The bit of code relavent to that snippit is:
Code:
 //example of writing data
  union FourByte data;
  data.command = 0b01000000; //Write to config register
  data.value = 1; //This is the default value from datasheet, just using it as an example.
  SPI_write(data);

In the code, the command is set to write to the config register (0b01000000 from the datasheet - page 26), and then the value to write to that register is 1 (if you look at the list of commands in the datasheet it shows that the default value for the config register is 1, this was just an example of usage, not a requirement).

When you are reading a register, the lower three bytes should be 0xFEFEFE as you pointed out. This is done in the SPI_Read() function for you.



@Paradigm yes,I'm on the same boat as you.  smiley and I used Energy IC diagram as in the data sheet page 42 to join the Arduino Uno....working out on the program..

@Tom  Thanks for the correction.. How can I print the voltage?I mean when I print out,the voltage value remains at 0.Should this line be in the loop?
Code:
unsigned long voltage = SPI_read(4);//Instantaneous Voltage Channel 1


That is an example of how to read a register, it doesn't actually do anything with the returned value. You could do something like this:

Code:
void loop() {
  delay(1000);
  unsigned long voltage = SPI_read(4);//Instantaneous Voltage Channel 1
  Serial.println(voltage); //print the voltage to the serial monitor (you will need to have called Serial.begin(...) in the setup() for it to work)
}


Quote
Also, it is definitely MODE_3. The datasheet talks about the SDI setup time before rising edge which is indicative of MODE_3 which the timing diagrams confirm.
How do you figure that? The way I see it, the timing diagram shows the capture is on the first rising edge after the CS goes LOW. That timing specification is marked (on the write timing) as "t3" (time required between the CS Falling and SCLK Rising) (edit: and "t6" on the read timing).

The read timing shows this best. SCLK is idle LOW with clock pulses going HIGH. That is SPI Mode 0.
http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus

Are we having fun yet?  smiley


The way I see the timing diagrams, it doesn't matter where the clock IDLEs in SPI. The clock is high when/as the SS line goes low. So we have:

SCLK is high.
SS drops low.
SCLK drops low.
MOSI is set to the correct value
SCLK rises high -> data is clocked in on the rising edge

All of that is indicative of MODE3.

Another way of putting it is that there is always a falling edge of SCLK before the first rising edge on which data is clocked - this is MODE3.
Logged

~Tom~

Miramar Beach, Florida
Online Online
Faraday Member
**
Karma: 144
Posts: 5985
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Another way of putting it is that there is always a falling edge of SCLK before the first rising edge on which data is clocked - this is MODE3.
I don't know what datasheet you are looking at, but not according to the read timing in the datasheet posted here. There is no falling edge before the rising edge. The write timing indicates there could be a falling edge prior to the rising edge, but it won't propagate the data.

It is probably just me, since yours is working, correct?
Logged

Offline Offline
Jr. Member
**
Karma: 0
Posts: 58
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi Tim and Tom,

            I did the Mode 3 and ClockDiv. But still cant read anything from the IC. Do I miss out something? Must we initalise the IC before it can be use? How can I send the continuos conversion command to the IC to continue reading data?

Hi Jaay,

           Any luck? You program can work on your hardware?

           Thanks a lot
Logged

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