Title: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on June 17, 2018, 02:41:13 AM ... or how to program your own interrupt driven input ;)
First and foremost - whatever you do with it, you take full responsibility for your doings. I will try to provide help here (hope others will too), but will not provide personal guidance through PMs (unless you pay me :D). Also, there might be errors in the code, I edited it for presentation. I was thinking for a while now if I should publish this or not, came to the conclusion that there is no such big market for this specific ECU and this feature (well OK, maybe in U.S. there is, there are both Fiats 500 and E85 in the same country). Besides, the way it is presented, it is neither complete nor directly reproducible nor easily transferable to other ME-s, you have to be very inclined to repeat the exercise (and if you can - good for you, I would only appreciate if you acknowledge me if you do it commercially). I will not post ready made patches. So to cut this long intro short, this is mostly for education (something that some of you seem to be craving on this forum). Well, OK, I also want to have some of my code scrutinised, I know it works, but in the process of testing and polishing it I have seen bugs. I do not intend to give much guidance on the actual E85/E100 tuning, though I will mention some things. I am simply no specialist here, you should ask pros for help. On the other hand, there is lots of misinformation about this out there (including this forum), I will come back to this. The particular bin I worked with is attached, this is ME7.9.10 software number 1037391689 for Fiat Grande Punto, 120hp t-jet engine. And some links to the ST10 documentation you may find useful (not precisely for the CPU in this particular ECU, but close enough for the purpose at hand): http://www.keil.com/dd/docs/datashts/infineon/c167cr_um.pdf (http://www.keil.com/dd/docs/datashts/infineon/c167cr_um.pdf) http://www.st.com/content/ccc/resource/technical/document/programming_manual/27/c0/48/83/94/9d/4d/45/CD00147146.pdf/files/CD00147146.pdf/jcr:content/translations/en.CD00147146.pdf (http://www.st.com/content/ccc/resource/technical/document/programming_manual/27/c0/48/83/94/9d/4d/45/CD00147146.pdf/files/CD00147146.pdf/jcr:content/translations/en.CD00147146.pdf) Hardware So, the task is to connect the Continental FlexFuel sensor (picture from Amazon): (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=14417.0;attach=25829;image) to the Bosch ME7.9.10 that runs the Fiat t-jet FIRE engine (picture from ECU Backup site): (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=14417.0;attach=25837;image) And provide a software patch for it. I used the small sensor, part number GM 13577429. When connected according to this scheme: (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=14417.0;attach=25831;image) it will produce a square wave 0-5V signal with the following characteristics, the frequency gives the Ethanol content reading, the pulse width gives the fuel temperature: 50Hz (20ms period) = 0% Ethanol, 150Hz (6.6(6)ms period) = 100% Ethanol, 180Hz+ -> contaminated fuel 1ms pulse width = -40 °C, 5ms pulse width = 125 °C (some sources say something about 151.25 °C ?) My first idea was to just go lazy and buy an external control module, like the Zeitronix one (http://www.zeitronix.com/Products/ECA/ECA.shtml (http://www.zeitronix.com/Products/ECA/ECA.shtml)), to get 0-5V analog signal and feed that to the ECU through ADC, but then I though it might be worth investigating if it can be connected directly somehow. To save some money and minimise clutter in the engine bay. For that I looked through the disassembly of my bin to see if there are any unused port pins on the ST10 that could be used to hook up an interrupt procedure. There were some potential candidates, but I also wanted something with a connection to the ECU plug. After taking the board under the magnifying glass I found the following connection: (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=14417.0;attach=25835;image) Logic wise, this is exactly what the sensor needs, only there is the additional in-series 100K resistor. I consulted an electronics engineer and was told this should not matter. Out of curiosity I also looked up Fiat t-jet docs I have - the ECU pin is described as "Oil condition sensor input (unused)". OK, let's use it then. Connect the +12V and ground of the FlexFuel sensor to ignition switched power, and the signal line to ECU pin 59 on the small connector (spare ECU plug to get extra connectors might be needed, I did not have one and did a bit of a bodge job there). So, in the end, there was not even any need to open the ECU, just adding one connector to the ECU plug and tapping into some power wires. At the expense of more involved software. And obviously connect the fuel lines. I connected mine on the return line (mostly for the reason of much lower fuel pressures and less likelihood of having pressure related leaks in my experimental set up). Out there you will find advice to do it on the return line, but also on the feed line (BTW, for high power applications the flow limitation of the sensor might be an issue). From the experience so far I already know that the feed line placement would give more stable readings, on the return line air pockets are caught by the sensor in some operating conditions skewing the readings (can be remedied by software). This is the complete hooked up sensor, minus securing the fuel lines (and fastening the sensor, I still have to do this): (http://nefariousmotorsports.com/forum/index.php?action=dlattach;topic=14417.0;attach=25833;image) Software Let's program this thing, the proper Bosch way - let's over-engineer it a bit. I mean, let's measure the CPU clock to get the sensor input precisely (the frequency and pulse width) to one clock tick to get both ethanol content and temperature, do error detection / recovery / reporting, readout smoothing / filtering, etc. The code below has some legacy from my earlier developments, which means things can be simplified and/or omitted, but once they worked I left them as is. In retrospect, to just get this working, things can be probably simplified to a couple of lines of assembly code. But we are here to learn ;) All addresses in the assembly code below are logical CPU addresses (so not the flash bin addresses like the direct addresses in your map pack, but that should be obvious). The memory map of ME7.9.10 is this. Internal flash is at $0000-$7FFF (as with most (all?) ST10 ME-s), the rest of the flash is mapped to $18000-$CFFFF, out of which $A8000-$BFFFF is the data area ($A0000-$A7FFF also, but it is unused, not sure why). The big RAM is at $F0000. Placing code in some flash areas requires care. For example, $18000-$20000 is the code image for RAM only operation (flashing, recovery boot), but generally can be used if free. The region $90000-$9FFFF, even though tempting (all empty) should be left untouched - this is where the ECU stores the boot code backup during flashing. The DPP registers are initialised as follows: dpp0 is $2A (data area $A8000-$ABFFF), dpp1 is $2B (data area $AC000-$AFFFF), dpp2 is $3C ($F0000-$F3FFF), dpp3 is $3 ($C000-$FFFF). So these areas can be addressed through DPP registers, everything else has to be done with extp/exts. The code for the sensor will operate on several layers. To start with, we need three things: (1) initialisation procedure that will set up things, reset variables, and enable our interrupt, (2) the interrupt procedure itself for the square wave signal processing with low-level diagnosis, and then (3) the high level diagnosis / application procedure. (2) and (3) will communicate to better discover errors. This is just to get sensor reading, the map modification (fuel, ignition, etc.) is done separately, and so is extending diagnostics interface to report the Ethanol readings. Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on June 17, 2018, 02:45:55 AM Finding memory
In terms of free space for variables, code, and data we need the following. A 32 byte register area in IRAM for the new interrupt, an external RAM piece for other variables, flash space for our new procedures, and data area for the calibration data (this does not have to be there by any necessity, but flashing data-only changes later with the right flasher will be quicker). On top of this we will patch a couple of places in the existing code to interface with our new procedures and provide mixture dependant operation of some maps. The flash space and data space are easily found by simply looking at the bin image. Several possibilities there, I decided to bravely stick code things at the end of $18000-$20000 and data after the factory calibration data:
The RAM things require looking more carefully at the disassembly. Starting at $F3900 there is a chunk of big RAM available until $F3FFC, and then much larger chunk after $F5000. The first one can be directly DPP addressed, so we can save on extp-s and exts-s. Some of these RAM areas are not cleared during ignition off (I believe, did not check this carefully), but that does not matter, we take care of cleaning / resetting ourselves, so:
Then the 32 byte register area. Every interrupt needs its own private register area for r0-r15 (well, not every, but without it things get very hairy). Finding this requires going through the disassembly and looking for "mov $FXXX, r0" instructions (typically followed by "sctx CP, #$FXXX"). This gives you the area where the 32 byte blocks are kept, and then you can identify which 32 blocks there are unused (there is no corresponding write of the quoted form). For our bin that gives at least $F940, $F960, $FAA0, $FAC0 (there are some more). For reasons now unclear to me, I picked the third one:
The interrupt set up So we have the P2.9 pin to service. This corresponds to the Capture-Compare (CC) register number 9 and this is what we have to set up. Pin P2.9 needs to be set up for input, but this is already taken care of in the existing code. We want to trigger the interrupt procedure on both edge changes (remember, we want the frequency and the pulse width of the signal from the sensor) and connect it to a clock with suitable resolution - clock with overflow range larger than our longest possible period (20ms, 50Hz), but small enough range to have precision measurements. The only choice we have for CC9 to have a hardware clock capture is timers T0 and T1 (CAPCOM module 1). And we cannot change the timer setup. On this ECU they are configured in the following way in the T01CON register: T0: $4A (counter mode, pre-scaler 2) T1: $42 (duration mode, pre-scaler 2) We want duration kind, so T1 it is. Pre-scaler is 2, which for the 40MHz clock this ECU has means that the total period of this clock is 52.5ms, resolution (one tick) is 0.8us. Just what we need (if it wasn't like this, stuff would get much harder). The CC9 behaviour is set up in the second nibble of the CCM2 register:
Another important (very!) thing is the interrupt priority. Too low - it will be pushed away by other interrupts and we will miss edge changes. Too high - it will pre-empt other important interrupts. In fact, with very high priorities the ECU crashes after connecting the sensor. Experimentally, this value seems to work fine (essentially mid range priority):
This is also a priority that is not used by any other interrupt (for this you have to scan the disassembly for writes to the other interrupt control registers), this is a good thing to have (though not necessary IIRC). We can then enable the interrupt:
This code so far should go into our initialisation procedure, but after some variables are initialised, so for now just the assembly statements for the interrupt initialisation. The interrupt The interrupt procedure has only one job - to provide raw sensor reading to the higher level procedure. But, since our high level procedure will execute every 100ms (could be more frequent, but really there is no point), and interrupt at least every 20ms, we can already do some signal pre-processing in the interrupt and the rest elsewhere. In the interrupt we will de-bounce the signal, validate edge alternations, validate edge periods, and do modest stepping average of the periods. The higher level procedure will then convert the period recorded in the interrupt, do filtering, and error processing. The interrupt procedure has to be as concise and quick as possible. So, for example, we will not do MDL/MDH operations in the interrupt to calculate the average, but rather do division by 2/4 with shr. The nice thing about the interrupt procedure is that it has its own private register space (the 32 bytes above). This means that whatever we store in r0 through r15 we can leave it there for the next interrupt round, we can access the registers from the higher level procedure by addressing them explicitly in IRAM (BTW, I do not recall seeing this trick done on Bosch-es, maybe didn't look hard enough, but several times on Marelli systems), and we can have our own private DPP register values to optimise RAM and data access within the interrupt. The registers will serve the following purposes: r0 - this has to be the current local stack pointer, even though we do not use the stack r1 - flags set 1 - status_flags r7 - flags set 2 - heartbeat_flags r8 - the clock stamp of the last edge seen (any edge) r9 - the clock stamp of the last high edge seen (the edge that starts both the pulse width and period) Otherwise, we can use them freely for temporary storage. r1/r7 separation is one of the legacy things, the flags could be squeezed into one register. In any case, r1/r7 will be IRAM accessed from the higher-level procedure:
Also, the notion of the high/low edge needs care. At first, before I got the actual sensor and simulated it on Arduino instead, I thought the signal is like this:
where the first chunk is the PW (temperature) and the complete chunk is the period. So all "high" terms in the code refer to the first chunk, the "low" ones to the the second chunk. But, with the actual sensor it is the other way round, freely floating 5V pull-up gets pulled to 0V during the PW chunk. Without rewriting the code I just introduced a calibration flag to account for the other possibility (for example, where the ECU does not allow for direct connection and additional circuitry might be needed). For calculating the period and the pulse time we use two 12 byte / 6 word arrays:
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on June 17, 2018, 02:47:49 AM The interrupt procedure
We are now ready to write the interrupt service procedure. The POFF(X) is X & $3FFF (page offset), DPP(X,Y) is (X*$4000 | Y) (DPP based addressing), the meaning of the bits in r1/r7 is explained as we go:
Finally, we can install our interrupt in the interrupt vector (in the factory code this is a self loop - the interrupt is never serviced):
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on June 17, 2018, 02:48:20 AM And of course we need the calibration data that we used in the code:
This is first step, it gets us to the point where we have the high-to-high 4-value-averaged time reading stored in period_val, and high-to-low 4-value-averaged time reading stored in pulse_val, effectively raw ethanol content and fuel temperature. And some error flags in r1/status_flags. This now all needs to be converted to more digestible format and dealt with for error reporting, filtering, and the dynamics of the fuel system. And then for map alterations. But for now, I leave you bunch with this to digest and waiting for opinions whether I should continue ;) Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: jcsbanks on June 17, 2018, 03:59:50 AM Nice work. There is a shortage of these skills and commercially viable stuff to do on later platforms for sure.
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: 370rx on October 03, 2018, 06:18:03 AM A lot of work has been done!
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on October 04, 2018, 02:31:15 PM And it continues, I have really shitty time (because of lack of it) to properly calibrate cranking and transients when cold.
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: 370rx on October 05, 2018, 09:37:07 AM when the outside temperature is from 3 to 15 degrees I'm experiencing the same problems as you (you wrote about them in the topic Re: Porsche Cayenne ME7.1 RE85 half warm start problem), and gasoline 95,98. This problem is many of my friends on 1.4 t-jet, but not as obvious as you.
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: MyTunes on November 10, 2018, 09:40:28 PM And it continues, I have really shitty time (because of lack of it) to properly calibrate cranking and transients when cold. Does the MED9 have the ability to do multiple spark like the ME7? I thought that this had helped some people on E-85 cold startup? Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on November 11, 2018, 02:02:10 AM Don't understand me wrong - I get a start on the first key all the time, down to 0*C, we did not have colder days than this yet. It's just that it is not as clean and predictable as the gasoline start. Sometimes it turns a lot without catching and then catches on very nicely hitting the target RPM without hesitation (that's probably the sweet spot I want to have), sometimes it catches on much quicker (too quick?), but hesitates and chokes a bit before hitting the target RPM. My ECU has multi-spark enabled by default (if I checked everything right) and I played back and forth with FKSTT, FKSTT reduce factor, small start ignition offsets (though so far one way, I also have to try small retards). The WORST part of all this is that get one (two if I happen to let the car stay for most of the day) try per day, each day different temp. And my AFR controller shuts down during cranking.
Cold transients are a different story, now I have a tank of E15 out of necessity, and I did several cold logs to see how it should be. My E75 pattern seems to match on negative transients, so I should be fine there, yet on acceleration transients I run horribly lean (and get occasional chokes and hesitation) on E75 compared to E15. So either I still need to go much higher with KFBAKL, or start playing with the reduction factor in ZBAKM. But it's all very suspicious, because the log figures tell me I am *pouring* fuel on accelerations rather than injecting it, perhaps I went too far and the lean condition is caused by flooding. And the same problem of one experiment per day. It seems that now they have introduced a true winter blend of E85 in the country, I judge this from a visibly increased price I see displayed. What exactly is the blend I will get to see once I empty the tank sufficiently. Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: Cheekano on August 20, 2023, 09:41:08 PM Thank you for this post. It has really helped me with my current plan to implement flex fuel. May I ask how you were able to implement scaling the KRKTE?
Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: prj on August 21, 2023, 12:55:20 AM I'll just leave this comment here, maybe someone thinks before doing it.
Zeitronix has this available: https://zeitronix.com/Products/ECA/ECA2CAN.shtml (https://zeitronix.com/Products/ECA/ECA2CAN.shtml) Using this piece of hardware you can put the ethanol sensor signal on CAN, and then you can read it from the ECU. Much better idea than messing with the PCB, inputs, interrupts etc on ECU's that have no native flex fuel sensor support. I have done this successfully on MED17, but it can be done just as well on ME7. Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: Cheekano on August 21, 2023, 07:31:42 AM I'll just leave this comment here, maybe someone thinks before doing it. itZeitronix has this available: https://zeitronix.com/Products/ECA/ECA2CAN.shtml (https://zeitronix.com/Products/ECA/ECA2CAN.shtml) Using this piece of hardware you can put the ethanol sensor signal on CAN, and then you can read it from the ECU. Much better idea than messing with the PCB, inputs, interrupts etc on ECU's that have no native flex fuel sensor support. I have done this successfully on MED17, but it can be done just as well on ME7. I have a similar hardware but not the CAN version. Plan is to wire it via O2 sensor uushk/ushk as input to the ECU. I'm more curious how to integrate a factor/multiplier for the KRKTE. I've looked at FRs of some flex fuel vehicles and it seems it is implemented elsewhere as diagram for KRKTE is showing as standard. I've seen ASM on here for map switching which is straight forward but there's no blending/interpolation going on. Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: prj on August 21, 2023, 10:35:03 AM So write your own blending/interpolation logic... you can use the built in ECU map lookup commands.
You're going to need to do a ton of this. On port injected engines cold start needs a huge amount of work. And you need to do 3 axis ignition, target load and constant maps, because ignition does not really change much after E40-E50. Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: woj on August 24, 2023, 03:35:59 AM I'll just leave this comment here, maybe someone thinks before doing it. Zeitronix has this available: https://zeitronix.com/Products/ECA/ECA2CAN.shtml (https://zeitronix.com/Products/ECA/ECA2CAN.shtml) Using this piece of hardware you can put the ethanol sensor signal on CAN, and then you can read it from the ECU. Much better idea than messing with the PCB, inputs, interrupts etc on ECU's that have no native flex fuel sensor support. I have done this successfully on MED17, but it can be done just as well on ME7. I am not here often, recently almost never in fact, but I can throw in my 5 cents, since I started this topic. Doing it the CAN ways indeed seems most appropriate and more scalable across different ECUs, though I am not sure if adding CAN signals to the ECU is that much easier than what I did, in both cases you still do need to know the ECU code quite well and know your way around ASM. As for "messing with PCB", not really sure what you mean, studying the PCB to figure out which of the undocumented ECU connector pins to use is hardly "messing", for implementing the actual project I did not even have to take the ECU out of the car, let alone open it. I did have to wire up a couple of things into the harness, but that still stands for adding CAN based devices. My other idea at the time, should I have failed with my approach, was to use one of the available 0-5V analog inputs on my ECU, do not remember any more what these were originally for, but they were there. Hell, I would have probably gone that route right away if I had the FlexFuel module, not just the sensor. Zeitronix provides 0-5V output too, and I guess, from the programming point of view, that is the easiest way. Anyhow, the project has been put on the shelf long time ago, first, the prices of E85 made it totally pointless, second, if done for increased power reasons, I totally grew out of trying to kill myself in the car stage of life ;) As for the Cheekano questions about scaling / interpolating. What prj says, you need to know what you already have in the ECU and use that. Studying FRs will not give you much, you need get hold of the actual procedures in the code used for all that. For the particular question about krkte, my hookup procedure (replaces write to krkte) is roughly this: Code: mov r13, DPP(fuel_scaler) Based on the ethanol content and fuel temperature, fuel_scaler is my variable read from maps using stock map reading functions, and mult_factor is a common procedure found all over the ECU that effectively does r4 = (r12*r13)/0xFFFF. As the dependency of krkte on ethanol content is essentially linear, here you could skip the whole E/temp map and just use ethanol content (but properly scaled / shifted) for mult_factor. But like prj said, not for ignition. Long story short, you need to know what you are doing, be fluent with ASM, and there is a lot to be done. Roughly scanning through my source, I have 18 hoop up functions just to modify the original ECU parameters, plus a ton of other things to prepare data for these hook ups. Title: Re: Adding FlexFuel to ME7.9.10 step by step... Post by: prj on August 24, 2023, 03:38:53 AM Doing it the CAN ways indeed seems most appropriate and more scalable across different ECUs, though I am not sure if adding CAN signals to the ECU is that much easier than what I did It is. Even on much newer ECU's.You're going to have to do a lot of reversing either way, but putting something extra on CAN is a much nicer solution. The only exception are the ECU's that have already native flex fuel input support. Simos 18, and MED17.1.1 on 4.0TT come to mind. |