element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Ben Heck Featured Content
  • Challenges & Projects
  • element14 presents
  • element14's The Ben Heck Show
  • Ben Heck Featured Content
  • More
  • Cancel
Ben Heck Featured Content
Forum Engine Management
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Ben Heck Featured Content to participate - click to join for free!
Actions
  • Share
  • More
  • Cancel
Forum Thread Details
  • Replies 63 replies
  • Subscribers 48 subscribers
  • Views 4644 views
  • Users 0 members are here
Related

Engine Management

jack.chaney56
jack.chaney56 over 9 years ago

Hi Ben,

I am a programmer with a very small amount of skill with circuits, and am looking to create a platform for an engine management system, using an Arduino Mega 2560. I had done a bit of the coding, when I ran into some timing issues with the built in Arduino manager, so I switched over and started using AVR Studio and a programmer to go directly to the chip itself.  The code looks like it should work ok, but now I need some additional circuits to handle the energy levels of coils and injectors (Something like IGBTs). Sensors are being run through simple dividers (no protection yet), and cam and crank inputs are through a simple comparitor

 

Let me know what you think,

Jack

  • Sign in to reply
  • Cancel

Top Replies

  • jack.chaney56
    jack.chaney56 over 7 years ago +2
    Back again... After a bit of time away seeking enlightenment (and a steady paycheck), I am ready to get back to work on my project. I have continued to play around with the code and a number of components…
  • jack.chaney56
    jack.chaney56 over 7 years ago +2
    I want to start this thing right, so the shopping list for people that want to play along at home: Raspberry Pi - version is not significant if you don't mind a slow response when using Eclipse, but 3B…
  • jack.chaney56
    jack.chaney56 over 7 years ago +2
    Start off with two things. First, I forgot (neglected) to provide instruction on how to get the compiled code onto the Nano. Fault of familiarity; having done the process so many times, I had shifted to…
  • rsc
    rsc over 7 years ago in reply to jack.chaney56

    Hardware is usually vehicle specific, what is your target platform?

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to rsc

    Funny you should say that. The truth is the hardware is pretty much portable. The difference for system timing comes down to the cam and crank wheels and the signals they produce. I have software that does the cam decoding for simple pulse or half moon, Mopar 4/6/or 8 cylinder, and GM VVT. The crank signal is based on the call out for how many teeth, and if there are filled or missing teeth. The other parameters are for injector size and the variety of sensors. I had similar code operating a GM LS, a MOPAR SRT, and a Ford Cobra (with multi-strike CD), The input signals might need some conditioning for hall effect, I will need to see about that. My focus is primarily on the coding side of the process.

     

    The primary target for the controller project is actually Porsche and VW 4 cyl, and Corvair 6 cyl. But I have built the code and my breadboard to run up to 8 cylinder COP, with direct sequential injection.

     

    Jack

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • Cancel
  • fayobambam@gmail.com
    fayobambam@gmail.com over 7 years ago in reply to jack.chaney56

    www.speeduino.com that's the homepage. Glad to be of help

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to fayobambam@gmail.com

    Thanks a lot for the link. I looked over the site and kind of gleaned much of the information. The information provided shows they are using the Arduino interface, which might explain the reason for upgrading to the ARM processor version. The Arduino interface takes time away from the operation. I also see they are working on some CAM and Crank problems that I have already resolved and will present here. The fun thing to see is how they have a developed UI stage for updating calibration information. This is where a one man show, can be a little slow. I know what needs to be done, and I have a mental image of the interface and the code to make it work, but I just haven't done the deep dive into writing the code.

     

    My aim is to use off the shelf open source tools, so everything is repeatable by other members. So, I have started building a simplified UI using GCC and have been flip flopping between GTK+ or QT, but I am leaning to GTK because of some licensing questions I have about QT. We shall see.

     

    Thanks again for the link,

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • fayobambam@gmail.com
    fayobambam@gmail.com over 7 years ago in reply to jack.chaney56

    Not a software person myself pretty much at beginner level. The mega is the primary platform for the project and some new additions had to be made to the Arduino software side to speed up things. The injection and ignition channels are limited by the number of timers; (9) I think? The crank and cam triggers are kind of modular ;missing tooth on crank or cam is functioning properly and other patterns have been added. You may get in touch with Josh the developer if you need more info.  A more closer to the hardware approach like yours would probably utilize the available resources more efficiently. When its ready I would love to be a tester

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to fayobambam@gmail.com

    Hi,

     

    Timers can be a little obscure if you don't work with them all the time. There are actually 6 timers on the 2560 numbered  0 through 5. Timers 0 and 2 are 8 bit timers and have 8 bit compare registers. Timers 1, 3, 4 and 5 are 16 bit timers, and have 16 bit compare registers. 3, 4, and 5 also each have 3 compare registers, so that might be where the idea of 9 timers comes in.

     

    I invite you to read the description of how the source works for my project further down, and I am happy to answer questions about technique.  I think I am up to programming methods for doing formulas that are fast and accurate. I already covered linear and planar interpolation. I also covered use of binary radians to provide simplification of the equations. Stuff coming up is when to perform the calculations, what information is necessary, and how to generalize operations so they can become reused processes.

     

    Look forward to hearing more from you,

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to jack.chaney56

    I thought I would clean things up a bit...

    Attachments:
    imageE14_ECM.pdf
    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago

    A little dental work, or what to do about missing teeth.

     

    The more advanced timing wheels on motors have high tooth count and also throw in areas where teeth are deleted, in order to provide sub-timing to catch ignition in less than one full crank. It is my observation, this is overkill, because, the increase in processing needed for high level detection, often results in missing the special event, and it still requires multiple rotations to capture timing.  However, because they didn't listen to me, and implemented missing teeth anyway, coding must be made to mitigate the event.

     

    There are two processes that must be implemented, first is detection of the missing tooth event. The second is compensating for the event.  Detecting the event requires notification of the potential for a missing event, so a calibration value of missing teeth is needed. Missing teeth is not the total number of missing teeth. It is the number of missing teeth together. Meaning it is possible to have a missing tooth at 10 degrees and a second at 100 degrees, even though in total, there are two missing teeth, the value of missing teeth in calibration is still one. I hope that is clear enough.

     

    The detection of a missing tooth event, is; first, is there a missing tooth (missing > 0), and when the measured Diff value tmpDiff (current) is greater than 1.5 times the previous Diff (crkDiff). Because the change in crkDiff from tooth to tooth is relatively small, if the change in crkDiff is greater than 1.5 times, it is the indication of a missing tooth event. Once the missing tooth event has been detected, a correction to operating variables is required. First, update the cam angle, then correct for error, repeating once for each missing tooth. This operation is performed in the crank interrupt. Because it only requires comparison and addition, the impact is very slight.

     

        if (isInt0Low() ^ isCrkRising()) {
            tmOut = QUART_SEC;
    /**************************************************************************************************
      use the cam signal to locate the tooth
    **************************************************************************************************/
            if (isCamDet()) {
                setCamDet(false);                       /* cam detected so clear the flag */
                camAngle = 0;
                camError = 0;
            } else {
    /**************************************************************************************************
            Because tooth angle may not be an even division, an error correction is performed
            at each update. If the error exceeds the threshold, the angle value is incremented,
            and the threshold value is removed from the error.
    **************************************************************************************************/
                camAngle += toothAngle;
                camError += toothError; if (toothError >= teeth) { camAngle++; camError -= teeth; }
            }
    /**************************************************************************************************
            Special case op for missing tooth, if no missing tooth, then skip this whole part.
            The detection of an event is both there is a missing tooth, and the DIFF is longer
            than 1.5 of the previous event DIFF.
    **************************************************************************************************/
            if ((missing > 0) && (tmpDiff > (crkDiff + (crkDiff / 2)))) {
    /**************************************************************************************************
            Missing tooth detected, so correct the angle for one missing tooth (at least)
    **************************************************************************************************/
                camAngle += toothAngle; camError += toothEr; if (camError >= toothCt) { curAngl++; camError -= toothCt; }
    /**************************************************************************************************
                If more missing teeth, correct again for each (math runs fast, so little or
                no impact)
    **************************************************************************************************/
                if (missing > 1) { camAngle += toothAngle; camError += toothEr; if (camError >= toothCt) { curAngl++; camError -= toothCt; } }
                if (missing > 2) { camAngle += toothAngle; camError += toothEr; if (camError >= toothCt) { curAngl++; camError -= toothCt; } }
    /**************************************************************************************************
                If there was a missing tooth the value of tmpDiff is extended, so replace
                tmpDiff with the old value of DIFF to prevent calculation problems.
    **************************************************************************************************/
                tmpDiff = crkDiff;
            }
            crkTime = tmpTime;
            crkDiff = tmpDiff;

     

    The value of "missing" is read from calibration at engine stop.

     

    /* Calibration value in future, but for now just provide a constant */
    SWord getCrankToothCt(void) { return 4; }
    SWord getCrankToothMissing(void) { return 0; }
    
           missing = getCrankToothMissing();

     

    TTFN,

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago

    The magic formula....

     

    It all starts with something called charged air mass. The steady state fueling is calculated based on mass air flow combined with a targeted air:fuel ratio. The mass of fuel is then applied to the system by injectors of fixed flow rate measured in pounds per hour.

     

    The first variable is air charge, which is the quantity of air that is moved through the system in a single period of time. In a four cycle engine, this is a single cam cycle, or two revolutions of the crank shaft  Volume is the second variable, and is relatively constant, but differs in each instance of an engine. Volume is the total displacement of the engine and is measured as the sum of the difference of each cylinder volume from lowest point to highest point in the cycle. Third is a more complex concept for a variable; Volumetric Efficiency (VE) is the effectiveness of the engine to move the total volume in a single cam cycle, and is measured as a ratio or percentage. The three variables relate as:

     

    AirCharge = Volume * VE

     

    Next is the conversion from air charge to air mass. the ratio between air charge and air mass is rho. The value is comprised of the volume of air and the mass of air. The mass of air is considered as dry air and because air density is relevant, the barometric pressure will be factored into the equation:

     

                AirMass

    rho = --------------

              AirCharge

     

    Now it is necessary to add in the ideal gas law to provide a base for calculations:

     

    pV = nRT

     

    But the value of rho is a dynamic value based on the volume flow of air mass. The static value of air mass has been measured extensively and is provided in the Handbook of Chemistry and Physics.
    (weight of dry air at sea level 28.966 g/mol::F-201 Handbook of Chemistry and Physics 56th ed.) This is the value of n, and V is the total displacement of the engine. Because the system is dynamic, the equivalent component for rho is:

     

                n
    rho := ---
                V

    Last is the controllable element of the operation. The equation's goal is calculating fuel mass. The mass of fuel is combined with the volume of air based on a target ratio of fuel to air, or the Air-Fuel Ratio(A:F)

     

                AirMass
    A:F = --------------  and  AirMass = AirCharge * rho
               FuelMass

     

                         AirCharge * rho
    FuelMass = ----------------------
                                   A:F

     

    Air charge can be replaced with Volume * VE, and because, from the ideal gas law, rho equates to:

     

                 p
    rho = --------
               R * T

     

    The equation for fuel mass becomes:

     

                         Volume * VE * p
    FuelMass = ----------------------
                              A:F * R * T

     

    In the total of the equation, there is one constant R which is the ideal gas constant and has the value: Calculated from base information Boltzmann's Constant k = 1.3807e-23 J/K combined with Avagadro's Number N(a) = 6.0220e23 /mol provides a value:

     

    k * N(a) = 8.3145754 J/mol-K

     

    - The value of pressure is absolute and is measured in Newtons per square meter (Pascals).

    - Temperature is absolute and measured in degrees Kelvin, VE and A:F are both ratios and have no units, and because 1 Joule => 1 m3-Pa, the measurement for volume is in cubic meters.

     

    The last part of the process is to eliminate units based on fuel mass:

     

                                   m3 * Pa

    FuelMass => --------------------------  => mol

                            m3-Pa/mol-K * K

     

    Then multiplying the value by the mass of dry air, in g/mol, yields the fuel mass in grams, and the final equation resolves to:

     

                          Volume * VE * p * 28.966
    FuelMass = -----------------------------------
                              A:F * T * 8.3145754

     

    The units for each of the items is:

     

    FuelMass - grams

    Volume - cubic meter

    p - Pascals

    T - degrees Kelvin

     

    To provide workable sized variables, so the intermediate values don't get too big or too small to manage with integers only, some base 10 elements are implemented. Vehicle engines have their displacement rated in cubic inches or liters, and often in cubic centimeter. Conversions to all these units are readily available, and since the equation started with cubic meters, cubic centimeter (cc) is chosen to provide sufficient resolution. Pressure sensors are rated in kilo-Pascals or often BAR (base atmosphere), so the selection for pressure is kilo-Pascal (kPa). Because temperature is in degrees kelvin, there is no need to change to another unit, and leave conversion to Centigrade (C) or Fahrenheit (F) to the user interface. Last, because grams is a very large value in fueling, the fuel mass will be in miligrams.

    Conversions:


    grams = 103 miligrams
    cubic meter = 106 cubic centimeter
    Pascal = 10-3 kilo-Pascals

     

                               V * VE * P * 28.966 * 10^3
    FuelMass = ------------------------------------------------
                          A:F * T * 8.3145754 * 10^6 * 10^-3

     

    Leaving a single constant 3.483761781

     

    Now for my stump speech about not using floating point...

     

    Don't use floating point for embedded processes. The conversions eat up all sorts of valuable time, and it is really quite unnecessary if the operations are well planned.  For the fueling equation, VE and A:F are both ratios, so any value used for the fixed point method will divide out. In other words, if you multiply a ratio by 1000 so that 99.9% becomes 999 integer value, if the same multiplier is used in the numerator and denominator, they will cancel each other out. If temperature is stored as an absolute value K * 100 and pressure is stored as kilo-pascals * 100, the same elimination will occur. This leaves only the constant 3.483761781.

     

    Planning this out, it is possible to use a numerator portion and a denominator portion. When I do this type of operation, I like to use either the numerator or the denominator as a power of 2. This way, the multiplication, or division operation is resolved to a simple logical shift right or left.  After some playing with values, I came up with

     

    16384

    --------- =  3.483733787 (I think that's close enough)

      4703

     

    So now the total fueling calculation only has the penalty of multiplication and division. If the calculations are done in a proper sequence, the error loss is minimized. The result is fuel mass in mg per CAM cycle.

     

    FuelMass = Volume * VE;

    FuelMass /= AF;

    FuelMass *= PortPressure;

    FuelMass /= PortTemp;

    FuelMass *= 16384;

    FuelMass /= 4703;

     

    Because of the values involved, it is a good idea to use a 32bit long for all the intermediate values (casting when necessary).

     

    Because injectors are rated in pounds per hour, a conversion to mg is needed. The value in calibration is all that is necessary so the conversion can be performed at the UI level.

    453.592 grams per pound

    3600 seconds per hour

     

    1 lb/hr = 125.998 mg/s

     

    Build this into a spreadsheet and play around with the numbers and let me know what you find.

     

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
  • jack.chaney56
    jack.chaney56 over 7 years ago in reply to jack.chaney56

    A little more math calisthenics. The injectors are rated in lb/hr, but are stored in calibration in mg/s so a 40# injector is stored as 5040 (5039.92 rounded integer). Remembering the scheduler resolves to system tics (2MHz). The pulse width should be calculated as number of tics and still retain significant digits using integer math.  The total possible volume is a summation of all the injectors.

     

    The total fuel mass per cam cycle is in mg. The total pulse width per cam cycle then is:

     

         fuel mass * TICS_PER_SEC

         -------------------------------------

             total injector volume

     

    For batch and staggered, the pulse is done twice so the pulse width is divided in two.  For TBI the pulse is done four times so the pulse width is divided by 4.

     

    When to do calculations is now what is necessary. The formula provided is for steady state fueling, where there are no changes to demand or RPM, and the A:F ratio remains generally constant.  The equations can be performed generally at any time, meaning they do not need to be done in the tooth interrupt. However, the volume of fuel required does change and needs to be updated regularly and at a high enough rate to maintain smooth operation.  Examining the information, it is possible to not some items that do not change during runtime, and can be performed during engine stop, summation of injectors as an example.

     

    For the timing of events, the scheduler is employed in exactly the same manner as before, for TBI and staggered batch, four evenly spaced events, and for standard batch two evenly spaced events. The last case of sequential fueling, needs to activate the injector during the intake stroke of the cylinder. This begins at the top of the exhaust stroke, which is 360 degrees from TDC, which is the value of the tach event from ignition timing.  Using another array for the injector start point, it is a simple case to add provision for injector scheduling the same as with ignition.

     

    I kind of glossed over something from before, the value of advance was determined in units of degrees, and I kind of fudged the value for dwell. In actuality, dwell is a time value for how long it takes to bring the coil to a full charge. Since the operation of the scheduler is based on angle, it is necessary to convert the dwell time into a dwell angle.  This is done using the magic number "base" described before. The value of base was used in the scheduling operation to convert the value of angle to time, but it can also be used in the reverse operation.  Because the dwell time value doesn't change significantly, dwell angle only needs to be calculated as speed changes, usually in the mS routine.  It is also possible at the same time to do the same operation with pulse width. Dividing by 2 (batch) or 4 (TBI) can be done during the scheduling event, because it is only a right shift operation. If at this point it starts to look like the 1mS operation is getting too fat with processes, it is always possible to run the calculations interleaved.  Doing the ignition calculations on one pass, then the fueling calculation on the second pass. This is something that would require some physical testing to see if it is a concern.  Time to run the experiment.

     

    Jack

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • Cancel
<>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2025 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube