I trying to read data from a Daly BMS, which has been a pain in the backside to say the least.
I tried their CAN bus, which eventually shows data corruption, and gave up.
Now I am trying the RS485 port... without any luck.
The BMS needs to be queried in order to provide a reply. This is done by sending a start byte, host address, message id and frame length, and empty or rather 0x00 data bytes, plus a simple checksum; all up 13 bytes; like so
SB HA MI FL Data................... CS
A5 40 91 08 00 00 00 00 00 00 00 00 7E
It is supposed to return a response like this:
A5 01 91 08 0C F4 05 0C C9 08 00 00 CS
Here what I am getting back:
--> 14604912 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14604942 | 91 | 00 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 0B | 0F | 0C | F2 |
<UART>[MsgID: 0x91][CRC Rec: 64][CRC Calc: A]
--> 14607955 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14607985 | 91 | 00 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 06 | 0E | 0C | F5 |
<UART>[MsgID: 0x91][CRC Rec: 61][CRC Calc: 1]
--> 14610997 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14611027 | 91 | 00 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 0C | 0F | 0C | F3 |
<UART>[MsgID: 0x91][CRC Rec: 66][CRC Calc: A]
--> 14614040 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14614072 | 91 | 00 | 00 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 0A | 0F | 0C |
<UART>[MsgID: 0x91][CRC Rec: 71][CRC Calc: F0]
--> 14617086 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14617112 | 91 | A8 | 5D | B0 | E4 | 84 | 0D | 08 | 0E | 0C | F5 | 01 | 00 |
<UART>[MsgID: 0x91][CRC Rec: 42][CRC Calc: 0]
--> 14620123 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14620153 | 91 | 00 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 08 | 0E | 0C | F2 |
<UART>[MsgID: 0x91][CRC Rec: 60][CRC Calc: 1]
--> 14623165 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14623199 | 91 | 02 | 00 | 00 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 09 | 0F |
<UART>[MsgID: 0x91][CRC Rec: 66][CRC Calc: C]
--> 14626212 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14626247 | 91 | 00 | 01 | 00 | 00 | A5 | 01 | 91 | 08 | 0D | 0A | 0F | 0C |
<UART>[MsgID: 0x91][CRC Rec: 72][CRC Calc: F3]
--> 14629260 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14629284 | 91 | 00 | 00 | 08 | 00 | 12 | 81 | 49 | 40 | E9 | 80 | 91 | 08 |
<UART>[MsgID: 0x91][CRC Rec: 26][CRC Calc: D]
--> 14632301 | 91 | A5 | 40 | 91 | 08 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 00 | 7E |
<-- 14632328 | 91 | 00 | 00 | 95 | 0B | 16 | 0E | 58 | 18 | B0 | 18 | D8 | 3E |
<UART>[MsgID: 0x91][CRC Rec: 12][CRC Calc: 61]
More often than not, the start byte appears in the middle or not at all. However, what follows the start byte seems to represent valid data. But, because I am reading 13 bytes, the remainder is cut off.
Any ideas why this is not working as intended?
The code I use:
#include <Arduino.h>
#include <SoftwareSerial.h>
#define BAUD_RATE_HW 115200
#define BAUD_RATE_485 9600
#define MAX485_DI 2 // TX
#define MAX485_DE 3
#define MAX485_RE_NEG 4
#define MAX485_R0 5 // RX
#define START_BYTE 0xA5
#define HOST_ADRESS 0x40
#define FRAME_LENGTH 0x08
#define XFER_BUFFER_LENGTH 13
enum MSG_ID
{
MSG_ID_BATTERY_PACK_DATA = 0x90,
MSG_ID_MIN_MAX_CELLS = 0x91,
MSG_ID_MIN_MAX_TEMPERATURE = 0x92,
MSG_ID_MOSFET_CHARGE_STATUS = 0x93,
MSG_ID_STATUS_INFO = 0x94,
MSG_ID_CELL_VOLTAGES = 0x95,
MSG_ID_CELL_TEMPERATURES = 0x96,
MSG_ID_CELL_BALANCE_STATUS = 0x97,
MSG_ID_BATTERY_FAILURE_STATUS = 0x98
};
uint8_t rx_frame_buffer[XFER_BUFFER_LENGTH * 12];
uint8_t frame_buffer[12][XFER_BUFFER_LENGTH];
uint8_t frame_Counter;
uint8_t rx_buffer[XFER_BUFFER_LENGTH] = {0};
uint8_t tx_buffer[XFER_BUFFER_LENGTH] = {0};
SoftwareSerial rs485(MAX485_R0, MAX485_DI); // RX, TX
void pre_transmission()
{
digitalWrite(MAX485_RE_NEG, 1);
digitalWrite(MAX485_DE, 1);
}
void post_transmission()
{
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
}
void clear_rs485_input_buffer()
{
while (rs485.available() > 0)
{
rs485.read();
}
}
/*
// 1 2 3 4 5 6 7 8 9 10 11 12 13
// --> A5 40 90 08 00 00 00 00 00 00 00 00 7D
// <-- A5 01 90 08 02 7B 00 00 75 30 03 C1 24
*/
bool request_data(uint8_t message_id, uint8_t frame_amount)
{
uint8_t tx_checksum = 0x00; // transmit checksum buffer
uint8_t byte_counter = 0;
// Clear out the buffers
memset(tx_buffer, 0x00, XFER_BUFFER_LENGTH);
memset(rx_frame_buffer, 0x00, sizeof(rx_frame_buffer));
memset(frame_buffer, 0x00, sizeof(frame_buffer));
// Populate the frame with static data and message ID
tx_buffer[0] = START_BYTE;
tx_buffer[1] = HOST_ADRESS;
tx_buffer[2] = message_id;
tx_buffer[3] = FRAME_LENGTH;
// Calculate the checksum
for (uint8_t i = 0; i < XFER_BUFFER_LENGTH - 1; i++)
{
tx_checksum += tx_buffer[i];
}
// add check sum to the frame buffer
tx_buffer[12] = tx_checksum;
Serial.print("--> ");
Serial.print(millis());
Serial.print(" (");
Serial.print(message_id, HEX);
Serial.print(") ");
for (uint8_t i = 0; i < sizeof(tx_buffer); i++)
{
if (tx_buffer[i] < 0x10)
{
Serial.print("0");
}
Serial.print(tx_buffer[i], HEX);
Serial.print(" ");
}
Serial.println();
pre_transmission();
rs485.write(tx_buffer, XFER_BUFFER_LENGTH);
post_transmission();
// wait for transmission end
rs485.flush();
// Receive data
rs485.readBytes(rx_frame_buffer, XFER_BUFFER_LENGTH * frame_amount);
uint8_t rx_checksum = 0x00;
for (size_t i = 0; i < frame_amount; i++)
{
for (size_t j = 0; j < XFER_BUFFER_LENGTH; j++)
{
frame_buffer[i][j] = rx_frame_buffer[byte_counter];
byte_counter++;
}
Serial.print("<-- ");
Serial.print(millis());
Serial.print(" (");
Serial.print(message_id, HEX);
Serial.print(") ");
for (int k = 0; k < XFER_BUFFER_LENGTH - 1; k++)
{
rx_checksum += frame_buffer[i][k];
if (frame_buffer[i][k] < 0x10)
{
Serial.print("0");
}
Serial.print(frame_buffer[i][k], HEX);
Serial.print(" ");
}
Serial.println();
// Output debugging information
char debugBuff[128];
sprintf
(
debugBuff,
"<UART>[MsgID: 0x%2X][CRC Rec: %2X][CRC Calc: %2X]",
message_id, rx_checksum, frame_buffer[i][XFER_BUFFER_LENGTH - 1]
);
Serial.println(debugBuff);
if (rx_checksum != frame_buffer[i][XFER_BUFFER_LENGTH - 1])
{
Serial.println("<BMS.> CRC fail");
return false;
}
if (rx_checksum == 0)
{
Serial.println("<BMS.> No data");
return false;
}
if (frame_buffer[i][1] >= 0x20)
{
Serial.println("<BMS.> BMS sleeping");
return false;
}
}
return true;
}
void setup()
{
pinMode(MAX485_RE_NEG, OUTPUT);
pinMode(MAX485_DE, OUTPUT);
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
Serial.begin(BAUD_RATE_HW);
delay(300);
rs485.begin(BAUD_RATE_485);
Serial.println("Ready");
}
void loop()
{
//request_data(MSG_ID_BATTERY_PACK_DATA, 1);
request_data(MSG_ID_MIN_MAX_CELLS, 1);
//request_data(MSG_ID_MIN_MAX_TEMPERATURE, 1);
//request_data(MSG_ID_MOSFET_CHARGE_STATUS, 1);
//request_data(MSG_ID_STATUS_INFO, 1);
//request_data(MSG_ID_CELL_VOLTAGES, 1);
//request_data(MSG_ID_CELL_TEMPERATURES, 1);
//request_data(MSG_ID_CELL_BALANCE_STATUS, 1);
//request_data(MSG_ID_BATTERY_FAILURE_STATUS, 1);
delay(3000);
}