Best $40.00 I’ve spent in a while…

So after 16 years my old truck was close to giving up the ghost. Treated myself to a new 2019 F-150, but it had one thing that annoyed the heck out of me. Auto stop/start! I don’t know why, but this feature (really for MPG) drives me crazy.

Enter the Auto Stop/Start Eliminator by WesternDiesel, pretty easy install and now Auto Stop/Start is permanently disabled unless *I* enable it!

Look for a quick vid of the install soon!

Finished! Custom Carbon Fiber Fuse/Relay Center With 6061 Aluminum Bracket

After deciding to not share any of the stock vehicle wiring with the Megasquirt Fuel Injection system being installed in my 1995 Lightning project it was time to build a custom fuse and relay center. There really were no affordable off the shelf setups so I began piecing one together that met my needs. 1st and foremost you need to properly plan for two items. One, what is the total amount of current you will run through the setup and two will you be using negative triggered relays or positive triggers or both? Looking over the items being being used in the fuel injection setup (namely 8 IGN-1A coils) I needed several relays and fused circuits. A couple of the relays would handle quite large current and then I needed one main relay that was ground triggered.

The solution, I picked up a Bussman 15303-2 fuse/relay center for all my positively triggered relays and fuse needs, 4 terminal blocks to provide connectivity to and from the fuse/relay center, two very cool Bussman AMI fuse holders to protect the dual 40A IGN-1A coil circuits, 3 Picker 40A relays (these are mounted to the fender) two for the IGN-1As and one as a main, and a Blue Sea Systems power block to provide power and ground from the battery.

The whole setup is activated using a 40A Picker relay as a main relay, this relay controls all the others and is only energized when the key is on. I also utilized the stock Ford fuel pump inertia switch. This switch can sense impact and it will kill the main relays ground circuit which in turn shuts everything down. This way in a crash my fuel pump, fans, O2 sensor, coils, injectors, etc will all shut down.  

Below is the circuit diagram.

 

Megasquirt Relay Layout v2

After planning the electrical portion it was time to figure out where to mount this setup. The project that I am building this for has a perfect place, right where the stock air filter box was mounted. ‘Cause who keeps the stock air filter? After choosing the location I figured I needed some nice material to house the components. I picked up some Carbon Fiber from Tim McAmis Performance Parts for the board and then some .125” 6061 Aluminum sheet for the bracket. Then went to work on the CNC router.

Here’s a couple of quick videos showing the Carbon Fiber cut and the aluminum cut.

While the Carbon Fiber is trick, it’s not as rigid as I’d like so I put use some aluminum stand-offs between it and the bracket for extra strength.

Finished board and bracket. The bracket and stand-offs will be going to the powdercoaters to get a nice semi-gloss black coating.

20171028_024545405_iOS

20171024_032124656_iOS

20171024_032214837_iOS

 

All mounted up in the truck. 

20171028_215221242_iOS

20171028_222317939_iOS

 

Parts list:

Real Carbon Fiber 

Bussman 15303-2 if you want to assemble it yourself or pick up a pre-populated unit from Concours Specialties

Blue Sea Systems Dualbus Plus Stud, Screw Terminal

Bussman 5 terminal 30A blocks

Bussman 2 terminal 75A block

Bussman AMI fuse holders

Carbon fiber sheet

.125” 6061 aluminum sheet

Destiny Viper end mill

1.25 LED” voltmeter

Aluminum stand-offs

 

 

It’s here! Part 1 how to Display Data Over a CAN bus From Your Megasquirt or Microsquirt

An alternative to tablets and PCs

One of the cool things about the Megasquirt fuel injection system is its ability to broadcast data over a CAN bus. This is exactly how OEM automotive systems connect all the different vehicle control systems in modern vehicle and provides a very flexible platform for aftermarket connectivity as well.

1st let’s quickly go over, at a high level, what CAN bus is and how it operates. CAN is a multi-master serial bus standard for connecting vehicle subsystems (e.g. a vehicle’s ECU is a subsystem or node).  There’s physical aspects and software aspects. Wiring (a physical aspect) is generally a twisted pair with a 120Ω resistor at each end of the bus. This is important to note as improperly located or missing resistors will cause issues. The CAN protocol is one of the software aspects. The Megasquirt firmware uses an 11-bit protocol (for basic dash broadcasting) and a proprietary 29bit protocol for more in-depth communication between Mega/Microsquirt devices. For example, a Megasquirt unit controlling the engine and a Microsquirt controlling the transmission.

After soaking this information in I wanted to make use of what I feel is a very robust and reliable way to transfer data out of the Megasquirt or Microsquirt controller and display that in a useful manner. There are plenty of tablet based projects running Raspberry Pi or simply a full-blown Windows or Linux tablet, but I like the simple aspect of no operating system in between. It’s pretty much just data out of the controller and straight to the display no boot times, crashes, patching, etc., etc.

Unfortunately, it’s not as simple as broadcasting the CAN data out and picking that up with the display. There’s a few more pieces you’ll need. 1st you will need a CAN transceiver, this converts the CAN data in to a serial stream. For this I used an inexpensive Waveshare CAN transceiver from Amazon. Then you’ll need something to manipulate the data so your display can show it in an understandable format. I used a Teensy 3.2 microcontroller. The Teensy is an awesome little microcontroller that works with Arduino programming software.  And finally, you will need the display device itself so I tried out the Nextion 3.2” touch screen display. I like the Nextion as it offloads a lot of the processing load of the display from the microcontroller and is very easy to program, plus it is a touchscreen.

As you can see there’s going to be a few items with learning curves if you’ve never touched this stuff before. But the Arduino IDE and Nextion software are very easy to learn. This was my very first project with all of it!

Project in action. This is a simple video showing some of the different aspects of the operation. Visually still a work in progress, but this will help you get an idea of what you can do. You’ll find that the graphics are by far the item you’ll spend the most time on.

Here is the full parts list:

  1. Nextion 3.2″ TFT Display
  2. Waveshare CAN transceiver
  3. Teensy 3.2 Arduino compatible micro-controller
  4. Microsquirt v3 cased

Arduino sketch



#include 
#include 

FlexCAN CANbus(500000);
static CAN_message_t rxmsg;


byte indicator[7]; 
float  BATTV, IAC, dwell, idle_tar, AFRtgt, AFR, newBATTV, oldBATTV;
unsigned int MAP, SPKADV, RPM, TPS, MAT, CLT, injduty, Baro, PW1, nexAFR, nexCLT;

void setup() {



  CANbus.begin();




  Serial2.begin(115200);
}


void loop(void) {


  gauge_display();


  if ( CANbus.read(rxmsg) ) {
    switch (rxmsg.id) { 
      case 1520: 
        RPM = (float)(word(rxmsg.buf[6], rxmsg.buf[7]));
        PW1 = (float)(word(rxmsg.buf[2], rxmsg.buf[3]));
        injduty = ((PW1 / 1000 * RPM / 120) / 10);
        break;
      case 1521: 
        SPKADV = (float)(word(rxmsg.buf[0], rxmsg.buf[1]));
        indicator[0] = rxmsg.buf[3]; 
        AFRtgt = (float)(word(0x00, rxmsg.buf[4]));
        break;
      case 1522: 
        Baro = (float)(word(rxmsg.buf[0], rxmsg.buf[1]));
        MAP = (float)(word(rxmsg.buf[2], rxmsg.buf[3]));
        MAT = (float)(word(rxmsg.buf[4], rxmsg.buf[5]));
        CLT = (float)(word(rxmsg.buf[6], rxmsg.buf[7]));
        nexCLT = (float)(word(rxmsg.buf[6], rxmsg.buf[7]));

        break;
      case 1523: 
        TPS = (float)(word(rxmsg.buf[0], rxmsg.buf[1]));
        BATTV = (float)(word(rxmsg.buf[2], rxmsg.buf[3]));
        AFR = (float)(word(rxmsg.buf[4], rxmsg.buf[5]));
        nexAFR = (float)(word(rxmsg.buf[4], rxmsg.buf[5]));
        break;
      case 1524: 
        break;
      case 1526: 
        IAC = (float)(word(rxmsg.buf[6], rxmsg.buf[7])); //IAC = (IAC * 49) / 125;
      case 1529: 
        dwell = (float)(word(rxmsg.buf[4], rxmsg.buf[5]));
        break;
      case 1530: 
        indicator[1] = rxmsg.buf[0]; 
        indicator[2] = rxmsg.buf[1]; 
        indicator[3] = rxmsg.buf[2]; 
        indicator[6] = rxmsg.buf[6]; 
        indicator[7] = rxmsg.buf[7]; 
        break;
      case 1537: 

        break;
      case 1548: 
        idle_tar = (float)(word(rxmsg.buf[0], rxmsg.buf[1]));
        break;
      case 1551: 
        break;
      case 1574: 
        indicator[4] = rxmsg.buf[2]; 
        break;

    }


  }
}

elapsedMillis DisplayTime; 

void gauge_display() {  

  if ( DisplayTime < 150 ) return;
  DisplayTime = 0;






  Serial2.print("t3.txt=");
  Serial2.write(0x22);
  Serial2.print(SPKADV / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);



  Serial2.print("t4.txt=");
  Serial2.write(0x22);
  Serial2.print(MAP / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);



  Serial2.print("j6.val=");
  Serial2.print(nexAFR / 2); 
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("t14.txt=");
  Serial2.write(0x22);
  Serial2.print(AFR / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);



  if ((AFR / 10 < 10.5) && (AFR / 10 > 10) && (TPS / 10 > 80))
    gauge_display_AFR_YELLOW();

  if ((AFR / 10 < 10.0) && (TPS / 10 > 80))
    gauge_display_AFR_RED();

  if ((AFR / 10 < 12.5) && (AFR / 10 > 10.5) && (TPS / 10 > 80))
    gauge_display_AFR_BLACK();

  if ((AFR / 10 > 12.5) && (TPS / 10 > 80))
    gauge_display_AFR_RED();






  Serial2.print("j2.val=");
  Serial2.print(injduty);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("t15.txt=");
  Serial2.write(0x22);
  Serial2.print(injduty);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);



  if (injduty < 60)
    gauge_display_injduty_black();

  if ((injduty >= 60) && (injduty < 79))

    gauge_display_injduty_yellow();

  if (injduty > 79)

    gauge_display_injduty_RED();




  Serial2.print("j3.val=");
  Serial2.print(TPS / 10);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("t16.txt=");
  Serial2.write(0x22);
  Serial2.print(TPS / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);


  newBATTV = BATTV / 10;
  if ( newBATTV != oldBATTV )
    gauge_display_BATTV();

  Serial2.print("t8.txt=");
  Serial2.write(0x22);
  Serial2.print(MAT / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);



  Serial2.print("t0.txt=");
  Serial2.write(0x22);
  Serial2.print(RPM);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("j5.val=");
  Serial2.print(RPM / 100);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);



  if (RPM < 5000)
    gauge_display_RPM_BLACK();

  if ((RPM > 5000) && (RPM < 6000))
    gauge_display_RPM_YELLOW();

  if ((RPM > 6000))
    gauge_display_RPM_RED();



  Serial2.print("t17.txt=");
  Serial2.write(0x22);
  Serial2.print(CLT / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("j4.val=");
  Serial2.print(nexCLT / 20);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);
}



void gauge_display_injduty_black() {

  Serial2.print("j2.pco=BLACK");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("t15.pco=BLACK");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);
}

void gauge_display_injduty_yellow() {

  Serial2.print("j2.pco=YELLOW");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_injduty_RED() {

  Serial2.print("j2.pco=RED");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_BATTV() {

  oldBATTV =
    Serial2.print("t6.txt=");
  Serial2.write(0x22);
  Serial2.print(BATTV / 10);
  Serial2.write(0x22);
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_RPM_BLACK() {


  Serial2.print("t0.pco=BLACK");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("j5.pco=BLACK");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_RPM_YELLOW() {

  Serial2.print("t0.pco=YELLOW");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

  Serial2.print("j5.pco=YELLOW");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_RPM_RED() {

  Serial2.print("t0.pco=RED");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);


  Serial2.print("j5.pco=RED");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_AFR_RED() {


  Serial2.print("j6.pco=RED");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_AFR_YELLOW() {


  Serial2.print("j6.pco=YELLOW");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}

void gauge_display_AFR_BLACK() {

  Serial2.print("j6.pco=BLACK");
  Serial2.write(0xff);
  Serial2.write(0xff);
  Serial2.write(0xff);

}