Merge pull request #1494 from jonny5532/fix/change-can-speed

Fix multiple bugs with native change_can_speed operation to fix BMW PHEV
This commit is contained in:
Daniel Öster 2025-09-10 20:49:25 +03:00 committed by GitHub
commit 9b6f5409c2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 64 additions and 28 deletions

View file

@ -177,12 +177,15 @@ void BmwPhevBattery::wake_battery_via_canbus() {
// Followed by a Recessive interval of at least ~3µs (min) and at most ~10µs (max) // Followed by a Recessive interval of at least ~3µs (min) and at most ~10µs (max)
// Then a second dominant pulse of similar timing. // Then a second dominant pulse of similar timing.
auto original_speed = change_can_speed(CAN_Speed::CAN_SPEED_100KBPS); change_can_speed(CAN_Speed::CAN_SPEED_100KBPS);
transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST); transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST);
transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST); transmit_can_frame(&BMW_PHEV_BUS_WAKEUP_REQUEST);
change_can_speed(original_speed); // FIXME: This might not wait for the above frames to send before it changes
// the speed back. A state-machine controlled delay is likely necessary.
reset_can_speed();
logging.println("Sent magic wakeup packet to SME at 100kbps..."); logging.println("Sent magic wakeup packet to SME at 100kbps...");
} }

View file

@ -1,17 +1,18 @@
#include "CanBattery.h" #include "CanBattery.h"
CanBattery::CanBattery(CAN_Speed speed) { CanBattery::CanBattery(CAN_Speed speed) : CanBattery(can_config.battery, speed) {}
can_interface = can_config.battery;
register_transmitter(this);
register_can_receiver(this, can_interface, speed);
}
CanBattery::CanBattery(CAN_Interface interface, CAN_Speed speed) { CanBattery::CanBattery(CAN_Interface interface, CAN_Speed speed) {
can_interface = interface; can_interface = interface;
initial_speed = speed;
register_transmitter(this); register_transmitter(this);
register_can_receiver(this, can_interface, speed); register_can_receiver(this, can_interface, speed);
} }
CAN_Speed CanBattery::change_can_speed(CAN_Speed speed) { bool CanBattery::change_can_speed(CAN_Speed speed) {
return ::change_can_speed(can_interface, speed); return ::change_can_speed(can_interface, speed);
} }
void CanBattery::reset_can_speed() {
::change_can_speed(can_interface, initial_speed);
}

View file

@ -22,11 +22,13 @@ class CanBattery : public Battery, Transmitter, CanReceiver {
protected: protected:
CAN_Interface can_interface; CAN_Interface can_interface;
CAN_Speed initial_speed;
CanBattery(CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS); CanBattery(CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS);
CanBattery(CAN_Interface interface, CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS); CanBattery(CAN_Interface interface, CAN_Speed speed = CAN_Speed::CAN_SPEED_500KBPS);
CAN_Speed change_can_speed(CAN_Speed speed); bool change_can_speed(CAN_Speed speed);
void reset_can_speed();
void transmit_can_frame(const CAN_frame* frame) { transmit_can_frame_to_interface(frame, can_interface); } void transmit_can_frame(const CAN_frame* frame) { transmit_can_frame_to_interface(frame, can_interface); }
}; };

View file

@ -1,6 +1,4 @@
#include "comm_can.h" #include "comm_can.h"
#include <algorithm>
#include <map>
#include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h" #include "../../lib/pierremolinaro-ACAN2517FD/ACAN2517FD.h"
#include "../../lib/pierremolinaro-acan-esp32/ACAN_ESP32.h" #include "../../lib/pierremolinaro-acan-esp32/ACAN_ESP32.h"
#include "../../lib/pierremolinaro-acan2515/ACAN2515.h" #include "../../lib/pierremolinaro-acan2515/ACAN2515.h"
@ -11,6 +9,11 @@
#include "src/devboard/sdcard/sdcard.h" #include "src/devboard/sdcard/sdcard.h"
#include "src/devboard/utils/logging.h" #include "src/devboard/utils/logging.h"
#include <esp_private/periph_ctrl.h>
#include <algorithm>
#include <map>
volatile CAN_Configuration can_config = {.battery = CAN_NATIVE, volatile CAN_Configuration can_config = {.battery = CAN_NATIVE,
.inverter = CAN_NATIVE, .inverter = CAN_NATIVE,
.battery_double = CAN_ADDON_MCP2515, .battery_double = CAN_ADDON_MCP2515,
@ -35,7 +38,9 @@ void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, CAN_S
DEBUG_PRINTF("CAN receiver registered, total: %d\n", can_receivers.size()); DEBUG_PRINTF("CAN receiver registered, total: %d\n", can_receivers.size());
} }
ACAN_ESP32_Settings* settingsespcan; uint32_t init_native_can(CAN_Speed speed, gpio_num_t tx_pin, gpio_num_t rx_pin);
ACAN_ESP32_Settings* settingsespcan = nullptr;
static uint32_t QUARTZ_FREQUENCY; static uint32_t QUARTZ_FREQUENCY;
SPIClass SPI2515; SPIClass SPI2515;
@ -90,12 +95,7 @@ bool init_CAN() {
return false; return false;
} }
settingsespcan = new ACAN_ESP32_Settings((int)nativeIt->second.speed * 1000UL); const uint32_t errorCode = init_native_can(nativeIt->second.speed, tx_pin, rx_pin);
settingsespcan->mRequestedCANMode = ACAN_ESP32_Settings::NormalMode;
settingsespcan->mTxPin = tx_pin;
settingsespcan->mRxPin = rx_pin;
const uint32_t errorCode = ACAN_ESP32::can.begin(*settingsespcan);
if (errorCode == 0) { if (errorCode == 0) {
native_can_initialized = true; native_can_initialized = true;
logging.println("Native Can ok"); logging.println("Native Can ok");
@ -482,11 +482,41 @@ void restart_can() {
} }
} }
CAN_Speed change_can_speed(CAN_Interface interface, CAN_Speed speed) { // Initialize the native CAN interface with the given speed and pins.
auto oldSpeed = (CAN_Speed)settingsespcan->mDesiredBitRate; // This can be called repeatedly to change the interface speed (as some
if (interface == CAN_Interface::CAN_NATIVE) { // batteries require).
settingsespcan->mDesiredBitRate = (int)speed; uint32_t init_native_can(CAN_Speed speed, gpio_num_t tx_pin, gpio_num_t rx_pin) {
ACAN_ESP32::can.begin(*settingsespcan);
// TODO: check whether this is necessary? It seems to help with
// reinitialization.
periph_module_reset(PERIPH_TWAI_MODULE);
if (settingsespcan != nullptr) {
delete settingsespcan;
} }
return speed;
// Create a new settings object (as it does the bitrate calcs in the constructor)
settingsespcan = new ACAN_ESP32_Settings((int)speed * 1000UL);
settingsespcan->mRequestedCANMode = ACAN_ESP32_Settings::NormalMode;
settingsespcan->mTxPin = tx_pin;
settingsespcan->mRxPin = rx_pin;
// (Re)start the CAN interface
return ACAN_ESP32::can.begin(*settingsespcan);
}
// Change the speed of the given CAN interface. Returns true if successful.
bool change_can_speed(CAN_Interface interface, CAN_Speed speed) {
if (interface == CAN_Interface::CAN_NATIVE && settingsespcan != nullptr) {
// Reinitialize the native CAN interface with the new speed
const uint32_t errorCode = init_native_can(speed, settingsespcan->mTxPin, settingsespcan->mRxPin);
if (errorCode != 0) {
logging.print("Error Native Can: 0x");
logging.println(errorCode, HEX);
return false;
}
return true;
}
return false;
} }

View file

@ -102,7 +102,7 @@ void stop_can();
// Restart CAN communication for all interfaces // Restart CAN communication for all interfaces
void restart_can(); void restart_can();
// Change the speed of the CAN interface and return the old speed. // Change the speed of the CAN interface. Returns true if successful.
CAN_Speed change_can_speed(CAN_Interface interface, CAN_Speed speed); bool change_can_speed(CAN_Interface interface, CAN_Speed speed);
#endif #endif

View file

@ -5,8 +5,8 @@ void transmit_can_frame_to_interface(const CAN_frame* tx_frame, int interface) {
void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, CAN_Speed speed) {} void register_can_receiver(CanReceiver* receiver, CAN_Interface interface, CAN_Speed speed) {}
CAN_Speed change_can_speed(CAN_Interface interface, CAN_Speed speed) { bool change_can_speed(CAN_Interface interface, CAN_Speed speed) {
return CAN_Speed::CAN_SPEED_500KBPS; return true;
} }
void stop_can() {} void stop_can() {}