I've been attempting for too many hours now to get a Lolin D1 Mini (ESP8266) to interface with a CS5460a energy metering chip via SPI, and hoping someone here can help!
Hardware:
- Genuine Lolin D1 Mini
- DIY MORE CS5460a breakout board: CS5460A Serial Power Energy Metering Module – diymore
- PC running Windows 10 Home (Version 21H2)
The data sheet for the CS5460a is available here: CS5460A | Cirrus Logic
Wiring:
The data sheet includes a typical connection diagram:
The DIY MORE breakout board appears to include the following from the diagram above: a 4.096 MHz crystal as the clock source, the capacitors, the 10 ohm resistor between VA+ and VD+, the connection between VREFIN and VREFOUT, and the connection between VA- and DGND.
VA+ needs to be +5V to power the CS5460a. VD+ can be +5V or +3.3V depending on the MCU being interfaced with. Since I am using a D1 Mini, VD+ needs to be +3.3V. So, I removed the 10 ohm resistor from the DIY MORE breakout board and made the following connections between the D1 Mini and the DIY MORE board:
D1 MINI DIY MORE breakout board
~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~
+5V -> +VA
+3.3V -> +VD
GND -> GND
SCK -> SLK
MISO 12 -> SDO
MOSI 13 -> SDI
SS 15 -> CS
GPIO 16 -> RST
For now, I am leaving the VIN and IIN inputs unconnected, and am powering the D1 Mini via USB from my PC.
Software:
- Arduino 1.8.19
Code:
The code attempts to establish communication with the CS5460a chip via SPI. It attempts to read the status and config registers, and then to change 'current channel gain' register to a new value. Debugging values are printed to serial.
#include <SPI.h>
// Pin configurations
const int slaveSelectPin = 15;
const int resetPin = 16;
//Global variables
uint32_t returnedValue;
void setup() {
// Set pin modes
pinMode(resetPin, OUTPUT);
pinMode(slaveSelectPin, OUTPUT);
// reset the CS5460 device
digitalWrite(resetPin, LOW);
delay(100);
digitalWrite(resetPin, HIGH);
delay(100);
// initialise serial
Serial.begin(115200);
while (!Serial);
Serial.println();
Serial.println("setup...");
// initialise SPI
SPI.begin();
SPI.beginTransaction(SPISettings(1000000, MSBFIRST, SPI_MODE3));
// Set CS5460a to continuous mode
SPI.transfer16(0b11101000);
Serial.println("Attempted to transfer 11101000 to set continuous conversion mode");
//Check the status register
returnedValue = SPI.transfer(0b00011110); //read the status register.
Serial.print("Attempted to transfer 00011110 to get status register; returned value = ");
Serial.println(returnedValue, BIN);
//Check the config register
returnedValue = SPI.transfer(0b00000000); //read the config register.
Serial.print("Attempted to transfer 00000000 to get config register; returned value = ");
Serial.println(returnedValue, BIN);
//Check the Current Channel Gain register
returnedValue = SPI.transfer(0b00000100); //read the Current Channel Gain register.
Serial.print("Attempted to transfer 00000100 to get Current Channel Gain register; returned value = ");
Serial.println(returnedValue, BIN);
//Change the Current Channel Gain register
uint32_t thisData1;
uint32_t thisData2;
uint32_t *thisPointer;
thisData1 = 0b01000100;
thisData1 = thisData1 << 23;
thisData1=thisData1+0b1010;
thisData2=thisData1;
Serial.print("thisData1 = ");
Serial.println(thisData1,BIN);
Serial.print("thisData2 = ");
Serial.println(thisData2,BIN);
thisPointer = &thisData1;
Serial.print("thisPointer = ");
Serial.println(uint32_t(thisPointer),BIN);
Serial.print("thisData1 after setting pointer = ");
Serial.println(thisData1,BIN);
Serial.print("thisData2 after setting pointer = ");
Serial.println(thisData2,BIN);
uint8_t thisSize = 4;
Serial.print("thisData1 after declaring thisSize = ");
Serial.println(thisData1,BIN);
Serial.print("thisData2 after declaring thisSize = ");
Serial.println(thisData2,BIN);
SPI.transfer(thisPointer,thisSize);
Serial.print("thisData1 after calling SPI.transfer(thisPointer,thisSize); = ");
Serial.println(thisData1,BIN);
Serial.print("thisData2 after calling SPI.transfer(thisPointer,thisSize); = ");
Serial.println(thisData2,BIN);
Serial.print("thisPointer after calling SPI.transfer(thisPointer,thisSize); = ");
Serial.println(uint32_t(thisPointer),BIN);
Serial.print("Attempted to transfer ");
Serial.print(thisData1, BIN);
Serial.println(" to change Current Channel Gain register to 1010");
//Re-check the Current Channel Gain register to see if it was succesfully changed
returnedValue = SPI.transfer(0b00000100); //read the Current Channel Gain register.
Serial.print("Attempted to transfer 00000100 to get Current Channel Gain register; returned value = ");
Serial.println(returnedValue, BIN);
}
void loop() {
}
Serial output:
setup...
Attempted to transfer 11101000 to set continuous conversion mode
Attempted to transfer 00011110 to get status register; returned value = 0
Attempted to transfer 00000000 to get config register; returned value = 10
Attempted to transfer 00000100 to get Current Channel Gain register; returned value = 0
thisData1 = 100010000000000000000000001010
thisData2 = 100010000000000000000000001010
thisPointer = 111111111111111111111101110000
thisData1 after setting pointer = 100010000000000000000000001010
thisData2 after setting pointer = 100010000000000000000000001010
thisData1 after declaring thisSize = 100010000000000000000000001010
thisData2 after declaring thisSize = 100010000000000000000000001010
thisData1 after calling SPI.transfer(thisPointer,thisSize); = 1000000000000000
thisData2 after calling SPI.transfer(thisPointer,thisSize); = 100010000000000000000000001010
thisPointer after calling SPI.transfer(thisPointer,thisSize); = 111111111111111111111101110000
Attempted to transfer 1000000000000000 to change Current Channel Gain register to 1010
Attempted to transfer 00000100 to get Current Channel Gain register; returned value = 0
Problems
-
The request to read the status register returns 0, which (according to the datasheet) implies that it has received an invalid command. The only command sent before that was to set it to continuous conversion mode. Even when I comment out that command (so that the request to read the status register is the first data sent) the status register still returns 0.
-
Something weird happens with the line SPI.transfer(thisPointer,thisSize); ... It appears to change the value at thisPointer (i.e. the value of thisData1). I'm not sure if it is a related problem or something else.
A hypothesis
While writing this post, I came across this thread: SPI slave receive and return array using SPI.transfer(data,size)
It could be that my problem is that the SPI.transfer calls are not giving the CS5460a enough time to process and respond; especially with the multi-byte transfer (i.e. SPI.transfer(thisPointer,thisSize);). If so, do I have to go back and write low-level code to handle the comms between the master and slave rather than just using the built-in SPI library functions? If slaves so often need some delay time to process things before responding to the master, then shouldn't such delay be built in as a parameter to the SPI.transfer function?
Anyhow, any help to solve this would be greatly appreciated. Thank you very much for your time!