1

I am working with STPM10 energy metering chip (evaluation board) and I want to read the data from 8 internal registers of the chip each containing 32 bits. This is the 8 internal registers of the chip

The datasheet of the STPM10 chip suggested to have a simplex synchronous SPI where the MOSI of the Arduino is not connected to any pin on the energy chip. Instead they provided a timing diagram to switch from reading and writing on the energy chip.

enter image description here

After the t5, datasheet stated that we should apply 32 serial clocks per data record and up to 8 data records can be read this way. My problem is how to apply 32 serial clocks to the chip. Is the Serial clock on the Arduino SPI automatically activated after SPI.begin() ? If not, how can I start the serial clock? By the way, this is the code I've written:

#include <SPI.h>

SPISettings settingA(32000000, LSBFIRST, SPI_MODE0);
const byte SYN = 8;
void setup() {
  Serial.begin(9600);
  pinMode(SYN,OUTPUT);
 /*Initializes the SPI bus by setting SCK, MOSI and SS to outputs
  Pulling SCK, and MOSI low, and SS high */
  SPI.begin();
  SPI.beginTransaction(settingA);

  }



void loop() {
  //0----->t1
  digitalWrite(SS,HIGH);
  digitalWrite(SYN,HIGH);
  delay(500);
  //t1----->t2   
  digitalWrite(SYN,LOW);
  delayMicroseconds(1000);
  //t2----->t3
  digitalWrite(SYN,HIGH);
   delayMicroseconds(0.035);
  //t3----->t4
  digitalWrite(SS, LOW); 
  delayMicroseconds(0.035);
  //t4----->t5
  digitalWrite(SYN, LOW);
  delayMicroseconds(0.035);
  //t5---->t6
  digitalWrite(SYN, HIGH);
  delayMicroseconds(0.035);

  byte d1 = SPI.transfer(0x00);
  byte d2 = SPI.transfer(0x00);
  byte d3 = SPI.transfer(0x00);
  byte d4 = SPI.transfer(0x00);
  byte d5 = SPI.transfer(0x00);
  byte d6 = SPI.transfer(0x00);
  byte d7 = SPI.transfer(0x00);
  byte d8 = SPI.transfer(0x00);
  byte d9 = SPI.transfer(0x00);
  byte d10 = SPI.transfer(0x00);
  byte d11 = SPI.transfer(0x00);
  byte d12 = SPI.transfer(0x00);
  byte d13 = SPI.transfer(0x00);
  byte d14 = SPI.transfer(0x00);
  byte d15 = SPI.transfer(0x00);
  byte d16 = SPI.transfer(0x00);
  byte d17 = SPI.transfer(0x00);
  byte d18 = SPI.transfer(0x00);
  byte d19 = SPI.transfer(0x00);
  byte d20 = SPI.transfer(0x00);
  byte d21 = SPI.transfer(0x00);
  byte d22 = SPI.transfer(0x00);
  byte d23 = SPI.transfer(0x00);
  byte d24 = SPI.transfer(0x00);
  byte d25 = SPI.transfer(0x00);
  byte d26 = SPI.transfer(0x00);
  byte d27 = SPI.transfer(0x00);
  byte d28 = SPI.transfer(0x00);
  byte d29 = SPI.transfer(0x00);
  byte d30 = SPI.transfer(0x00);
  byte d31 = SPI.transfer(0x00);
  byte d32 = SPI.transfer(0x00);

  digitalWrite(SS,HIGH);
  digitalWrite(SYN,HIGH);
  delay(499);

  Serial.println(String(d4,BIN) + " " + String(d3,BIN) + " " +  String(d2,BIN) + " " +  String(d1,DEC));
  Serial.println(String(d8,BIN) + " " + String(d7,BIN) + " " +  String(d6,BIN) + " " +  String(d5,BIN));
  Serial.println(String(d12,BIN) + " " + String(d11,BIN) + " " +  String(d10,BIN) + " " +  String(d9,BIN));
  Serial.println(String(d16,BIN) + " " + String(d15,BIN) + " " +  String(d14,BIN) + " " +  String(d13,BIN));
  Serial.println(String(d20,BIN) + " " + String(d19,BIN) + " " +  String(d18,BIN) + " " +  String(d17,BIN));
  Serial.println(String(d24,BIN) + " " + String(d23,BIN) + " " +  String(d22,BIN) + " " +  String(d21,BIN));
  Serial.println(String(d28,BIN) + " " + String(d27,BIN) + " " +  String(d26,BIN) + " " +  String(d25,BIN));
  Serial.println(String(d32,BIN) + " " + String(d31,BIN) + " " +  String(d30,BIN) + " " +  String(d29,BIN));
  Serial.println(" ");
  • The timing diagram posted does not look like a standard SPI transaction. I am inclined to say you can not use the Arduino SPI library. Instead, you may need to bit-bang this out totally in software. For instance, I do not believe there is a "SYN" line in the standard SPI bus. And I don't believe the Chip Select line should go high before the end of the SPI transaction. – st2000 Apr 30 '16 at 5:00
  • This is basically a bidirectional SPI (which many of ST's MCUs support) plus a mode/latch pin - SYN which one would drive with a GPIO. I don't believe there is any requirement that the chip select go high early, especially as some of the timing diagrams in the data sheet show it low during the whole transfer. – Chris Stratton Jul 30 '16 at 17:30
1

The STPM10 specification describes a SPI bus unlike any I have seen. Apparently the STPM10 "SYN" line controls the direction of the "SDA" line. As far as I know, there is no "SYN" line in a SPI bus. As such I do not think a normal Arduino SPI library will talk to an STPM10.

A normal single port (MOSI and MISO combined) SPI slave would automatically switch between reading and writing bits. When interfacing with a two port master (such as an Arduino) a resistor is used between the MISO and MOSI nets.

This is the best image I could find. Ignore the chip names. And substitute MOSI for SDO and MISO for SDI. Note there is no "SYN" line in this SPI bus.

enter image description here

I'm showing this diagram as it appears the STPM10 is using a single line for both input and output data.

Because of the missing "SYN" line I do not think you can even use the SPI hardware in the Arduino's Atmel processor. I think your only option is to create a SPI driver from scratch only using software.

I see where STMicroelectronics offers an evaluation software package that talks to the STPM10. Guessing, it looks like they wrote it in National Instruments Lab View. If you could get the source code for that it may provide hints on writing your own STPM10 driver.

1

Like the datasheet says, its best if you implement writing in software and use the hardware SPI for reading. The steps for writing to the registers are as follows:

  1. disable the SPI peripheral;
  2. set MISO, SCLK and SS to be output;
  3. set the pin which is connected to SYN to be output high;
  4. activate SCS first and then SYN;
  5. activate SCL;
  6. apply a bit value to SDA and deactivate SCL;
  7. repeat the last two steps seven times to complete one byte transfer;
  8. repeat the last three steps for any remaining byte transfer;
  9. deactivate SYN and the SCS;
  10. enable again the SPI module;

In Arduino-speak:

#define SCS 4  // define your own CS to have better control

void setup(){
  pinMode(SS, OUTPUT);  //needed to use the SPI

  pinMode(SCS, OUTPUT);  // set SCS and SYN as output
  pinMode(SYN, OUTPUT);
  digitalWrite(SCS, HIGH);  // idle state
  digitalWrite(SYN, HIGH);
  SPI.beginTransaction(SPISettings(32000000, MSBFIRST, SPI_MODE3)) // mode 3, max read clock is 32mhz
}

void write_reg(byte addr, byte val){
  val = (val << 7) | (addr << 1);  // 6-bit addresses!
  SPI.end();  // disable SPI
  pinMode(MISO, OUTPUT);
  digitalWrite(SYN, HIGH);
  delayMicroseconds(10);

  digitalWrite(SCS, LOW);  // assert SCS and SYN
  digitalWrite(SYN, LOW);
  for (int i = 0; i < 8; i++){  // shift out a byte
    delayMicroseconds(10);
    digitalWrite(SCK, LOW);  // max clock is 100kHz
    digitalWrite(MISO, (val & 0x80) ? HIGH : LOW);
    delayMicroseconds(10);
    digitalWrite(SCK, HIGH);
    val <<= 1;
  }

  digitalWrite(SYN, HIGH); // deassert SCS and SYN
  digitalWrite(SCS, HIGH);

  SPI.beginTransaction(SPISettings(32000000, MSBFIRST, SPI_MODE3)); //restart SPI
}

For reading, you use the hardware SPI like this:

void read_regs(uint32_t data[], uint8_t len){  // an array to hold register data is passed
  digitalWrite(SYN, LOW);  // latching operation
  digitalWrite(SCS, LOW);
  digitalWrite(SYN, HIGH);

  uint32_t val = 0;
  for (int i = 0; i < len; i++){  // read the 8 32-bit registers into the array
    val = SPI.transfer(0);  // your 32 serial clocks
    val |= (uint32_t)SPI.transfer(0) << 8;
    val |= (uint32_t)SPI.transfer(0) << 16;
    val |= (uint32_t)SPI.transfer(0) << 24;
    data[i] = val;
  }

  digitalWrite(SCS, HIGH);  // deassert SCS
}

// Use the functions this way:

uint32_t reg_data[8];  // array to hold read data, max is 8

void loop(){
  write_reg(47, 1);  // set config bit 47
  read_regs(reg_data, 8);  // read all reg data into array

  for (int i = 0; i < 8; i++)
    Serial.println(reg_data[i], HEX);
}

The connections are:

Arduino MISO = SDA
Arduino SCK = SCL
Arduino D4 = SCS
Arduino D5 = SYN

Each call of SPI.transfer() yields 8 serial clocks i.e. a clock for each bit, so 32 serial clocks is merely 4 SPI.transfer() calls. Your code is actually producing 32 x 8 = 256 serial clocks. I suggest you read up on SPI.

I didn't include some of the delays in the datasheet because digitalWrite() on an Uno takes about 5us which is more than enough for this case. Of course, the code is untested so...I've done most of your work already, almost feels like I should be getting paid or something...

  • Will definitely test this once I have a breakout for the module. Will donate some cash to you when it works. 80% done on this non-SPI , SPI. – whatnick Aug 4 '16 at 4:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.