Instructions to change fuel maps on 14CUX Griffith, Chimaera

Instructions to change fuel maps on 14CUX Griffith, Chimaera

Author
Discussion

Mjstemp1

15 posts

91 months

Sunday 6th November 2016
quotequote all
Steve,

That XDF file corrected my issues. Now the Maps between TunerPro and RG match up.

As to the stumble I will continue to investigate. Switched back to map 5 on your "R3652_430_6250_LowBaseIdle" file as the stumble was less pronounced in this Map. Also looked to be running lean on the Map 2.

Saw some strange things while my assistance watched the RG. One time we saw a massive rpm increase to 6200! Too bad we were at 2000. So point towards ignition but what exactly I am not sure. Using a Delco Buick Distributor with Pertronix's module in it and a Pertronix coil. Both are less than a year old and never caused any issues with my old Carb setup. The lead to the ECU is kept at full voltage until inside the car then I split the signal off for my VDO tach and to the ECU where I have the 6800 ohm resistor. I will try a separate lead to the ECU from the coil in case some interference is happening and also add the resistor right at the coil.

Mike

stevesprint

Original Poster:

1,114 posts

179 months

Sunday 6th November 2016
quotequote all
Mjstemp1 said:
Steve,

That XDF file corrected my issues. Now the Maps between TunerPro and RG match up.

As to the stumble I will continue to investigate. Switched back to map 5 on your "R3652_430_6250_LowBaseIdle" file as the stumble was less pronounced in this Map. Also looked to be running lean on the Map 2.

Saw some strange things while my assistance watched the RG. One time we saw a massive rpm increase to 6200! Too bad we were at 2000. So point towards ignition but what exactly I am not sure. Using a Delco Buick Distributor with Pertronix's module in it and a Pertronix coil. Both are less than a year old and never caused any issues with my old Carb setup. The lead to the ECU is kept at full voltage until inside the car then I split the signal off for my VDO tach and to the ECU where I have the 6800 ohm resistor. I will try a separate lead to the ECU from the coil in case some interference is happening and also add the resistor right at the coil.

Mike
Excellent, I'm pleased TunerPro and RoverGauge now match, sorry must have been a very old XDF file.

How long did you see 6200 rpm for and where you logging??? That certainly would change the active fuel cell and therefore the fueling.

Here's my latest R3652_430_6250 with an improved coasting idle fix and a different cranking idle table. I've ben running it for the last few month and the coasting idle is much better but I'm not sure how it will start in really cold weather? If you get a chance to run it I would appreciate any feed back good or bad.

www.remap-14cux.info/R3652_430_6250_BVCatCrankFixe...

eisdielenbiker

10 posts

93 months

Monday 7th November 2016
quotequote all
Hi Steve,

thanks for the new updated XDF. It pointed me just right to the cure (stprMtrSaveValue) of the marginal problem I was encountering with my all new assembler build custom PROM based on the original R3652. It was yesterday at 1 degree above zero that I noticed the lingering idle at 1300 or more. That one settled after 2 seconds on standstill though. The cranking up was OK, but I am looking forward to check your latest updates in my MG RV8 soon. An Ostrich is so nice ...



Steve_D

13,747 posts

258 months

Tuesday 8th November 2016
quotequote all
Hi
Quick question if I may.
With your knowledge of the 14CUX inner workings can you tell me please what event or criteria is used to trigger the carbon canister purge valve?
Second, are there any plans to include an indicator or status lamp in Rovergauge?

Thanks
Steve

davep

1,143 posts

284 months

Wednesday 9th November 2016
quotequote all
Steve_D said:
Hi
Quick question if I may.
With your knowledge of the 14CUX inner workings can you tell me please what event or criteria is used to trigger the carbon canister purge valve?
Second, are there any plans to include an indicator or status lamp in Rovergauge?

Thanks
Steve
Adapted from LR reference sources:

14CUX pulses the valve open for short periods below 1720 RPM and holds it open at higher speeds once the engine has achieved operating temperature and is in closed loop. Operating temperature is defined as engine coolant temperature above 54 C (130 F). 14CUX monitors the need for canister purge by looking at the response of oxygen sensor values from the HO2S (Heated Oxygen Sensor) when the valve is opened. No change in HO2S response with the valve open indicates that the canister has been purged of fuel vapour and continued valve operation is no longer necessary. Operation of the purge function when no longer required can negatively impact vehicle emissions.

The Purge Valve control code is triggered by a timed interrupt, which is controlled by an output compare register, a free-running clock and one of the three MPU timers:

purgeValveInt   ldaa        timerCSR            ; OCF2 flag is reset by reading one of these two
ldaa timerStsReg ; locations and then writing to ocr2 high or low
ldaa $00E2
bita #$10 ; test X00E2.4
bne .LDB24 ; branch ahead if bit is set

ldd purgeValveTimer ; load purge valve timer value
subd #$0FA0 ; subtract 4000 dec
bcs .LDB24 ; branch to .LDB24 if value < 4000 dec

subd #$61A8 ; subtract 25,000 dec
bcc .LDB2E ; branch to .LDB2E if value > 29,000

ldaa port1data
eora #$02 ; toggle P1.1 (purge control valve)
staa port1data
bita #$02 ; and test it
bne .LDB34 ; branch to .LDB34 if bit is now set

ldd ocr2high ; <-- bit is low, purge valve turns ON (timer is between 4K and 29K)
addd purgeValveTimer ; (for between 4 and 29 ms)
std ocr2high
rti

.LDB24 ldaa port1data ; if here, X00E2.4 is set OR 'purgeValveTimer' is < 4000
oraa #$02 ; set P1.1 to turn purge valve OFF

.LDB28 staa port1data
ldd ocr2high ; just read ocr2 so we can write it back and clear the flag
bra .LDB3B ; branch down to write it back to register and rti

.LDB2E ldaa port1data ; if here, purgeValveTimer > 29,000
anda #$FD ; clear P1.1 to turn it ON
bra .LDB28
; if here, bit is high, purge valve turns OFF
.LDB34 ldd ocr2high ; purgeValveTimer is between 4K and 29K
addd #$7A12 ; 31250 dec (stay off for 31 minus ? ms)
subd purgeValveTimer ; subtract purge valve timer value

.LDB3B std ocr2high ; write to 16-bit MPU register


If you require further explanation of the above please ask.


Steve_D

13,747 posts

258 months

Wednesday 9th November 2016
quotequote all
Nothing further required thanks as that is perfectly described. I will post that info when the question comes up again.

Cheers
Steve

danbourassa

246 posts

137 months

Thursday 10th November 2016
quotequote all
Steve_D said:
Hi
Quick question if I may.
With your knowledge of the 14CUX inner workings can you tell me please what event or criteria is used to trigger the carbon canister purge valve?
Second, are there any plans to include an indicator or status lamp in Rovergauge?

Thanks
Steve
Steve, I'm happy that Dave was able to answer the first part of your question about what triggers the purge valve. As far as the status lamp in RG, it is possible to do some kind of indicator but I don't think it should be done. I'm almost convinced that this is a completely useless sub-system and what I think should be done is the removal of the purge valve interrupt and all its related subroutines from the code.

There is one thing that could make me hesitate on this. Has anyone ever had a purge valve fault (code 88) and successfully fixed it by replacing the valve or canister?

stevesprint

Original Poster:

1,114 posts

179 months

Friday 11th November 2016
quotequote all
eisdielenbiker said:
Hi,
I have just bought an MG with a 14CUX EFI. I also had some hesitation on accelerating hard at different rpm. One flat spot was around 1700 another in the upper 2000s. After this they were gone at higher revs. At least I didnt noticed them. A new Bosch coil, new HT leads and a more advanced ignition timing of at least 11 degrees at idle cured these problems.

If you allow I would like to ask another question to the experts:

Is it a bad idea to backup the ROM checksum at battery backed up location $54 which seems unused in order to reset the long term lambda trims if an emulated ROM is changed ? I am using an Ostrich 2 emulator and am a little annoyed by ever reconnecting the car battery. I tried my first code change like this and it seems to work:


ldab CHECKSUM_FIXER ;start of my code
cmpb $54 ;potential unused battery backed up ram location
beq .clr_int_ram ;ROM not changed
stab $54
ldd #$8000 ;reset long term trims
std secondaryLambdaR ;as when ECU was disconnected from power suppply
std longLambdaTrimR
std secondaryLambdaL
std longLambdaTrimL ;end of my code
;----------------------------
; Clear internal memory
;----------------------------
.clr_int_ram clra
ldx #$0055 ; *** Zero Memory $54 to $FA ***
ldab #$A5

.zeroRAM_0054 staa $00,x
inx
decb
bne .zeroRAM_0054 ; *** End Zero Memory ***

If it evolves satisfactory I would encapsulate the later original battery ram clear sequence in a subroutine. Possible the stepper motor value should be resetted too . The routine would do that also.

Cheers
Mark L
Mark L
Welcome and thanks for your really neat idea to automatically reset the battery saved data when changing proms, you soon got your head around Dan’s rebuild project. I personally will find your solution very useful as I’m bored of disconnecting my battery to reset the ECU even though I have a quick battery disconnect terminal, I much prefer you automatic software solutions. Yes I would also include stprMtrSavedValue that is copied from C242 during ECU battery power reset.

This is really a question for Dan, DaveP or Colin but I’ll have ago.

I see you’ve changed
ldx #$0054 ; *** Zero Memory $54 to $FA ***
to
ldx #$0055 ; *** Zero Memory $54 to $FA ***

so address $0054 doesn’t get cleared at restart

I’m concerned as I think address $0054 may actually be used as follows:
$0054 is copied to $0052 in idleControl (throttle pot min)
$0054 is subtracted from TPmin in throttlePot.asm
$0054 is copied to $0052 TPmin in shutDown.asm

I’m not an assembler programmer so would this mean Mark L checksum would be
copied to $0052 in idleControl (throttle pot min)
subtracted from TPmin in throttlePot.asm
copied to $0052 TPmin in shutDown.asm

Dan, DaveP or Colin help Please !!!

As $0054 is normally always zero could we comment out the three uses of $0054 above ???
Thanks, Steve

Edited by stevesprint on Saturday 12th November 21:51

eisdielenbiker

10 posts

93 months

Friday 11th November 2016
quotequote all
Steve,
Adress $54 did not work. You see I am not that deep into the code issue yet.
I am about to try $EF this weekend. This is the lower cpu stack boundary.
Seems to be probably unused as the code hierarchy is fairly flat in the 14CUX.
Mark L

danbourassa

246 posts

137 months

Friday 11th November 2016
quotequote all
eisdielenbiker said:
Steve,
Adress $54 did not work. You see I am not that deep into the code issue yet.
I am about to try $EF this weekend. This is the lower cpu stack boundary.
Seems to be probably unused as the code hierarchy is fairly flat in the 14CUX.
Mark L
Mark L, I'm so glad that you are taking an interest in the assembler code. There is a lot that is not fully understood yet, so any help is appreciated.

Obviously, you realized that the actual battery preserved area is 32 bytes long and extends to $005F. The 14CUX code only uses $0040 through $0053 in this way and the rest is treated like normal volatile RAM.

Steve is correct about the fact that $0054 is actually used as a throttle pot minimum value. This is for the throttle pot self-learning feature. I know how the confusion happened and it's my fault. I just looked at file 'ramLocations.asm' and noticed that I never assigned a variable name to location $0054. Maybe the mistake happened because location $0053 is actually reassigned after it is no longer needed as a checksum, so it has two assigned names.

Using the end of the stack area is clever and probably safe to do. I assume you would shorten the memory clearing loop to use this location.

Just for a little history on this, it may not be obvious to everyone that all names in the code (both variables and routines) were assigned by me in order to not only make it readable but to also make it modifiable. The dissassembler only knows address locations. At first, I was able to re-assemble and get back to the original code only without any changes. Adding something as innocuous as a single NOP (no operation) which would normally just burn a couple of clock cycles would shift everything downstrean of the NOP by a single byte and invalidate all of the hard-coded labels. Although I kept everthing in its original order for the sake of binary comparisons, we should now be able to shuffle code routines and RAM locations (with a few limitations). The assembler does two passes on the code. The first pass resolves label locations. The labels are then converted to actual memory locations and plugged in on the second pass.

stevesprint

Original Poster:

1,114 posts

179 months

Saturday 12th November 2016
quotequote all
danbourassa said:
Mark L, I'm so glad that you are taking an interest in the assembler code. There is a lot that is not fully understood yet, so any help is appreciated.

Obviously, you realized that the actual battery preserved area is 32 bytes long and extends to $005F. The 14CUX code only uses $0040 through $0053 in this way and the rest is treated like normal volatile RAM.

Steve is correct about the fact that $0054 is actually used as a throttle pot minimum value. This is for the throttle pot self-learning feature. I know how the confusion happened and it's my fault. I just looked at file 'ramLocations.asm' and noticed that I never assigned a variable name to location $0054. Maybe the mistake happened because location $0053 is actually reassigned after it is no longer needed as a checksum, so it has two assigned names.

Using the end of the stack area is clever and probably safe to do. I assume you would shorten the memory clearing loop to use this location.

Just for a little history on this, it may not be obvious to everyone that all names in the code (both variables and routines) were assigned by me in order to not only make it readable but to also make it modifiable. The dissassembler only knows address locations. At first, I was able to re-assemble and get back to the original code only without any changes. Adding something as innocuous as a single NOP (no operation) which would normally just burn a couple of clock cycles would shift everything downstrean of the NOP by a single byte and invalidate all of the hard-coded labels. Although I kept everthing in its original order for the sake of binary comparisons, we should now be able to shuffle code routines and RAM locations (with a few limitations). The assembler does two passes on the code. The first pass resolves label locations. The labels are then converted to actual memory locations and plugged in on the second pass.
Dan,
You always manage to dive in and rescue me when I’m getting out of my depth, thank you. I’m also glad Mark L is interested in the code and I'm sure we’ll all learn more together as he is renewing our interest in the code with his new ideas.

Dave explained to me a long time ago about the symbol tables you created with all the variable and routine names you invented so the reversed engineered machine code is Human Dan readable and I will always be inpressed with the huge effort involved that most people don't realise. I’m equally impressed how Colin fixed and increased CRASM instruction set for the M6803U4 so we all can recompile the assembler code in Windows from one batch file.

Back to business
Dan, I see you are right only 32 bytes, According to the M6803U4 spec sheet below there are only 32 bytes of retainable RAM when powered down, therefore I would have thought near the end of the stack $EF is passed the RAM retained when powered down, ($0040 + 32 byte = $005F). If this is correct could Mark move one of working varables out of the retained RAM to free up a retained byte for the checksum fixer?



Mark, you can download all Dan's data sheets from www.remap-14cux.info/RebuildProject including this MC6803U4.pdf, they are sure to send you to sleep at night.

Edited by stevesprint on Saturday 12th November 21:13

danbourassa

246 posts

137 months

Saturday 12th November 2016
quotequote all
Yes, if Mark's value needs to survive a loss of main power, he needs a retained location. There are 3 files that use $0054. They are 'throttlePot.asm', 'shutDown.asm' and 'idleControl.asm'. Change the references to $0070 which is an unused location. Then $0054 will be free to use.

davep

1,143 posts

284 months

Saturday 12th November 2016
quotequote all
danbourassa said:
...I'm almost convinced that this is a completely useless sub-system and what I think should be done is the removal of the purge valve interrupt and all its related subroutines from the code.

There is one thing that could make me hesitate on this. Has anyone ever had a purge valve fault (code 88) and successfully fixed it by replacing the valve or canister?
Dan, since a good number of TVR owners have pruned the carbon canister and associated purge valve hardware out of the system I would expect fault code 88 to be commonplace. In these cases it's a shame that the 14CUX MPU is overlooked and remains burdened with having to comply with the purge interrupt, monitor HO2S levels, etc, etc, when in closed loop! I've looked for the earliest and most convenient point in the flow to take the purge code out but it's complicated by the fact that the main purge subroutine is called from other places, ECT for instance. Is it possible to simply disable the IRQ2 interrupt by tweaking the four purgeValveInt vectors in vectors.asm or is it hard coded?



danbourassa

246 posts

137 months

Saturday 12th November 2016
quotequote all
Dave, I think you confirmed what I suspected. The software is trying to detect something that is almost undetectable. It is also sending a pulse as narrow as 4 mSec to a solenoid valve that probably needs 50 mSec just to come off its seat. And it gets even more absurd. If the software can't even detect whether the incoming purge stream is present or not, how could it ever detect whether or not the stream still has fuel vapors in order to determine purge completion?

Since Steve_D's question, I have been looking at the purge valve code again. It may be possible to just disable the interrupt but I would prefer removing the subroutines as well. I hope to have more info on this soon.

stevesprint

Original Poster:

1,114 posts

179 months

Saturday 12th November 2016
quotequote all
Dan
Please confirm I've interpreted the folowing code correctly as it appears $0054 isn't actually updated/modifed where as throttlePotMinimum($0051/$0052) is re-calculated in throttlePot.asm or am I missing something?

idleControl.asm === $0054 copied to $0052 (throttle pot min)
ldaa $0054 ; throttle pot min
staa $0052 ; throttle pot min (battery saved)

throttlePot.asm === Subtracts value at $0054 from Accumulator A
suba $0054 ; the 8-bit TPMin working value??

shutDown.asm === $0054 copied to $0052 (throttle pot min)
ldaa $0054 ; load working value of Throttle Pot Minimum (TPmin)
staa $0052 ; store TPmin in battery backed RAM

eisdielenbiker

10 posts

93 months

Sunday 13th November 2016
quotequote all
$0053 and $0054 i.e. throttlePotMinCopy is only set in reset.asm:

;----------------------------
; Verify Battery-Backed RAM
;----------------------------
ldab ramControl ; check reliability of RAM (see mpu doc)
bpl .ramUnreliable ; branch ahead if battery-backed RAM is no good

jsr calcBatteryBackedChecksum ; this code executes when ram is reliable
tab ; Xfer sum from A to B
ldaa ramChecksum
cba ; Compare accumulators
bne .initDefaults ; Branch if bad checksum (battery backed)

ldd throttlePotMinimum ; if here, stored data in RAM is good
; std throttlePotMinCopy ; overwrites RAM checksum

I have just kicked out all references in any asm-file to this Label and will give it a try driving this afternoon. I dont see much sense in this location at all besides some possible fall back when much worse things effect in a fault code situation. That could occur only at Shutdown or Reset at all.

Mark L

davep

1,143 posts

284 months

Sunday 13th November 2016
quotequote all
danbourassa said:
Dave, I think you confirmed what I suspected. The software is trying to detect something that is almost undetectable. It is also sending a pulse as narrow as 4 mSec to a solenoid valve that probably needs 50 mSec just to come off its seat. And it gets even more absurd. If the software can't even detect whether the incoming purge stream is present or not, how could it ever detect whether or not the stream still has fuel vapors in order to determine purge completion?

Since Steve_D's question, I have been looking at the purge valve code again. It may be possible to just disable the interrupt but I would prefer removing the subroutines as well. I hope to have more info on this soon.
Dan, the purge feedback element is realised by HO2S monitoring (secondaryLambda) and a lot of assumption, isn't it? Where at up to 1720 RPM (start and warming up) the canister is vented regularly with short pulses, subsequently with engine up to temperature and fuel mixture running a tad lean now's a good time to vent the carbon canister, continue until there's no change in HO2S sensor lean activity and purge valve open so now's the time to stop venting and close the valve. Well that's my theory anyways.

Edited by davep on Sunday 13th November 11:13

danbourassa

246 posts

137 months

Sunday 13th November 2016
quotequote all
stevesprint said:
Dan
Please confirm I've interpreted the folowing code correctly as it appears $0054 isn't actually updated/modifed where as throttlePotMinimum($0051/$0052) is re-calculated in throttlePot.asm or am I missing something?
Steve, you're paying attention. That's a great observation that also fooled me initially. What you will find in the code is this:

std  X0053

That location gets modified in several places as the 2nd byte of a 2-byte store.

danbourassa

246 posts

137 months

Sunday 13th November 2016
quotequote all
It seems to me that both throttlePotMinCopy ($0053) and unnamedVariable ($0054) would need to be moved as a pair due to the double store. Locations $00A2 and $00A3 are both unused, so it may be possible to move them here. I mentioned earlier that variables can be freely moved with some limitations. This looks like one of those limitations.

danbourassa

246 posts

137 months

Sunday 13th November 2016
quotequote all
davep said:
Dan, the purge feedback element is realised by HO2S monitoring (secondaryLambda) and a lot of assumption, isn't it? Where at up to 1720 RPM (start and warming up) the canister is vented regularly with short pulses, subsequently with engine up to temperature and fuel mixture running a tad lean now's a good time to vent the carbon canister, continue until there's no change in HO2S sensor lean activity and purge valve open so now's the time to stop venting and close the valve. Well that's my theory anyways.
Dave, you may have it right about the assumptions. I just don't like the asynchronous nature of this interrupt and how it must be either be preempting other, more important code or delaying the spark interrupt. I'm not at a point yet where I understand it enough to remove it but maybe we can do it in two stages. The first, as you mentioned, would be just disabling it.