Table of Contents
Intro
The common code is shared under the Creative Commons License BY-NC-SA, read more specifically here. Short and sweet, by using the code or making changes code must be shared under the same license, any derivative work must also be shared under the same license.
The common code is a general rule of thumb, get your vehicle running on this turbo code set. The variables are tunable to change the aggressiveness of the turbo without exceeding compressor limits. There is a idle section, a general normal mode of operation, and then top end control. Within that there are a lot of variables and math but to tune and control the turbo is a very simple matter once you understand what each variable does.
Main Code
Variables
Debug Serial Messages
boolean emulate = false;
– Toggles turbo eumulation
boolean serial_reading = false;
–true when reading Serial
boolean serial_out = true;
– Toggles serial output
Startup
byte startup = 200;
– startup timer to wait until turbo is ready
boolean turbo_online = false;
– true CANBUS from turbo is working
boolean bt_enabled = false;
– true if Bluetooth is paired
Timers
Timer t1;
Timer t2;
Controller Modes
byte port_d;
– Faster digital i/o reads
byte current_mode = 2;
– run mode byte
const String current_mode_array[7] = { “Idle”, “Idle Walk Down”, “Normal”, “Spare”, “Brake”, “Cruise”, “Performance” };
boolean idle_mode = false;
– toggles when turbo_rpm < idle_rpm
boolean idle_walkdown_mode = false;
– toggles when code is walking turbo down to idle
boolean spare_mode = false;
– spare digital i/o toggle
boolean brake_mode = false;
– exhaust brake toggle
boolean cruise_mode = false;
– cruise toggle
boolean performance_mode = false;
– performance toggle
boolean deceleration_mode = false;
– triggered for anti-surge
Boost Mode
boolean boost_enable = true;
– Enables boost mode
boolean boost_mode = false;
– boost mode toggle
int boost_timer = 0;
– boost time
byte boost_position = 0;
– boosted position
Minimum and Maximum Vane Positions
const unsigned int min_position = 40;
– absolute minimum vane position
const unsigned int max_position = 960;
– absolute maximum vane position
Vane Positions
const unsigned int idle_position = 40;
– position used when turbo is at idle stage
const unsigned int cruise_position = 500;
– position used when cruise mode is toggled
const unsigned int deceleration_position = 500;
– position used when deceleration mode is toggled
unsigned int vane_position = 40;
– calculated vane position
unsigned int last_vane_position = 0;
– vane position 2ms ago
unsigned int final_vane_position = 0;
– position used when sending vane position
Performance Positions
byte performance_position = 0;
– stored value from JP2
const byte perf_pos_1 = 40;
– position 1 for performance toggle
const byte perf_pos_2 = 80;
– position 2 for performance toggle
Turbo Idle
long idle_rpm = 11000;
– under this value turbo is idling
long idle_walkdown_rpm = 20000;
– once turbo_rpm reaches this, start walkdown process
Turbo Factors
const byte two_cm = 80;
– vane value for 2 cm²
const byte one_cm = 40;
– vane value for 1 cm²
const byte half_cm = 20;
– vane value for 1/2 cm²
const byte quarter_cm = 10;
– vane value for 1/4 cm²
Turbo Curves
byte current_curve = 0;
– current curve
const unsigned long top_end_rpm = 105000;
– first point in top end curve
const unsigned int curve_rpm[5] = { 15000, 22000, 30000, 55000, 80000 };
– curve rpm points
unsigned int turbo_curve[5] = { 0,0,0,0,0 };
– array to store curve from JP1
const unsigned int turbo_curve_1[5] = { 760,720,680,640,600 };
const unsigned int turbo_curve_2[5] = { 780,740,700,660,620 };
const unsigned int turbo_curve_3[5] = { 800,760,720,680,640 };
const unsigned int turbo_curve_4[5] = { 800,760,780,740,720 };
Turbo Variables
const int minimum_turbo_rpm = 1000;
– minimum required turbo rpm for pretty much everything
volatile long turbo_rpm = 0;
– current turbo rpm
long last_turbo_rpm = 0;
– turbo rpm 10ms & 100ms ago
int turbo_accel = 0;
– turbo acceleration variable
CANBUS Variables
long can_id = 0;
byte can_length;
byte can_data[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
byte turbo_flags[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
int turbo_position = 0;
byte turbo_temp = 0;
int turbo_cmd_position = 0;
byte turbo_feedback = 0;
Sweep Variables
boolean sweep_position = false;
– toggles on sweep command
boolean sweep_update = false;
– toggles every sweep
int sweep_counter = 0;
– counter chooses direction of sweep
Timer2 Variables
unsigned int timer = 0;
– main timer
boolean update_vane_position = false;
– toggle to calculate next vane position
Legend
GREEN – Safe to adjust
ORANGE – Careful adjusting this
RED – Editing can break everything
Accel Variable
The acceleration variable, is computed at 100ms and 10ms, and it represents the turbo rpm acceleration rate in, rpm per ms.
//---- Calculate turbo_accel ----// turbo_accel = (int) (turbo_rpm - last_turbo_rpm) / 100.0f; last_turbo_rpm = turbo_rpm;
last_turbo_rpm is updated every 100ms
Idle
The idling code is slightly complicated, in order to have the turbo in a non-aggressive vane position so that the turbo does not affect idle speed of the motor nor does it sound like a hair drier all day for absolutely no reason.
if (turbo_rpm <= curve_rpm[0]) { // ----- // Idle Section if (turbo_rpm <= idle_rpm) { idle_mode = true; idle_walkdown_mode = false; } else { idle_mode = false; } if (turbo_accel <= 2) { idle_counter++; } else { idle_counter = 0; vane_position = turbo_curve[0]; } if (idle_counter > 1) { idle_counter = 2; vane_position = idle_position; } } else { // ----- // Curve section if (turbo_rpm < idle_walkdown_rpm) { if (turbo_accel <= 2) { if (last_vane_position >= min_position + half_cm) { idle_walkdown_mode = true; vane_position = last_vane_position - half_cm; } else { vane_position = min_position; } } else { vane_position = turbo_curve[0]; } } else if (turbo_rpm <= curve_rpm[1]) { vane_position = map(turbo_rpm, curve_rpm[0], curve_rpm[1], turbo_curve[0], turbo_curve[1]); } else if (turbo_rpm <= curve_rpm[2]) { vane_position = turbo_curve[1]; } else if (turbo_rpm <= curve_rpm[3]) { vane_position = map(turbo_rpm, curve_rpm[2], curve_rpm[3], turbo_curve[1], turbo_curve[2]); } else { vane_position = map(turbo_rpm, curve_rpm[3], curve_rpm[4], turbo_curve[2], turbo_curve[3]); } if (turbo_accel > 2) { idle_walkdown_mode = false; }
Calculate Mode
Calculate mode, is ran in Timer2 every 100ms. It reads the PORTD on the Arduino, and decides what mode is set. Brake over Performance over Cruise.
void calculate_modes() { port_d = PIND; if (port_d & SWITCH_CRUISE) { cruise_mode = false; } else { cruise_mode = true; } if (port_d & SWITCH_PERFORMANCE) { performance_mode = false; } else { performance_mode = true; } if (port_d & SWITCH_BRAKE) { brake_mode = false; } else { brake_mode = true; } // if (digitalRead(SPARE_PIN) == LOW) { // spare_value = 0; // spare_mode = true; // } else { // spare_value = 1; // spare_mode = false; // } // Update current_mode current_mode = 2; if (boost_mode) { current_mode = 3; } if (idle_mode) { current_mode = 0; } if (idle_walkdown_mode) { current_mode = 1; } if (cruise_mode) { current_mode = 6; } if (performance_mode) { current_mode = 7; } if (brake_mode) { current_mode = 5; } if (spare_mode) { current_mode = 4; } // -- CRUISE MODE -- // if (cruise_mode && !brake_mode && !performance_mode) { cruise(); } // -- BRAKE MODE -- // if (brake_mode && !performance_mode) { exhaust_brake(); } }
current_mode is the global variable for the current mode in operation. If cruise_mode or brake_mode is set, their respective functions are ran at 100ms intervals as well.
MODES
The LBB Common Code has 3 programmed modes.
- Cruise
- Which is designed mostly for freeway use to lower back pressure to minimal levels while maintaining a small amount of boost.
- Brake
- Which is setup to create backpressure for engine braking
- Performance
- Which will move the turbo curve up substantially to try to spool the turbo as fast as possible
Cruise
Cruise mode tries to keep turbo rpm within 47,500 to 52,500. Roughly 5,000 total rpm difference.
byte counter = 0; byte adjustment = 0; void cruise() { if (turbo_rpm > 65000) { adjustment = one_cm; } if (turbo_rpm > 62500) { adjustment = half_cm; counter++; } if (counter > 3) { counter = 0; vane_position -= adjustment; } if (vane_position <= min_position) { vane_position = min_position; } if (turbo_rpm < 57500) { vane_position += quarter_cm; counter = 0; } if (vane_position >= cruise_position) { vane_position = cruise_position; } constrain(vane_position, min_position, max_position); }
- When turbo rpm is under 57,500 vane position increases by one quarter cm cruise_position.
- When turbo rpm is over 65,000 vane position decreases by one cm every ~100ms until turbo rpm is finally within bounds.
Brake
Default vane position Holset uses is 940 in other Cummins applications.
void exhaust_brake() { if (last_vane_position < 800) { vane_position = 800; } else if (last_vane_position < 900) { vane_position = 900; } else if (last_vane_position < 920) { vane_position = 920; } else { vane_position = max_position; } }
- Slowly walks position to the variable max_position
Performance
Performance mode sets vane position to current curve position + the position from JP1.
// -- PERFORMANCE MODE -- // if (performance_mode && turbo_rpm < top_end_rpm) { vane_position = vane_position + performance_position; }
- Calculated vane position is vane_position + performance_position
Timers
Timer1
void sweep() { if (turbo_feedback > 110) { Serial.print(F("POS: ")); Serial.print(turbo_cmd_position); Serial.print(F(" | Feedback : ")); Serial.print(turbo_feedback); Serial.println(F("%")); } if (sweep_update) { sweep_update = false; if (sweep_position && sweep_counter < 2) { if (sweep_counter < 1) { vane_position++; } if (vane_position > 960) { sweep_counter++; } if (sweep_counter > 0) { vane_position--; } if (vane_position < 40) { sweep_counter++; } } if (sweep_counter == 2 || !sweep_position) { sweep_position = false; sweep_update = false; sweep_counter = 0; Serial.println(F("Sweep done..")); } } else { sweep_update = true; } } void set_turbo_position() { // if not sweeping smoothe vane changes if (!sweep_position) { // Keep vane position within constraints constrain(vane_position, min_position, max_position); final_vane_position = vane_position; // Vane smoothing between large values if (turbo_rpm < curve_rpm[0] && (vane_position <= last_vane_position - half_cm)) { final_vane_position = last_vane_position - quarter_cm; } else if (!brake_mode && !boost_mode && turbo_rpm >= curve_rpm[1] && turbo_rpm < top_end_rpm) { // if vane_position change is 20 or more, move by half the difference if (vane_position >= last_vane_position + 20) { final_vane_position = vane_position + ((last_vane_position - vane_position) >> 2); } else if (vane_position <= last_vane_position - 20) { final_vane_position = vane_position - ((last_vane_position - vane_position) >> 2); } // if vane_position change is 10 or less, move by 2 if (vane_position - 10 >= last_vane_position) { final_vane_position = last_vane_position + 2; } else if (vane_position + 10 <= last_vane_position) { final_vane_position = last_vane_position - 2; } // End Smoothing } else if (turbo_rpm > top_end_rpm) { // remove jitter during top end turbo speeds if (vane_position - 5 >= last_vane_position || vane_position + 5 <= last_vane_position) { final_vane_position = vane_position; } else { final_vane_position = last_vane_position; } } //---- Decel Mode ----// if (deceleration_mode) { vane_position = deceleration_position; final_vane_position = deceleration_position; } // Constrain and update last_vane_position constrain(final_vane_position, min_position, max_position); last_vane_position = final_vane_position; } // Ignore vane changes until startup is complete if (startup > 1 && !sweep_position) { startup--; vane_position = min_position; last_vane_position = min_position; final_vane_position = min_position; } byte lo_byte = lowByte(final_vane_position); byte hi_byte = highByte(final_vane_position); byte do_calibrate = 0x01; if (calibrate) { do_calibrate = 0x02; } else { do_calibrate = 0x01; } byte data[] = { lo_byte, hi_byte, do_calibrate, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; // data message with an added counter // data[2] = 0x02 for recalibrating gearbox // Load message and send send_turbo_position(data); }
Timer2
void keep_time() { timer++; //---- Startup Timer ----// if (turbo_rpm < minimum_turbo_rpm) { if (startup > 249) { startup = 250; } startup++; } //---- Boost Mode ----// if (boost_timer > 0) { boost_timer--; } if (timer % 250 == 0 && boost_mode && boost_timer < 1) { boost_enable = true; boost_mode = false; } //---- Spare Pin Interrupt ----// /* if (timer % 250 == 0 && spare_count > 0) { // Spare Counting Fast detachInterrupt(2); spare_rpm[spare_counter] = 15.0f * 1000.0f * (spare_count / 250.0f); spare_count = 0; spare_value = (spare_value + ((spare_rpm[0] + spare_rpm[1] + spare_rpm[2] + spare_rpm[3]) / 4.0f)) / 2.0f; attachInterrupt(0, spare_counting, HIGH); spare_counter++; if (spare_counter > 3) { spare_counter = 0; } } */ // Update vane_position every 10ms 100k+ / 25ms 60k - 100k / 50ms 0 - 60k if (timer % 10 == 0 && turbo_rpm > top_end_rpm) { update_vane_position = true; } else if (timer % 25 == 0 && turbo_rpm > curve_rpm[4]) { update_vane_position = true; } else if (timer % 50 == 0) { update_vane_position = true; } if (timer % 10 == 0) { //---- Read Serial Input ----// check_serial(); } if (timer % 25 == 0) { //---- Read CAN BUS ----// read_can_data(can_id, can_length); } if (timer % 100 == 0) { //---- Calculate Modes ----// if (turbo_rpm < top_end_rpm) { calculate_modes(); } //---- Calculate turbo_accel ----// turbo_accel = (int) (turbo_rpm - last_turbo_rpm) / 100.0f; last_turbo_rpm = turbo_rpm; //---- Deceleration Mode ----// if (turbo_accel < -20 && turbo_rpm > 70000) { deceleration_mode = true; } else { deceleration_mode = false; } } // Sweep vane_position if (timer % 25 == 0 && sweep_position) { sweep(); } // Calculate vane_position if (update_vane_position && !sweep_position) { update_vane_position = false; calculate_vane_position(); if (serial_out) { serial_output(); } } if (timer == 1000) { timer = 0; } }