Skip to content

Commit

Permalink
Merge pull request #668 from dalathegreat/bugfix/precharge-pwm
Browse files Browse the repository at this point in the history
Bugfix: PWM causes precharge to break
  • Loading branch information
dalathegreat authored Dec 14, 2024
2 parents 888409f + 602fc6d commit 3f715bf
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 41 deletions.
61 changes: 30 additions & 31 deletions Software/Software.ino
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ MyTimer check_pause_2s(INTERVAL_2_S);

// Contactor parameters
#ifdef CONTACTOR_CONTROL
enum State { DISCONNECTED, PRECHARGE, NEGATIVE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
enum State { DISCONNECTED, START_PRECHARGE, PRECHARGE, POSITIVE, PRECHARGE_OFF, COMPLETED, SHUTDOWN_REQUESTED };
State contactorStatus = DISCONNECTED;

#define ON 1
Expand All @@ -126,30 +126,29 @@ State contactorStatus = DISCONNECTED;
#define ON 0
#undef OFF
#define OFF 1
#endif
#endif //NC_CONTACTORS

#define MAX_ALLOWED_FAULT_TICKS 1000
/* NOTE: modify the precharge time constant below to account for the resistance and capacitance of the target system.
* t=3RC at minimum, t=5RC ideally
*/
#define PRECHARGE_TIME_MS 160
#define NEGATIVE_CONTACTOR_TIME_MS 1000
#define POSITIVE_CONTACTOR_TIME_MS 2000
#define NEGATIVE_CONTACTOR_TIME_MS \
500 // Time after negative contactor is turned on, to start precharge (not actual precharge time!)
#define PRECHARGE_COMPLETED_TIME_MS \
1000 // After successful precharge, resistor is turned off after this delay (and contactors are economized if PWM enabled)
#define PWM_Freq 20000 // 20 kHz frequency, beyond audible range
#define PWM_Res 10 // 10 Bit resolution 0 to 1023, maps 'nicely' to 0% 100%
#define PWM_HOLD_DUTY 250
#define PWM_OFF_DUTY 0
#define PWM_ON_DUTY 1023
#define POSITIVE_PWM_Ch 0
#define NEGATIVE_PWM_Ch 1
#define PWM_Positive_Channel 0
#define PWM_Negative_Channel 1
unsigned long prechargeStartTime = 0;
unsigned long negativeStartTime = 0;
unsigned long prechargeCompletedTime = 0;
unsigned long timeSpentInFaultedMode = 0;
#endif

void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFFFFFFFF) {
void set(uint8_t pin, bool direction, uint32_t pwm_freq = 0xFFFF) {
#ifdef PWM_CONTACTOR_CONTROL
if (pwm_freq != 0xFFFFFFFFFF) {
if (pwm_freq != 0xFFFF) {
ledcWrite(pin, pwm_freq);
return;
}
Expand Down Expand Up @@ -518,23 +517,22 @@ void init_contactors() {
// Init contactor pins
#ifdef CONTACTOR_CONTROL
#ifdef PWM_CONTACTOR_CONTROL
ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res,
POSITIVE_PWM_Ch); // Setup PWM Channel Frequency and Resolution
ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res,
NEGATIVE_PWM_Ch); // Setup PWM Channel Frequency and Resolution
ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY); // Set Positive PWM to 0%
ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY); // Set Negative PWM to 0%
#else //Normal CONTACTOR_CONTROL
// Setup PWM Channel Frequency and Resolution
ledcAttachChannel(POSITIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Positive_Channel);
ledcAttachChannel(NEGATIVE_CONTACTOR_PIN, PWM_Freq, PWM_Res, PWM_Negative_Channel);
// Set all pins OFF (0% PWM)
ledcWrite(POSITIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
ledcWrite(NEGATIVE_CONTACTOR_PIN, PWM_OFF_DUTY);
#else //Normal CONTACTOR_CONTROL
pinMode(POSITIVE_CONTACTOR_PIN, OUTPUT);
set(POSITIVE_CONTACTOR_PIN, OFF);
pinMode(NEGATIVE_CONTACTOR_PIN, OUTPUT);
set(NEGATIVE_CONTACTOR_PIN, OFF);
#endif
#endif // Precharge never has PWM regardless of setting
pinMode(PRECHARGE_PIN, OUTPUT);
set(PRECHARGE_PIN, OFF);
#endif //CONTACTOR_CONTROL
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY

pinMode(SECOND_POSITIVE_CONTACTOR_PIN, OUTPUT);
set(SECOND_POSITIVE_CONTACTOR_PIN, OFF);
pinMode(SECOND_NEGATIVE_CONTACTOR_PIN, OUTPUT);
Expand Down Expand Up @@ -814,7 +812,7 @@ void handle_contactors() {

if (datalayer.system.status.battery_allows_contactor_closing &&
datalayer.system.status.inverter_allows_contactor_closing && !datalayer.system.settings.equipment_stop_active) {
contactorStatus = PRECHARGE;
contactorStatus = START_PRECHARGE;
}
}

Expand All @@ -829,31 +827,32 @@ void handle_contactors() {
}

unsigned long currentTime = millis();
// Handle actual state machine. This first turns on Precharge, then Negative, then Positive, and finally turns OFF precharge
// Handle actual state machine. This first turns on Negative, then Precharge, then Positive, and finally turns OFF precharge
switch (contactorStatus) {
case PRECHARGE:
set(PRECHARGE_PIN, ON);
case START_PRECHARGE:
set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
prechargeStartTime = currentTime;
contactorStatus = NEGATIVE;
contactorStatus = PRECHARGE;
break;

case NEGATIVE:
if (currentTime - prechargeStartTime >= PRECHARGE_TIME_MS) {
set(NEGATIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
case PRECHARGE:
if (currentTime - prechargeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) {
set(PRECHARGE_PIN, ON);
negativeStartTime = currentTime;
contactorStatus = POSITIVE;
}
break;

case POSITIVE:
if (currentTime - negativeStartTime >= NEGATIVE_CONTACTOR_TIME_MS) {
if (currentTime - negativeStartTime >= PRECHARGE_TIME_MS) {
set(POSITIVE_CONTACTOR_PIN, ON, PWM_ON_DUTY);
prechargeCompletedTime = currentTime;
contactorStatus = PRECHARGE_OFF;
}
break;

case PRECHARGE_OFF:
if (currentTime - negativeStartTime >= POSITIVE_CONTACTOR_TIME_MS) {
if (currentTime - prechargeCompletedTime >= PRECHARGE_COMPLETED_TIME_MS) {
set(PRECHARGE_PIN, OFF);
set(NEGATIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY);
set(POSITIVE_CONTACTOR_PIN, ON, PWM_HOLD_DUTY);
Expand Down
1 change: 1 addition & 0 deletions Software/USER_SETTINGS.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
//#define HW_3LB

/* Contactor settings. If you have a battery that does not activate contactors via CAN, configure this section */
#define PRECHARGE_TIME_MS 500 //Precharge time in milliseconds. Modify to suit your inverter (See wiki for more info)
//#define CONTACTOR_CONTROL //Enable this line to have the emulator handle automatic precharge/contactor+/contactor- closing sequence (See wiki for pins)
//#define CONTACTOR_CONTROL_DOUBLE_BATTERY //Enable this line to have the emulator hardware control secondary set of contactors for double battery setups (See wiki for pins)
//#define PWM_CONTACTOR_CONTROL //Enable this line to use PWM for CONTACTOR_CONTROL, which lowers power consumption and heat generation. CONTACTOR_CONTROL must be enabled.
Expand Down
36 changes: 26 additions & 10 deletions Software/src/devboard/webserver/webserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,21 +685,29 @@ String processor(const String& var) {
content += "<h4 style='color: red;'>Power status: " + String(get_emulator_pause_status().c_str()) + " </h4>";

#ifdef CONTACTOR_CONTROL
content += "<h4>Contactors controlled by Battery-Emulator: ";
content += "<h4>Contactors controlled by emulator, state: ";
if (datalayer.system.status.contactors_engaged) {
content += "<span style='color: green;'>ON</span>";
} else {
content += "<span style='color: red;'>OFF</span>";
}
content += "</h4>";

content += "<h4>Pre Charge: ";
if (digitalRead(PRECHARGE_PIN) == HIGH) {
content += "<span style='color: green;'>&#10003;</span>";
content += "<h4>Precharge: (";
content += PRECHARGE_TIME_MS;
content += " ms) Cont. Neg.: ";
#ifdef PWM_CONTACTOR_CONTROL
if (datalayer.system.status.contactors_engaged) {
content += "<span style='color: green;'>Economized</span>";
content += " Cont. Pos.: ";
content += "<span style='color: green;'>Economized</span>";
} else {
content += "<span style='color: red;'>&#10005;</span>";
content += " Cont. Pos.: ";
content += "<span style='color: red;'>&#10005;</span>";
}
content += " Cont. Neg.: ";

#else // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded
if (digitalRead(NEGATIVE_CONTACTOR_PIN) == HIGH) {
content += "<span style='color: green;'>&#10003;</span>";
} else {
Expand All @@ -712,6 +720,7 @@ String processor(const String& var) {
} else {
content += "<span style='color: red;'>&#10005;</span>";
}
#endif //no PWM_CONTACTOR_CONTROL
content += "</h4>";
#endif

Expand Down Expand Up @@ -816,21 +825,27 @@ String processor(const String& var) {
content += "<h4 style='color: red;'>Power status: " + String(get_emulator_pause_status().c_str()) + " </h4>";

#ifdef CONTACTOR_CONTROL
content += "<h4>Contactors controlled by Battery-Emulator: ";
content += "<h4>Contactors controlled by emulator, state: ";
if (datalayer.system.status.contactors_battery2_engaged) {
content += "<span style='color: green;'>ON</span>";
} else {
content += "<span style='color: red;'>OFF</span>";
}
content += "</h4>";
#ifdef CONTACTOR_CONTROL_DOUBLE_BATTERY
content += "<h4>Pre Charge: ";
if (digitalRead(SECOND_PRECHARGE_PIN) == HIGH) {
content += "<span style='color: green;'>&#10003;</span>";
content += "<h4>Cont. Neg.: ";
#ifdef PWM_CONTACTOR_CONTROL
if (datalayer.system.status.contactors_battery2_engaged) {
content += "<span style='color: green;'>Economized</span>";
content += " Cont. Pos.: ";
content += "<span style='color: green;'>Economized</span>";
} else {
content += "<span style='color: red;'>&#10005;</span>";
content += " Cont. Pos.: ";
content += "<span style='color: red;'>&#10005;</span>";
}
content += " Cont. Neg.: ";

#else // No PWM_CONTACTOR_CONTROL , we can read the pin and see feedback. Helpful if channel overloaded
if (digitalRead(SECOND_NEGATIVE_CONTACTOR_PIN) == HIGH) {
content += "<span style='color: green;'>&#10003;</span>";
} else {
Expand All @@ -843,6 +858,7 @@ String processor(const String& var) {
} else {
content += "<span style='color: red;'>&#10005;</span>";
}
#endif //no PWM_CONTACTOR_CONTROL
content += "</h4>";
#endif // CONTACTOR_CONTROL_DOUBLE_BATTERY
#endif // CONTACTOR_CONTROL
Expand Down

0 comments on commit 3f715bf

Please sign in to comment.