User Tools

Site Tools


common_code_v2

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; }
}
common_code_v2.txt · Last modified: 2018/07/02 13:28 by hakcenter