DIY Electric Car Forums banner

1st Gen Chevy Volt BMS Balance Commands Found

16481 Views 32 Replies 13 Participants Last post by  Saniyo
Here's how to command your OEM Chevy Volt BMS BICMs (slaves) to bleed charge off of specific cells in order to keep them in balance.

This does not involve the BECM (master). I wasn't able to figure out the command(s) to send the BECM to get it to initiate this work. This is a more manual method that involves sending the BICMs commands indicating which specific cells to bleed. You still have to figure out which cells are out of balance and do the heavy lifting of dropping them to the right level. This would be done by continually sending these commands to the BICMs on a CAN bus with just the BICMs, no BECM.

A little background is useful. In normal operation every 200 milliseconds the BECM sends 3 CAN frames: 0x200, 0x300 and 0x310. If the 0x200 CAN frame contains data content of 0x020000, all connected BICMs send back the voltage and temperatures of their battery modules. That much has been documented.

It turns out that 0x300 and 0x310 are queuing commands for bleeding energy from specific cells. When a specific cell location is sent in either of those commands, the next 0x200#020000 frame causes the BICM to bleed energy from that cell for about 130 milliseconds.
Attached is a scope cap showing that action. This was taken from a BICM PCB across a 1 ohm resistor on the trace that connects the cells to the measuring/bleeding circuits.

The first two blips are the BICM opening a small transistor on the trace to measure the cell voltage. Negative blip is the cell we're watching, positive blip is the next higher cell.
Then since this cell was commanded to bleed, the BICM opens its circuit to bleed across a couple of 15 ohm resistors in series. There are a couple of 1 ohm resistors and a diode in that path so the bleed current ends up being about 100 mA.

If the right 0x300/310 command is sent, this happens every 200 msec.

I've mapped out the right 0x300/310 data bits that correspond to each cell and will drop them in the next post.

Attachments

See less See more
1 - 20 of 33 Posts
Hat off to you. :cool:

Very good work, i will now look at implementing it in my code ofcourse.
That's huge, thanks!

Sent from my SM-N960U using Tapatalk
Thanks, guys.
Here are the details.

0x300 takes 8 bytes of data
0x310 takes 5 bytes.

I'll attach a csv/xls with the location mapping table, but it looks like this:

Code:
0x460:	1	3	1-3	300#XX.00.00.00.00.00.00.00	01	02	04	
0x470:	1	3	4-6	300#XX.00.00.00.00.00.00.00	08	10	20	
0x461:	1	4	7-10	300#00.XX.00.00.00.00.00.00	08	04	02	01
0x471:	1	4	11-14	300#00.XX.00.00.00.00.00.00	80	40	20	10
0x462:	1	4	15-18	300#00.00.XX.00.00.00.00.00	01	02	04	08
0x472:	1	4	19-22	300#00.00.XX.00.00.00.00.00	10	20	40	80
0x463:	1	4	23-26	300#00.00.00.XX.00.00.00.00	01	02	04	08
0x473:	1	4	27-30	300#00.00.00.XX.00.00.00.00	10	20	40	80
The files have column headers but they mess up the formatting here, so:
The first column is the voltage reporting CAN frame ID,
the second is the BICM number,
the third is the number of cells in that CAN frame group,
the fourth is the cell number designation starting from the POSITIVE end,
the fifth is the specific CAN command (in linux canutils cansend format) to designate that cell with XX placeholding for the next columns
and the last four are the specific hex data values that go in the placeholder for each sequential cell in that group.

Again, look at the file, it will make better sense.

So to draw down the cell at the most positive end of the pack, you would send:
0x300#01.00.00.00.00.00.00.00
0x200#020000

every 200 milliseconds until it reaches the voltage you want.

I don't know what the rules are for queuing multiple cells as it's a pain to detect when one of these things is bleeding, let alone monitoring multiple cells at once. I know you can't queue adjacent cells because I tried it. Which makes sense. The higher cell dumps its current onto the high volt trace of the lower cell.
I would guess that at the very least you could queue up cells in different BICMs, possible even the different computational groups within each BICM.

If anyone knows of an easy way to detect multiple cell bleed activity, please let me know. I need to do this same mapping on my car pack. My car pack is two parallel 42 cell strings and the BICMs send duplicate voltage reporting frames (like two 0x460 frames) and I need to be able to detect if that means the bleed mapping duplicates as well.

Attachments

See less See more
That is some great work!

How did you find the the relevant labels (0x300, 0x310, 0x200)?
That is some great work!

How did you find the the relevant labels (0x300, 0x310, 0x200)?
Thanks but it was really just luck.

If you look at the BECM-BICM CAN bus traffic, it's constantly repeating the same small number of frames. Other people had decoded all of the module voltage and temperature frames that the BICMs put out so it was easy to eliminate those.
That left only 0x200, 0x300 and 0x310.
0x300 and 0x310 are always empty (that I'd seen. Now we know why).

Awhile back I tried repeating a captured 0x200 frame to just the BICMs and quickly figured out that it was the prompt for them to spit out their data. That left 300 and 310. I could never figure out what they did.

When I got interested recently in the balancing command again I did what I could on the external BECM bus using your ideas but couldn't get anything to work. I was still sniffing the internal BECM-BICM bus so I went back to that. I had also soldered some leads to one of the BICM balance resistors so I could tell when balancing was happening for one cell.
It occurred to me that those two unknown CAN ids might have something to do with balancing so I ran cangen and put random data in those frames. Luckily I still had the BECM on the bus so it was still generating the 0x200 frames. Very quickly I saw blips on the balance resistor and then it was just a matter of elimination to replay bits of traffic to home in on the relevant commands.

Mapping the cells is a pain in the butt. I certainly wasn't going to solder leads to every single BICM cell position so I made a breakout board with a protoboard and jumper leads to get easy (relatively) access to the BICM-battery wiring. It turns out that if you put a scope on a cell positive and negative leads it will pick up that balancing activity. Probably the little bit of resistance added by my breakout board connections helped that. Then it was just a matter of a couple of hours to swap it onto the different BICM connectors and map out the bit pattern.
See less See more
  • Like
Reactions: 2
Awesome work. I wish I could buy you a beer


Sent from my iPhone using Tapatalk
Looking at the build up of the balancing messages its really straight forward.

Atleast that is if you take the reporting message IDs to build your voltage arrays.

I literally just take the report message id - 459 and then use that to bit shift the cell positions in to the various bytes of the messages.

Luckily there is logic between how they number and report out cell voltages and how they structure the balancing requests.

Anyone want to sniff around in my code:

Code:
void BMSModuleManager::balanceCells()
{
  for (int c = 0; c < 8; c++)
  {
    msg.buf[c] = 0;
  }
  for (int y = 1; y < 9; y++)
  {
    if (modules[y].isExisting() == 1)
    {
      int balance = 0;
      for (int i = 1; i < 9; i++)
      {

        if (getLowCellVolt() < modules[y].getCellVoltage(i))
        {
          balance = balance | (1 << i);
        }
      }
      msg.buf[y - 1] = balance;
    }
  }
  msg.id  = 0x300;
  msg.len = 8;
  Can0.write(msg);

  for (int c = 0; c < 8; c++)
  {
    msg.buf[c] = 0;
  }
  for (int y = 1; y < 9; y++)
  {
    if (modules[y].isExisting() == 1)
    {
      int balance = 0;
      for (int i = 1; i < 9; i++)
      {
        if (getLowCellVolt() < modules[y].getCellVoltage(i))
        {
          if (y < 11 || i < 4)
          {
            balance = balance | (1 << i);
          }
          else
          {
            balance = balance | (1 << (i+1));
          }
        }
      }
      msg.buf[y - 8] = balance;
    }
  }
  msg.id  = 0x310;
  msg.len = 5;
  Can0.write(msg);
}
Full bms code: https://github.com/tomdebree/AmperaBattery/tree/master/VoltBMSV2
See less See more
  • Like
Reactions: 1
Nice, Tom. That'll make it a lot easier to use balancing. Thanks.

Oh, I was wrong about not being able to queue up adjacent cells. You can, it's just harder to see. The way I am detecting it, adjacent signals stomp on each other a little.

I've confirmed that carries through a full module; you can queue up more than one cell to balance in a module. And I'm sure that carries through the whole pack.
I've yet to try more than two at a time (next on the to-do list), but I'd be surprised if there was a limit.

It takes quite awhile to see the results. I've run the experiment to confirm a rough calculation: it takes on the order of an hour of feeding the balance command every 200 ms to see an unmistakable change in the cell voltage reported (0.001V).
One confounding problem is that the whole pack is also slowly drawing down from the act of sampling the voltages at the same time the balancing is occurring. It's a noticeable drain when running the BMS for an extended period and tracking cell voltages to the millivolt.

The other confounding issue is that the voltage readings bounce around more than 0.001V. It'd probably be easier to see by averaging the reading over time.
See less See more
Using a 12 cell module on BICM 4, I've confirmed that at least every other cell in a module can be queued up for balancing in one shot.
e.g., I saw balancing on cells 1,3,5,7,9 and 11 at one shot.

I gave up at that because as I said it's very difficult to see balancing when adjacent cells are active.

Although I did see that queuing ALL of the cells didn't work. Nothing balanced in that case.

So somewhere between every other cell and all cells there is a limit.

The queuing rules so far:
1. Every other cell can be queued.

2. Adjacent cells can be queued to some unknown limit. Limit is greater 2 and less than 12.
- All cells cannot be queued.
See less See more
Looking at the build up of the balancing messages its really straight forward.

Atleast that is if you take the reporting message IDs to build your voltage arrays.

I literally just take the report message id - 459 and then use that to bit shift the cell positions in to the various bytes of the messages.

Luckily there is logic between how they number and report out cell voltages and how they structure the balancing requests.

Anyone want to sniff around in my code:

Code:
void BMSModuleManager::balanceCells()
{
  for (int c = 0; c < 8; c++)
  {
    msg.buf[c] = 0;
  }
  for (int y = 1; y < 9; y++)
  {
    if (modules[y].isExisting() == 1)
    {
      int balance = 0;
      for (int i = 1; i < 9; i++)
      {

        if (getLowCellVolt() < modules[y].getCellVoltage(i))
        {
          balance = balance | (1 << i);
        }
      }
      msg.buf[y - 1] = balance;
    }
  }
  msg.id  = 0x300;
  msg.len = 8;
  Can0.write(msg);

  for (int c = 0; c < 8; c++)
  {
    msg.buf[c] = 0;
  }
  for (int y = 1; y < 9; y++)
  {
    if (modules[y].isExisting() == 1)
    {
      int balance = 0;
      for (int i = 1; i < 9; i++)
      {
        if (getLowCellVolt() < modules[y].getCellVoltage(i))
        {
          if (y < 11 || i < 4)
          {
            balance = balance | (1 << i);
          }
          else
          {
            balance = balance | (1 << (i+1));
          }
        }
      }
      msg.buf[y - 8] = balance;
    }
  }
  msg.id  = 0x310;
  msg.len = 5;
  Can0.write(msg);
}
Full bms code: https://github.com/tomdebree/AmperaBattery/tree/master/VoltBMSV2
Slightly off topic:
wait....this is all c++...since when is automotive code not in asm? Is this for a custom board or for an arduino? Where can I find out more about how you guys are putting this stuff together and compiling code?

Sorry for derailing the convo a bit.
Slightly off topic:
wait....this is all c++...since when is automotive code not in asm? Is this for a custom board or for an arduino? Where can I find out more about how you guys are putting this stuff together and compiling code?

Sorry for derailing the convo a bit.
Actually, we're talking CAN. There are many ways to speak CAN to the BMS. I'm using a CAN adapter on a Raspberry Pi with Python. Tom has his own custom board (that uses the Arduino IDE tool chain I think).
Nice, Tom. That'll make it a lot easier to use balancing. Thanks.
Well, it would if I could actually follow what you're doing. :(
That's beyond my meager coding skills.
Actually, we're talking CAN. There are many ways to speak CAN to the BMS. I'm using a CAN adapter on a Raspberry Pi with Python. Tom has his own custom board (that uses the Arduino IDE tool chain I think).
where did you get your adapter? Where can I learn more about this stuff?
where did you get your adapter? Where can I learn more about this stuff?
There's a ton of info on using various computing platforms to read/write CAN. Just start with your favorite SBC and add "CAN bus" to the google search. All kinds of videos and tutorials will pop up.

Personally, I've used both a Raspberry Pi with a Canberry
http://www.industrialberry.com/canberrydual-v2-1/

as well as a MUCH cheaper chinese adaptor with equal success.
https://www.aliexpress.com/item/She...978.html?spm=a2g0s.9042311.0.0.7c364c4d1GtTku

The canberry is a lot more plug-and-play and appropriate for starting out.
There's a ton of info on using various computing platforms to read/write CAN. Just start with your favorite SBC and add "CAN bus" to the google search. All kinds of videos and tutorials will pop up.

Personally, I've used both a Raspberry Pi with a Canberry
http://www.industrialberry.com/canberrydual-v2-1/

as well as a MUCH cheaper chinese adaptor with equal success.
https://www.aliexpress.com/item/She...978.html?spm=a2g0s.9042311.0.0.7c364c4d1GtTku

The canberry is a lot more plug-and-play and appropriate for starting out.
awesome, thanks for this info!
Thanks, guys.
Here are the details.

0x300 takes 8 bytes of data
0x310 takes 5 bytes.
......
Great job done! I take off my hat))
I have recently bought a Gen 1 Volt battery set. I am working on putting it in my S10 that has been sitting parked with no batteries for about 5 years. Here are a few questions I have about cell balancing:
1. If I leave the set originally wired (96 cells in series) and I give 12V power and ignition signal to BEMC (and it starts communicating with slaves - confirmed) will it (BEMC) take care of cell balancing if needed? Or, does it need to talk to someone else, or … ?
2. If so …. and if I re-wire the set into two strings of 48 cells each (first 30 and last 18 will make one string and the rest will be the other) would BEMC be bothered by it or will it continue to monitor/balance the cells?

Thanks
I have recently bought a Gen 1 Volt battery set. I am working on putting it in my S10 that has been sitting parked with no batteries for about 5 years. Here are a few questions I have about cell balancing:
1. If I leave the set originally wired (96 cells in series) and I give 12V power and ignition signal to BEMC (and it starts communicating with slaves - confirmed) will it (BEMC) take care of cell balancing if needed? Or, does it need to talk to someone else, or … ?
2. If so …. and if I re-wire the set into two strings of 48 cells each (first 30 and last 18 will make one string and the rest will be the other) would BEMC be bothered by it or will it continue to monitor/balance the cells?

Thanks
I'm not aware that anyone has seen the BECM initiate balancing on its own. It needs a command from somewhere else to do that.
I'm also not aware that anyone has figured out what that command sequence is.
I'm currently working on a Volt pack with SimpBMS, configured as 2 strings in parallel.
Does anyone know if the canbus connections to the slaves can be swapped?
eg: Original wiring goes through modules 30-24-24-18, with 30 being the first and 18 the last.

The reconfiguration means now that I have 30+18 in the front, and 24+24 in the back, and for simplifying the wiring I would like to connect them in the order 30-18-24-24.

Would that work or there's something in the last slave (18) that would need to keep it the last in the chain?
1 - 20 of 33 Posts
Top