IAC Firmware related
Hints setting iac speed:
Firmware versions after 1.0.30 support iac_speed config variable to tweak pwm frequency/movement speed. If using a solenoid valve, freq of 100Hz is a good point to start, but it depends on the type/condition of valve of course. Willingnes of valve to move might change during the range it can reach: rarely used ranges (end positions probably) might be tighter than mid-range.
When freq is too high, valve gets lazy and won't react to small (~2-5 values with mdi commands) movement. If freq is too low, valve starts to follow physically the oscillation of pwm current and this causes valve internals to hit end positions when nearly value (f.e. mdi05, mdifa) is set. This can be heard as knocking noise from valve exactly at the frequency set.
Made some tables for setting desired iac_speed values quickly:
( [Source XLS] )
- Here's a [config] of a working BMW iac on M30B35 engine with 1.0.38 firmware. PID is far from perfect, but working.
Finally get a working battery and took a ride with the car, using firmware 1.0.30rc2 with the mods below.
Everything seemed fine, including IAC!
Looking at the logs made, I've found some strange behaviors (to me):
- Why IAC valve is automatically ON when TP is below iac_tps_thres? (neglecting RPM)
- the historical reason is that the control was first written for stepper-iac where it makes no sense to move back the pin to 0. But I agree, for a solenoid, it makes sense to unpower it.
- if you care about RPM, overrun_fuelcut can be useful for you
- Similarly, EGOC is reset to zero when TP < iac_tps_thres. (This means EGO correction is totally switched off at idle)
- try to remove (engine.status & (_BV(tpsaen) | _BV(tpsden))) || from ego.c. It's ment to prevent enrichening when overrun fuelcut pumps fresh air through the engine when a bad ego config is used that allows significant positive enrichment (see "Ego correction" on TuningSession/VEtuning that explains which ego-correction direction is sane).
Finally found the bug in 1.0.30rc2 vems.c:
#define IACFREQ_PWM (4 + (config.iac_speed & 0x3F))
#define IACFREQ_PWM ((4 + (config.iac_speed & 0x3F)) << 7)
Compiled the firmware with the change above and now the sound and reactions of my valve seems good. (However I couldn't start the car because my battery is dead - I love you, Murphy...)
actually <<8 should be <<7 te get the suggested range of max 244 Hz, but good find i was just working on it and reached the same conclusion :) - DB
This has been merged to stable in 1.0.30, enabled by configuring precise_idle, stepper=off and iac_conf bit5 (dualpwm) on. See GenBoard/UnderDevelopment/FirmwareChanges.
I'm testing firmware v30rc2 now, and it's almost OK, excepting my IAC...
I've set iac_speed=6 which should mean 97.65 Hz PWM freq.
It should be very close to factory 100Hz measurement, however I get very slow valve reaction (tested with mdi commands), or no reaction at all (small value changes).
Sound of the valve is quite different than with my good-old firmware, or stock motronic.
Checked the codes at iac.c and vems.c and implementations look very-very similar.
I have some measurements now, with soundcard.
Both of these wav files are recorded with very similar settings. These contain only one IAC channel (not sure whether the primary or the inverted signal), with IAC positions: 01-11-21-31-41-51-61-71-81-91-A1-B1-C1-D1-E1-F1.
The known-good v14RC1 with hacks (detailed below on this page):
And the new one with v30RC2:
Difference is obvious even by ear, but I don't see how this correlates with the firmware code yet. (I guess it has something to do with timing).
It seems that freq is too high (likely a documentation bug, check freq again). Period seems 4 msec instead of 8.
PWM switched ground to pin1 and pin3 moves the valve to opposite directions, if pin2 has stable 12V+ supply. Connecting pin1 to GND closes the valve.
Control relatively simple. Some changes and things to-check required in idle_solenoid() :
- 2 channels must be used instead of config.iac_sol_channel. However, I don't see a reason to add a config variable to make them independent. Eg. config.iac_sol_channel and config.iac_sol_channel+16 would work well (that means if mdh02/mdh82 is used for one solenoid, mdh12/mdh92 can be used for the other).
- if one solenoid is powered, the other must be unpowered. This can be remembered or done dumbly every time (SRAM/cycles tradeoff).
- iac_conf can be cleaned-up (while merging the unipolar-iac support) as on GenBoard/UnderDevelopment/FirmWare/PowerRelated to make space for the new bit that activates BAC-mode.
Changed the end of idle_solenoid() in iac.c so it sets 2 output channels instead of one:
cli(); digitalout(config.iac_sol_channel, output); sei_nop_cli(); digitalout(config.iac_sol_channel + 0x10, output ^ 0x80 ); sei();
config.iac_sol_channel has been set to 0x36 (stepper channel A)
This way 0x46 (stepper channel B) is inverted. Connections are according to GenBoard/Manual/DigitalOut/Table.
IAC control is working this way, I can use mdh/mdi commands and idle changes. For warm engine value around mdi70 seems a good approximation for 900 rpm. I've found that small changes to value doesn't reflect in rpm immediately (or at all). Big changes (like mdiff :) are noticeable promptly.
Idle controlled by GenBoard, but the idle controller (reference positions, ign-adv based control, iac-PID) is not yet tuned. Kindof instable now, see logs:
- What are the currently known good values used ? Recent config file would be appreciated. Trying firmware 1.0.73.
- [ Config and data saved in MegaSquirt]
- [Datalog (XLS) from megasquirt. I've made a chart in it also]
Definitely relative heavy actuator couldn't cope with such a high PWMming (2kHz), decreasing control frequency was reasonable. MembersPage/BengtR measured frequency from couple of 'similar' (but different part ie. Bosch part number vice) valves, they all were controlled with 50 to 150 hz signals.
I've modified the firmware to call the idle solenoid code with 100Hz frequency (20 times slower, than original solenoid freq in GenBoard). It seems to be working now, changes like 1-2 (hex) iac values reflected quickly in rpm.
- I've got strange behavior which might be firmware related (IAC setting). Every time I switch the ignition ON idle setting is OK according to iac_*_start_pos. Right before cranking it's jumping to 100% and then (while cranking) jumps back to the preset value. After it jumps again to 100% and slowly falling back to the right value. (Takes seconds, and engine is revving up to 2200 rpm). Engine status bits are suspicious to me but don't see the reason why this 100% IacDC? occurs. Please check my [XLS] logfile if interested.
As you might see on the picture, I started the engine, where 100% IAC happened, then falled back to "normal" levels, then fixed the setting to 70(?) manually, and at the end set it to 0.
I think that IAC behaviour (description above) happens quite normally when PID target rpm is not reached. However when cranking and immediately after the engine has started this causes bit high rpm. Note - that this is somewhat the kind of behaviour that original ECU's (Bosch, Weber, Siemens etc.) also has.
- Try to adjust iac_integral_limit_inc so you limit the max opening.
- Got it. Limit was way to much (226?), now I chosed a value similar to dec limit and it seems OK now!
- also, it seems that there is oscillation (when PID is allowed to control, not during the mdi70 session) that could be eliminated by proper PID tuning.
Adjusting gain and/or pid integrator values, rpm falling time to regulated idle rpm could be adjusted.
- Where to start adjusting for that? Do we have a writeup on idle control algorythm and meaning of parameters?
- of course you have: it's standard PID control with reference positions depending on coolant temp (iac_ref_pos), and sepearate integral limit for negative and positive (iac_integral_limit_dec and iac_integral_limit_inc).
- It seemed to me that this is not related to PID. According to the XLS above, I have iac value series like(in %): 40, 40, 40....40, 100, 100, 40, 40, 40, 100, 100, 99, 98, 97.. 42, 41, 40, 40....
- I've got a new idea about fluctuating idle, it might be related to the fact that I use 6 banks alternating inj config but no cam sync. Maybe it'd be better to fire them all at once while no camsync?
- I doubt, but easy to try (no wiring-change needed, just change h table)
TODO: drop this section as it gets merged to mainstream kernel
Using similar IAC valve? Check my firmware!
- Download my modified [iac.c] using 2 channels with inverted signals as mentioned above
- Download modified [vems.c] which is calling idle_solenoid() function at a 10ms interval
- or Download my compiled firmware [vems.hex] to burn.
All above is based on firmware v14rc1. Be careful of using the very next channel related to config.iac_sol_channel since it is hardcoded to produce my inverted IAC signal!
Can you provide a patch in "diff -r -U 5 -B olddir newdir" format ?
[HERE] you are. However I'm not sure it's usable :)
Actually I just compiled your changes after I copy & pasted them into rev23 code. For anybody that might want to try it:
[BMW Idle Control Rev23 Firmware] (everything same as in firmware copy in my_make other then turned off BENCHMARK flag) - Rename to .hex, have mapping issues on webserver doesn't like .hex
Note!!! I've tried it and something really wrong happened, flooded the engine with fuel, misfire, no IAC control at all, etc.
- It's obvious now, that flood was caused by an un(mis)configured channel (tach-out, new since v14) which caused an injector channel to be turned on a lot.