speeduino/speeduino/speeduino.ino

1709 lines
85 KiB
Arduino
Raw Normal View History

/*
Speeduino - Simple engine management for the Arduino Mega 2560 platform
Copyright (C) Josh Stewart
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,la
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
/** @file
* Speeduino initialisation and main loop.
*/
2019-07-08 00:56:02 -07:00
#include <stdint.h> //developer.mbed.org/handbook/C-Data-Types
//************************************************
#include "globals.h"
#include "speeduino.h"
#include "scheduler.h"
#include "comms.h"
#include "comms_legacy.h"
#include "comms_secondary.h"
#include "maths.h"
#include "corrections.h"
#include "timers.h"
#include "decoders.h"
#include "idle.h"
#include "auxiliaries.h"
#include "sensors.h"
#include "storage.h"
#include "crankMaths.h"
#include "init.h"
#include "utilities.h"
#include "engineProtection.h"
#include "scheduledIO.h"
#include "secondaryTables.h"
2023-10-12 18:25:05 -07:00
#include "comms_CAN.h"
2021-10-12 17:53:46 -07:00
#include "SD_logger.h"
#include "schedule_calcs.h"
#include "auxiliaries.h"
2021-10-12 18:42:52 -07:00
#include RTC_LIB_H //Defined in each boards .h file
#include BOARD_H //Note that this is not a real file, it is defined in globals.h.
uint16_t req_fuel_uS = 0; /**< The required fuel variable (As calculated by TunerStudio) in uS */
uint16_t inj_opentime_uS = 0;
uint8_t ignitionChannelsOn; /**< The current state of the ignition system (on or off) */
uint8_t ignitionChannelsPending = 0; /**< Any ignition channels that are pending injections before they are resumed */
uint8_t fuelChannelsOn; /**< The current state of the fuel system (on or off) */
uint32_t rollingCutLastRev = 0; /**< Tracks whether we're on the same or a different rev for the rolling cut */
uint16_t staged_req_fuel_mult_pri = 0;
uint16_t staged_req_fuel_mult_sec = 0;
#ifndef UNIT_TEST // Scope guard for unit testing
2022-11-05 15:43:29 -07:00
void setup(void)
{
2023-12-05 19:47:13 -08:00
currentStatus.initialisationComplete = false; //Tracks whether the initialiseAll() function has run completely
initialiseAll();
}
inline uint16_t applyFuelTrimToPW(trimTable3d *pTrimTable, int16_t fuelLoad, int16_t RPM, uint16_t currentPW)
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
uint8_t pw1percent = 100U + get3DTableValue(pTrimTable, fuelLoad, RPM) - OFFSET_FUELTRIM;
return percentage(pw1percent, currentPW);
}
/** Speeduino main loop.
*
* Main loop chores (roughly in the order that they are performed):
* - Check if serial comms or tooth logging are in progress (send or receive, prioritise communication)
* - Record loop timing vars
* - Check tooth time, update @ref statuses (currentStatus) variables
* - Read sensors
* - get VE for fuel calcs and spark advance for ignition
* - Check crank/cam/tooth/timing sync (skip remaining ops if out-of-sync)
* - execute doCrankSpeedCalcs()
*
* single byte variable @ref LOOP_TIMER plays a big part here as:
* - it contains expire-bits for interval based frequency driven events (e.g. 15Hz, 4Hz, 1Hz)
* - Can be tested for certain frequency interval being expired by (eg) BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)
*
*/
2022-11-05 15:43:29 -07:00
void loop(void)
{
mainLoopCount++;
LOOP_TIMER = TIMER_mask;
2020-08-04 22:11:51 -07:00
//SERIAL Comms
//Initially check that the last serial send values request is not still outstanding
Refactor comms: save 130+ bytes RAM (#906) * Remove serialCRC - only used within parseSerial() Also hoist the CRC read into a function. * Minimize global variable visibility * Encapsulate write of multi-byte primitives * Factor out sendBufferAndCrc() * Push safety test into TS_CommandButtonsHandler() * Extract writePage() * Simpler parsing * Remove some functions from public interface * Store constant arrays in progmem * Centralize high speed logger start/stop code * Factor out loadO2Calibration() * Factor out temperature calibration table update functions * Remove dead code * Fix sendToothLog() * Fix sendCompositeLog() * Replace tooth log send booleans with an enum Saves a byte * Remove sendBufferAndCrcProgMem() Use serialPayload to send * Whitespace clean up * Optimize comms.cpp for size * Replace global unsigned long with bool Saves 2 bytes * Replace 2 global bools with an enum Saves a byte, reads better. * Remove global FastCRC instance * Make sendSerialReturnCode blocking. It was using non-blocking functions but was never re-entered. Rename to make blocking & non-blocking calls more obvious. * Use one uint16_t to track RX/TX byte count * Simplify new comms log tx API * Extract loadPageToBuffer function * All endianess changes use the same code * Doxygen comments and code organization * Remove serialWriteUpdateCrc() & updateTmpCalibration() * Combine SerialStatus & logSendStatus enums. Makes sense since we can only be doing one thing at a time. * Remove global inProgressCompositeTime Only used when sending composite log * Replace 3 global bools with expanded SerialStatus enum * Remove unused global tsCanId * Limit scope of some comms globals. * Remove isMap global - replace witth function * Reduce the serial API to only 2 calls transmit & receive * Tidy up #define visibility * Fix Black* build errors * Workaround Teensy code race condition availableForWrite() is not reliable. * Prevent race condition Was pematurely setting the serialStatusFlag to SERIAL_INACTIVE before final CRC ws read from serial. * Use post write buffer availability checks Remove buffer size check prior to writing. * Write multi-byte values as single bytes. (attempt to fix Teensy 3.5 issue) * Only use Serial.available() as a boolean test (Teensy fix) * writeNonBlocking checks Serial.write() return value * Non-blocking CRC write In sendBufferAndCrcNonBlocking(). * Fix compile warning * Set serial status flag prior to transmitting! * Reliable blocking byte writes. * Fix timeout code: not firing under some conditions * MISRA fixes
2023-02-20 17:55:54 -08:00
if (serialTransmitInProgress())
{
Refactor comms: save 130+ bytes RAM (#906) * Remove serialCRC - only used within parseSerial() Also hoist the CRC read into a function. * Minimize global variable visibility * Encapsulate write of multi-byte primitives * Factor out sendBufferAndCrc() * Push safety test into TS_CommandButtonsHandler() * Extract writePage() * Simpler parsing * Remove some functions from public interface * Store constant arrays in progmem * Centralize high speed logger start/stop code * Factor out loadO2Calibration() * Factor out temperature calibration table update functions * Remove dead code * Fix sendToothLog() * Fix sendCompositeLog() * Replace tooth log send booleans with an enum Saves a byte * Remove sendBufferAndCrcProgMem() Use serialPayload to send * Whitespace clean up * Optimize comms.cpp for size * Replace global unsigned long with bool Saves 2 bytes * Replace 2 global bools with an enum Saves a byte, reads better. * Remove global FastCRC instance * Make sendSerialReturnCode blocking. It was using non-blocking functions but was never re-entered. Rename to make blocking & non-blocking calls more obvious. * Use one uint16_t to track RX/TX byte count * Simplify new comms log tx API * Extract loadPageToBuffer function * All endianess changes use the same code * Doxygen comments and code organization * Remove serialWriteUpdateCrc() & updateTmpCalibration() * Combine SerialStatus & logSendStatus enums. Makes sense since we can only be doing one thing at a time. * Remove global inProgressCompositeTime Only used when sending composite log * Replace 3 global bools with expanded SerialStatus enum * Remove unused global tsCanId * Limit scope of some comms globals. * Remove isMap global - replace witth function * Reduce the serial API to only 2 calls transmit & receive * Tidy up #define visibility * Fix Black* build errors * Workaround Teensy code race condition availableForWrite() is not reliable. * Prevent race condition Was pematurely setting the serialStatusFlag to SERIAL_INACTIVE before final CRC ws read from serial. * Use post write buffer availability checks Remove buffer size check prior to writing. * Write multi-byte values as single bytes. (attempt to fix Teensy 3.5 issue) * Only use Serial.available() as a boolean test (Teensy fix) * writeNonBlocking checks Serial.write() return value * Non-blocking CRC write In sendBufferAndCrcNonBlocking(). * Fix compile warning * Set serial status flag prior to transmitting! * Reliable blocking byte writes. * Fix timeout code: not firing under some conditions * MISRA fixes
2023-02-20 17:55:54 -08:00
serialTransmit();
}
Refactor comms: save 130+ bytes RAM (#906) * Remove serialCRC - only used within parseSerial() Also hoist the CRC read into a function. * Minimize global variable visibility * Encapsulate write of multi-byte primitives * Factor out sendBufferAndCrc() * Push safety test into TS_CommandButtonsHandler() * Extract writePage() * Simpler parsing * Remove some functions from public interface * Store constant arrays in progmem * Centralize high speed logger start/stop code * Factor out loadO2Calibration() * Factor out temperature calibration table update functions * Remove dead code * Fix sendToothLog() * Fix sendCompositeLog() * Replace tooth log send booleans with an enum Saves a byte * Remove sendBufferAndCrcProgMem() Use serialPayload to send * Whitespace clean up * Optimize comms.cpp for size * Replace global unsigned long with bool Saves 2 bytes * Replace 2 global bools with an enum Saves a byte, reads better. * Remove global FastCRC instance * Make sendSerialReturnCode blocking. It was using non-blocking functions but was never re-entered. Rename to make blocking & non-blocking calls more obvious. * Use one uint16_t to track RX/TX byte count * Simplify new comms log tx API * Extract loadPageToBuffer function * All endianess changes use the same code * Doxygen comments and code organization * Remove serialWriteUpdateCrc() & updateTmpCalibration() * Combine SerialStatus & logSendStatus enums. Makes sense since we can only be doing one thing at a time. * Remove global inProgressCompositeTime Only used when sending composite log * Replace 3 global bools with expanded SerialStatus enum * Remove unused global tsCanId * Limit scope of some comms globals. * Remove isMap global - replace witth function * Reduce the serial API to only 2 calls transmit & receive * Tidy up #define visibility * Fix Black* build errors * Workaround Teensy code race condition availableForWrite() is not reliable. * Prevent race condition Was pematurely setting the serialStatusFlag to SERIAL_INACTIVE before final CRC ws read from serial. * Use post write buffer availability checks Remove buffer size check prior to writing. * Write multi-byte values as single bytes. (attempt to fix Teensy 3.5 issue) * Only use Serial.available() as a boolean test (Teensy fix) * writeNonBlocking checks Serial.write() return value * Non-blocking CRC write In sendBufferAndCrcNonBlocking(). * Fix compile warning * Set serial status flag prior to transmitting! * Reliable blocking byte writes. * Fix timeout code: not firing under some conditions * MISRA fixes
2023-02-20 17:55:54 -08:00
//Check for any new or in-progress requests from serial.
if (Serial.available()>0 || serialRecieveInProgress())
{
Refactor comms: save 130+ bytes RAM (#906) * Remove serialCRC - only used within parseSerial() Also hoist the CRC read into a function. * Minimize global variable visibility * Encapsulate write of multi-byte primitives * Factor out sendBufferAndCrc() * Push safety test into TS_CommandButtonsHandler() * Extract writePage() * Simpler parsing * Remove some functions from public interface * Store constant arrays in progmem * Centralize high speed logger start/stop code * Factor out loadO2Calibration() * Factor out temperature calibration table update functions * Remove dead code * Fix sendToothLog() * Fix sendCompositeLog() * Replace tooth log send booleans with an enum Saves a byte * Remove sendBufferAndCrcProgMem() Use serialPayload to send * Whitespace clean up * Optimize comms.cpp for size * Replace global unsigned long with bool Saves 2 bytes * Replace 2 global bools with an enum Saves a byte, reads better. * Remove global FastCRC instance * Make sendSerialReturnCode blocking. It was using non-blocking functions but was never re-entered. Rename to make blocking & non-blocking calls more obvious. * Use one uint16_t to track RX/TX byte count * Simplify new comms log tx API * Extract loadPageToBuffer function * All endianess changes use the same code * Doxygen comments and code organization * Remove serialWriteUpdateCrc() & updateTmpCalibration() * Combine SerialStatus & logSendStatus enums. Makes sense since we can only be doing one thing at a time. * Remove global inProgressCompositeTime Only used when sending composite log * Replace 3 global bools with expanded SerialStatus enum * Remove unused global tsCanId * Limit scope of some comms globals. * Remove isMap global - replace witth function * Reduce the serial API to only 2 calls transmit & receive * Tidy up #define visibility * Fix Black* build errors * Workaround Teensy code race condition availableForWrite() is not reliable. * Prevent race condition Was pematurely setting the serialStatusFlag to SERIAL_INACTIVE before final CRC ws read from serial. * Use post write buffer availability checks Remove buffer size check prior to writing. * Write multi-byte values as single bytes. (attempt to fix Teensy 3.5 issue) * Only use Serial.available() as a boolean test (Teensy fix) * writeNonBlocking checks Serial.write() return value * Non-blocking CRC write In sendBufferAndCrcNonBlocking(). * Fix compile warning * Set serial status flag prior to transmitting! * Reliable blocking byte writes. * Fix timeout code: not firing under some conditions * MISRA fixes
2023-02-20 17:55:54 -08:00
serialReceive();
}
2023-12-05 19:47:13 -08:00
//Check for any CAN comms requiring action
#if defined(secondarySerial_AVAILABLE)
//if can or secondary serial interface is enabled then check for requests.
if (configPage9.enable_secondarySerial == 1) //secondary serial interface enabled
{
if ( ((mainLoopCount & 31) == 1) || (secondarySerial.available() > SERIAL_BUFFER_THRESHOLD) )
{
if (secondarySerial.available() > 0) { secondserial_Command(); }
2023-12-05 19:47:13 -08:00
}
}
#endif
#if defined (NATIVE_CAN_AVAILABLE)
if (configPage9.enable_intcan == 1) // use internal can module
{
//check local can module
// if ( BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ) or (CANbus0.available())
while (CAN_read())
{
can_Command();
readAuxCanBus();
Add support for RusEFI CAN Wideband based on STM32F042 (#1146) * CAN WBO Support * fix typo * Change data handling * add source repo information * Added heater functionality and fixed value handling * Missed 0 * Better condition handling and minor fixes to multiplication * Remove code duplication * fix * Error fixing and correct address of controller for outgoing frames * Page layout adjustment * fix * Second WBO added to be used in TS / MLV * Add extended flag to out frame * Functional test and fixes * typo * CAN WBO Support fix typo Change data handling add source repo information Added heater functionality and fixed value handling Missed 0 Better condition handling and minor fixes to multiplication Remove code duplication fix Error fixing and correct address of controller for outgoing frames Page layout adjustment fix Second WBO added to be used in TS / MLV Add extended flag to out frame Add support for BlitzBox hardware in speeduino firmware (#1148) * Add support for BlitzBox in init.cpp added case 42 for BlitzBox support * Added support for Blitzbox to speeduino.ini Added support for Blitzbox to speeduino.ini to get an ECU entry in Tunerstudio * Enabled spare pins in pin layout Functional test and fixes typo Fix issue with LED indicator not working when MC33810 was in use Resolve issue with Teensy not sending CAN msgs Fix regression on MC33810 units from af2815d818668d45d7fc271c195c03f0d9c7582e Added check for AFR greater than 25.5 Added overflow check of O2 value Code clean up Bump actions/upload-artifact from 3 to 4 (#1149) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Spelling and typo correction missing space * Fix possible overflow * Allow for future CAN based WBO modules to be added * rusEFI case as requested. * fix * CAN WBO Support * fix typo * Change data handling * add source repo information * Added heater functionality and fixed value handling * Missed 0 * Better condition handling and minor fixes to multiplication * Remove code duplication * fix * Error fixing and correct address of controller for outgoing frames * Page layout adjustment * fix * Second WBO added to be used in TS / MLV * Add extended flag to out frame * Functional test and fixes * typo * Allow for future CAN based WBO modules to be added * CAN WBO Support fix typo Change data handling add source repo information Added heater functionality and fixed value handling Missed 0 Better condition handling and minor fixes to multiplication Remove code duplication fix Error fixing and correct address of controller for outgoing frames Page layout adjustment fix Second WBO added to be used in TS / MLV Add extended flag to out frame Add support for BlitzBox hardware in speeduino firmware (#1148) * Add support for BlitzBox in init.cpp added case 42 for BlitzBox support * Added support for Blitzbox to speeduino.ini Added support for Blitzbox to speeduino.ini to get an ECU entry in Tunerstudio * Enabled spare pins in pin layout Functional test and fixes typo Fix issue with LED indicator not working when MC33810 was in use Resolve issue with Teensy not sending CAN msgs Fix regression on MC33810 units from af2815d818668d45d7fc271c195c03f0d9c7582e Added check for AFR greater than 25.5 Added overflow check of O2 value Code clean up Bump actions/upload-artifact from 3 to 4 (#1149) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Spelling and typo correction missing space * rusEFI case as requested. * Revert "Merge branch 'master' of https://github.com/dynfer/speeduino" This reverts commit 49dc0eab0814cd9e55435178ab0cbb74741b473a, reversing changes made to 56abc790086ba1b5f0d2efdbc7947c60c6b34f9a. * fix merge * fixes * Added overflow prevention * Final --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2024-02-04 02:34:29 -08:00
if (configPage2.canWBO > 0) { receiveCANwbo(); }
}
}
#endif
if(currentLoopTime > micros_safe())
{
//Occurs when micros() has overflowed
deferEEPROMWritesUntil = 0; //Required to ensure that EEPROM writes are not deferred indefinitely
}
currentLoopTime = micros_safe();
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
uint32_t timeToLastTooth = (currentLoopTime - toothLastToothTime);
if ( (timeToLastTooth < MAX_STALL_TIME) || (toothLastToothTime > currentLoopTime) ) //Check how long ago the last tooth was seen compared to now. If it was more than half a second ago then the engine is probably stopped. toothLastToothTime can be greater than currentLoopTime if a pulse occurs between getting the latest time and doing the comparison
{
2018-07-19 06:26:31 -07:00
currentStatus.longRPM = getRPM(); //Long RPM is included here
currentStatus.RPM = currentStatus.longRPM;
currentStatus.RPMdiv100 = div100(currentStatus.RPM);
if(currentStatus.RPM > 0)
{
FUEL_PUMP_ON();
currentStatus.fuelPumpOn = true;
}
}
else
{
//We reach here if the time between teeth is too great. This VERY likely means the engine has stopped
currentStatus.RPM = 0;
2022-04-09 16:07:21 -07:00
currentStatus.RPMdiv100 = 0;
currentStatus.PW1 = 0;
currentStatus.VE = 0;
currentStatus.VE2 = 0;
toothLastToothTime = 0;
toothLastSecToothTime = 0;
//toothLastMinusOneToothTime = 0;
currentStatus.hasSync = false;
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_HALFSYNC);
currentStatus.runSecs = 0; //Reset the counter for number of seconds running.
currentStatus.startRevolutions = 0;
toothSystemCount = 0;
secondaryToothCount = 0;
MAPcurRev = 0;
MAPcount = 0;
currentStatus.rpmDOT = 0;
AFRnextCycle = 0;
ignitionCount = 0;
ignitionChannelsOn = 0;
fuelChannelsOn = 0;
2023-12-05 19:47:13 -08:00
if (currentStatus.fpPrimed == true) { FUEL_PUMP_OFF(); currentStatus.fuelPumpOn = false; } //Turn off the fuel pump, but only if the priming is complete
if (configPage6.iacPWMrun == false) { disableIdle(); } //Turn off the idle PWM
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK); //Clear cranking bit (Can otherwise get stuck 'on' even with 0 rpm)
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_WARMUP); //Same as above except for WUE
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_RUN); //Same as above except for RUNNING status
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_ASE); //Same as above except for ASE status
2020-05-03 02:59:00 -07:00
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_ACC); //Same as above but the accel enrich (If using MAP accel enrich a stall will cause this to trigger)
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_DCC); //Same as above but the decel enleanment
//This is a safety check. If for some reason the interrupts have got screwed up (Leading to 0rpm), this resets them.
//It can possibly be run much less frequently.
//This should only be run if the high speed logger are off because it will change the trigger interrupts back to defaults rather than the logger versions
if( (currentStatus.toothLogEnabled == false) && (currentStatus.compositeTriggerUsed == 0) ) { initialiseTriggers(); }
VVT1_PIN_LOW();
VVT2_PIN_LOW();
DISABLE_VVT_TIMER();
boostDisable();
if(configPage4.ignBypassEnabled > 0) { digitalWrite(pinIgnBypass, LOW); } //Reset the ignition bypass ready for next crank attempt
}
//***Perform sensor reads***
//-----------------------------------------------------------------------------------------------------
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_1KHZ)) //Every 1ms. NOTE: This is NOT guaranteed to run at 1kHz on AVR systems. It will run at 1kHz if possible or as fast as loops/s allows if not.
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_1KHZ);
readMAP();
}
if(BIT_CHECK(LOOP_TIMER, BIT_TIMER_200HZ))
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_200HZ);
2023-12-05 19:47:13 -08:00
#if defined(ANALOG_ISR)
//ADC in free running mode does 1 complete conversion of all 16 channels and then the interrupt is disabled. Every 200Hz we re-enable the interrupt to get another conversion cycle
BIT_SET(ADCSRA,ADIE); //Enable ADC interrupt
#endif
}
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_15HZ)) //Every 32 loops
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_15HZ);
#if TPS_READ_FREQUENCY == 15
readTPS(); //TPS reading to be performed every 32 loops (any faster and it can upset the TPSdot sampling time)
#endif
2020-07-22 16:39:51 -07:00
#if defined(CORE_TEENSY35)
if (configPage9.enable_intcan == 1) // use internal can module
{
// this is just to test the interface is sending
//sendCancommand(3,((configPage9.realtime_base_address & 0x3FF)+ 0x100),currentStatus.TPS,0,0x200);
}
#endif
checkLaunchAndFlatShift(); //Check for launch control and flat shift being active
//And check whether the tooth log buffer is ready
2017-10-23 22:54:18 -07:00
if(toothHistoryIndex > TOOTH_LOG_SIZE) { BIT_SET(currentStatus.status1, BIT_STATUS1_TOOTHLOG1READY); }
2022-02-22 04:29:41 -08:00
}
if(BIT_CHECK(LOOP_TIMER, BIT_TIMER_10HZ)) //10 hertz
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_10HZ);
2021-02-01 20:45:13 -08:00
//updateFullStatus();
checkProgrammableIO();
idleControl(); //Perform any idle related actions. This needs to be run at 10Hz to align with the idle taper resolution of 0.1s
Air Conditioning Control - Feature Implementation (#665) * 19.09.2021 * Final testing of AC Control, some idle features fixed AC control feature added, better than the existing idle-up feature (which can still be used for other things, e.g. electrical load detection). Air conditioning is locked out with coolant temp, RPM high/low, and high TPS. So the A/C automatically cuts out when driving hard. Idle step now works correctly with closed loop PWM, open loop PWM, and closed+open loop PWM. Untested with stepper motor, but no reason it shouldn't work. * Fixed mistakenly incremented page sizes * Initial changes as per HWright9 -Renamed engineRunSeconds to acAfterEngineStartDelay -Formatted large if statements better -Fixed acStartDelay overflow bug -Improved readability of logic * Final fixes as per HWright9's feedback -Add high/low RPM lockout delay, similar to the high TPM lockout delay -General tidy-up * Added stand-alone fan, moved config data in EEPROM -Added additional configurable stand-alone A/C fan output, for when there is dedicated cooling fan for the A/C compressor. This is independent of the engine cooling fan logic. -Moved config storage in EEPROM to configPage9, as noisymime's SD card logging has used the (previously unused) bytes I had used in configPage13. -Minor bug fix - rename Aux in 1-16 to Aux in 0-15 * Revert to current master branch - as of master commit 97f8ef795a514c9a5693e85be6cdb8bdee8ef2c5 * A/C Control Re-Integrated from AC-Control-Clean-3 (@Corey-Harding). Tested & ready to merge. Additionally, added @HazuTo25's lines into the update() routine to configure default A/C settings. * Changed updates.ino to just set A/C to disabled * Fix change reverted by mistake - master merge commit 73badbce8ca171faa8c58575947917829adfc1ba * Fix remaining mistakes from previous master merge * Remove test statements left in by mistake * define unusedBits * Remove test statements left in by mistake * Increase timing granularity to 0.1s * idleUpRPMAdder * Remove another line put in by mistake by auto merge * idleUpRPMFixes * Update speeduino.ino * Tweak A/C idle up descriptions * Tweak A/C TS descriptors again * Fixed alignment bug that turned page 15 config values into gobbledegook. This had the symptom of the A/C request never triggering, because when a pin was assigned in TS (e.g. I did 27), a completely different pin would be read from config15 (in my case 22 - connecting the button to pin 22 would work in this case, even though TS was set to 27). * Fix bit count - should be 6 to match ini file * Increase minimum RPM lockout granularity * Change granularity of A/C minimum RPM lockout to 10 RPM; Inline some functions for readability * Add static inline function prototypes to auxiliaries.h as per the style guide. * Fixed page 15 merge errors * Style changes to suit new pinIsUsed() checks in setPinMappings() * Add PWM Fan Control Minimum Clamp Value when A/C Compressor Engaged * Fix comment * Fix bug with stand-alone fan initialisation Pin was unable to be used in prog. I/O even if fan was disabled, because it was always initialised as an output even if it was disabled. Fixed in this commit. * Correction to Fahrenheit temperature scaling * Move A/C updates to correct next release Co-authored-by: shiznit304 <62686180+shiznit304@users.noreply.github.com> Co-authored-by: Josh Stewart <josh@noisymime.org>
2022-09-06 17:23:01 -07:00
// Air conditioning control
airConControl();
2021-09-14 04:45:44 -07:00
currentStatus.vss = getSpeed();
currentStatus.gear = getGear();
2021-10-12 17:53:46 -07:00
#ifdef SD_LOGGING
if(configPage13.onboard_log_file_rate == LOGGER_RATE_10HZ) { writeSDLogEntry(); }
#endif
}
2017-09-17 17:38:49 -07:00
if(BIT_CHECK(LOOP_TIMER, BIT_TIMER_30HZ)) //30 hertz
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_30HZ);
2017-09-19 21:06:55 -07:00
//Most boost tends to run at about 30Hz, so placing it here ensures a new target time is fetched frequently enough
boostControl();
//VVT may eventually need to be synced with the cam readings (ie run once per cam rev) but for now run at 30Hz
vvtControl();
//Water methanol injection
wmiControl();
#if defined(NATIVE_CAN_AVAILABLE)
if (configPage2.canBMWCluster == true) { sendBMWCluster(); }
if (configPage2.canVAGCluster == true) { sendVAGCluster(); }
#endif
#if TPS_READ_FREQUENCY == 30
readTPS();
#endif
Add support for RusEFI CAN Wideband based on STM32F042 (#1146) * CAN WBO Support * fix typo * Change data handling * add source repo information * Added heater functionality and fixed value handling * Missed 0 * Better condition handling and minor fixes to multiplication * Remove code duplication * fix * Error fixing and correct address of controller for outgoing frames * Page layout adjustment * fix * Second WBO added to be used in TS / MLV * Add extended flag to out frame * Functional test and fixes * typo * CAN WBO Support fix typo Change data handling add source repo information Added heater functionality and fixed value handling Missed 0 Better condition handling and minor fixes to multiplication Remove code duplication fix Error fixing and correct address of controller for outgoing frames Page layout adjustment fix Second WBO added to be used in TS / MLV Add extended flag to out frame Add support for BlitzBox hardware in speeduino firmware (#1148) * Add support for BlitzBox in init.cpp added case 42 for BlitzBox support * Added support for Blitzbox to speeduino.ini Added support for Blitzbox to speeduino.ini to get an ECU entry in Tunerstudio * Enabled spare pins in pin layout Functional test and fixes typo Fix issue with LED indicator not working when MC33810 was in use Resolve issue with Teensy not sending CAN msgs Fix regression on MC33810 units from af2815d818668d45d7fc271c195c03f0d9c7582e Added check for AFR greater than 25.5 Added overflow check of O2 value Code clean up Bump actions/upload-artifact from 3 to 4 (#1149) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Spelling and typo correction missing space * Fix possible overflow * Allow for future CAN based WBO modules to be added * rusEFI case as requested. * fix * CAN WBO Support * fix typo * Change data handling * add source repo information * Added heater functionality and fixed value handling * Missed 0 * Better condition handling and minor fixes to multiplication * Remove code duplication * fix * Error fixing and correct address of controller for outgoing frames * Page layout adjustment * fix * Second WBO added to be used in TS / MLV * Add extended flag to out frame * Functional test and fixes * typo * Allow for future CAN based WBO modules to be added * CAN WBO Support fix typo Change data handling add source repo information Added heater functionality and fixed value handling Missed 0 Better condition handling and minor fixes to multiplication Remove code duplication fix Error fixing and correct address of controller for outgoing frames Page layout adjustment fix Second WBO added to be used in TS / MLV Add extended flag to out frame Add support for BlitzBox hardware in speeduino firmware (#1148) * Add support for BlitzBox in init.cpp added case 42 for BlitzBox support * Added support for Blitzbox to speeduino.ini Added support for Blitzbox to speeduino.ini to get an ECU entry in Tunerstudio * Enabled spare pins in pin layout Functional test and fixes typo Fix issue with LED indicator not working when MC33810 was in use Resolve issue with Teensy not sending CAN msgs Fix regression on MC33810 units from af2815d818668d45d7fc271c195c03f0d9c7582e Added check for AFR greater than 25.5 Added overflow check of O2 value Code clean up Bump actions/upload-artifact from 3 to 4 (#1149) Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Spelling and typo correction missing space * rusEFI case as requested. * Revert "Merge branch 'master' of https://github.com/dynfer/speeduino" This reverts commit 49dc0eab0814cd9e55435178ab0cbb74741b473a, reversing changes made to 56abc790086ba1b5f0d2efdbc7947c60c6b34f9a. * fix merge * fixes * Added overflow prevention * Final --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2024-02-04 02:34:29 -08:00
if (configPage2.canWBO == 0)
{
readO2();
readO2_2();
}
2021-10-12 17:53:46 -07:00
#ifdef SD_LOGGING
if(configPage13.onboard_log_file_rate == LOGGER_RATE_30HZ) { writeSDLogEntry(); }
#endif
2022-02-22 04:29:41 -08:00
//Check for any outstanding EEPROM writes.
Refactor comms: save 130+ bytes RAM (#906) * Remove serialCRC - only used within parseSerial() Also hoist the CRC read into a function. * Minimize global variable visibility * Encapsulate write of multi-byte primitives * Factor out sendBufferAndCrc() * Push safety test into TS_CommandButtonsHandler() * Extract writePage() * Simpler parsing * Remove some functions from public interface * Store constant arrays in progmem * Centralize high speed logger start/stop code * Factor out loadO2Calibration() * Factor out temperature calibration table update functions * Remove dead code * Fix sendToothLog() * Fix sendCompositeLog() * Replace tooth log send booleans with an enum Saves a byte * Remove sendBufferAndCrcProgMem() Use serialPayload to send * Whitespace clean up * Optimize comms.cpp for size * Replace global unsigned long with bool Saves 2 bytes * Replace 2 global bools with an enum Saves a byte, reads better. * Remove global FastCRC instance * Make sendSerialReturnCode blocking. It was using non-blocking functions but was never re-entered. Rename to make blocking & non-blocking calls more obvious. * Use one uint16_t to track RX/TX byte count * Simplify new comms log tx API * Extract loadPageToBuffer function * All endianess changes use the same code * Doxygen comments and code organization * Remove serialWriteUpdateCrc() & updateTmpCalibration() * Combine SerialStatus & logSendStatus enums. Makes sense since we can only be doing one thing at a time. * Remove global inProgressCompositeTime Only used when sending composite log * Replace 3 global bools with expanded SerialStatus enum * Remove unused global tsCanId * Limit scope of some comms globals. * Remove isMap global - replace witth function * Reduce the serial API to only 2 calls transmit & receive * Tidy up #define visibility * Fix Black* build errors * Workaround Teensy code race condition availableForWrite() is not reliable. * Prevent race condition Was pematurely setting the serialStatusFlag to SERIAL_INACTIVE before final CRC ws read from serial. * Use post write buffer availability checks Remove buffer size check prior to writing. * Write multi-byte values as single bytes. (attempt to fix Teensy 3.5 issue) * Only use Serial.available() as a boolean test (Teensy fix) * writeNonBlocking checks Serial.write() return value * Non-blocking CRC write In sendBufferAndCrcNonBlocking(). * Fix compile warning * Set serial status flag prior to transmitting! * Reliable blocking byte writes. * Fix timeout code: not firing under some conditions * MISRA fixes
2023-02-20 17:55:54 -08:00
if( (isEepromWritePending() == true) && (serialStatusFlag == SERIAL_INACTIVE) && (micros() > deferEEPROMWritesUntil)) { writeAllConfig(); }
}
2017-09-17 17:38:49 -07:00
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_4HZ))
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_4HZ);
2019-01-10 22:36:54 -08:00
//The IAT and CLT readings can be done less frequently (4 times per second)
readCLT();
readIAT();
readBat();
nitrousControl();
2021-10-12 17:53:46 -07:00
//Lookup the current target idle RPM. This is aligned with coolant and so needs to be calculated at the same rate CLT is read
if( (configPage2.idleAdvEnabled >= 1) || (configPage6.iacAlgorithm != IAC_ALGORITHM_NONE) )
{
currentStatus.CLIdleTarget = (byte)table2D_getValue(&idleTargetTable, currentStatus.coolant + CALIBRATION_TEMPERATURE_OFFSET); //All temps are offset by 40 degrees
Air Conditioning Control - Feature Implementation (#665) * 19.09.2021 * Final testing of AC Control, some idle features fixed AC control feature added, better than the existing idle-up feature (which can still be used for other things, e.g. electrical load detection). Air conditioning is locked out with coolant temp, RPM high/low, and high TPS. So the A/C automatically cuts out when driving hard. Idle step now works correctly with closed loop PWM, open loop PWM, and closed+open loop PWM. Untested with stepper motor, but no reason it shouldn't work. * Fixed mistakenly incremented page sizes * Initial changes as per HWright9 -Renamed engineRunSeconds to acAfterEngineStartDelay -Formatted large if statements better -Fixed acStartDelay overflow bug -Improved readability of logic * Final fixes as per HWright9's feedback -Add high/low RPM lockout delay, similar to the high TPM lockout delay -General tidy-up * Added stand-alone fan, moved config data in EEPROM -Added additional configurable stand-alone A/C fan output, for when there is dedicated cooling fan for the A/C compressor. This is independent of the engine cooling fan logic. -Moved config storage in EEPROM to configPage9, as noisymime's SD card logging has used the (previously unused) bytes I had used in configPage13. -Minor bug fix - rename Aux in 1-16 to Aux in 0-15 * Revert to current master branch - as of master commit 97f8ef795a514c9a5693e85be6cdb8bdee8ef2c5 * A/C Control Re-Integrated from AC-Control-Clean-3 (@Corey-Harding). Tested & ready to merge. Additionally, added @HazuTo25's lines into the update() routine to configure default A/C settings. * Changed updates.ino to just set A/C to disabled * Fix change reverted by mistake - master merge commit 73badbce8ca171faa8c58575947917829adfc1ba * Fix remaining mistakes from previous master merge * Remove test statements left in by mistake * define unusedBits * Remove test statements left in by mistake * Increase timing granularity to 0.1s * idleUpRPMAdder * Remove another line put in by mistake by auto merge * idleUpRPMFixes * Update speeduino.ino * Tweak A/C idle up descriptions * Tweak A/C TS descriptors again * Fixed alignment bug that turned page 15 config values into gobbledegook. This had the symptom of the A/C request never triggering, because when a pin was assigned in TS (e.g. I did 27), a completely different pin would be read from config15 (in my case 22 - connecting the button to pin 22 would work in this case, even though TS was set to 27). * Fix bit count - should be 6 to match ini file * Increase minimum RPM lockout granularity * Change granularity of A/C minimum RPM lockout to 10 RPM; Inline some functions for readability * Add static inline function prototypes to auxiliaries.h as per the style guide. * Fixed page 15 merge errors * Style changes to suit new pinIsUsed() checks in setPinMappings() * Add PWM Fan Control Minimum Clamp Value when A/C Compressor Engaged * Fix comment * Fix bug with stand-alone fan initialisation Pin was unable to be used in prog. I/O even if fan was disabled, because it was always initialised as an output even if it was disabled. Fixed in this commit. * Correction to Fahrenheit temperature scaling * Move A/C updates to correct next release Co-authored-by: shiznit304 <62686180+shiznit304@users.noreply.github.com> Co-authored-by: Josh Stewart <josh@noisymime.org>
2022-09-06 17:23:01 -07:00
if(BIT_CHECK(currentStatus.airConStatus, BIT_AIRCON_TURNING_ON)) { currentStatus.CLIdleTarget += configPage15.airConIdleUpRPMAdder; } //Adds Idle Up RPM amount if active
}
2021-10-12 17:53:46 -07:00
#ifdef SD_LOGGING
if(configPage13.onboard_log_file_rate == LOGGER_RATE_4HZ) { writeSDLogEntry(); }
2023-05-01 20:13:19 -07:00
syncSDLog(); //Sync the SD log file to the card 4 times per second.
2021-10-12 17:53:46 -07:00
#endif
2020-07-22 16:39:51 -07:00
currentStatus.fuelPressure = getFuelPressure();
currentStatus.oilPressure = getOilPressure();
Air Conditioning Control - Feature Implementation (#665) * 19.09.2021 * Final testing of AC Control, some idle features fixed AC control feature added, better than the existing idle-up feature (which can still be used for other things, e.g. electrical load detection). Air conditioning is locked out with coolant temp, RPM high/low, and high TPS. So the A/C automatically cuts out when driving hard. Idle step now works correctly with closed loop PWM, open loop PWM, and closed+open loop PWM. Untested with stepper motor, but no reason it shouldn't work. * Fixed mistakenly incremented page sizes * Initial changes as per HWright9 -Renamed engineRunSeconds to acAfterEngineStartDelay -Formatted large if statements better -Fixed acStartDelay overflow bug -Improved readability of logic * Final fixes as per HWright9's feedback -Add high/low RPM lockout delay, similar to the high TPM lockout delay -General tidy-up * Added stand-alone fan, moved config data in EEPROM -Added additional configurable stand-alone A/C fan output, for when there is dedicated cooling fan for the A/C compressor. This is independent of the engine cooling fan logic. -Moved config storage in EEPROM to configPage9, as noisymime's SD card logging has used the (previously unused) bytes I had used in configPage13. -Minor bug fix - rename Aux in 1-16 to Aux in 0-15 * Revert to current master branch - as of master commit 97f8ef795a514c9a5693e85be6cdb8bdee8ef2c5 * A/C Control Re-Integrated from AC-Control-Clean-3 (@Corey-Harding). Tested & ready to merge. Additionally, added @HazuTo25's lines into the update() routine to configure default A/C settings. * Changed updates.ino to just set A/C to disabled * Fix change reverted by mistake - master merge commit 73badbce8ca171faa8c58575947917829adfc1ba * Fix remaining mistakes from previous master merge * Remove test statements left in by mistake * define unusedBits * Remove test statements left in by mistake * Increase timing granularity to 0.1s * idleUpRPMAdder * Remove another line put in by mistake by auto merge * idleUpRPMFixes * Update speeduino.ino * Tweak A/C idle up descriptions * Tweak A/C TS descriptors again * Fixed alignment bug that turned page 15 config values into gobbledegook. This had the symptom of the A/C request never triggering, because when a pin was assigned in TS (e.g. I did 27), a completely different pin would be read from config15 (in my case 22 - connecting the button to pin 22 would work in this case, even though TS was set to 27). * Fix bit count - should be 6 to match ini file * Increase minimum RPM lockout granularity * Change granularity of A/C minimum RPM lockout to 10 RPM; Inline some functions for readability * Add static inline function prototypes to auxiliaries.h as per the style guide. * Fixed page 15 merge errors * Style changes to suit new pinIsUsed() checks in setPinMappings() * Add PWM Fan Control Minimum Clamp Value when A/C Compressor Engaged * Fix comment * Fix bug with stand-alone fan initialisation Pin was unable to be used in prog. I/O even if fan was disabled, because it was always initialised as an output even if it was disabled. Fixed in this commit. * Correction to Fahrenheit temperature scaling * Move A/C updates to correct next release Co-authored-by: shiznit304 <62686180+shiznit304@users.noreply.github.com> Co-authored-by: Josh Stewart <josh@noisymime.org>
2022-09-06 17:23:01 -07:00
if(auxIsEnabled == true)
{
2018-12-29 09:26:30 -08:00
//TODO dazq to clean this right up :)
//check through the Aux input channels if enabled for Can or local use
for (byte AuxinChan = 0; AuxinChan <16 ; AuxinChan++)
{
2018-12-29 09:26:30 -08:00
currentStatus.current_caninchannel = AuxinChan;
if (((configPage9.caninput_sel[currentStatus.current_caninchannel]&12) == 4)
&& (((configPage9.enable_secondarySerial == 1) && ((configPage9.enable_intcan == 0)&&(configPage9.intcan_available == 1)))
|| ((configPage9.enable_secondarySerial == 1) && ((configPage9.enable_intcan == 1)&&(configPage9.intcan_available == 1))&&
((configPage9.caninput_sel[currentStatus.current_caninchannel]&64) == 0))
|| ((configPage9.enable_secondarySerial == 1) && ((configPage9.enable_intcan == 1)&&(configPage9.intcan_available == 0)))))
{ //if current input channel is enabled as external & secondary serial enabled & internal can disabled(but internal can is available)
// or current input channel is enabled as external & secondary serial enabled & internal can enabled(and internal can is available)
//currentStatus.canin[13] = 11; Dev test use only!
if (configPage9.enable_secondarySerial == 1) // megas only support can via secondary serial
{
sendCancommand(2,0,currentStatus.current_caninchannel,0,((configPage9.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+0x100));
//send an R command for data from caninput_source_address[currentStatus.current_caninchannel] from secondarySerial
}
}
else if (((configPage9.caninput_sel[currentStatus.current_caninchannel]&12) == 4)
&& (((configPage9.enable_secondarySerial == 1) && ((configPage9.enable_intcan == 1)&&(configPage9.intcan_available == 1))&&
((configPage9.caninput_sel[currentStatus.current_caninchannel]&64) == 64))
|| ((configPage9.enable_secondarySerial == 0) && ((configPage9.enable_intcan == 1)&&(configPage9.intcan_available == 1))&&
((configPage9.caninput_sel[currentStatus.current_caninchannel]&128) == 128))))
{ //if current input channel is enabled as external for canbus & secondary serial enabled & internal can enabled(and internal can is available)
// or current input channel is enabled as external for canbus & secondary serial disabled & internal can enabled(and internal can is available)
//currentStatus.canin[13] = 12; Dev test use only!
#if defined(CORE_STM32) || defined(CORE_TEENSY)
if (configPage9.enable_intcan == 1) // if internal can is enabled
{
sendCancommand(3,configPage9.speeduino_tsCanId,currentStatus.current_caninchannel,0,((configPage9.caninput_source_can_address[currentStatus.current_caninchannel]&2047)+0x100));
//send an R command for data from caninput_source_address[currentStatus.current_caninchannel] from internal canbus
}
#endif
}
else if ((((configPage9.enable_secondarySerial == 1) || ((configPage9.enable_intcan == 1) && (configPage9.intcan_available == 1))) && (configPage9.caninput_sel[currentStatus.current_caninchannel]&12) == 8)
2018-12-29 09:26:30 -08:00
|| (((configPage9.enable_secondarySerial == 0) && ( (configPage9.enable_intcan == 1) && (configPage9.intcan_available == 0) )) && (configPage9.caninput_sel[currentStatus.current_caninchannel]&3) == 2)
|| (((configPage9.enable_secondarySerial == 0) && (configPage9.enable_intcan == 0)) && ((configPage9.caninput_sel[currentStatus.current_caninchannel]&3) == 2)))
{ //if current input channel is enabled as analog local pin
//read analog channel specified
//currentStatus.canin[13] = (configPage9.Auxinpina[currentStatus.current_caninchannel]&63); Dev test use only!127
currentStatus.canin[currentStatus.current_caninchannel] = readAuxanalog(pinTranslateAnalog(configPage9.Auxinpina[currentStatus.current_caninchannel]&63));
}
else if ((((configPage9.enable_secondarySerial == 1) || ((configPage9.enable_intcan == 1) && (configPage9.intcan_available == 1))) && (configPage9.caninput_sel[currentStatus.current_caninchannel]&12) == 12)
2018-12-29 09:26:30 -08:00
|| (((configPage9.enable_secondarySerial == 0) && ( (configPage9.enable_intcan == 1) && (configPage9.intcan_available == 0) )) && (configPage9.caninput_sel[currentStatus.current_caninchannel]&3) == 3)
|| (((configPage9.enable_secondarySerial == 0) && (configPage9.enable_intcan == 0)) && ((configPage9.caninput_sel[currentStatus.current_caninchannel]&3) == 3)))
{ //if current input channel is enabled as digital local pin
//read digital channel specified
//currentStatus.canin[14] = ((configPage9.Auxinpinb[currentStatus.current_caninchannel]&63)+1); Dev test use only!127+1
currentStatus.canin[currentStatus.current_caninchannel] = readAuxdigital((configPage9.Auxinpinb[currentStatus.current_caninchannel]&63)+1);
} //Channel type
} //For loop going through each channel
} //aux channels are enabled
} //4Hz timer
2017-09-17 17:38:49 -07:00
if (BIT_CHECK(LOOP_TIMER, BIT_TIMER_1HZ)) //Once per second)
{
BIT_CLEAR(TIMER_mask, BIT_TIMER_1HZ);
2017-09-17 17:38:49 -07:00
readBaro(); //Infrequent baro readings are not an issue.
2020-07-26 17:10:28 -07:00
if ( (configPage10.wmiEnabled > 0) && (configPage10.wmiIndicatorEnabled > 0) )
{
// water tank empty
if (BIT_CHECK(currentStatus.status4, BIT_STATUS4_WMI_EMPTY) > 0)
{
// flash with 1sec interval
digitalWrite(pinWMIIndicator, !digitalRead(pinWMIIndicator));
}
else
{
digitalWrite(pinWMIIndicator, configPage10.wmiIndicatorPolarity ? HIGH : LOW);
}
}
2021-10-12 17:53:46 -07:00
#ifdef SD_LOGGING
if(configPage13.onboard_log_file_rate == LOGGER_RATE_1HZ) { writeSDLogEntry(); }
#endif
} //1Hz timer
2021-12-08 13:52:56 -08:00
if( (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OL)
|| (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_CL)
|| (configPage6.iacAlgorithm == IAC_ALGORITHM_STEP_OLCL) )
{
idleControl(); //Run idlecontrol every loop for stepper idle.
}
//VE and advance calculation were moved outside the sync/RPM check so that the fuel and ignition load value will be accurately shown when RPM=0
currentStatus.VE1 = getVE1();
currentStatus.VE = currentStatus.VE1; //Set the final VE value to be VE 1 as a default. This may be changed in the section below
currentStatus.advance1 = getAdvance1();
currentStatus.advance = currentStatus.advance1; //Set the final advance value to be advance 1 as a default. This may be changed in the section below
calculateSecondaryFuel();
calculateSecondarySpark();
//Always check for sync
//Main loop runs within this clause
if ((currentStatus.hasSync || BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC)) && (currentStatus.RPM > 0))
{
2019-01-10 22:36:54 -08:00
//Check whether running or cranking
if(currentStatus.RPM > currentStatus.crankRPM) //Crank RPM in the config is stored as a x10. currentStatus.crankRPM is set in timers.ino and represents the true value
{
BIT_SET(currentStatus.engine, BIT_ENGINE_RUN); //Sets the engine running bit
//Only need to do anything if we're transitioning from cranking to running
if( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) )
{
2019-01-10 22:36:54 -08:00
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_CRANK);
2018-07-19 06:26:31 -07:00
if(configPage4.ignBypassEnabled > 0) { digitalWrite(pinIgnBypass, HIGH); }
}
}
else
2019-01-10 22:36:54 -08:00
{
if( !BIT_CHECK(currentStatus.engine, BIT_ENGINE_RUN) || (currentStatus.RPM < (currentStatus.crankRPM - CRANK_RUN_HYSTER)) )
{
//Sets the engine cranking bit, clears the engine running bit
BIT_SET(currentStatus.engine, BIT_ENGINE_CRANK);
BIT_CLEAR(currentStatus.engine, BIT_ENGINE_RUN);
currentStatus.runSecs = 0; //We're cranking (hopefully), so reset the engine run time to prompt ASE.
if(configPage4.ignBypassEnabled > 0) { digitalWrite(pinIgnBypass, LOW); }
//Check whether the user has selected to disable to the fan during cranking
if(configPage2.fanWhenCranking == 0) { FAN_OFF(); }
}
}
//END SETTING ENGINE STATUSES
//-----------------------------------------------------------------------------------------------------
//Begin the fuel calculation
//Calculate an injector pulsewidth from the VE
currentStatus.corrections = correctionsFuel();
currentStatus.PW1 = PW(req_fuel_uS, currentStatus.VE, currentStatus.MAP, currentStatus.corrections, inj_opentime_uS);
//Manual adder for nitrous. These are not in correctionsFuel() because they are direct adders to the ms value, not % based
if( (currentStatus.nitrous_status == NITROUS_STAGE1) || (currentStatus.nitrous_status == NITROUS_BOTH) )
{
int16_t adderRange = (configPage10.n2o_stage1_maxRPM - configPage10.n2o_stage1_minRPM) * 100;
int16_t adderPercent = ((currentStatus.RPM - (configPage10.n2o_stage1_minRPM * 100)) * 100) / adderRange; //The percentage of the way through the RPM range
adderPercent = 100 - adderPercent; //Flip the percentage as we go from a higher adder to a lower adder as the RPMs rise
currentStatus.PW1 = currentStatus.PW1 + (configPage10.n2o_stage1_adderMax + percentage(adderPercent, (configPage10.n2o_stage1_adderMin - configPage10.n2o_stage1_adderMax))) * 100; //Calculate the above percentage of the calculated ms value.
}
if( (currentStatus.nitrous_status == NITROUS_STAGE2) || (currentStatus.nitrous_status == NITROUS_BOTH) )
{
int16_t adderRange = (configPage10.n2o_stage2_maxRPM - configPage10.n2o_stage2_minRPM) * 100;
int16_t adderPercent = ((currentStatus.RPM - (configPage10.n2o_stage2_minRPM * 100)) * 100) / adderRange; //The percentage of the way through the RPM range
adderPercent = 100 - adderPercent; //Flip the percentage as we go from a higher adder to a lower adder as the RPMs rise
currentStatus.PW1 = currentStatus.PW1 + (configPage10.n2o_stage2_adderMax + percentage(adderPercent, (configPage10.n2o_stage2_adderMin - configPage10.n2o_stage2_adderMax))) * 100; //Calculate the above percentage of the calculated ms value.
}
int injector1StartAngle = 0;
uint16_t injector2StartAngle = 0;
uint16_t injector3StartAngle = 0;
uint16_t injector4StartAngle = 0;
2019-03-24 20:47:41 -07:00
#if INJ_CHANNELS >= 5
uint16_t injector5StartAngle = 0;
2019-03-24 20:47:41 -07:00
#endif
#if INJ_CHANNELS >= 6
uint16_t injector6StartAngle = 0;
2019-03-24 20:47:41 -07:00
#endif
#if INJ_CHANNELS >= 7
uint16_t injector7StartAngle = 0;
2019-03-24 20:47:41 -07:00
#endif
#if INJ_CHANNELS >= 8
uint16_t injector8StartAngle = 0;
2019-03-24 20:47:41 -07:00
#endif
2024-01-15 21:21:18 -08:00
2017-12-06 18:46:25 -08:00
//Check that the duty cycle of the chosen pulsewidth isn't too high.
uint16_t pwLimit = calculatePWLimit();
//Apply the pwLimit if staging is disabled and engine is not cranking
2018-07-19 06:26:31 -07:00
if( (!BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) && (configPage10.stagingEnabled == false) ) { if (currentStatus.PW1 > pwLimit) { currentStatus.PW1 = pwLimit; } }
2017-12-06 18:46:25 -08:00
calculateStaging(pwLimit);
//***********************************************************************************************
//BEGIN INJECTION TIMING
2021-12-08 20:55:40 -08:00
currentStatus.injAngle = table2D_getValue(&injectorAngleTable, currentStatus.RPMdiv100);
2024-01-15 21:21:18 -08:00
if(currentStatus.injAngle > uint16_t(CRANK_ANGLE_MAX_INJ)) { currentStatus.injAngle = uint16_t(CRANK_ANGLE_MAX_INJ); }
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
unsigned int PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW1); //How many crank degrees the calculated PW will take at the current speed
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector1StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
//Repeat the above for each cylinder
switch (configPage2.nCylinders)
{
2018-12-29 09:26:30 -08:00
//Single cylinder
case 1:
//The only thing that needs to be done for single cylinder is to check for staging.
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
2018-12-29 09:26:30 -08:00
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW2); //Need to redo this for PW2 as it will be dramatically different to PW1 when staging
//injector3StartAngle = calculateInjector3StartAngle(PWdivTimerPerDegree);
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
2018-12-29 09:26:30 -08:00
}
break;
//2 cylinders
case 2:
//injector2StartAngle = calculateInjector2StartAngle(PWdivTimerPerDegree);
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
if ( (configPage2.injLayout == INJ_SEQUENTIAL) && (configPage6.fuelTrimEnabled > 0) )
{
currentStatus.PW1 = applyFuelTrimToPW(&trim1Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW1);
currentStatus.PW2 = applyFuelTrimToPW(&trim2Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW2);
}
else if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
2018-12-29 09:26:30 -08:00
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW3); //Need to redo this for PW3 as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
2018-12-29 09:26:30 -08:00
injector4StartAngle = injector3StartAngle + (CRANK_ANGLE_MAX_INJ / 2); //Phase this either 180 or 360 degrees out from inj3 (In reality this will always be 180 as you can't have sequential and staged currently)
if(injector4StartAngle > (uint16_t)CRANK_ANGLE_MAX_INJ) { injector4StartAngle -= CRANK_ANGLE_MAX_INJ; }
}
break;
//3 cylinders
case 3:
//injector2StartAngle = calculateInjector2StartAngle(PWdivTimerPerDegree);
//injector3StartAngle = calculateInjector3StartAngle(PWdivTimerPerDegree);
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
if ( (configPage2.injLayout == INJ_SEQUENTIAL) && (configPage6.fuelTrimEnabled > 0) )
{
currentStatus.PW1 = applyFuelTrimToPW(&trim1Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW1);
currentStatus.PW2 = applyFuelTrimToPW(&trim2Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW2);
currentStatus.PW3 = applyFuelTrimToPW(&trim3Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW3);
#if INJ_CHANNELS >= 6
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW4); //Need to redo this for PW4 as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
}
#endif
}
else if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW4); //Need to redo this for PW3 as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
#if INJ_CHANNELS >= 6
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
#endif
}
break;
//4 cylinders
case 4:
//injector2StartAngle = calculateInjector2StartAngle(PWdivTimerPerDegree);
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
if((configPage2.injLayout == INJ_SEQUENTIAL) && currentStatus.hasSync)
{
if( CRANK_ANGLE_MAX_INJ != 720 ) { changeHalfToFullSync(); }
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel4InjDegrees, currentStatus.injAngle);
#if INJ_CHANNELS >= 8
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW5); //Need to redo this for PW5 as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector7StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
injector8StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel4InjDegrees, currentStatus.injAngle);
}
#endif
2018-07-19 06:26:31 -07:00
if(configPage6.fuelTrimEnabled > 0)
{
currentStatus.PW1 = applyFuelTrimToPW(&trim1Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW1);
currentStatus.PW2 = applyFuelTrimToPW(&trim2Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW2);
currentStatus.PW3 = applyFuelTrimToPW(&trim3Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW3);
currentStatus.PW4 = applyFuelTrimToPW(&trim4Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW4);
}
}
else if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
2017-12-06 18:46:25 -08:00
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW3); //Need to redo this for PW3 as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
2017-12-06 18:46:25 -08:00
}
else
{
if( BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) && (CRANK_ANGLE_MAX_INJ != 360) ) { changeFullToHalfSync(); }
}
break;
//5 cylinders
case 5:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel4InjDegrees, currentStatus.injAngle);
2019-03-24 20:47:41 -07:00
#if INJ_CHANNELS >= 5
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel5InjDegrees, currentStatus.injAngle);
2019-03-24 20:47:41 -07:00
#endif
//Staging is possible by using the 6th channel if available
#if INJ_CHANNELS >= 6
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW6);
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel6InjDegrees, currentStatus.injAngle);
}
#endif
break;
//6 cylinders
case 6:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
2019-03-24 20:47:41 -07:00
#if INJ_CHANNELS >= 6
if((configPage2.injLayout == INJ_SEQUENTIAL) && currentStatus.hasSync)
2019-03-24 20:47:41 -07:00
{
if( CRANK_ANGLE_MAX_INJ != 720 ) { changeHalfToFullSync(); }
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel4InjDegrees, currentStatus.injAngle);
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel5InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel6InjDegrees, currentStatus.injAngle);
2021-02-14 21:01:28 -08:00
if(configPage6.fuelTrimEnabled > 0)
{
currentStatus.PW1 = applyFuelTrimToPW(&trim1Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW1);
currentStatus.PW2 = applyFuelTrimToPW(&trim2Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW2);
currentStatus.PW3 = applyFuelTrimToPW(&trim3Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW3);
currentStatus.PW4 = applyFuelTrimToPW(&trim4Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW4);
currentStatus.PW5 = applyFuelTrimToPW(&trim5Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW5);
currentStatus.PW6 = applyFuelTrimToPW(&trim6Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW6);
2021-02-14 21:01:28 -08:00
}
//Staging is possible with sequential on 8 channel boards by using outputs 7 + 8 for the staged injectors
#if INJ_CHANNELS >= 8
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW4); //Need to redo this for staging PW as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
}
#endif
2019-03-24 20:47:41 -07:00
}
else
{
if( BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) && (CRANK_ANGLE_MAX_INJ != 360) ) { changeFullToHalfSync(); }
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW4); //Need to redo this for staging PW as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
}
}
2019-03-24 20:47:41 -07:00
#endif
break;
//8 cylinders
case 8:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector2StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector3StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
injector4StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel4InjDegrees, currentStatus.injAngle);
#if INJ_CHANNELS >= 8
if((configPage2.injLayout == INJ_SEQUENTIAL) && currentStatus.hasSync)
{
if( CRANK_ANGLE_MAX_INJ != 720 ) { changeHalfToFullSync(); }
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel5InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel6InjDegrees, currentStatus.injAngle);
injector7StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel7InjDegrees, currentStatus.injAngle);
injector8StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel8InjDegrees, currentStatus.injAngle);
2021-02-14 21:01:28 -08:00
if(configPage6.fuelTrimEnabled > 0)
{
currentStatus.PW1 = applyFuelTrimToPW(&trim1Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW1);
currentStatus.PW2 = applyFuelTrimToPW(&trim2Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW2);
currentStatus.PW3 = applyFuelTrimToPW(&trim3Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW3);
currentStatus.PW4 = applyFuelTrimToPW(&trim4Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW4);
currentStatus.PW5 = applyFuelTrimToPW(&trim5Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW5);
currentStatus.PW6 = applyFuelTrimToPW(&trim6Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW6);
currentStatus.PW7 = applyFuelTrimToPW(&trim7Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW7);
currentStatus.PW8 = applyFuelTrimToPW(&trim8Table, currentStatus.fuelLoad, currentStatus.RPM, currentStatus.PW8);
2021-02-14 21:01:28 -08:00
}
}
else
{
if( BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) && (CRANK_ANGLE_MAX_INJ != 360) ) { changeFullToHalfSync(); }
if( (configPage10.stagingEnabled == true) && (BIT_CHECK(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE) == true) )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
PWdivTimerPerDegree = timeToAngleDegPerMicroSec(currentStatus.PW5); //Need to redo this for PW3 as it will be dramatically different to PW1 when staging
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
injector5StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel1InjDegrees, currentStatus.injAngle);
injector6StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel2InjDegrees, currentStatus.injAngle);
injector7StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel3InjDegrees, currentStatus.injAngle);
injector8StartAngle = calculateInjectorStartAngle(PWdivTimerPerDegree, channel4InjDegrees, currentStatus.injAngle);
}
}
#endif
break;
2018-12-29 09:26:30 -08:00
//Will hit the default case on 1 cylinder or >8 cylinders. Do nothing in these cases
default:
break;
}
//***********************************************************************************************
//| BEGIN IGNITION CALCULATIONS
//Set dwell
//Dwell is stored as ms * 10. ie Dwell of 4.3ms would be 43 in configPage4. This number therefore needs to be multiplied by 100 to get dwell in uS
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) ) {
currentStatus.dwell = (configPage4.dwellCrank * 100U); //use cranking dwell
}
else
{
if ( configPage2.useDwellMap == true )
{
currentStatus.dwell = (get3DTableValue(&dwellTable, currentStatus.ignLoad, currentStatus.RPM) * 100U); //use running dwell from map
}
else
{
currentStatus.dwell = (configPage4.dwellRun * 100U); //use fixed running dwell
}
}
currentStatus.dwell = correctionsDwell(currentStatus.dwell);
// Convert the dwell time to dwell angle based on the current engine speed
calculateIgnitionAngles(timeToAngleDegPerMicroSec(currentStatus.dwell));
//If ignition timing is being tracked per tooth, perform the calcs to get the end teeth
//This only needs to be run if the advance figure has changed, otherwise the end teeth will still be the same
2020-02-16 00:54:52 -08:00
//if( (configPage2.perToothIgn == true) && (lastToothCalcAdvance != currentStatus.advance) ) { triggerSetEndTeeth(); }
if( (configPage2.perToothIgn == true) ) { triggerSetEndTeeth(); }
//***********************************************************************************************
//| BEGIN FUEL SCHEDULES
//Finally calculate the time (uS) until we reach the firing angles and set the schedules
//We only need to set the schedule if we're BEFORE the open angle
//This may potentially be called a number of times as we get closer and closer to the opening time
//Determine the current crank angle
int crankAngle = injectorLimits(getCrankAngle());
// if(Serial && false)
// {
// if(ignition1StartAngle > crankAngle)
// {
// noInterrupts();
// Serial.print("Time2LastTooth:"); Serial.println(micros()-toothLastToothTime);
// Serial.print("elapsedTime:"); Serial.println(elapsedTime);
// Serial.print("CurAngle:"); Serial.println(crankAngle);
// Serial.print("RPM:"); Serial.println(currentStatus.RPM);
// Serial.print("Tooth:"); Serial.println(toothCurrentCount);
// Serial.print("timePerDegree:"); Serial.println(timePerDegree);
// Serial.print("IGN1Angle:"); Serial.println(ignition1StartAngle);
// Serial.print("TimeToIGN1:"); Serial.println(angleToTime((ignition1StartAngle - crankAngle), CRANKMATH_METHOD_INTERVAL_REV));
// interrupts();
// }
// }
//Check for any of the engine protections or rev limiters being turned on
uint16_t maxAllowedRPM = checkRevLimit(); //The maximum RPM allowed by all the potential limiters (Engine protection, 2-step, flat shift etc). Divided by 100. `checkRevLimit()` returns the current maximum RPM allow (divided by 100) based on either the fixed hard limit or the current coolant temp
//Check each of the functions that has an RPM limit. Update the max allowed RPM if the function is active and has a lower RPM than already set
if( checkEngineProtect() && (configPage4.engineProtectMaxRPM < maxAllowedRPM)) { maxAllowedRPM = configPage4.engineProtectMaxRPM; }
if ( (currentStatus.launchingHard == true) && (configPage6.lnchHardLim < maxAllowedRPM) ) { maxAllowedRPM = configPage6.lnchHardLim; }
maxAllowedRPM = maxAllowedRPM * 100; //All of the above limits are divided by 100, convert back to RPM
if ( (currentStatus.flatShiftingHard == true) && (currentStatus.clutchEngagedRPM < maxAllowedRPM) ) { maxAllowedRPM = currentStatus.clutchEngagedRPM; } //Flat shifting is a special case as the RPM limit is based on when the clutch was engaged. It is not divided by 100 as it is set with the actual RPM
if( (configPage2.hardCutType == HARD_CUT_FULL) && (currentStatus.RPM > maxAllowedRPM) )
{
//Full hard cut turns outputs off completely.
switch(configPage6.engineProtectType)
{
case PROTECT_CUT_OFF:
//Make sure all channels are turned on
ignitionChannelsOn = 0xFF;
fuelChannelsOn = 0xFF;
currentStatus.engineProtectStatus = 0;
break;
case PROTECT_CUT_IGN:
ignitionChannelsOn = 0;
break;
case PROTECT_CUT_FUEL:
fuelChannelsOn = 0;
break;
case PROTECT_CUT_BOTH:
ignitionChannelsOn = 0;
fuelChannelsOn = 0;
break;
default:
ignitionChannelsOn = 0;
fuelChannelsOn = 0;
break;
}
} //Hard cut check
else if( (configPage2.hardCutType == HARD_CUT_ROLLING) && (currentStatus.RPM > (maxAllowedRPM + (configPage15.rollingProtRPMDelta[0] * 10))) ) //Limit for rolling is the max allowed RPM minus the lowest value in the delta table (Delta values are negative!)
{
uint8_t revolutionsToCut = 1;
if(configPage2.strokes == FOUR_STROKE) { revolutionsToCut *= 2; } //4 stroke needs to cut for at least 2 revolutions
if( (configPage4.sparkMode != IGN_MODE_SEQUENTIAL) || (configPage2.injLayout != INJ_SEQUENTIAL) ) { revolutionsToCut *= 2; } //4 stroke and non-sequential will cut for 4 revolutions minimum. This is to ensure no half fuel ignition cycles take place
if(rollingCutLastRev == 0) { rollingCutLastRev = currentStatus.startRevolutions; } //First time check
if ( (currentStatus.startRevolutions >= (rollingCutLastRev + revolutionsToCut)) || (currentStatus.RPM > maxAllowedRPM) ) //If current RPM is over the max allowed RPM always cut, otherwise check if the required number of revolutions have passed since the last cut
{
uint8_t cutPercent = 0;
int16_t rpmDelta = currentStatus.RPM - maxAllowedRPM;
if(rpmDelta >= 0) { cutPercent = 100; } //If the current RPM is over the max allowed RPM then cut is full (100%)
else { cutPercent = table2D_getValue(&rollingCutTable, (rpmDelta / 10) ); } //
for(uint8_t x=0; x<max(maxIgnOutputs, maxInjOutputs); x++)
{
if( (cutPercent == 100) || (random1to100() < cutPercent) )
{
switch(configPage6.engineProtectType)
{
case PROTECT_CUT_OFF:
//Make sure all channels are turned on
ignitionChannelsOn = 0xFF;
fuelChannelsOn = 0xFF;
break;
case PROTECT_CUT_IGN:
BIT_CLEAR(ignitionChannelsOn, x); //Turn off this ignition channel
disablePendingIgnSchedule(x);
break;
case PROTECT_CUT_FUEL:
BIT_CLEAR(fuelChannelsOn, x); //Turn off this fuel channel
disablePendingFuelSchedule(x);
break;
case PROTECT_CUT_BOTH:
BIT_CLEAR(ignitionChannelsOn, x); //Turn off this ignition channel
BIT_CLEAR(fuelChannelsOn, x); //Turn off this fuel channel
disablePendingFuelSchedule(x);
disablePendingIgnSchedule(x);
break;
default:
BIT_CLEAR(ignitionChannelsOn, x); //Turn off this ignition channel
BIT_CLEAR(fuelChannelsOn, x); //Turn off this fuel channel
break;
}
}
else
{
//Turn fuel and ignition channels on
//Special case for non-sequential, 4-stroke where both fuel and ignition are cut. The ignition pulses should wait 1 cycle after the fuel channels are turned back on before firing again
if( (revolutionsToCut == 4) && //4 stroke and non-sequential
(BIT_CHECK(fuelChannelsOn, x) == false) && //Fuel on this channel is currently off, meaning it is the first revolution after a cut
(configPage6.engineProtectType == PROTECT_CUT_BOTH) //Both fuel and ignition are cut
)
{ BIT_SET(ignitionChannelsPending, x); } //Set this ignition channel as pending
else { BIT_SET(ignitionChannelsOn, x); } //Turn on this ignition channel
BIT_SET(fuelChannelsOn, x); //Turn on this fuel channel
}
}
rollingCutLastRev = currentStatus.startRevolutions;
}
//Check whether there are any ignition channels that are waiting for injection pulses to occur before being turned back on. This can only occur when at least 2 revolutions have taken place since the fuel was turned back on
//Note that ignitionChannelsPending can only be >0 on 4 stroke, non-sequential fuel when protect type is Both
if( (ignitionChannelsPending > 0) && (currentStatus.startRevolutions >= (rollingCutLastRev + 2)) )
{
ignitionChannelsOn = fuelChannelsOn;
ignitionChannelsPending = 0;
}
} //Rolling cut check
else
{
currentStatus.engineProtectStatus = 0;
//No engine protection active, so turn all the channels on
if(currentStatus.startRevolutions >= configPage4.StgCycles)
{
//Enable the fuel and ignition, assuming staging revolutions are complete
ignitionChannelsOn = 0xff;
fuelChannelsOn = 0xff;
}
}
#if INJ_CHANNELS >= 1
if( (maxInjOutputs >= 1) && (currentStatus.PW1 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ1_CMD_BIT)) )
{
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule1, channel1InjDegrees, injector1StartAngle, crankAngle);
if (timeOut>0U)
{
setFuelSchedule(fuelSchedule1,
timeOut,
(unsigned long)currentStatus.PW1
);
}
}
#endif
/*-----------------------------------------------------------------------------------------
| A Note on tempCrankAngle and tempStartAngle:
| The use of tempCrankAngle/tempStartAngle is described below. It is then used in the same way for channels 2, 3 and 4+ on both injectors and ignition
| Essentially, these 2 variables are used to realign the current crank angle and the desired start angle around 0 degrees for the given cylinder/output
| Eg: If cylinder 2 TDC is 180 degrees after cylinder 1 (Eg a standard 4 cylinder engine), then tempCrankAngle is 180* less than the current crank angle and
| tempStartAngle is the desired open time less 180*. Thus the cylinder is being treated relative to its own TDC, regardless of its offset
|
| This is done to avoid problems with very short of very long times until tempStartAngle.
|------------------------------------------------------------------------------------------
*/
#if INJ_CHANNELS >= 2
if( (maxInjOutputs >= 2) && (currentStatus.PW2 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ2_CMD_BIT)) )
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule2, channel2InjDegrees, injector2StartAngle, crankAngle);
if ( timeOut>0U )
{
setFuelSchedule(fuelSchedule2,
timeOut,
(unsigned long)currentStatus.PW2
);
}
}
#endif
#if INJ_CHANNELS >= 3
if( (maxInjOutputs >= 3) && (currentStatus.PW3 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ3_CMD_BIT)) )
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule3, channel3InjDegrees, injector3StartAngle, crankAngle);
if ( timeOut>0U )
{
setFuelSchedule(fuelSchedule3,
timeOut,
(unsigned long)currentStatus.PW3
);
}
}
#endif
#if INJ_CHANNELS >= 4
if( (maxInjOutputs >= 4) && (currentStatus.PW4 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ4_CMD_BIT)) )
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule4, channel4InjDegrees, injector4StartAngle, crankAngle);
if ( timeOut>0U )
{
setFuelSchedule(fuelSchedule4,
timeOut,
(unsigned long)currentStatus.PW4
);
}
}
#endif
#if INJ_CHANNELS >= 5
if( (maxInjOutputs >= 5) && (currentStatus.PW5 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ5_CMD_BIT)) )
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule5, channel5InjDegrees, injector5StartAngle, crankAngle);
if ( timeOut>0U )
{
setFuelSchedule(fuelSchedule5,
timeOut,
(unsigned long)currentStatus.PW5
);
}
}
#endif
#if INJ_CHANNELS >= 6
if( (maxInjOutputs >= 6) && (currentStatus.PW6 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ6_CMD_BIT)) )
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule6, channel6InjDegrees, injector6StartAngle, crankAngle);
if ( timeOut>0U )
{
setFuelSchedule(fuelSchedule6,
timeOut,
2018-01-22 21:14:03 -08:00
(unsigned long)currentStatus.PW6
);
}
}
#endif
#if INJ_CHANNELS >= 7
if( (maxInjOutputs >= 7) && (currentStatus.PW7 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ7_CMD_BIT)) )
2018-01-22 21:14:03 -08:00
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule7, channel7InjDegrees, injector7StartAngle, crankAngle);
if ( timeOut>0U )
2018-01-22 21:14:03 -08:00
{
setFuelSchedule(fuelSchedule7,
timeOut,
2018-01-22 21:14:03 -08:00
(unsigned long)currentStatus.PW7
);
}
}
#endif
#if INJ_CHANNELS >= 8
if( (maxInjOutputs >= 8) && (currentStatus.PW8 >= inj_opentime_uS) && (BIT_CHECK(fuelChannelsOn, INJ8_CMD_BIT)) )
2018-01-22 21:14:03 -08:00
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateInjectorTimeout(fuelSchedule8, channel8InjDegrees, injector8StartAngle, crankAngle);
if ( timeOut>0U )
2018-01-22 21:14:03 -08:00
{
setFuelSchedule(fuelSchedule8,
timeOut,
2018-01-22 21:14:03 -08:00
(unsigned long)currentStatus.PW8
);
}
}
#endif
//***********************************************************************************************
//| BEGIN IGNITION SCHEDULES
2019-01-10 22:36:54 -08:00
//Same as above, except for ignition
//fixedCrankingOverride is used to extend the dwell during cranking so that the decoder can trigger the spark upon seeing a certain tooth. Currently only available on the basic distributor and 4g63 decoders.
if ( configPage4.ignCranklock && BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK) && (BIT_CHECK(decoderState, BIT_DECODER_HAS_FIXED_CRANKING)) )
{
fixedCrankingOverride = currentStatus.dwell * 3;
//This is a safety step to prevent the ignition start time occurring AFTER the target tooth pulse has already occurred. It simply moves the start time forward a little, which is compensated for by the increase in the dwell time
if(currentStatus.RPM < 250)
{
ignition1StartAngle -= 5;
2018-04-20 00:02:35 -07:00
ignition2StartAngle -= 5;
ignition3StartAngle -= 5;
ignition4StartAngle -= 5;
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
#if IGN_CHANNELS >= 5
ignition5StartAngle -= 5;
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
#endif
#if IGN_CHANNELS >= 6
ignition6StartAngle -= 5;
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
#endif
#if IGN_CHANNELS >= 7
ignition7StartAngle -= 5;
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
#endif
#if IGN_CHANNELS >= 8
ignition8StartAngle -= 5;
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
#endif
}
}
else { fixedCrankingOverride = 0; }
if(ignitionChannelsOn > 0)
{
//Refresh the current crank angle info
//ignition1StartAngle = 335;
crankAngle = ignitionLimits(getCrankAngle()); //Refresh the crank angle info
#if IGN_CHANNELS >= 1
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
uint32_t timeOut = calculateIgnitionTimeout(ignitionSchedule1, ignition1StartAngle, channel1IgnDegrees, crankAngle);
if ( (timeOut > 0U) && (BIT_CHECK(ignitionChannelsOn, IGN1_CMD_BIT)) )
{
setIgnitionSchedule(ignitionSchedule1, timeOut,
currentStatus.dwell + fixedCrankingOverride);
}
#endif
#if defined(USE_IGN_REFRESH)
2018-12-29 09:26:30 -08:00
if( (ignitionSchedule1.Status == RUNNING) && (ignition1EndAngle > crankAngle) && (configPage4.StgCycles == 0) && (configPage2.perToothIgn != true) )
{
unsigned long uSToEnd = 0;
2018-01-03 01:48:35 -08:00
crankAngle = ignitionLimits(getCrankAngle()); //Refresh the crank angle info
//ONLY ONE OF THE BELOW SHOULD BE USED (PROBABLY THE FIRST):
//*********
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
if(ignition1EndAngle > crankAngle) { uSToEnd = angleToTimeMicroSecPerDegree( (ignition1EndAngle - crankAngle) ); }
else { uSToEnd = angleToTimeMicroSecPerDegree( (360 + ignition1EndAngle - crankAngle) ); }
//*********
//uSToEnd = ((ignition1EndAngle - crankAngle) * (toothLastToothTime - toothLastMinusOneToothTime)) / triggerToothAngle;
//*********
2017-12-06 18:46:25 -08:00
refreshIgnitionSchedule1( uSToEnd + fixedCrankingOverride );
}
#endif
#if IGN_CHANNELS >= 2
if (maxIgnOutputs >= 2)
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition2StartTime = calculateIgnitionTimeout(ignitionSchedule2, ignition2StartAngle, channel2IgnDegrees, crankAngle);
if ( (ignition2StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN2_CMD_BIT)) )
{
setIgnitionSchedule(ignitionSchedule2, ignition2StartTime,
currentStatus.dwell + fixedCrankingOverride);
}
}
#endif
#if IGN_CHANNELS >= 3
if (maxIgnOutputs >= 3)
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition3StartTime = calculateIgnitionTimeout(ignitionSchedule3, ignition3StartAngle, channel3IgnDegrees, crankAngle);
if ( (ignition3StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN3_CMD_BIT)) )
{
setIgnitionSchedule(ignitionSchedule3, ignition3StartTime,
currentStatus.dwell + fixedCrankingOverride);
}
}
#endif
#if IGN_CHANNELS >= 4
if (maxIgnOutputs >= 4)
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition4StartTime = calculateIgnitionTimeout(ignitionSchedule4, ignition4StartAngle, channel4IgnDegrees, crankAngle);
if ( (ignition4StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN4_CMD_BIT)) )
{
setIgnitionSchedule(ignitionSchedule4, ignition4StartTime,
currentStatus.dwell + fixedCrankingOverride);
}
}
#endif
#if IGN_CHANNELS >= 5
if (maxIgnOutputs >= 5)
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition5StartTime = calculateIgnitionTimeout(ignitionSchedule5, ignition5StartAngle, channel5IgnDegrees, crankAngle);
if ( (ignition5StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN5_CMD_BIT)) )
{
setIgnitionSchedule(ignitionSchedule5, ignition5StartTime,
currentStatus.dwell + fixedCrankingOverride);
}
}
#endif
#if IGN_CHANNELS >= 6
if (maxIgnOutputs >= 6)
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition6StartTime = calculateIgnitionTimeout(ignitionSchedule6, ignition6StartAngle, channel6IgnDegrees, crankAngle);
if ( (ignition6StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN6_CMD_BIT)) )
{
setIgnitionSchedule(ignitionSchedule6, ignition6StartTime,
currentStatus.dwell + fixedCrankingOverride);
}
}
#endif
2019-09-04 01:25:02 -07:00
#if IGN_CHANNELS >= 7
if (maxIgnOutputs >= 7)
2019-09-04 01:25:02 -07:00
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition7StartTime = calculateIgnitionTimeout(ignitionSchedule7, ignition7StartAngle, channel7IgnDegrees, crankAngle);
2019-09-04 01:25:02 -07:00
if ( (ignition7StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN7_CMD_BIT)) )
2019-09-04 01:25:02 -07:00
{
setIgnitionSchedule(ignitionSchedule7, ignition7StartTime,
currentStatus.dwell + fixedCrankingOverride);
2019-09-04 01:25:02 -07:00
}
}
#endif
#if IGN_CHANNELS >= 8
if (maxIgnOutputs >= 8)
2019-09-04 01:25:02 -07:00
{
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
unsigned long ignition8StartTime = calculateIgnitionTimeout(ignitionSchedule8, ignition8StartAngle, channel8IgnDegrees, crankAngle);
2019-09-04 01:25:02 -07:00
if ( (ignition8StartTime > 0) && (BIT_CHECK(ignitionChannelsOn, IGN8_CMD_BIT)) )
2019-09-04 01:25:02 -07:00
{
setIgnitionSchedule(ignitionSchedule8, ignition8StartTime,
currentStatus.dwell + fixedCrankingOverride);
2019-09-04 01:25:02 -07:00
}
}
#endif
} //Ignition schedules on
2018-07-19 06:26:31 -07:00
if ( (!BIT_CHECK(currentStatus.status3, BIT_STATUS3_RESET_PREVENT)) && (resetControl == RESET_CONTROL_PREVENT_WHEN_RUNNING) )
{
//Reset prevention is supposed to be on while the engine is running but isn't. Fix that.
digitalWrite(pinResetControl, HIGH);
BIT_SET(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
}
} //Has sync and RPM
2018-07-19 06:26:31 -07:00
else if ( (BIT_CHECK(currentStatus.status3, BIT_STATUS3_RESET_PREVENT) > 0) && (resetControl == RESET_CONTROL_PREVENT_WHEN_RUNNING) )
{
digitalWrite(pinResetControl, LOW);
BIT_CLEAR(currentStatus.status3, BIT_STATUS3_RESET_PREVENT);
}
2017-10-06 12:44:29 -07:00
} //loop()
#endif //Unit test guard
/**
* @brief This function calculates the required pulsewidth time (in us) given the current system state
*
* @param REQ_FUEL The required fuel value in uS, as calculated by TunerStudio
* @param VE Lookup from the main fuel table. This can either have been MAP or TPS based, depending on the algorithm used
* @param MAP In KPa, read from the sensor (This is used when performing a multiply of the map only. It is applicable in both Speed density and Alpha-N)
* @param corrections Sum of Enrichment factors (Cold start, acceleration). This is a multiplication factor (Eg to add 10%, this should be 110)
* @param injOpen Injector opening time. The time the injector take to open minus the time it takes to close (Both in uS)
* @return uint16_t The injector pulse width in uS
*/
2019-12-01 19:47:30 -08:00
uint16_t PW(int REQ_FUEL, byte VE, long MAP, uint16_t corrections, int injOpen)
{
//Standard float version of the calculation
//return (REQ_FUEL * (float)(VE/100.0) * (float)(MAP/100.0) * (float)(TPS/100.0) * (float)(corrections/100.0) + injOpen);
//Note: The MAP and TPS portions are currently disabled, we use VE and corrections only
uint16_t iVE, iCorrections;
uint16_t iMAP = 100;
uint16_t iAFR = 147;
//100% float free version, does sacrifice a little bit of accuracy, but not much.
//If corrections are huge, use less bitshift to avoid overflow. Sacrifices a bit more accuracy (basically only during very cold temp cranking)
byte bitShift = 7;
if (corrections > 511 ) { bitShift = 6; }
if (corrections > 1023) { bitShift = 5; }
2024-01-17 23:03:46 -08:00
//iVE = ((unsigned int)VE << 7) / 100;
2024-01-17 23:20:57 -08:00
iVE = div100(((uint16_t)VE << 7));
//Check whether either of the multiply MAP modes is turned on
2024-01-17 23:03:46 -08:00
//if ( configPage2.multiplyMAP == MULTIPLY_MAP_MODE_100) { iMAP = ((unsigned int)MAP << 7) / 100; }
if ( configPage2.multiplyMAP == MULTIPLY_MAP_MODE_100) { iMAP = div100( ((uint16_t)MAP << 7U) ); }
else if( configPage2.multiplyMAP == MULTIPLY_MAP_MODE_BARO) { iMAP = ((unsigned int)MAP << 7) / currentStatus.baro; }
if ( (configPage2.includeAFR == true) && (configPage6.egoType == EGO_TYPE_WIDE) && (currentStatus.runSecs > configPage6.ego_sdelay) ) {
iAFR = ((unsigned int)currentStatus.O2 << 7) / currentStatus.afrTarget; //Include AFR (vs target) if enabled
}
2020-08-13 05:48:26 -07:00
if ( (configPage2.incorporateAFR == true) && (configPage2.includeAFR == false) ) {
iAFR = ((unsigned int)configPage2.stoich << 7) / currentStatus.afrTarget; //Incorporate stoich vs target AFR, if enabled.
}
2024-01-17 23:03:46 -08:00
//iCorrections = (corrections << bitShift) / 100;
iCorrections = div100((corrections << bitShift));
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
uint32_t intermediate = ((uint32_t)REQ_FUEL * (uint32_t)iVE) >> 7; //Need to use an intermediate value to avoid overflowing the long
if ( configPage2.multiplyMAP > 0 ) { intermediate = (intermediate * (uint32_t)iMAP) >> 7; }
if ( (configPage2.includeAFR == true) && (configPage6.egoType == EGO_TYPE_WIDE) && (currentStatus.runSecs > configPage6.ego_sdelay) ) {
//EGO type must be set to wideband and the AFR warmup time must've elapsed for this to be used
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
intermediate = (intermediate * (uint32_t)iAFR) >> 7;
}
2020-08-13 05:48:26 -07:00
if ( (configPage2.incorporateAFR == true) && (configPage2.includeAFR == false) ) {
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
intermediate = (intermediate * (uint32_t)iAFR) >> 7;
2020-08-13 05:48:26 -07:00
}
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
intermediate = (intermediate * (uint32_t)iCorrections) >> bitShift;
if (intermediate != 0)
{
//If intermediate is not 0, we need to add the opening time (0 typically indicates that one of the full fuel cuts is active)
intermediate += injOpen; //Add the injector opening time
2023-01-09 15:46:34 -08:00
//AE calculation only when ACC is active.
if ( BIT_CHECK(currentStatus.engine, BIT_ENGINE_ACC) )
{
2023-01-09 15:46:34 -08:00
//AE Adds % of req_fuel
if ( configPage2.aeApplyMode == AE_MODE_ADDER )
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
intermediate += div100(((uint32_t)REQ_FUEL) * (currentStatus.AEamount - 100U));
2023-01-09 15:46:34 -08:00
}
}
2023-01-09 15:46:34 -08:00
2024-01-17 23:03:46 -08:00
if ( intermediate > UINT16_MAX)
{
2024-01-17 23:03:46 -08:00
intermediate = UINT16_MAX; //Make sure this won't overflow when we convert to uInt. This means the maximum pulsewidth possible is 65.535mS
}
}
return (unsigned int)(intermediate);
}
2018-01-22 21:14:03 -08:00
/** Lookup the current VE value from the primary 3D fuel map.
* The Y axis value used for this lookup varies based on the fuel algorithm selected (speed density, alpha-n etc).
*
* @return byte The current VE value
*/
2022-11-05 15:43:29 -07:00
byte getVE1(void)
{
byte tempVE = 100;
if (configPage2.fuelAlgorithm == LOAD_SOURCE_MAP) //Check which fuelling algorithm is being used
{
//Speed Density
currentStatus.fuelLoad = currentStatus.MAP;
}
else if (configPage2.fuelAlgorithm == LOAD_SOURCE_TPS)
{
//Alpha-N
currentStatus.fuelLoad = currentStatus.TPS * 2;
}
else if (configPage2.fuelAlgorithm == LOAD_SOURCE_IMAPEMAP)
{
//IMAP / EMAP
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
currentStatus.fuelLoad = ((int16_t)currentStatus.MAP * 100U) / currentStatus.EMAP;
}
else { currentStatus.fuelLoad = currentStatus.MAP; } //Fallback position
tempVE = get3DTableValue(&fuelTable, currentStatus.fuelLoad, currentStatus.RPM); //Perform lookup into fuel map for RPM vs MAP value
return tempVE;
}
/** Lookup the ignition advance from 3D ignition table.
* The values used to look this up will be RPM and whatever load source the user has configured.
*
* @return byte The current target advance value in degrees
*/
2022-11-05 15:43:29 -07:00
byte getAdvance1(void)
{
byte tempAdvance = 0;
if (configPage2.ignAlgorithm == LOAD_SOURCE_MAP) //Check which fuelling algorithm is being used
{
//Speed Density
currentStatus.ignLoad = currentStatus.MAP;
}
2018-05-14 21:05:45 -07:00
else if(configPage2.ignAlgorithm == LOAD_SOURCE_TPS)
{
//Alpha-N
currentStatus.ignLoad = currentStatus.TPS * 2;
}
2018-05-14 21:05:45 -07:00
else if (configPage2.fuelAlgorithm == LOAD_SOURCE_IMAPEMAP)
{
//IMAP / EMAP
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
currentStatus.ignLoad = ((int16_t)currentStatus.MAP * 100U) / currentStatus.EMAP;
2018-05-14 21:05:45 -07:00
}
tempAdvance = get3DTableValue(&ignitionTable, currentStatus.ignLoad, currentStatus.RPM) - OFFSET_IGNITION; //As above, but for ignition advance
tempAdvance = correctionsIgn(tempAdvance);
return tempAdvance;
}
/** Calculate the Ignition angles for all cylinders (based on @ref config2.nCylinders).
* both start and end angles are calculated for each channel.
* Also the mode of ignition firing - wasted spark vs. dedicated spark per cyl. - is considered here.
*/
void calculateIgnitionAngles(uint16_t dwellAngle)
{
2020-02-16 00:54:52 -08:00
//This test for more cylinders and do the same thing
switch (configPage2.nCylinders)
{
//1 cylinder
case 1:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
break;
2020-02-16 00:54:52 -08:00
//2 cylinders
case 2:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
calculateIgnitionAngle(dwellAngle, channel2IgnDegrees, currentStatus.advance, &ignition2EndAngle, &ignition2StartAngle);
2020-02-16 00:54:52 -08:00
break;
//3 cylinders
case 3:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
calculateIgnitionAngle(dwellAngle, channel2IgnDegrees, currentStatus.advance, &ignition2EndAngle, &ignition2StartAngle);
calculateIgnitionAngle(dwellAngle, channel3IgnDegrees, currentStatus.advance, &ignition3EndAngle, &ignition3StartAngle);
2020-02-16 00:54:52 -08:00
break;
//4 cylinders
case 4:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
calculateIgnitionAngle(dwellAngle, channel2IgnDegrees, currentStatus.advance, &ignition2EndAngle, &ignition2StartAngle);
2020-02-16 00:54:52 -08:00
#if IGN_CHANNELS >= 4
if((configPage4.sparkMode == IGN_MODE_SEQUENTIAL) && currentStatus.hasSync)
2020-02-16 00:54:52 -08:00
{
if( CRANK_ANGLE_MAX_IGN != 720 ) { changeHalfToFullSync(); }
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel3IgnDegrees, currentStatus.advance, &ignition3EndAngle, &ignition3StartAngle);
calculateIgnitionAngle(dwellAngle, channel4IgnDegrees, currentStatus.advance, &ignition4EndAngle, &ignition4StartAngle);
2020-02-16 00:54:52 -08:00
}
else if(configPage4.sparkMode == IGN_MODE_ROTARY)
{
byte splitDegrees = 0;
splitDegrees = table2D_getValue(&rotarySplitTable, currentStatus.ignLoad);
2020-02-16 00:54:52 -08:00
//The trailing angles are set relative to the leading ones
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionTrailingRotary(dwellAngle, splitDegrees, ignition1EndAngle, &ignition3EndAngle, &ignition3StartAngle);
calculateIgnitionTrailingRotary(dwellAngle, splitDegrees, ignition2EndAngle, &ignition4EndAngle, &ignition4StartAngle);
2020-02-16 00:54:52 -08:00
}
else
{
if( BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) && (CRANK_ANGLE_MAX_IGN != 360) ) { changeFullToHalfSync(); }
}
#endif
2020-02-16 00:54:52 -08:00
break;
//5 cylinders
case 5:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
calculateIgnitionAngle(dwellAngle, channel2IgnDegrees, currentStatus.advance, &ignition2EndAngle, &ignition2StartAngle);
calculateIgnitionAngle(dwellAngle, channel3IgnDegrees, currentStatus.advance, &ignition3EndAngle, &ignition3StartAngle);
calculateIgnitionAngle(dwellAngle, channel4IgnDegrees, currentStatus.advance, &ignition4EndAngle, &ignition4StartAngle);
#if (IGN_CHANNELS >= 5)
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel5IgnDegrees, currentStatus.advance, &ignition5EndAngle, &ignition5StartAngle);
#endif
2020-02-16 00:54:52 -08:00
break;
//6 cylinders
case 6:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
calculateIgnitionAngle(dwellAngle, channel2IgnDegrees, currentStatus.advance, &ignition2EndAngle, &ignition2StartAngle);
calculateIgnitionAngle(dwellAngle, channel3IgnDegrees, currentStatus.advance, &ignition3EndAngle, &ignition3StartAngle);
#if IGN_CHANNELS >= 6
if((configPage4.sparkMode == IGN_MODE_SEQUENTIAL) && currentStatus.hasSync)
{
if( CRANK_ANGLE_MAX_IGN != 720 ) { changeHalfToFullSync(); }
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel4IgnDegrees, currentStatus.advance, &ignition4EndAngle, &ignition4StartAngle);
calculateIgnitionAngle(dwellAngle, channel5IgnDegrees, currentStatus.advance, &ignition5EndAngle, &ignition5StartAngle);
calculateIgnitionAngle(dwellAngle, channel6IgnDegrees, currentStatus.advance, &ignition6EndAngle, &ignition6StartAngle);
}
else
{
if( BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) && (CRANK_ANGLE_MAX_IGN != 360) ) { changeFullToHalfSync(); }
}
#endif
2020-02-16 00:54:52 -08:00
break;
//8 cylinders
case 8:
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel1IgnDegrees, currentStatus.advance, &ignition1EndAngle, &ignition1StartAngle);
calculateIgnitionAngle(dwellAngle, channel2IgnDegrees, currentStatus.advance, &ignition2EndAngle, &ignition2StartAngle);
calculateIgnitionAngle(dwellAngle, channel3IgnDegrees, currentStatus.advance, &ignition3EndAngle, &ignition3StartAngle);
calculateIgnitionAngle(dwellAngle, channel4IgnDegrees, currentStatus.advance, &ignition4EndAngle, &ignition4StartAngle);
#if IGN_CHANNELS >= 8
if((configPage4.sparkMode == IGN_MODE_SEQUENTIAL) && currentStatus.hasSync)
{
if( CRANK_ANGLE_MAX_IGN != 720 ) { changeHalfToFullSync(); }
Save 600+ bytes RAM (step 3 of 9) - remove per-channel schedule calculation functions, use generic equivalents instead (#1018) * calculateInjector1Timeout proxies calculateInjectorNTimeout Unit test still pass. * Remove calculateInjector1Timeout, Replace with call to calculateInjectorTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnition1Timeout proxies calculateIgnitionNTimeout Unit test all pass * Remove calculateIgnition1Timeout, Replace with call to calculateIgnitionTimeout All unit tests still pass. * Remove unecassary unit test * calculateIgnitionAngle\d proxies calculateIgnitionAngle Unit tests all pass * Remove calculateIgnitionAngle\d Just call calculateIgnitionAngle() directly * Route rotary ignition angle calcs through generic calculateIgnitionTrailingRotary function. * Remove calculateIgnitionAngle\d Just call calculateIgnitionTrailingRotary() directly * calculateInjectorStartAngle: inject all parameters Do not rely on global state Easier unit testing. * calculateIgnitionAngle: inject all parameters Do not rely on global state Easier unit testing. * Pull all ignition global vars into schedule_calcs * Conditional compile for schedule calc vars Saves memory * Optimize: break out angleToTimeIntervalRev from angleToTime. The new function will always be inlined. * Optimize - simpler code path when no channel offset (zero) Some optimization of arithmetic operations. * Fix unit tests * Fix bug on injector angle calculations Need while loops to correctly bring intermediate values into range --------- Co-authored-by: Josh Stewart <josh@noisymime.org>
2023-06-25 19:13:53 -07:00
calculateIgnitionAngle(dwellAngle, channel5IgnDegrees, currentStatus.advance, &ignition5EndAngle, &ignition5StartAngle);
calculateIgnitionAngle(dwellAngle, channel6IgnDegrees, currentStatus.advance, &ignition6EndAngle, &ignition6StartAngle);
calculateIgnitionAngle(dwellAngle, channel7IgnDegrees, currentStatus.advance, &ignition7EndAngle, &ignition7StartAngle);
calculateIgnitionAngle(dwellAngle, channel8IgnDegrees, currentStatus.advance, &ignition8EndAngle, &ignition8StartAngle);
}
else
{
if( BIT_CHECK(currentStatus.status3, BIT_STATUS3_HALFSYNC) && (CRANK_ANGLE_MAX_IGN != 360) ) { changeFullToHalfSync(); }
}
#endif
2020-02-16 00:54:52 -08:00
break;
//Will hit the default case on >8 cylinders. Do nothing in these cases
2020-02-16 00:54:52 -08:00
default:
break;
}
}
uint16_t calculatePWLimit()
{
uint32_t tempLimit = percentage(configPage2.dutyLim, revolutionTime); //The pulsewidth limit is determined to be the duty cycle limit (Eg 85%) by the total time it takes to perform 1 revolution
//Handle multiple squirts per rev
if (configPage2.strokes == FOUR_STROKE) { tempLimit = tempLimit * 2; }
//Optimise for power of two divisions where possible
switch(currentStatus.nSquirts)
{
case 1:
//No action needed
break;
case 2:
tempLimit = tempLimit / 2;
break;
case 4:
tempLimit = tempLimit / 4;
break;
case 8:
tempLimit = tempLimit / 8;
break;
default:
//Non-PoT squirts value. Perform (slow) uint32_t division
tempLimit = tempLimit / currentStatus.nSquirts;
break;
}
if(tempLimit > UINT16_MAX) { tempLimit = UINT16_MAX; }
return tempLimit;
}
void calculateStaging(uint32_t pwLimit)
{
//Calculate staging pulsewidths if used
//To run staged injection, the number of cylinders must be less than or equal to the injector channels (ie Assuming you're running paired injection, you need at least as many injector channels as you have cylinders, half for the primaries and half for the secondaries)
if( (configPage10.stagingEnabled == true) && (configPage2.nCylinders <= INJ_CHANNELS || configPage2.injType == INJ_TYPE_TBODY) && (currentStatus.PW1 > inj_opentime_uS) ) //Final check is to ensure that DFCO isn't active, which would cause an overflow below (See #267)
{
//Scale the 'full' pulsewidth by each of the injector capacities
currentStatus.PW1 -= inj_opentime_uS; //Subtract the opening time from PW1 as it needs to be multiplied out again by the pri/sec req_fuel values below. It is added on again after that calculation.
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
uint32_t tempPW1 = div100((uint32_t)currentStatus.PW1 * staged_req_fuel_mult_pri);
if(configPage10.stagingMode == STAGING_MODE_TABLE)
{
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
uint32_t tempPW3 = div100((uint32_t)currentStatus.PW1 * staged_req_fuel_mult_sec); //This is ONLY needed in in table mode. Auto mode only calculates the difference.
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
uint8_t stagingSplit = get3DTableValue(&stagingTable, currentStatus.fuelLoad, currentStatus.RPM);
currentStatus.PW1 = div100((100U - stagingSplit) * tempPW1);
currentStatus.PW1 += inj_opentime_uS;
//PW2 is used temporarily to hold the secondary injector pulsewidth. It will be assigned to the correct channel below
if(stagingSplit > 0)
{
BIT_SET(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Set the staging active flag
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
currentStatus.PW2 = div100(stagingSplit * tempPW3);
currentStatus.PW2 += inj_opentime_uS;
}
else
{
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
currentStatus.PW2 = 0;
}
}
else if(configPage10.stagingMode == STAGING_MODE_AUTO)
{
currentStatus.PW1 = tempPW1;
//If automatic mode, the primary injectors are used all the way up to their limit (Configured by the pulsewidth limit setting)
//If they exceed their limit, the extra duty is passed to the secondaries
if(tempPW1 > pwLimit)
{
BIT_SET(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Set the staging active flag
uint32_t extraPW = tempPW1 - pwLimit + inj_opentime_uS; //The open time must be added here AND below because tempPW1 does not include an open time. The addition of it here takes into account the fact that pwLlimit does not contain an allowance for an open time.
currentStatus.PW1 = pwLimit;
Performance: optimize division (#1082) * Add udiv_32_16 * Apply udiv_32_16() where possible * Convert udiv_32_16 to assembler It's worth 20 loop/s * Remove unused functions * Remove degreesPeruSx2048 - unused * Remove angleToTime - replace with direct calls 1. Drop angleToTime() It's slow, only partially implemented and adds zero value (and has MISRA violations) 2. Consistent function naming 3. Doxygen * triggerPri_Nissan360 shouldn't set timePerDegree. It will be overwritten every loop by doCrankSpeedCalcs() * Use angleToTimeMicroSecPerDegree() instead of timePerDegree No loss in performance Increased injection open/close time accuracy (so unit test values must change) Can remove timePerDegree global. * Hide (encapsulate) crank math globals. * Base all angle to time conversions on decoder computed variables. This is within 2us of the revolution based method and is much faster - which is essentially zero percent change. * Performance: move calculation of degreesPeruSx32768 into decoders. Remove doCrankSpeedCalcs() - it's doing nothing at the moment. * Apply libdivide to triggerSetEndTeeth functions. Since triggerToothAngle is set once at initialization time, we can generate the libdivide struct once and reuse it many times. * Remove lastToothCalcAdvance - unused * Replace 16-bit division with shift * Replace 32-bit divison with 16-bit division * Avoid 32-bit division; use div100() * inline percentage() * Optimize div100() * MISRA fixes * Replace magic numbers with #defs * Replace libdivide structs with inline constants No perf or memory changes * Use fixed types for PWM max count variables * Accurate rounded integer division * Formalise rounding behavior (DIV_ROUND_CORRECT) * Apply DIV_ROUND_CORRECT to DIV_ROUND_CLOSEST(), UDIV_ROUND_CLOSEST(), div100(), div360(), percentage() & halfPercentage() * Add, fix & improve unit tests * Add udiv_32_16_closest() * Perf: Limit percentage calculations to 16-bits * MISRA fixes * Add compare_executiontime() to encapsulate common perf testing code * Signed to unsigned division * Convert ignitionLimits() to an inline function. Slight speed up, probably due to removing multiple evaluations of macro arguments. * Split unit tests up. * udiv_32_16 - check for valid parameters
2023-11-05 14:10:08 -08:00
currentStatus.PW2 = udiv_32_16(extraPW * staged_req_fuel_mult_sec, staged_req_fuel_mult_pri); //Convert the 'left over' fuel amount from primary injector scaling to secondary
currentStatus.PW2 += inj_opentime_uS;
}
else
{
//If tempPW1 < pwLImit it means that the entire fuel load can be handled by the primaries and staging is inactive.
currentStatus.PW1 += inj_opentime_uS; //Add the open time back in
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
currentStatus.PW2 = 0; //Secondary PW is simply set to 0 as it is not required
}
}
//Allocate the primary and secondary pulse widths based on the fuel configuration
switch (configPage2.nCylinders)
{
case 1:
//Nothing required for 1 cylinder, channels are correct already
break;
case 2:
//Primary pulsewidth on channels 1 and 2, secondary on channels 3 and 4
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
break;
case 3:
//6 channels required for 'normal' 3 cylinder staging support
#if INJ_CHANNELS >= 6
//Primary pulsewidth on channels 1, 2 and 3, secondary on channels 4, 5 and 6
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
#else
//If there are not enough channels, then primary pulsewidth is on channels 1, 2 and 3, secondary on channel 4
currentStatus.PW4 = currentStatus.PW2;
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
break;
case 4:
if( (configPage2.injLayout == INJ_SEQUENTIAL) || (configPage2.injLayout == INJ_SEMISEQUENTIAL) )
{
//Staging with 4 cylinders semi/sequential requires 8 total channels
#if INJ_CHANNELS >= 8
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
#else
//This is an invalid config as there are not enough outputs to support sequential + staging
//Put the staging output to the non-existent channel 5
currentStatus.PW5 = currentStatus.PW2;
#endif
}
else
{
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
}
break;
case 5:
//No easily supportable 5 cylinder staging option unless there are at least 5 channels
#if INJ_CHANNELS >= 5
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW5 = currentStatus.PW2;
}
#if INJ_CHANNELS >= 6
currentStatus.PW6 = currentStatus.PW2;
#endif
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
break;
case 6:
#if INJ_CHANNELS >= 6
//8 cylinder staging only if not sequential
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
}
#if INJ_CHANNELS >= 8
else
{
//If there are 8 channels, then the 6 cylinder sequential option is available by using channels 7 + 8 for staging
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW1;
currentStatus.PW5 = currentStatus.PW1;
currentStatus.PW6 = currentStatus.PW1;
}
#endif
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
break;
case 8:
#if INJ_CHANNELS >= 8
//8 cylinder staging only if not sequential
if (configPage2.injLayout != INJ_SEQUENTIAL)
{
currentStatus.PW5 = currentStatus.PW2;
currentStatus.PW6 = currentStatus.PW2;
currentStatus.PW7 = currentStatus.PW2;
currentStatus.PW8 = currentStatus.PW2;
}
#endif
currentStatus.PW2 = currentStatus.PW1;
currentStatus.PW3 = currentStatus.PW1;
currentStatus.PW4 = currentStatus.PW1;
break;
default:
//Assume 4 cylinder non-seq for default
currentStatus.PW3 = currentStatus.PW2;
currentStatus.PW4 = currentStatus.PW2;
currentStatus.PW2 = currentStatus.PW1;
break;
}
}
else
{
if(maxInjOutputs >= 2) { currentStatus.PW2 = currentStatus.PW1; }
else { currentStatus.PW2 = 0; }
if(maxInjOutputs >= 3) { currentStatus.PW3 = currentStatus.PW1; }
else { currentStatus.PW3 = 0; }
if(maxInjOutputs >= 4) { currentStatus.PW4 = currentStatus.PW1; }
else { currentStatus.PW4 = 0; }
if(maxInjOutputs >= 5) { currentStatus.PW5 = currentStatus.PW1; }
else { currentStatus.PW5 = 0; }
if(maxInjOutputs >= 6) { currentStatus.PW6 = currentStatus.PW1; }
else { currentStatus.PW6 = 0; }
if(maxInjOutputs >= 7) { currentStatus.PW7 = currentStatus.PW1; }
else { currentStatus.PW7 = 0; }
if(maxInjOutputs >= 8) { currentStatus.PW8 = currentStatus.PW1; }
else { currentStatus.PW8 = 0; }
BIT_CLEAR(currentStatus.status4, BIT_STATUS4_STAGING_ACTIVE); //Clear the staging active flag
}
}
void checkLaunchAndFlatShift()
{
//Check for launching/flat shift (clutch) based on the current and previous clutch states
2023-12-05 19:47:13 -08:00
currentStatus.previousClutchTrigger = currentStatus.clutchTrigger;
//Only check for pinLaunch if any function using it is enabled. Else pins might break starting a board
if(configPage6.flatSEnable || configPage6.launchEnabled)
{
2023-12-05 19:47:13 -08:00
if(configPage6.launchHiLo > 0) { currentStatus.clutchTrigger = digitalRead(pinLaunch); }
else { currentStatus.clutchTrigger = !digitalRead(pinLaunch); }
}
2023-12-05 19:47:13 -08:00
if(currentStatus.clutchTrigger && (currentStatus.previousClutchTrigger != currentStatus.clutchTrigger) ) { currentStatus.clutchEngagedRPM = currentStatus.RPM; } //Check whether the clutch has been engaged or disengaged and store the current RPM if so
//Default flags to off
currentStatus.launchingHard = false;
BIT_CLEAR(currentStatus.spark, BIT_SPARK_HLAUNCH);
currentStatus.flatShiftingHard = false;
2023-12-05 19:47:13 -08:00
if (configPage6.launchEnabled && currentStatus.clutchTrigger && (currentStatus.clutchEngagedRPM < ((unsigned int)(configPage6.flatSArm) * 100)) && (currentStatus.TPS >= configPage10.lnchCtrlTPS) )
{
//Check whether RPM is above the launch limit
uint16_t launchRPMLimit = (configPage6.lnchHardLim * 100);
if( (configPage2.hardCutType == HARD_CUT_ROLLING) ) { launchRPMLimit += (configPage15.rollingProtRPMDelta[0] * 10); } //Add the rolling cut delta if enabled (Delta is a negative value)
if(currentStatus.RPM > launchRPMLimit)
{
//HardCut rev limit for 2-step launch control.
currentStatus.launchingHard = true;
BIT_SET(currentStatus.spark, BIT_SPARK_HLAUNCH);
}
}
else
{
//If launch is not active, check whether flat shift should be active
2023-12-05 19:47:13 -08:00
if(configPage6.flatSEnable && currentStatus.clutchTrigger && (currentStatus.clutchEngagedRPM >= ((unsigned int)(configPage6.flatSArm * 100)) ) )
{
uint16_t flatRPMLimit = currentStatus.clutchEngagedRPM;
if( (configPage2.hardCutType == HARD_CUT_ROLLING) ) { flatRPMLimit += (configPage15.rollingProtRPMDelta[0] * 10); } //Add the rolling cut delta if enabled (Delta is a negative value)
if(currentStatus.RPM > flatRPMLimit)
{
//Flat shift rev limit
currentStatus.flatShiftingHard = true;
}
}
}
}