From some posts back i developed new Teensy 4.1 VCU board here...
https://evmeganetech.wordpress.com/2025 ... velopment/
Part of design was curiousity and making the most out of the wiring. But i also wanted more options for controling CAN decvices such as ZEVA BMS.
My VCU allready operates on CAN2 channel and there are Inverter, Charger, Heater and AC compressor on that line.
Plan was to fully utilize ZEVA CAN reporting on channel CAN1 to gain actual Voltage, Current, Temperature and SOC reports from ZEVA.
End goal is VCU integrated BMS and CHADEMO charging which should be operating on its own CAN bus. That would be CAN3 then.
There was just ONE obstacle! And that would be my VCU couldnt read ZEVA CAN traffic. Could as well be a mile apart!!!
I tried to change CAN transciever, replacing 120R resistor, i even tested another ESP32 board connected to the same CAN.
To make long story short, i forgot that mailboxes for FlexCAN library specify which ID AND which type of message would be filtered in.
So i forgot to set them up to receive extended CAN messages....EXT.
I really needed to cleanup the code...
First i corrected some obvious mistakes.....
Code: Select all
FlexCAN_T4<CAN1, RX_SIZE_256, TX_SIZE_16> Can1;
FlexCAN_T4<CAN2, RX_SIZE_256, TX_SIZE_16> Can2;
#define NUM_TX_MAILBOXES 6
#define NUM_RX_MAILBOXES 10
There are only 16 possible mailboxes per CAN port. So i had to select between TX and RX. RX should be more important because there is true filtering going on.
Of course i forgot to setup mailbox filters to EXT so that they could sense extended IDs.
FlexCAN allows to declare two position IDs in EXT mailboxes and it will use them as EXT such as 0x28 should be automatically used as 0x00000028
Code: Select all
// setup mailbox
Can1.setMaxMB(16);
Can2.setMaxMB(16);
Can1.setMaxMB(NUM_TX_MAILBOXES + NUM_RX_MAILBOXES);
for (int i = 0; i < NUM_RX_MAILBOXES; i++)
{
Can1.setMB((FLEXCAN_MAILBOX)i, RX, EXT); //CAN1 mailboxes set to receive STD and EXT messages
}
Can2.setMaxMB(NUM_TX_MAILBOXES + NUM_RX_MAILBOXES);
for (int i = 0; i < NUM_RX_MAILBOXES; i++)
{
Can2.setMB((FLEXCAN_MAILBOX)i, RX, STD); // Only STD messages filtered
}
// open mailbox
for (int i = NUM_RX_MAILBOXES; i < (NUM_TX_MAILBOXES + NUM_RX_MAILBOXES); i++)
{
Can1.setMB((FLEXCAN_MAILBOX)i, TX, EXT); //CAN1 mailboxes set to transmitt STD and EXT messages
Can2.setMB((FLEXCAN_MAILBOX)i, TX, STD);
}
// setup filters
Can1.setMBFilter(REJECT_ALL);
Can1.enableMBInterrupts();
Can2.setMBFilter(REJECT_ALL);
Can2.enableMBInterrupts();
// Can3.setMBFilter(REJECT_ALL);
// Can3.enableMBInterrupts();
// prepare which IDs we will look for in mailbox on CAN1
Can1.onReceive(MB0, canRX_28); // BMS Current sensor
Can1.onReceive(MB1, canRX_1E); // BMS report
Can2.onReceive(MB0, canRX_305); // Eltek Charger Stats
Can2.onReceive(MB1, canRX_377); // Charger LV Stats
Can2.onReceive(MB2, canRX_38A); // Charger LV Stats
Can2.onReceive(MB3, canRX_389); // Charger HV Stats
Can2.onReceive(MB4, canRX_398); // Heater Stats
Can2.onReceive(MB5, canRX_289); // Inverter RPM Battery and Torque
Can2.onReceive(MB6, canRX_299); // Inverter Temps
Can2.onReceive(MB7, canRX_732); // Inverter current
Can2.onReceive(MB8, canRX_733); // Inverter Temps
Can2.onReceive(MB9, canRX_388); // AC compressor HV Stats
Can1.setMBFilter(MB0, 0x28); // message ID will be handled as extended because it is EXT mailbox
Can1.setMBFilter(MB1, 0x1E);
Can2.setMBFilter(MB0, 0x305);
Can2.setMBFilter(MB1, 0x377);
Can2.setMBFilter(MB2, 0x38A);
Can2.setMBFilter(MB3, 0x389);
Can2.setMBFilter(MB4, 0x398);
Can2.setMBFilter(MB5, 0x289);
Can2.setMBFilter(MB6, 0x299);
Can2.setMBFilter(MB7, 0x732);
Can2.setMBFilter(MB8, 0x733);
Can2.setMBFilter(MB9, 0x388);
Now that i received something i setup reading functions to gather data. Of course data was in form of 16bit and 24bit integers. Because there would be some aritmetic involved i decided to use float values
For the current sensor ther is an offset to allow positive and negative values. I prepared equasion to substract offset and divide by milliAmps.
The EVMS should receive battery current over CAN bus on ID 40. The packet contains a single 24-
bit value (big endian format) for instantaneous battery current, in milliamps. The value is unsigned
but with a 8388608 offset, i.e subtract this number from the received value to get a signed value
for current in milliamps.
Code: Select all
float BMS_24current = 0; // current value is 24bit value for milliamps
float BMS_voltage = 0; // voltage value is 16bit value for 0.1V
float BMS_SOC = 0; // value is 16bit value for 0.1Ah
uint8_t BMS_temp = 0; // Temperature of the BMS - 40
.....
void canRX_28(const CAN_message_t &msg) // receive telegram ID40 in 24bit value
{
BMS_24current = (((msg.buf[0] << 16) | (msg.buf[1] << 8) | msg.buf[2]) - 8388608) / 1000.0f; // 8388608 is sensor offset!
}
// We need to receive voltage as well
void canRX_1E(const CAN_message_t &msg) // receive telegram ID30 in 16bit value
{
BMS_error = msg.buf[0]; // We also receive the error status from byte 0
BMS_SOC = ((msg.buf[1] << 8) | msg.buf[2]) / 10.0f; // SOC status in AH value
BMS_voltage = ((msg.buf[3] << 8) | msg.buf[4]) / 10.0f; // Voltage
BMS_temp = (msg.buf[7]) - 40; // Voltage
}
Result is a good value in serial report. Evident from screenshots...
Works with heater on as well as in charging bome with negative value current report.
Now i can move to another step with CHADEMO signal programming.