EcoModder.com

EcoModder.com (https://ecomodder.com/forum/)
-   OpenGauge / MPGuino FE computer (https://ecomodder.com/forum/opengauge-mpguino-fe-computer.html)
-   -   Advisory for Chrysler Returnless Fuel Supply Systems (https://ecomodder.com/forum/showthread.php/advisory-chrysler-returnless-fuel-supply-systems-26165.html)

t vago 06-17-2013 08:32 AM

Advisory for Chrysler Returnless Fuel Supply Systems
 
Chrysler vehicles with returnless fuel supply systems will have MPGuino fuel economy figures that will be thrown off by an average of 3% from actual, on an otherwise properly calibrated MPGuino. This is currently unavoidable. Tweaking MPGuino fuel calibration on these vehicles will only minimize this error, but will not eliminate it. Ford (and presumably other vehicle manufacturers) returnless fuel supply systems do not have this problem.

If your returnless fuel supply system features a fuel pressure sensor and a fuel pump that is controlled by the engine computer to regulate fuel pressure, then you do not have this problem. If your returnless fuel supply system features an in-tank mechanical fuel pressure regulator, you have this problem.

The reason is this:

In performing fuel delivery calculations, MPGuino assumes a fuel pressure that is a constant value above intake manifold pressure. This assumption is perfectly valid for older vehicles that have a return-style fuel supply system, because they have a mechanical fuel pressure regulator that is controlled by engine vacuum. The regulator will cause a constant pressure difference across the fuel injectors, regardless of engine vacuum, such that the same amount of fuel will be squirted for a given injector cycle time every time.

Returnless fuel supply systems were introduced by the major auto manufacturers as a way to comply with pollution regulations regarding unburnt fuel emissions. Currently, there are two different returnless system designs in use.

The first system design, introduced by Chrysler, uses an in-tank mechanical fuel pressure regulator that does not get connected to engine vacuum. This regulator regulates fuel pressure to a constant 58 psig above ambient atmospheric pressure, instead. This is mechanically a very simple design, but it does require that the engine computer take this into account when performing fuel delivery calculations, as there is now a variable pressure difference across the fuel injectors. This difference is directly related to engine vacuum. For a given injector cycle time, more fuel will be squirted out of the fuel injectors with a high engine vacuum, than would be with a low engine vacuum. Therefore, for this fuel supply system, the MPGuino fuel pressure assumption is not valid, and MPGuino fuel delivery calculations may be in error by as much as 7%, on an otherwise perfectly calibrated unit.

The second system design, introduced by Ford, and also used by other vehicle manufacturers, uses no mechanical fuel pressure regulator. Instead, fuel pressure is regulated directly by the engine computer. The engine computer does this by reading a fuel pressure sensor, then electronically controlling the fuel pump to obtain a desired fuel pressure. This system regulates fuel pressure identically to an older return-style mechanical system that uses a fuel pressure regulator controlled by engine vacuum. This system will cause a constant pressure difference across the fuel injectors, regardless of engine vacuum, such that the same amount of fuel will be squirted for a given injector cycle time every time. The engine computer has simpler fuel delivery calculations as a result, but it does have to have an additional task of controlling the fuel pump to regulate fuel pressure. Therefore, for this fuel supply system, the MPGuino fuel pressure assumption is valid, and MPGuino fuel delivery calculations should not be in error on an otherwise perfectly calibrated unit.

---

Original post: I bought an MPGuino a few days ago, and received it in the mail. Impressive-looking little unit.

However, I've had less than stellar luck with having one question answered: Does MPGuino handle returnless fuel lines? That's when either an in-tank regulator or a power-modulated fuel pump supplies constant pressure to the fuel line and fuel rail, regardless of intake manifold vacuum; and there is only one fuel line coming out of the tank.

I've searched EcoModder.com high and low, and this is all that I could come up with: MPGuino and a Series 3 Supercharged

I strongly suspect that I know the answer already, though... Might have to dust off my microcontroller skills and add this capability.

NachtRitter 06-17-2013 12:45 PM

Does having a returnless system mean that different amounts of fuel can be injected with the same length injector pulse? If it's the same amount of fuel for the same length of pulse, then I'm not understanding how the fact that the system is returnless would make a difference to the MPGuino...

t vago 06-17-2013 01:03 PM

Quote:

Originally Posted by NachtRitter (Post 376698)
Does having a returnless system mean that different amounts of fuel can be injected with the same length injector pulse?

Yes. In a returnless system that uses a constant-pressure fuel regulator, fuel injector pulse time is one of two variables that determines the amount of fuel to be delivered. Returnless systems, that vary the voltage of the fuel pump to vary the fuel pressure, are likely not affected, but I don't know for certain.

In a returnless system that uses a constant-pressure fuel regulator, the amount of fuel to be injected is now also affected by the pressure differential across the fuel injector itself. In fact, it will vary as the square root of the pressure differential. Earlier systems used a fuel pressure regulator that was indexed to intake manifold vacuum, thus providing a constant pressure differential across the fuel injector. These earlier systems would reliably squirt the same amount of fuel for a given fuel injector pulse, whether at idle or at cruise or going up a hill or at WOT.

Given that my fuel pressure regulator regulates to a constant 58 psig, regardless of intake manifold vacuum, and that my intake manifold vacuum could vary from 5 to 14 psig, that means that the fuel injectors could themselves see anywhere from 63 to 72 psig of differential pressure. This translates to about a 7% variation of the amount of fuel that may be delivered, for a given length injector pulse. The engine computer knows this and will compensate, but the MPGuino does not (and cannot, in base form).

NachtRitter 06-17-2013 01:34 PM

Interesting! Thanks for the explanation.

Sounds like you'll be taking a reading off the manifold pressure (along with the injector pulse) so you can emulate the ECM?

Any particular reason you didn't go with an OBDII approach (OBDuino, Scangauge, etc)?

t vago 06-17-2013 05:24 PM

Quote:

Originally Posted by NachtRitter (Post 376705)
Interesting! Thanks for the explanation.

Sounds like you'll be taking a reading off the manifold pressure (along with the injector pulse) so you can emulate the ECM?

Any particular reason you didn't go with an OBDII approach (OBDuino, Scangauge, etc)?

I currently use an Ultragauge in the Karen-mobile, and a ScanGauge II in the Fiat Dakota.

Not sure about the OBDuino or the Scanguage, but I know for a fact that the UltraGauge cannot accurately show the effect of the ecomods I have done to the engine of the Karen-mobile. For instance, this post about initial EGR sensor modification results showed a real-world fill-up FE figure of 25.8 MPG. However, the Ultragauge only recorded a per-tank average of 23.9 MPG. This, after I had previously calibrated the Ultragauge to get its average FE reading to within 0.2 MPG of the calculated fill-up FE figure. It's very likely that it has something to do with the way that the Ultragauge estimates fuel consumption. If I am lowering intake manifold via increasing EGR opening, then the MAP sensor reading will reflect that, and the Ultragauge is likely showing that as a artificially lower fuel economy figure.

The Scangauge is likely going to use some version of MAF to estimate fuel consumption. The OBDuino get_icons function actually does do this -> "formula: (3600 * MAF) / (14.7 * 730 * VSS)".

The only way to really get around that, IMO, is to directly measure fuel consumption. The MPGuino is still going to provide an estimate, but it should be very accurate, compared to the estimation formulas used in OBDII instrumentation. I got a couple of MAP sensors laying about, so I can get both ambient and intake manifold pressures with little effort. The JellyBeanDriver version of the MPGuino has hardware provisions for collecting 2 different analog signals, and it should be a relatively simple matter to code in a simple square root function.

moorecomp 06-18-2013 09:40 AM

Quote:

Originally Posted by t vago (Post 376680)
I bought an MPGuino a few days ago, and received it in the mail. Impressive-looking little unit.

However, I've had less than stellar luck with having one question answered: Does MPGuino handle returnless fuel lines? That's when either an in-tank regulator or a power-modulated fuel pump supplies constant pressure to the fuel line and fuel rail, regardless of intake manifold vacuum; and there is only one fuel line coming out of the tank.

I've searched EcoModder.com high and low, and this is all that I could come up with: MPGuino and a Series 3 Supercharged

I strongly suspect that I know the answer already, though... Might have to dust off my microcontroller skills and add this capability.

My car and many others here with an MPGuino installed have returnless fuel delivery systems. I have no complaints with the accuracy of the guino.

t vago 06-18-2013 09:55 AM

Quote:

Originally Posted by moorecomp (Post 376797)
My car and many others here with an MPGuino installed have returnless fuel delivery systems. I have no complaints with the accuracy of the guino.

Good data points.

Ford ERFS patent - first used in 1998 Ford vehicles. Varies fuel pressure according to load.

2009 Toyota RAV4 New Features - uses a mechanical fuel pressure regulator in-tank, implying a constant pressure fuel system.

Your RAV4 MPGuino is accurate?

moorecomp 06-18-2013 10:22 AM

Quote:

Originally Posted by t vago (Post 376800)
Good data points.

Ford ERFS patent - first used in 1998 Ford vehicles. Varies fuel pressure according to load.

2009 Toyota RAV4 New Features - uses a mechanical fuel pressure regulator in-tank, implying a constant pressure fuel system.

Your RAV4 MPGuino is accurate?

I don't have one in the RAV, only the ZX2. You say the min and max could vary by up to 7%, but what percent of your driving is actually at the ends of that range? The majority of my driving (85-90%) is highway at 55 mph. So the actual influence on the indicated mpg is minimal.

t vago 06-18-2013 10:45 AM

Quote:

Originally Posted by moorecomp (Post 376803)
I don't have one in the RAV, only the ZX2. You say the min and max could vary by up to 7%, but what percent of your driving is actually at the ends of that range? The majority of my driving (85-90%) is highway at 55 mph. So the actual influence on the indicated mpg is minimal.

It is an inaccuracy in measurement. For fuel economy purposes, I'm ditching the Ultragauge I have now, in favor of the MPGuino, because of a 6% inaccuracy in fuel economy measurement that cropped up because I performed one ecomod.

Say that I have the MPGuino installed, as is, in the Karen-mobile. I have it tuned for highway driving. There is no compensation for the constant pressure returnless fuel system. Now, if I turn around and do a bunch of city driving, then the MPGuino will now indicate less fuel was consumed, than would actually be the case. This would be because the vehicle would be under less loading than on the highway. This would not be reliable.

I might as well have just relied on the Ultragauge I have now.

NachtRitter 06-18-2013 12:29 PM

Quote:

Originally Posted by t vago (Post 376731)
Not sure about the OBDuino or the Scanguage, but I know for a fact that the UltraGauge cannot accurately show the effect of the ecomods I have done to the engine of the Karen-mobile.
...

Got it... forgot that you'd done some ECM-fooling mods. Since the OBDuino does provide the MAF reading via OBD and can be tweaked to your needs (by modifying the formula and adding a separate injector pulse input, for instance), could that meet your needs? Seems like the OBDuino can give you access to quite a bit of additional data from the ECM that you'd need to manually wire up with the MPGuino.

Not questioning your approach (please don't take it that way), but I am very interested in your thought process... it's an interesting problem.

P-hack 06-18-2013 02:07 PM

sounds like you need to modify the injector pulse reading based on a maf reading? That could take some experiment and custom mapping and a maf sensor input. Lower maf reading would mean the injector squirted more fuel for a given open time, so the code would bump up the time by some percentage of maf or something. Or some external adapter maybe, op amps and duty cycle and etc.

P-hack 06-18-2013 02:10 PM

what would your car do if you installed a regulator that referenced manifold pressure? Would it adapt? How for off is the guino?

t vago 06-18-2013 10:21 PM

Quote:

Originally Posted by NachtRitter (Post 376814)
Got it... forgot that you'd done some ECM-fooling mods. Since the OBDuino does provide the MAF reading via OBD and can be tweaked to your needs (by modifying the formula and adding a separate injector pulse input, for instance), could that meet your needs? Seems like the OBDuino can give you access to quite a bit of additional data from the ECM that you'd need to manually wire up with the MPGuino.

I thought about modifying an OBDuino to take advantage of the fact that it likely would return both a manifold air pressure value and an ambient air pressure value as PIDs, but that was after I had already received this MPGuino. Interesting problem, indeed.

From what I can see, it'll be a simple matter of soldering in another wiring terminal for the two analog channels of this particular MPGuino, then running the wiring to support the two spare MAP sensors I have laying around (one for ambient pressure, and one for manifold vacuum). Since the MPGuino code (excuse me, "sketch") is written in some variant of C, it should really simple to initialize the analog channels, and convert their read-in values into pressure. Only challenge I see is to write a fairly quick square root routine - apparently, the complete math library wasn't loaded into the MPGuino in an effort to save programming space.

t vago 06-18-2013 10:29 PM

Quote:

Originally Posted by P-hack (Post 376829)
what would your car do if you installed a regulator that referenced manifold pressure? Would it adapt? How for off is the guino?

The existing fuel pressure regulator is combined with the in-tank fuel filter. Installing an external regulator is not advised, as the engine computer already takes the existing regulator into account.

meelis11 06-20-2013 03:58 AM

Quote:

Originally Posted by t vago (Post 376885)
I thought about modifying an OBDuino to take advantage of the fact that it likely would return both a manifold air pressure value and an ambient air pressure value as PIDs, but that was after I had already received this MPGuino. Interesting problem, indeed.

From what I can see, it'll be a simple matter of soldering in another wiring terminal for the two analog channels of this particular MPGuino, then running the wiring to support the two spare MAP sensors I have laying around (one for ambient pressure, and one for manifold vacuum). Since the MPGuino code (excuse me, "sketch") is written in some variant of C, it should really simple to initialize the analog channels, and convert their read-in values into pressure. Only challenge I see is to write a fairly quick square root routine - apparently, the complete math library wasn't loaded into the MPGuino in an effort to save programming space.

You can try to include complete math library - it was not fitting when atmega 168 was used (16KB flash space), if you have atmega 328 chip then you have 32KB of flash - you probaly have enough room for math library.

Meelis

t vago 06-20-2013 10:19 AM

Quote:

Originally Posted by meelis11 (Post 377086)
You can try to include complete math library - it was not fitting when atmega 168 was used (16KB flash space), if you have atmega 328 chip then you have 32KB of flash - you probaly have enough room for math library.

Meelis

Thanks! I may try that.

I've compiled the major steps I will need to proceed with this project:

1. Dust off an old MicroCore11, and turn it into a simple SCI programmer (they call it an "ICSP interface" - how cute!).
2. Obtain the latest MPGuino code
3. Solder an extra set of terminals onto board
4. Construct a testing pigtail that will connect to two MAP sensors
5. Add in-car wiring
6. Modify MPGuino code to include editable parameters relating to add-on MAP sensors
7. Modify MPGuino code to interface with said sensors
8. Modify MPGuino code to utilize sensor readings

t vago 07-09-2013 12:33 AM

Well, I got a little side-tracked with going through the MPGuino v0.86 code, to figure out how it all works. However, I am through it, and have figured out the likely spot to inject the pressure correction factor (the fuel injector shut-off interrupt handler), and have also figured out that the factor will likely be calculated on-the-fly in the main body of the program code. The interrupt handler simply cannot be saddled down with anything resembling a square root calculation. Having the correction factor being calculated once per display update cycle will lead to inaccuracy, but I think it'll be orders of magnitude better than having no correction factor at all.

In the course of figuring out how the code works, I've managed to shave off some 3000 compiled program bytes and some 100 lines from the code, to optimize the code somewhat to add the correction factor computing. I will go through this subforum to glean off some other interesting ideas.

t vago 07-09-2013 05:42 PM

Miscellaneous MPGuino optimization note
 
This:
Code:

        if (parms[metricIdx] == 1){
                distancefactor /= 1.609;
                fuelfactor /= 3.785;
        }

is 572 bytes larger than this:
Code:

        if (parms[metricIdx] == 1){
                distancefactor = 1000 * distancefactor / 1609;
                fuelfactor = 1000 * fuelfactor / 3785;
        }


t vago 07-11-2013 04:07 AM

% shavesizenotes
.17160original v0.86
99.817126streamline LCD hardware functions
94.416196consolidate initGuino, create editGuino, get rid of floating point
93.316006fold instantlkm into instantmpg, get rid of (dispadj, dispadj2)
91.415692fold Trip::lkm into Trip::mpg, remove lkm bug
90.115468expand eq64 and lt64; get rid of functions eq64 and lt64
89.715400move processInjOpen and processInjClosed into their respective ISR functions, get rid of int0func and int1func
90.015450get rid of interrupt disable bug in microSeconds()


Notes on what I did this past night...

KY Metro 07-11-2013 10:37 AM

Very interested in following this! Thumbs up to T Vago!

I've got a 92 Dodge Dakota that needs monitoring, and it has the Chrysler constant pressure setup. I want to build a custom MPGuino with fuel pressure monitoring.

An added wrinkle... this truck also runs on wood. I start on gasoline and switch over gradually. So to shut off the gasoline I reduce the fuel pump voltage to lean out the mixture as I transition to woodgas. This lowers the fuel pressure and leans the mix, while I simultaneously ramp up the woodgas. Eventually I reach 0 pressure and no gasoline, although the injectors still fire. A stock MPGuino would be way thrown off by this. But if it could compensate for the pressure...

T Vago, will the code be able to reduce the fuel usage to zero at no pressure? That would be awesome.

KY Metro 07-11-2013 10:43 AM

OK, I read it closer, you're working off the MAP sensor.

Could the same code be converted to work with a fuel pressure sensor instead?

t vago 07-11-2013 05:48 PM

Quote:

Originally Posted by KY Metro (Post 380052)
OK, I read it closer, you're working off the MAP sensor.

Could the same code be converted to work with a fuel pressure sensor instead?

Can't see why not. You could also use a MAP sensor and a fuel pressure sensor, to more accurately read the gauge pressure across the fuel injectors. This would assume that both the MAP sensor and the fuel pressure sensor would read absolute pressure. If the fuel pressure sensor reads gauge pressure, then that would add a bit of complexity to the algorithm.

t vago 07-13-2013 11:36 PM

% shavesizenotes
.17160original v0.86
89.815410consolidate setup(), mainloop() into main.
89.415340Folded enableXButton procedures into main()
89.015272Got rid of events[] feature.
88.615202pushed display names firmly into flash.
88.315144transformed getstr() into LCD::flashPrint(). Rewrote hardware initialization code to be more understandable.
98.216846converted to hardware timer-based delay scheme, modified delay2(), modified mainloop cpu utilization reporting, modified timeout feature, fixed wake-on-button bug, added button debouncing, got rid of microseconds(), got rid of millis2()
92.215820shifted tmptrip measurement transfers completely to timer 2 overflow interrupt, re-wrote calculations, got rid of tmptrip, got rid of instantmpg() and instantmph() and instantgph(). Renamed class functions to remove references to gallons and miles.
90.015436Added idleFuelRate, EOCSpeed functions. Consolidated speed, distance, fuel consumed, fuel rate functions. Keypress examination now done with value checking, and not doing bit conditions.
87.415006Converted display routines to use indexed character strings instead of conditional us/metric strings.


^ Notes on what I did today to my MPGuino code.

Also experimented in Excel about what sort of square root algorithm to use.

t vago 07-15-2013 11:36 PM

% shavesizenotes
.17160original v0.86
91.615718Re-wrote editparms and editGuino to be more user-friendly. Added ability to turn off serial transmitter via setup menu. Bit-wise parameters (injector trigger, metric, and serial transmitter on/off) no longer require a 32-bit number for EEPROM storage. VSS pulses/mile, contrast, and rpm factor turned into 8-bit values.
93.616062Re-wrote display routines to reduce processing overhead. Got rid of displayTripCombo() and tDisplay() and dispv().
95.216332Added clock display screen. Added time "hhmmss" numeric formatting function. Added "long button press" functionality. Moved tank clear and current trip clear to long button presses. Added ability to call up cpu utilization for any screen via long center button.


^ What I have done in the past two days. Probably going to make my own "version 2" thread.

(still haven't decided on a suitable square root function yet...)

t vago 07-16-2013 08:28 PM

Testing my updated code revealed that rather interesting fuel consumption runaway bug that was first documented in this post by DCB. It is always interesting to see my tank fuel economy just drop from 23.6 MPG to 1.0 MPG.

Re-examined the code and did some more searching around this sub-forum, and theorized that when my car goes into DFCO, it shuts off the fuel injectors, but it still sends little pulses, like in this post by rmccomiskie. I can reliably see the above fuel consumption runaway happen on every commute so far. Hopefully, tonight, when I load in this code, it will squash this bug.

Code:

ISR(INT0_vect) { // fuel injector open event handler

        injOpenStart = timer2_overflow_count | TCNT2; // calculate current cycle count
        // if timer overflow condition occurred, recalculate current cycle count and fold in overflow
        if (TIFR2 & 0b00000001) injOpenStart = (timer2_overflow_count + 256) | TCNT2;

        dirty |= dirtyInjTick; // tell close event handler that fuel injector has in fact opened

}

ISR(INT1_vect) { // fuel injector close event handler

        injOpenStop = timer2_overflow_count | TCNT2; // calculate current cycle count
        // if timer overflow condition occurred, recalculate current cycle count and fold in overflow
        if (TIFR2 & 0b00000001) injOpenStop = (timer2_overflow_count + 256) | TCNT2;

        if (dirty & dirtyInjTick) { // must have read in a injector start event first

                // calculate fuel injector pulse length
                if (injOpenStop < injOpenStart) cycleLength = 4294967295ul - injOpenStop + injOpenStart + 1;
                else cycleLength = injOpenStop - injOpenStart;

                if (cycleLength > injSettleCycles) { // if the pulse length is greater than the settle time, it's valid

                        cycleTemp = injOpenCycles[1] + cycleLength - injSettleCycles; // add to injector cycle accumulator
                        if (injOpenCycles[1] > cycleTemp) injOpenCycles[0]++; // handle any possible overflow
                        injOpenCycles[1] = cycleTemp;
                        injPulseCount++; // update pulse count
                        timerStatus |= timerWakeUp; // tell timer to wake up main program
                        dirty |= dirtyInj; // signal that a valid fuel injector pulse has just been read

                }

                dirty &= ~dirtyInjTick; // ignore any more close events until another open event is received

        }

}

Astute readers will be able to make out the remnants of functions microSeconds() and elapsedMicroseconds().

nickdigger 07-20-2013 02:36 AM

Quote:

Originally Posted by t vago (Post 380632)
VSS pulses/mile, contrast, and rpm factor turned into 8-bit values.

I can't think of a car that could use an 8-bit value for VSS/mile.

One thing i did with contrast, is built-in the brightness setting into it. I.e, take the LSB 2 bits of Contrast to determine which brightness index to use. So 44 would be brightness[0], 45 is [1], 46 is [2], 47 is [3], 48 is [0]. I found that I was never ever changing the brightness, so I re-assigned the middle button to other things, and just make it dim-out a couple minutes after engine-off.

I would like to see how you cleaned up the timers & buttons. I like what you did in the Inj ISRs, by directly grabbing TCNT2 and overflow_count instead of calling microseconds().

I only recently discovered that recursive microseconds bug & got rid of it after i couldn't understand why it should ever do that. I still have an older bug that's hanging my 'guino up, right near the time when the timer2 value rolls over past 0xFFFF FFFF. Unfortunately, it takes 5-7 days for the bug to trigger, so I'm still waiting to catch it.

nickdigger 07-20-2013 03:25 AM

One thing about your injOpenStop = timer2_overflow_count | TCNT2; code: Are you using the same prescale factor=64 (TCCR2B= 1<<CS22;); If so, I believe each tick is worth 4usec, so your calculation should be multiplied by 4. (I think. I've only just started looking into timers.)

t vago 07-20-2013 10:50 AM

Quote:

Originally Posted by nickdigger (Post 381294)
I can't think of a car that could use an 8-bit value for VSS/mile.

Ooops! I meant to say that the VSS debounce factor got turned into an 8-bit value. The VSS pulses/mile factor is still a 32-bit value (for now).

Code:

volatile uint8_t lastPINCstate = PINC;
uint8_t VSSCounts = 0;

...

ISR( PCINT1_vect ) {

        static uint8_t p;
        static uint8_t q;

        p = PINC; // read current pin C state
        q = p ^ lastPINCstate; // detect any changes from the last time this ISR is called

        timerStatus |= timerWakeUp; // tell system timer to wake up the main program

        if (q & vssBit) { // if a VSS pulse is received

                if (vssPause == 0) { // if there is no VSS pulse delay defined

                        vssPulseCount++; // immediately update the VSS pulse count
                        dirty |= dirtyVSS; // tell system timer that raw readings changed, and that the VSS reading itself has changed

                } else VSSCounts = vssPause; // otherwise, set VSS debounce count and let system timer handle the debouncing

        }

        if (q & buttonsUp) { // if a button press is detected

                keyCounts = keyDelay; // set keypress debounce count, and let system timer handle the debouncing

        }

        lastPINCstate = p; // remember the current pin C state for the next time this ISR gets called

}

This above is the current keypress/VSS interrupt handler. It, of course, fires any time a VSS pulse or a keypress is detected. It is important to note that this ISR will get called more than once each time a button is pressed, and that the debounce is handled by the use of a counter that is updated by the system timer. Once the counter winds down to zero, the new keypress has been stable for that amount of time, and the system timer then passes the keypress off to the main program. This is also how I created "long" button press detection.

Code:

ISR(TIMER2_OVF_vect) { // system timer interrupt handler

(...)

        if (VSSCounts != 0) { // if there is a VSS debounce countdown in progress

                VSSCounts--; // bump down the VSS count
                if (VSSCounts == 0) { // if count has reached zero,

                        vssPulseCount++; // update the VSS pulse count
                        dirty |= dirtyVSS; // tell system timer that raw readings changed, and that the VSS reading itself has changed

                }

        }

        if (keyCounts) { // if there is a button press debounce countdown in progress

                keyCounts--; // bump down the button press count by one

                if (keyCounts == 0) { // if the count has reached zero

                        lastKeyPressed |= vssBit; // use vssBit to signal that a "long" keypress has been detected
                        buttonState = lastKeyPressed; // pass off the remembered keypress status to the main program
                        timerStatus &= ~timerKeyWait; // signal main program that a key press was detected

                }

                if (keyCounts == keyShortDelay) { // if button debounce countdown reaches this point

                        tempFlags = buttonsUp & lastPINCstate; // figure out what buttons are being pressed

                        if ((tempFlags != buttonsUp) || (lastKeyPressed & vssBit)) { // if any buttons are pressed, or there is a long press status

                                lastKeyPressed = tempFlags; // remember the keypress status for later

                        } else { // all buttons have been released, and there is no long keypress status detected

                                buttonState = lastKeyPressed; // pass off the remembered keypress status to the main program
                                timerStatus &= ~timerKeyWait; // signal main program that a key press was detected
                                keyCounts = 0; // reset button press debounce countdown to zero

                        }

                }

        }

(...)

}

This code is in the system timer ISR. It enables a couple of things. First, if the user presses a button, then releases it, it will release just that keypress. If the user presses two buttons together, and releases them, it will release this combination. However, if the user presses the two buttons, and there is a slight delay between, say, pressing the center button and the left button, then the code will wait for the buttons to stabilize. Finally, if the user holds down the button combination for more than one second, the code will pass that along. The difference there is that the short keypresses require that the user release the buttons first, while the long keypresses only require that the buttons have been pressed for a second.

Quote:

Originally Posted by nickdigger (Post 381298)
One thing about your injOpenStop = timer2_overflow_count | TCNT2; code: Are you using the same prescale factor=64 (TCCR2B= 1<<CS22;); If so, I believe each tick is worth 4usec, so your calculation should be multiplied by 4. (I think. I've only just started looking into timers.)

Heh. It's good that you noticed that.

After going through the code, I decided I just didn't need that any more. For one thing, it wasn't really returning values in true microseconds. For 16 MHz systems, it'd return values in units of (16 000 000 / 64), or 4 us, but for 20 MHz values, it't return values in units of (20 000 000 / 64), or 3.2 us. Besides that, doing the conversion was just another arithmetic operation that could have been folded into the mileage/distance/economy/time calculations. So, fuel injector pulse times, idle times, and even the system time are now measured in timer2 cycles

Also, to optimize calculations involving timer2_overflow_count, I decided to have the timer2 overflow handler bump timer2_overflow_count by 256 instead of by 1. That got rid of constantly having to multiply timer2_overflow_count by 256 whenever it was desired to read the time.

The timer2 overflow has been vastly expanded, to get rid of microseconds() altogether. The main loop uses timer2 to do its loop delays now, instead of having to track the time by itself. I'm thinking that this may have gotten rid of that freeze-up bug altogether. Also, function delay2() now "calls" the overflow timer to do its delays, but also I'm thinking to get rid of that, in favor of having timer2 drive the LCD output directly by using an output buffer.

Code:

        injOpenStop = timer2_overflow_count + TCNT2; // read current TCNT2
        if (TIFR2 & (1 << TOV2)) injOpenStop = timer2_overflow_count + 256 + TCNT2; // if overflow occurred, re-read TCNT2 and adjust for overflow

That above is a slightly modified version that actually manages to save about 18 bytes or so in compilation. Who knew that logical OR-ing would take up more space than just adding? Heh.

nickdigger 07-20-2013 12:14 PM

Quote:

Originally Posted by t vago (Post 381315)
Also, to optimize calculations involving timer2_overflow_count, I decided to have the timer2 overflow handler bump timer2_overflow_count by 256 instead of by 1. That got rid of constantly having to multiply timer2_overflow_count by 256 whenever it was desired to read the time. Also, function delay2() now "calls" the overflow timer to do its delays, but also I'm thinking to get rid of that, in favor of having timer2 drive the LCD output directly by using an output buffer.

Code:

injOpenStop = timer2_overflow_count + TCNT2;
if (TIFR2 & (1 << TOV2)) injOpenStop = timer2_overflow_count + 256 + TCNT2;

That above is a slightly modified version that actually manages to save about 18 bytes or so in compilation. Who knew that logical OR-ing would take up more space than just adding? Heh.

The OR was probably (stupidly) ORing 0x00 to each of the 3 high bytes as well. I've been using unions, as below, to eliminate some of that nonsense. With the add-256 method, the compiler knew the high bytes would just carry-the-one from the lower add, hence the "better" compile.
Here's how I optimized my microseconds():
Code:

typedef union { ulong  ul;
                struct {uint i0; uint i1;};
                struct {byte b0; byte b1; byte b2; byte b3;}; } union32;

ulong microSeconds (void)
{
  union32 tmp;
  const byte *t2ocptr = (byte *)&timer2_overflow_count;

  cli();
  //tmp.ul = timer2_overflow_count<<8;
  //tmp_tcnt2 = TCNT2;
  tmp.b3 = *(t2ocptr+2);
  tmp.b2 = *(t2ocptr+1);
  tmp.b1 = *(t2ocptr);
  tmp.b0 = TCNT2;
  sei();
  //return (tmp + tmp_tcnt2) * 4;
  return tmp.ul * 4;

//each TCNT2 == 4us
//each timer2_overflow == 1024us == 256us*4
//return (timer2_overflow*256*4 + TCNT2*4)
//ie, return (timer2_overflow*256 + TCNT2) * 4

It's pretty tight. Only 38 bytes compiled, no stack usage, and only 5 instructions between cli & sei. Now that I look at it, 14 of those 38 are the mult-by-4 op.


Quote:

The timer2 overflow has been vastly expanded, to get rid of microseconds() altogether. The main loop uses timer2 to do its loop delays now, instead of having to track the time by itself. I'm thinking that this may have gotten rid of that freeze-up bug altogether.
I didn't know others were freezing as well. My "blank" screen after the 7min timeout now displays a running clock, and the timer_overflow values. Hopefully this will help me catch the bug in the act.

t vago 07-20-2013 05:33 PM

I noticed that when I started to perform code optimization of the 0.86 code, it would start to just freeze up. I haven't yet figured out why, though, as I had already progressed on more-or-less re-writing the 0.86 code. That code is nice and rock-solid stable.

Quote:

Originally Posted by nickdigger (Post 381318)
Here's how I optimized my microseconds():[/code]

Hey, that's pretty cool. I might try that, too, at some point.

Are you calling your microSeconds() function in your ISRs? If you are, you might want to slightly modify your interrupt disabling mechanism a bit. Something more like:

Code:

ulong microSeconds (void)
{
  union32 tmp;
  const byte *t2ocptr = (byte *)&timer2_overflow_count;

  byte oldSREG = SREG; // save interrupt flag status (in case an ISR called here)
  cli(); // now, we disable interrupts
  //tmp.ul = timer2_overflow_count<<8;
  //tmp_tcnt2 = TCNT2;
  tmp.b3 = *(t2ocptr+2);
  tmp.b2 = *(t2ocptr+1);
  tmp.b1 = *(t2ocptr);
  tmp.b0 = TCNT2;
  SREG = oldSREG; // restore previous interrupt flag state
//  sei();
  //return (tmp + tmp_tcnt2) * 4;
  return tmp.ul * 4;

This way, you're not inadvertently re-enabling interrupts while servicing an interrupt. Nested interrupts a a total PITA at best.

Remember also that if you happen to read TCNT2, it might roll over and overflow right before you read it, thus giving a false lower value. This is why it's generally better to read the value, check for overflow condition, then read again and adjust for the overflow if the overflow condition is found to exist. All this, of course, is done while interrupts are disabled. I strongly suspect this is why the original microSeconds() function had a recursive call, to try to get around this quirky aspect of timers.

nickdigger 07-20-2013 06:26 PM

Quote:

byte oldSREG = SREG;
Ah, thanks. I was calling it from an ISR or two.

I'll ponder the whole Read-CheckOverflow-ReadAgain thing later. I'm not sure it really makes a big difference. If it's off by 256usec (or 1024), it only affects a calculation at that moment, and it's not cumulative, so what are we really losing? There's a total of 11 clock cycles (< 0.7usec @16mhz) between cli & sei here.


The original recursion code was testing against 4290560000, which is 4407296 less than FFFF FFFF. That means it would recurse, except during the last 4.4 seconds of the timer's 68 minute life cycle. I tried googling around for those numbers, but was only pointed back to the mpguino code, so it doesn't appear to be an established practice.

Also, i only removed that recursion thing very, very recently, so i dont think it was preventing any freezes or resets i was having.

nickdigger 07-21-2013 03:49 PM

Quote:

Remember also that if you happen to read TCNT2, it might roll over and overflow right before you read it, thus giving a false lower value. This is why it's generally better to read the value, check for overflow condition, then read again and adjust for the overflow if the overflow condition is found to exist. All this, of course, is done while interrupts are disabled.
Looking at this again, I thought cli also shuts off timers, thus preventing any undesired counter hijinks.

t vago 07-21-2013 05:06 PM

Quote:

Originally Posted by nickdigger (Post 381446)
Looking at this again, I thought cli also shuts off timers, thus preventing any undesired counter hijinks.

Nope. cli() only disables interrupts. The timers themselves will keep on going, with all that that implies.

For instance, say you disable interrupts inside MPGuino using cli(). Timer 2 is still merrily going on its way at 1/64th of the system clock, as it was configured. During the course of your routine, timer 2 overflows. It sets the overflow flag, but since interrupts are still disabled, your routine will continue to execute without any interruption. Once interrupts are re-enabled (via sei(), or restoring the SREG from a pre-cli() state), the timer 2 overflow interrupt will now fire.

baldlobo 07-21-2013 09:53 PM

vago; where'd you get your fuel pressure from because everything i've read for every chrysler produced from 99 or earlier, on is suppost to be 49+/-5psi?

if your fuel pressure reg is actually getting 58+psi(you said 58psi over atmospheric so 72psi) you might want to replace/fix it; it might fix your problem

from a factory service manual

(4) If operating pressure is above 54.2 psi, electric
fuel pump is OK, but fuel pressure regulator is defective.
Replace fuel filter/fuel pressure regulator. Refer
to Fuel Filter/Fuel Pressure Regulator Removal/Installation
for more information.

t vago 07-22-2013 10:02 AM

1 Attachment(s)
Quote:

Originally Posted by baldlobo (Post 381484)
vago; where'd you get your fuel pressure from because everything i've read for every chrysler produced from 99 or earlier, on is suppost to be 49+/-5psi?

if your fuel pressure reg is actually getting 58+psi(you said 58psi over atmospheric so 72psi) you might want to replace/fix it; it might fix your problem

from a factory service manual

(4) If operating pressure is above 54.2 psi, electric
fuel pump is OK, but fuel pressure regulator is defective.
Replace fuel filter/fuel pressure regulator. Refer
to Fuel Filter/Fuel Pressure Regulator Removal/Installation
for more information.

From page 14-2 of the 2005 LX platform Factory Service Manual:
http://ecomodder.com/forum/attachmen...1&d=1374501620
58 psig, or 400 kPa.

Now, my truck, on the other hand, does have that 49.5 psig rating. That's good to know information - I will need to add another eeprom parameter to compensate.

t vago 09-02-2013 12:17 PM

[youtube]IHs_eQlXDd8[/youtube]

The injector pressure differential correction factor code has been written, and is now in a stable version. Code testing is underway.

t vago 09-03-2013 05:51 PM

WARNING - Novel Alert
 
Results of testing today - Partial success.

Today, on my drive to work, the calculated injector correction factor was a bit off, from what I expected, leading to lower-than-correct fuel consumption readings.

However, my code was easily able to read and process MAP sensor readings for each individual fuel injector event. Given that said events can occur from once every 150 ms to once every 19 ms, this represents a very significant capability.

Equation 1 below is used to correct the fuel injector pulse length reading for a returnless fuel system-equipped vehicle, when said vehicle uses a constant-pressure fuel pressure regulator.

(1) - F = sqrt( P(diff inj) / P(fuel pressure regulator) )

However, the equation for determining the pressure differential across the fuel injector,

(2) - P(diff inj) = P(fuel system) - P(intake)

has some complication associated with it. In particular, P(fuel pressure regulator) is a gauge pressure reading, while P(intake) is an absolute pressure. Or,

(3) - P(fuel system) = P(baro) + P(fuel pressure regulator)

Where P(fuel pressure regulator) is the rated fuel pressure of my fuel pressure regulator, and p(baro) is the absolute atmospheric pressure. Thus, equation 2 above turns into:

(4) - p(diff inj) = P(fuel pressure regulator) + P(baro) - P(intake)

Right now, my P(baro) estimator works by setting P(baro) to P(intake) when it senses that both the engine is turned off, and the vehicle is not moving. Ideally, this would give an accurate P(baro) right before the engine is turned on. However, in real life, this isn't always the case. The MPGuino hardware is always turned on, but the engine computer is sometimes shut off. When this happens, the power to the MAP sensor goes to 0 VDC, so the MAP sensor output itself goes to 0 VDC. This is what happened today.

I noticed that my estimated P(baro) was effectively at zero psi. This will (and did, of course) throw off the correction factor, rendering it useless for its intended purpose. Clearly, I will need to do something about that.

Now, I could recode the P(baro) estimator, but it would cause my code to grow more than it already is. As of right now, the code sits at 19640 bytes. Or, I could retain the existing code, and simply wait for a few seconds or so, after turning the ignition key to On, and before starting the engine. That would certainly give me an accurate P(baro). However, that would require that the driver wait before starting the engine every single time. Maybe the average MPGuino user would be this anal... I don't know. However, I don't want to depend on that.

Just had this thought - even if I did get an accurate P(baro) right before starting the engine, that P(baro) would only be accurate for a little while. Weather changes, elevation changes, and temperature changes all affect P(baro). My engine computer gets around this by estimating P(baro) based on throttle position, the MAP sensor, engine speed, and a lookup table. However, to implement something like that into my code would require both using the remaining analog input, and a calibration to generate a suitable lookup table. That could prove to be very challenging.

Were I to add a separate pressure sensor dedicated to solely measuring atmospheric pressure, that would certainly get rid of any costy estimation code, and any undue expectation on the part of the driver, but it would do so at the cost of using up the remaining analog input. This might not be a problem, but then again, it might be. For instance, I've read in this forum that other users saw how system voltage changes cause changes in injector reaction time, and went about coding to compensate for that. Well, that needs an analog input to be able to measure system voltage. If that input were instead used for barometric pressure, one would have to assume a more-or-less constant system voltage (which the base MPGuino code does, BTW).

Not to mention that a separate MAP sensor costs in the range of $40 or so.

I will probably end up going with adding a separate MAP sensor that is dedicated as a barometric pressure sensor. It will, of course, eat up that remaining analog input. However, it might be beneficial to members like KY Metro, who are looking to add a fuel pressure sensor due to how they operate their fuel pump. As long as the fuel pressure sensor would also read absolute pressures, this would not pose any problem with my code.

nickdigger 09-03-2013 06:26 PM

If you only need one more analog pin, you could move the VSS over to your newly-free pin3.

The buttons are a big waste of analog inputs. I plan to add resistors to mine, and have all 3 (plus a 4th) share a single pin.

Also, if you happen to use a TQFP atmega, there are 2 extra analog inputs available: A6 and A7.

josemapiro 09-04-2013 02:45 PM

Quote:

Originally Posted by nickdigger (Post 388645)
The buttons are a big waste of analog inputs. I plan to add resistors to mine, and have all 3 (plus a 4th) share a single pin.

The idea to use one pin for the buttons, it is a good idea but in other projects, this project is more difficult due to the combination of buttons, that causes the value of resistances combined, is identical in some combinations of buttons .
But try it yourself.

José Rodrigues

nickdigger 09-05-2013 03:49 AM

That's easy for you to say, Jose, with your 16 Analog & 53 Digital I/O =)
I am going to try it though.


All times are GMT -4. The time now is 11:10 AM.

Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2024, vBulletin Solutions Inc.
Content Relevant URLs by vBSEO 3.5.2
All content copyright EcoModder.com