Page 4 of 9
Re: Kia Niro BMS
Posted: Thu Oct 05, 2023 3:43 pm
by bigmotherwhale
Does anyone have an idea if this code will work with the Hyundai / Kia hybrid packs?
Edit: looking deeper it seems that it will
could anyone tell me whether you can use the BMS master and the CAN messages alone instead of directly connecting to the slaves?
Thanks
Re: Kia Niro BMS
Posted: Sun Oct 08, 2023 9:09 am
by maciek16c
I think it should be possible to use stock BMS. Looks like a lot of CAN messages are the same or similar between different Hyundai / Kia models and i have Hyundai Santa-Fe PHEV battery working using Savvycan script or zombieverter (there are still some obd-2 errors, but probably not critical)
Re: Kia Niro BMS
Posted: Sun Oct 08, 2023 1:08 pm
by bigmotherwhale
I already went ahead and bought the pack its a Hyundai IONIQ PHEV, its nice to know that it can be done, would you mind sharing your code? Thanks
Re: Kia Niro BMS
Posted: Tue Oct 10, 2023 8:52 am
by maciek16c
I added short description of my battery in my thread:
viewtopic.php?p=62256
Re: Kia Niro BMS
Posted: Wed Oct 25, 2023 1:21 pm
by bigmotherwhale
Hello, im trying to use your code and an Arduino to patch into a HEV BMS from a niro as i have been unable to find the CAN commands for the contactors, I have connected to the spi and i think im getting them to talk but the board design is different to that of the CMUs, It has 8X max17845 chips onboard.
I tried playing with the code but i dont know what im doing, and I keep getting "error byte cleared" in serial.
Is it possible to get this to work? could i get some help.
Thank you
Re: Kia Niro BMS
Posted: Thu Oct 26, 2023 4:17 am
by bexander
Yes, this seem to be a integrated BMS, interesting.
So you have connected via SPI to the onborad MAX17841, correct?
My SW is hard coded to 12 slaves with 4+4 cells connected at pos 1-4 and 6-9. This will have to be changed to 8 slaves with 9 cells connected.
The number of slaves also determines the value of check byte so this have to match.
Please provide a serial print out of your results so far, helps a lot for me to determine your progress.
Re: Kia Niro BMS
Posted: Thu Oct 26, 2023 4:29 am
by bexander
bexander wrote: ↑Thu Oct 26, 2023 4:17 am
The number of slaves also determines the value of check byte so this have to match.
I ment the alive-counter. 0x0C with 12 slaves, 0x08 with 8 slaves. Will need to be changed in 3 places in the SW, daisyChainInit(), writeAllSlaves() and readAllSlaves().
That should get you through the setup.
Re: Kia Niro BMS
Posted: Thu Oct 26, 2023 1:46 pm
by bigmotherwhale
Thankyou this is exactly what i needed to know.
Yes I have connected to the SPI of the MAX17841 and pulled up the respective pins.
So i have edited 0x0c to 0x08 in the code.
does this need to be edited too?
"* Reads data from slaves and stores in arrays *
**********************************************/
void readData()
{
for(int i=0; i<4; i++)
{
readAllSlaves((0x20 + i), true); // Read CELL 1-4 of all slaves
}
for(int i=0; i<4; i++)
{
readAllSlaves((0x25 + i), true); // Read CELL 5-8 of all slaves"
and this
* Stores measured cell voltage data in cellVoltage array *
*********************************************************/
void storeCellVoltage(uint8_t dataRegister, uint8_t readRegisterData[29])
{
if((dataRegister >= 0x20) && (dataRegister <= 0x23)) // Cell voltage registers 1-4
{
uint8_t cellNumberOffset = dataRegister - 0x20;
for(int i=0; i<12; i++)
{
uint16_t measVoltage = ((readRegisterData[25-i*2] << 8) + readRegisterData[24-i*2]);
measVoltage = (measVoltage >> 2) * (uint32_t)5000 / 0x3FFF;
cellVoltage[i*8 + cellNumberOffset] = measVoltage;
}
}
if((dataRegister >= 0x25) && (dataRegister <= 0x28)) // Cell voltage registers 5-8
{
uint8_t cellNumberOffset = dataRegister - 0x20 - 1;
for(int i=0; i<12; i++)
{
uint16_t measVoltage = ((readRegisterData[25-i*2] << 8) + readRegisterData[24-i*2]);
measVoltage = (measVoltage >> 2) * (uint32_t)5000 / 0x3FFF;
cellVoltage[i*8 + cellNumberOffset] = measVoltage;
}
Im not exactly sure how to edit this i just want the voltages from 1-8 on each chip, there are 72 channels even though my bms only uses 64 of them there are no thermistors connected to any of the slaves,
Im not very good at coding i can understand some of it but this is way to much for me, if i start editing this its going to be more of a guess than anything else.
Re: Kia Niro BMS
Posted: Fri Oct 27, 2023 11:43 am
by bexander
bigmotherwhale wrote: ↑Thu Oct 26, 2023 1:46 pm
void readData()
{
for(int i=0; i<4; i++)
{
readAllSlaves((0x20 + i), true); // Read CELL 1-4 of all slaves
}
for(int i=0; i<4; i++)
{
readAllSlaves((0x25 + i), true); // Read CELL 5-8 of all slaves"
Try this:
Code: Select all
void readData()
{
for(int i=0; i<8; i++)
{
readAllSlaves((0x20 + i), true); // Read CELL 1-8 of all slaves
}
//readAllSlaves(0x2D, true); // Read AIN1 of all slaves (Cell temperature)
readAllSlaves(0x50, true); // Read DIAG (Die temperature) of all slaves
}
Re: Kia Niro BMS
Posted: Fri Oct 27, 2023 11:46 am
by bexander
bigmotherwhale wrote: ↑Thu Oct 26, 2023 1:46 pm
void storeCellVoltage(uint8_t dataRegister, uint8_t readRegisterData[29])
{
if((dataRegister >= 0x20) && (dataRegister <= 0x23)) // Cell voltage registers 1-4
{
uint8_t cellNumberOffset = dataRegister - 0x20;
for(int i=0; i<12; i++)
{
uint16_t measVoltage = ((readRegisterData[25-i*2] << 8) + readRegisterData[24-i*2]);
measVoltage = (measVoltage >> 2) * (uint32_t)5000 / 0x3FFF;
cellVoltage[i*8 + cellNumberOffset] = measVoltage;
}
}
if((dataRegister >= 0x25) && (dataRegister <= 0x28)) // Cell voltage registers 5-8
{
uint8_t cellNumberOffset = dataRegister - 0x20 - 1;
for(int i=0; i<12; i++)
{
uint16_t measVoltage = ((readRegisterData[25-i*2] << 8) + readRegisterData[24-i*2]);
measVoltage = (measVoltage >> 2) * (uint32_t)5000 / 0x3FFF;
cellVoltage[i*8 + cellNumberOffset] = measVoltage;
}
Try this:
Code: Select all
void storeCellVoltage(uint8_t dataRegister, uint8_t readRegisterData[29])
{
if((dataRegister >= 0x20) && (dataRegister <= 0x27)) // Cell voltage registers 1-8
{
uint8_t cellNumberOffset = dataRegister - 0x20;
for(int i=0; i<8; i++)
{
uint16_t measVoltage = ((readRegisterData[25-i*2] << 8) + readRegisterData[24-i*2]);
measVoltage = (measVoltage >> 2) * (uint32_t)5000 / 0x3FFF;
cellVoltage[i*8 + cellNumberOffset] = measVoltage;
}
}
}
Re: Kia Niro BMS
Posted: Fri Oct 27, 2023 11:48 am
by bexander
I would also comment out this part:
Code: Select all
if(dataRegister == 0x2D) // Aux voltage measurements (external temperature sensors)
{
storeCellTemperature(readRegisterData);
}
Like this:
Code: Select all
/*if(dataRegister == 0x2D) // Aux voltage measurements (external temperature sensors)
{
storeCellTemperature(readRegisterData);
}*/
Re: Kia Niro BMS
Posted: Fri Oct 27, 2023 11:50 am
by bexander
Change:
const uint8_t numberOfCells = 96;
to
const uint8_t numberOfCells = 64;
Re: Kia Niro BMS
Posted: Fri Oct 27, 2023 11:58 am
by bexander
Also this function needs to be changed
Code: Select all
boolean balanceCells(uint16_t lowestCellVoltage)
{
static uint8_t counter = 1;
static uint16_t cellToBalanceFilter = 0x0FFF & 0x5555; // Every odd cell
boolean measureVoltages = false;
//if(1 == counter) Serial.println("Balance cells");
writeAllSlaves(0x18, 0x1500, true); // Set WATCHDOG timer to 5s
if(0 == counter)
{
cellToBalanceFilter = 0x0FFF & ~cellToBalanceFilter; // Every other cell
writeAllSlaves(0x1A, 0x0000, true); // Turn off all cell balancing for one cycle to avoid any switch overlap
}
if(1 == counter)
{
measureVoltages = true; // OK to measure cell voltages
}
for (int i=0; i < 12; i++) // Go through modules to set cells for balancing
{
if(2 == counter) // Only set cells once every counter cycle
{
uint16_t cellToBalance = 0x0000;
for (int j=0; j < 8; j++) // Go through cells to set cells for balancing
{
uint8_t cellNumber = j+i*8;
if ((cellVoltage[cellNumber] > startShuntVoltage) && ((int16_t)(cellVoltage[cellNumber] - lowestCellVoltage) > voltageAllowance)) // Ok to balance
{
if (j < 4)
{
cellToBalance |= (0x01 << j);
}
else if (j >= 4 && j <8)
{
cellToBalance |= (0x01 << (j+1));
}
else //Error
{
cellToBalance = 0x0000;
}
}
}
cellToBalance &= cellToBalanceFilter; // To avoid enabling adjacent balance switches
writeAddressedSlave(0x1A, cellToBalance, i, true); // Send request to set cell balance switches
Serial.print(i+1);
Serial.print(": ");
//Serial.println(cellToBalance, BIN);
for(int i=0; i < 8; i++)
{
if(4 == i) Serial.print(" ");
if(i < 4)
{
Serial.print((uint8_t)((cellToBalance >> i) & 0x01));
}
else
{
Serial.print((uint8_t)((cellToBalance >> (i + 1)) & 0x01));
}
}
Serial.println();
}
if(dieTemperature[i] > 100) // Check die overtemp
{
writeAddressedSlave(0x1A, 0x0000, i, true); // Turn off cell balancing for the module with die overtemp
Serial.print("Die overtemp, module ");
Serial.println(i+1);
}
}
counter++;
if(counter > balanceCellCounterTurnAround)
{
counter = 0;
}
return measureVoltages;
}
To:
Code: Select all
boolean balanceCells(uint16_t lowestCellVoltage)
{
static uint8_t counter = 1;
static uint16_t cellToBalanceFilter = 0x00FF & 0x5555; // Every odd cell
boolean measureVoltages = false;
//if(1 == counter) Serial.println("Balance cells");
writeAllSlaves(0x18, 0x1500, true); // Set WATCHDOG timer to 5s
if(0 == counter)
{
cellToBalanceFilter = 0x0FFF & ~cellToBalanceFilter; // Every other cell
writeAllSlaves(0x1A, 0x0000, true); // Turn off all cell balancing for one cycle to avoid any switch overlap
}
if(1 == counter)
{
measureVoltages = true; // OK to measure cell voltages
}
for (int i=0; i < 8; i++) // Go through modules to set cells for balancing
{
if(2 == counter) // Only set cells once every counter cycle
{
uint16_t cellToBalance = 0x0000;
for (int j=0; j < 8; j++) // Go through cells to set cells for balancing
{
uint8_t cellNumber = j+i*8;
if ((cellVoltage[cellNumber] > startShuntVoltage) && ((int16_t)(cellVoltage[cellNumber] - lowestCellVoltage) > voltageAllowance)) // Ok to balance
{
if (j < 8)
{
cellToBalance |= (0x01 << j);
}
else //Error
{
cellToBalance = 0x0000;
}
}
}
cellToBalance &= cellToBalanceFilter; // To avoid enabling adjacent balance switches
writeAddressedSlave(0x1A, cellToBalance, i, true); // Send request to set cell balance switches
Serial.print(i+1);
Serial.print(": ");
//Serial.println(cellToBalance, BIN);
for(int i=0; i < 8; i++)
{
Serial.print((uint8_t)((cellToBalance >> i) & 0x01));
}
Serial.println();
}
if(dieTemperature[i] > 100) // Check die overtemp
{
writeAddressedSlave(0x1A, 0x0000, i, true); // Turn off cell balancing for the module with die overtemp
Serial.print("Die overtemp, module ");
Serial.println(i+1);
}
}
counter++;
if(counter > balanceCellCounterTurnAround)
{
counter = 0;
}
return measureVoltages;
}
Re: Kia Niro BMS
Posted: Fri Oct 27, 2023 3:25 pm
by bigmotherwhale
Thankyou for helping, I tried the above i think i may have got something wrong as an extra bracket stopped me from compiling, I removed what I thought was the right one and uploaded it and this is what i got. I have included the log and the modified .ino
could you have a look at see i haven't missed something? thanks
Re: Kia Niro BMS
Posted: Sat Oct 28, 2023 4:42 pm
by bexander
Replace the entire readAllSlaves() with this:
Code: Select all
void readAllSlaves(uint8_t dataRegister, boolean setupDone) // Read all slaves
{
uint8_t command = 0x03; // READALL
uint8_t byteList[3] = {command, dataRegister, 0x00};
uint8_t PEC = calculatePEC(byteList, 3);
uint8_t readRegisterData[21];
uint8_t errorByte = 0x00;
static uint8_t resendCounter = 0;
//static uint8_t failCounter = 0;
/*if(failCounter >= 4)
{
//clearBuffers();
failCounter = 0; // Reset counter
Serial.println("Buffers cleared");
}*/
SPI.beginTransaction(MAX17841);
// Load the READALL command sequence into the load queue
digitalWrite(SPI_MAX_CS_PIN, LOW);
SPI.transfer(0xC0); // WR_LD_Q SPI command byte (write the load queue)
SPI.transfer(0x15); // Message length (5 + 2 x n = 21)
SPI.transfer(command); // READALL command byte
SPI.transfer(dataRegister); // Register address
SPI.transfer(0x00); // Data-check byte (seed value = 0x00)
SPI.transfer(PEC); // PEC byte
SPI.transfer(0x00); // Alive-counter byte (seed value = 0x00)
digitalWrite(SPI_MAX_CS_PIN, HIGH);
transmitQueue();
// Read the receive buffer
digitalWrite(SPI_MAX_CS_PIN, LOW);
SPI.transfer(0x93); // RD_NXT_MSG SPI command byte
for(int i=0; i<21; i++)
{
readRegisterData[i] = SPI.transfer(0x93);
}
errorByte |= receiveBufferError();
SPI.endTransaction();
// Verify that the device register data is received correctly during the READALL sequence
if(!((readRegisterData[0] == command) && (readRegisterData[1] == dataRegister)))
{
errorByte |= mismatchBefore;
}
if(setupDone)
{
uint8_t checkPEC = calculatePEC(readRegisterData, 19);
// Check check-byte, PEC and alive-counter
if(!((readRegisterData[18] == 0x00) && (readRegisterData[19] == checkPEC) && (readRegisterData[20] == 0x08)))
{
errorByte |= mismatchAfter;
if(readRegisterData[18] != 0x00)
{
readAllSlaves(0x02, false); // Read STATUS of all slaves with checks ignored
writeAllSlaves(0x02, 0x0000, true); // Clear STATUS register
Serial.println("STATUS cleared");
}
}
}
/*// Print data received
for(int i=0; i<21; i++)
{
Serial.print(readRegisterData[i], HEX);
Serial.print(" ");
}
Serial.println();*/
if(errorByte) // Error
{
resendCounter++;
Serial.println(errorByte, HEX);
errorByte &= 0x00; // Clear errors
Serial.println("errorByte cleared");
if(resendCounter > 2)
{
Serial.println("READALL fail");
resendCounter = 0;
//failCounter++;
return;
}
delay(1);
readAllSlaves(dataRegister, setupDone); // Resend READALL
}
else // No errors, clear counters and store data received
{
resendCounter = 0; // Reset counter
//failCounter = 0; // Reset counter
if((dataRegister >= 0x20) && (dataRegister <= 0x2B)) // Cell voltage measurements
{
storeCellVoltage(dataRegister, readRegisterData);
}
/*if(dataRegister == 0x2D) // Aux voltage measurements (external temperature sensors)
{
storeCellTemperature(readRegisterData);
}*/
if(dataRegister == 0x50) // Die temperature measurements
{
storeDieTemperature(readRegisterData);
}
if(dataRegister == 0x13) // Read SCANCTRL to check if data is ready to be read
{
checkDataReady(readRegisterData);
}
if(dataRegister == 0x02) // Read STATUS and print content
{
// Print data received
for(int i=0; i<21; i++)
{
Serial.print(readRegisterData[i], HEX);
Serial.print(" ");
}
Serial.println();
}
}
}
Adjusted for 8 slave modules.
Re: Kia Niro BMS
Posted: Sat Oct 28, 2023 5:07 pm
by bigmotherwhale
Okay thanks again, I will give that a go and report back.
Re: Kia Niro BMS
Posted: Sat Oct 28, 2023 11:20 pm
by bigmotherwhale
Seems to be getting closer, still seems to have 12 groups in the readout though?
Here is what im getting.
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 6:33 am
by bexander
In writeAllSlaves() there is an error in your code:
Code: Select all
// Check alive-counter
if(!(readRegisterData[5] == 0x0))
{
errorByte |= mismatchAfter;
}
Should be:
Code: Select all
// Check alive-counter
if(!(readRegisterData[5] == 0x08))
{
errorByte |= mismatchAfter;
}
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 6:41 am
by bexander
There is also a lot of other places that need to be changed, I realize.
Post your latest code and I will make some changes to it and post it back.
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 12:39 pm
by bigmotherwhale
Here is the code its been modified just by your suggestions.
Cheers
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 2:28 pm
by bexander
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 2:43 pm
by bigmotherwhale
i get errorbyte cleared 1
Would it be a good ide to enable the HEX output in the code to see what the slaves are spitting out?
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 3:30 pm
by bexander
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 3:51 pm
by bigmotherwhale
It has the correct number of cells but im getting measurecelldata wd timeout
Re: Kia Niro BMS
Posted: Sun Oct 29, 2023 4:24 pm
by bexander