From 143975073160895193dc793fd727b539e3867628 Mon Sep 17 00:00:00 2001 From: Josh Stewart Date: Tue, 16 Jan 2024 22:25:15 +1100 Subject: [PATCH] Separate PW Limit calculation into own function and optimise. Add unit tests for this --- speeduino/speeduino.h | 1 + speeduino/speeduino.ino | 39 ++++++++++++++++++++++++++++++-------- test/test_fuel/test_PW.cpp | 23 ++++++++++++++++++++++ test/test_fuel/test_PW.h | 4 +++- 4 files changed, 58 insertions(+), 9 deletions(-) diff --git a/speeduino/speeduino.h b/speeduino/speeduino.h index 49869312..6a6bbbc6 100644 --- a/speeduino/speeduino.h +++ b/speeduino/speeduino.h @@ -20,6 +20,7 @@ void loop(void); uint16_t PW(int REQ_FUEL, byte VE, long MAP, uint16_t corrections, int injOpen); byte getVE1(void); byte getAdvance1(void); +uint16_t calculatePWLimit(); void calculateStaging(uint32_t); void calculateIgnitionAngles(int dwellAngle); void checkLaunchAndFlatShift(); diff --git a/speeduino/speeduino.ino b/speeduino/speeduino.ino index 29b96416..532d4555 100644 --- a/speeduino/speeduino.ino +++ b/speeduino/speeduino.ino @@ -467,14 +467,7 @@ void loop(void) #endif //Check that the duty cycle of the chosen pulsewidth isn't too high. - uint32_t pwLimit = 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) { pwLimit = pwLimit * 2; } - // This requires 32-bit division, which is very slow on Mega 2560. - // So only divide if necessary - nSquirts is often only 1. - if (currentStatus.nSquirts!=1) { - pwLimit = pwLimit / currentStatus.nSquirts; - } + uint16_t pwLimit = calculatePWLimit(); //Apply the pwLimit if staging is disabled and engine is not cranking if( (!BIT_CHECK(currentStatus.engine, BIT_ENGINE_CRANK)) && (configPage10.stagingEnabled == false) ) { if (currentStatus.PW1 > pwLimit) { currentStatus.PW1 = pwLimit; } } @@ -1440,6 +1433,36 @@ void calculateIgnitionAngles(int dwellAngle) } } +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 diff --git a/test/test_fuel/test_PW.cpp b/test/test_fuel/test_PW.cpp index 837d6d7b..309e5cc2 100644 --- a/test/test_fuel/test_PW.cpp +++ b/test/test_fuel/test_PW.cpp @@ -14,6 +14,8 @@ void testPW(void) RUN_TEST(test_PW_Large_Correction); RUN_TEST(test_PW_Very_Large_Correction); RUN_TEST(test_PW_4Cyl_PW0); + RUN_TEST(test_PW_Limit_Long_Revolution); + RUN_TEST(test_PW_Limit_90pct); } int16_t REQ_FUEL; @@ -141,4 +143,25 @@ void test_PW_4Cyl_PW0(void) loop(); TEST_ASSERT_EQUAL(0, currentStatus.PW3); TEST_ASSERT_EQUAL(0, currentStatus.PW4); +} + +//Tests the PW Limit calculation for a normal scenario +void test_PW_Limit_90pct(void) +{ + revolutionTime = 10000UL; //6000 rpm + configPage2.dutyLim = 90; + + //Duty limit of 90% for 10,000uS should give 9,000 + TEST_ASSERT_EQUAL(9000, calculatePWLimit()); +} + +//Tests the PW Limit calculation when the revolution time is greater than the max UINT16 value +//Occurs at approx. 915rpm +void test_PW_Limit_Long_Revolution(void) +{ + revolutionTime = 100000UL; //600 rpm, below 915rpm cutover point + configPage2.dutyLim = 90; + + //Duty limit of 90% for 100,000uS should give 90,000, but as this would overflow the PW value, this should default to UINT16 Max + TEST_ASSERT_EQUAL(UINT16_MAX, calculatePWLimit()); } \ No newline at end of file diff --git a/test/test_fuel/test_PW.h b/test/test_fuel/test_PW.h index 436341ca..5d0dbe2f 100644 --- a/test/test_fuel/test_PW.h +++ b/test/test_fuel/test_PW.h @@ -6,4 +6,6 @@ void test_PW_MAP_Multiply_Compatibility(void); void test_PW_ALL_Multiply(void); void test_PW_Large_Correction(); void test_PW_Very_Large_Correction(); -void test_PW_4Cyl_PW0(void); \ No newline at end of file +void test_PW_4Cyl_PW0(void); +void test_PW_Limit_90pct(void); +void test_PW_Limit_Long_Revolution(void); \ No newline at end of file