Interfacing Arduino Mega and LTC1325 - Page 1
Forum section: electronics / general

author: lucatz
author_rank: Contributor
timestamp: November 08, 2020, 06:40:52 pm
content: Hi All,Trying to get LTC1325 Battery Management chip interfaced with Arduino as a project. I need to send command word of 22 bits to LTC via SPI bus. Little over my head as I am not a great programmer so trying to learn in process. I would appreciate some help with this part. So far my code seems to do something from what I see on Oscope but not sure it is actually doing what I want. Once the command word is sent I should receive 8 bits to confirm all is good. Somehow would be best if serial.print was was used to output what I send and receive from LTC1325. Attached is LTC1325 doc.Thank YouLucaCode:#include <SPI.h>void setup() {// Enable SPI for LTC1325digitalWrite(SS, HIGH); // ensure SS stays high for now// Put SCK, MOSI, SS pins into output mode// also put SCK, MOSI into LOW state, and SS into HIGH state.// Then put SPI hardware into Master mode and turn SPI onSPI.begin();// Slow down the master a bit//SPI.setClockDivider(SPI_CLOCK_DIV64);const int CS_Pin = 7;SPI.beginTransaction(SPISettings(250000, MSBFIRST, SPI_MODE0));pinMode(CS_Pin, OUTPUT); // The CS_Pin should remain in a high impedance state (INPUT) when it is not in use.digitalWrite(CS_Pin, LOW); // Activate the CS line (CS is active LOW)SPI.transfer(0b00000010); // Send First byteSPI.transfer(0b00100100); // Send Second byteSPI.transfer(0b00000000); // Send Third byteSPI.transfer(0b00000000); // Send Forth byteSPI.transfer(0b00000000); // Send Fifth byteSPI.transfer(0b00000000); // Send Sixte bytepinMode(CS_Pin, INPUT); // Set CS_Pin to high impedance to allow pull-up to reset CS to inactive.digitalWrite(CS_Pin, HIGH); // Enable internal pull-up}void loop() {//Loop Read from LTC1325const int CS_Pin = 7;pinMode(CS_Pin, OUTPUT); // The CS_Pin should remain in a high impedance state (INPUT) when it is not in use.digitalWrite(CS_Pin, LOW); // Activate the CS line (CS is active LOW)SPI.transfer(0b00000000); // Just send 0'spinMode(CS_Pin, INPUT); // Set CS_Pin to high impedance to allow pull-up to reset CS to inactivedigitalWrite(CS_Pin, HIGH); // Enable internal pull-up}

author: rstofer
author_rank: Super Contributor
timestamp: November 08, 2020, 08:51:32 pm
content: You're pretty close, now that I look at the 6 byte transfer...Read the Datasheet on Page 25 under Motorola SPI and note:The command is sent as 4 8-bit bytes and the result is read when two more bytes of 0x00 are sent. You have that right but...So, you need 4 SPI.transfer statements to send out the command word and two to read like this:SPI.transfer(FirstByteOfCommand);SPI.transfer(SecondByteOfCommand);SPI.transfer(ThirdByteOfCommand);SPI.transfer(FourthByteOfCommand);thenval1 = SPI.transfer(0x00); // get resultval2 = SPI.transfer(0x00);You have it right except for not putting the returned status into variables. However, you have the 6 byte transfer in the setup() code and down in the loop() code you transfer a single byte. I didn't see anything like that one byte transfer in the datasheet. AFAIK, you need to do the entire 6 byte transaction in the loop() function. Did I miss something?QuoteTable 1-6 gives all of the command details along with the receipt of the results.The table shows for Bytes 5 & 6 Tx a sent value of "don't care" but it is traditional to send 0x00 as you did.

author: lucatz
author_rank: Contributor
timestamp: November 08, 2020, 10:38:10 pm
content: rstoferI'm surprised that I'm even closeno sure it needs to go in LOOP as this should be sent once then LTC will reply with byte 6. I would send 6 bytes and receive 6 to set a function in the LTC then wait for it to do it's thing ie charge/discharge etc... or maybe it should be sent continuously with same data and then it would continue doing whatever it is as nothing changed but this way I get to see new received bytes hmmm...Received bytes 4, 5 ,6 are needed, you gave me a hint that these received bytes should go into a variable and saved for viewing to get an idea of what it is doing. This I will researchThanks

author: rstofer
author_rank: Super Contributor
timestamp: November 09, 2020, 01:12:08 am
content: For the examples given in the datasheet, all are 6 byte transfers. I just assumed you send it the same command, over and over, as you wanted status. You would change the command for a different function and still get status back.In the table, they clearly show the 2 high order A/D bits in the byte 4 RX value. So, maybe there are 3 bytes sent without saving the return values and 3 bytes sent with the return values saved. Nowhere else does it mention this and all of the examples look at just 2 bytes for the return values but it is clearly a 10 bit ADC.Sometimes you just have to use Serial.print to see what is going on.It wouldn't hurt to grab up all 6 return values into an array just to see what you getfor (i = 0; i < 6; i++){Received(i) = SPI.transmit(Command(i);}Then you could do a pretty-print with Serial.print(). Maybe break out the bits and label them and so on.You could wrap all the debug code in an#ifdef DebugPrint // defined at the top of the file---- Debug printout code#endifAt the top of the code you have either#define DebugPrint...or...#undef DebugPrintYour production code wouldn't want to use the serial port for debugging but it will be handy during development.

author: lucatz
author_rank: Contributor
timestamp: November 09, 2020, 10:22:19 pm
content: This does not compute for me sorry not my day job programmingfor (i = 0; i < 6; i++){Received(i) = SPI.transfer(Command(i);}Luca

author: rstofer
author_rank: Super Contributor
timestamp: November 10, 2020, 04:16:22 pm
content: This code compiles but it doesn't do anything real. First, the command string needs to be set up properly and then maybe print some values.The 'for' loop just eliminates a bunch of lines of code and puts all of the return bytes in a simple array. For each of the 6 bytes transmitted, we store the received value. The first 3 are meaningless, the last 3 contain the A/D value and the status.During the loop processing, you may need to change the Command values. No problem, just rewrite them as necessary. The values in the array definition are just the initial command.Code:#include <SPI.h>const int slaveSelectPin = 10;void setup() {// put your setup code here, to run once:Serial.begin(9600);// start the SPI library:pinMode(slaveSelectPin, OUTPUT);SPI.begin();}void loop() {// put your main code here, to run repeatedly:uint8_t Received;uint8_t Command = {0x00,0x01,0x02,0x03,0x04,0x05}; // replace with proper values for commanddigitalWrite(slaveSelectPin, LOW);for (int i = 0; i < 6; i++) // send and receive 6 bytes{Received = SPI.transfer(Command);}digitalWrite(slaveSelectPin, HIGH);// do somethine with received data, maybe Serial.print() some values// put more logic here, it will be executed each time through loop}

author: lucatz
author_rank: Contributor
timestamp: November 10, 2020, 06:03:38 pm
content: Thank You rstoferI think I may have found another issue (apart from my poor coding skills). Arduino requires minimum voltage of 2.4v to see a logic high. Seems the LTC1325 only outputs 0-.5 volts. Exploring a opamp to boost signal. something like a UA741CP, saw many ways of getting this done but this seems to explain Arduino only seeing zero's. Oscope shows an output but just to low.will report back. Once i'm done final sketch will be posted. Overall project is somewhat more complicated and will also get posted once it somewhat working.https://www.newark.com/pdfs/techarticles/microchip/3_3vto5vAnalogTipsnTricksBrchr.pdfThanksLuca

author: Ian.M
author_rank: Super Contributor
timestamp: November 10, 2020, 06:19:05 pm
content: No, if you are only getting 0.5V on Dout, something's badly wrong. The LTC1325's SPI interface is TTL compatible, and the datasheet says for logic '1' it will output over 2.4V while sourcing 1.6mA (Voh, near the top of page 3) If that's not enough for the Arduino pin you are using's logic '1' input threshold, you could try a 3K3 pullup to +5V to get it closer to 5V CMOS levels.

author: lucatz
author_rank: Contributor
timestamp: November 10, 2020, 07:02:27 pm
content: Oddly Dout is very low...see pics of output.I have not completed the circuit some components have not been added ie mfets...thought that would not cause issue with logic portion. Maybe it would but doubt it.Luca

author: rstofer
author_rank: Super Contributor
timestamp: November 10, 2020, 07:19:10 pm
content: Is MOSI on the Arduino connected to MOSI on the LTC? That's the way they are connected.MOSI <-> MOSIMISO <-> MISO

author: lucatz
author_rank: Contributor
timestamp: November 10, 2020, 07:30:17 pm
content: I have it hooked upMISO <--> DoutMOSI <--> DinPage 22Luca

author: rstofer
author_rank: Super Contributor
timestamp: November 11, 2020, 01:09:27 am
content: In setup(), just before setting pinmode, set the output high:digitalWrite(slaveSelectPin, HIGH); // set output state highpinMode(slaveSelectPin, OUTPUT); // before setting the pin to outputI don't think this will solve your issues...

author: lucatz
author_rank: Contributor
timestamp: November 12, 2020, 02:16:03 am
content: Whatever is causing my issues in unknown to me at this point. For whatever reason Dout of LTC1325 does not meet TTL standards. So Arduino will not trigger. Scope shows approx 200mv pk-pk which is too low. No clue, maybe bad chip. Will try and get another to test...Thanks to all in thread

author: rstofer
author_rank: Super Contributor
timestamp: November 13, 2020, 01:14:30 am
content: When I work with new uC prototypes and especially for FPGA projects, I stick a 330 Ohm resistor in series with all inputs and outputs. This will limit the current flow to 10 mA on a 3.3V system if I should happen to short or misconnect a pin.There is so little current flow in CMOS chip inputs and outputs, the resistor doesn't drop any measurable voltage. Maybe for a 5V system I might up it to 470 Ohms, give or take. In any event, I would look at the max output current for either end and size the resistor accordingly.On my FPGA daughter cards (add on peripherals and such), I sometimes leave the resistors even after I know the circuit works. The problem with FPGAs is that the edges are so sharp there are reflections up and down the trace. The series resistor tends to prevent that.

author: lucatz
author_rank: Contributor
timestamp: November 13, 2020, 02:34:37 am
content: Yes I may have miss connected

author: lucatz
author_rank: Contributor
timestamp: February 01, 2021, 03:28:45 am
content: For anyone searching. I resolved by doing this...took a while but hey I learnt something todaySPI.transfer(0x00)orSPI.transfer(0b00000000)Will send 8 bits via SPI transferVariable = SPI.transfer(0b00000000)Will Send 8 bits and store response in VariableReading up rstofer was right on...QuoteCode:// Set CS Pin LOWdigitalWrite(CS_Pin, LOW); // Activate the CS line (CS is active LOW)delay(1);//Send 6 Bytes to ltc1325SPI.transfer(0b00000010); // Send First byteSPI.transfer(0b00100100); // Send Second byteSPI.transfer(0b00000011); // Send Third byteLTC1325ADC = SPI.transfer16(0b1100000000000000); // SEND TX4&TX5 get RX4&RX5 result and place in ADCLTC1325Status = SPI.transfer(0b00000000); // Send TX6 get RX6 result and place in LTC1325Status//Set CS_Pin HighdigitalWrite(CS_Pin, HIGH); // Enable internal pull-up