test_math: make unit tests pass on Teensy (#1137)

Required converting dwell, actualDwell, dwellCrank & dwellRun to unsigned.
This commit is contained in:
tx_haggis 2024-03-20 19:45:10 -05:00 committed by GitHub
parent 3a712baf23
commit e08d5dab25
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 65 additions and 35 deletions

View File

@ -842,7 +842,7 @@ void sendValuesLegacy(void)
bytestosend -= Serial.write(temp >> 8); // MAPdot
bytestosend -= Serial.write(temp); // MAPdot
temp = currentStatus.dwell * 10;
temp = currentStatus.dwell * 10U;
bytestosend -= Serial.write(temp>>8); // dwell
bytestosend -= Serial.write(temp); // dwell

View File

@ -607,8 +607,8 @@ struct statuses {
int batADC;
int O2ADC;
int O2_2ADC;
int dwell; ///< dwell (coil primary winding/circuit on) time (in ms * 10 ? See @ref correctionsDwell)
volatile int16_t actualDwell; ///< actual dwell time if new ignition mode is used (in uS)
uint16_t dwell; ///< dwell (coil primary winding/circuit on) time (in ms * 10 ? See @ref correctionsDwell)
volatile uint16_t actualDwell; ///< actual dwell time if new ignition mode is used (in uS)
byte dwellCorrection; /**< The amount of correction being applied to the dwell time (in unit ...). */
byte battery10; /**< The current BRV in volts (multiplied by 10. Eg 12.5V = 125) */
int8_t advance; /**< The current advance value being used in the spark calculation. Can be the same as advance1 or advance2, or a calculated value of both */
@ -909,8 +909,8 @@ struct config4 {
byte triggerFilter : 2; //The mode of trigger filter being used (0=Off, 1=Light (Not currently used), 2=Normal, 3=Aggressive)
byte ignCranklock : 1; //Whether or not the ignition timing during cranking is locked to a CAS (crank) pulse. Only currently valid for Basic distributor and 4G63.
byte dwellCrank; ///< Dwell time whilst cranking
byte dwellRun; ///< Dwell time whilst running
uint8_t dwellCrank; ///< Dwell time whilst cranking
uint8_t dwellRun; ///< Dwell time whilst running
byte triggerTeeth; ///< The full count of teeth on the trigger wheel if there were no gaps
byte triggerMissingTeeth; ///< The size of the tooth gap (ie number of missing teeth)
byte crankRPM; ///< RPM below which the engine is considered to be cranking

View File

@ -269,7 +269,7 @@ int16_t getReadableLogEntry(uint16_t logIndex)
case 60: statusValue = currentStatus.fuelLoad; break;
case 61: statusValue = currentStatus.ignLoad; break;
case 62: statusValue = currentStatus.dwell; break;
case 62: statusValue = (int16_t)currentStatus.dwell; break;
case 63: statusValue = currentStatus.CLIdleTarget; break;
case 64: statusValue = currentStatus.mapDOT; break;
case 65: statusValue = currentStatus.vvt1Angle; break;

View File

@ -144,7 +144,7 @@ static inline uint32_t div100(uint32_t n) {
#endif
}
#if defined(__arm__)
#if defined(__arm__) && !defined(CORE_TEENSY)
static inline int div100(int n) {
return DIV_ROUND_CLOSEST(n, 100U, int);
}
@ -156,7 +156,7 @@ static inline int32_t div100(int32_t n) {
}
return libdivide::libdivide_s32_do_raw(n + (DIV_ROUND_CORRECT(UINT16_C(100), uint32_t) * (n<0 ? -1 : 1)), 1374389535L, 5);
#else
return DIV_ROUND_CLOSEST(n, UINT32_C(100), int32_t);
return DIV_ROUND_CLOSEST(n, INT32_C(100), int32_t);
#endif
}
#endif

View File

@ -61,10 +61,10 @@ static inline uint16_t __attribute__((always_inline)) calculateInjectorStartAngl
static inline uint32_t __attribute__((always_inline)) calculateInjectorTimeout(const FuelSchedule &schedule, int channelInjDegrees, int injectorStartAngle, int crankAngle);
static inline void __attribute__((always_inline)) calculateIgnitionAngle(const int dwellAngle, const uint16_t channelIgnDegrees, int8_t advance, int *pEndAngle, int *pStartAngle);
static inline void __attribute__((always_inline)) calculateIgnitionAngle(const uint16_t dwellAngle, const uint16_t channelIgnDegrees, int8_t advance, int *pEndAngle, int *pStartAngle);
// Ignition for rotary.
static inline void __attribute__((always_inline)) calculateIgnitionTrailingRotary(int dwellAngle, int rotarySplitDegrees, int leadIgnitionAngle, int *pEndAngle, int *pStartAngle);
static inline void __attribute__((always_inline)) calculateIgnitionTrailingRotary(uint16_t dwellAngle, int rotarySplitDegrees, int leadIgnitionAngle, int *pEndAngle, int *pStartAngle);
static inline uint32_t __attribute__((always_inline)) calculateIgnitionTimeout(const IgnitionSchedule &schedule, int startAngle, int channelIgnDegrees, int crankAngle);

View File

@ -57,7 +57,7 @@ static inline uint32_t calculateInjectorTimeout(const FuelSchedule &schedule, in
return _calculateInjectorTimeout(schedule, _adjustToInjChannel(openAngle, channelInjDegrees), _adjustToInjChannel(crankAngle, channelInjDegrees));
}
static inline void calculateIgnitionAngle(const int dwellAngle, const uint16_t channelIgnDegrees, int8_t advance, int *pEndAngle, int *pStartAngle)
static inline void calculateIgnitionAngle(const uint16_t dwellAngle, const uint16_t channelIgnDegrees, int8_t advance, int *pEndAngle, int *pStartAngle)
{
*pEndAngle = (int16_t)(channelIgnDegrees==0U ? (uint16_t)CRANK_ANGLE_MAX_IGN : channelIgnDegrees) - (int16_t)advance;
if(*pEndAngle > CRANK_ANGLE_MAX_IGN) {*pEndAngle -= CRANK_ANGLE_MAX_IGN;}
@ -65,7 +65,7 @@ static inline void calculateIgnitionAngle(const int dwellAngle, const uint16_t c
if(*pStartAngle < 0) {*pStartAngle += CRANK_ANGLE_MAX_IGN;}
}
static inline void calculateIgnitionTrailingRotary(int dwellAngle, int rotarySplitDegrees, int leadIgnitionAngle, int *pEndAngle, int *pStartAngle)
static inline void calculateIgnitionTrailingRotary(uint16_t dwellAngle, int rotarySplitDegrees, int leadIgnitionAngle, int *pEndAngle, int *pStartAngle)
{
*pEndAngle = leadIgnitionAngle + rotarySplitDegrees;
*pStartAngle = *pEndAngle - dwellAngle;

View File

@ -22,7 +22,7 @@ byte getVE1(void);
byte getAdvance1(void);
uint16_t calculatePWLimit();
void calculateStaging(uint32_t);
void calculateIgnitionAngles(int dwellAngle);
void calculateIgnitionAngles(uint16_t dwellAngle);
void checkLaunchAndFlatShift();
extern uint16_t req_fuel_uS; /**< The required fuel variable (As calculated by TunerStudio) in uS */

View File

@ -716,24 +716,23 @@ void loop(void)
//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 * 100); //use cranking dwell
currentStatus.dwell = (configPage4.dwellCrank * 100U); //use cranking dwell
}
else
{
if ( configPage2.useDwellMap == true )
{
currentStatus.dwell = (get3DTableValue(&dwellTable, currentStatus.ignLoad, currentStatus.RPM) * 100); //use running dwell from map
currentStatus.dwell = (get3DTableValue(&dwellTable, currentStatus.ignLoad, currentStatus.RPM) * 100U); //use running dwell from map
}
else
{
currentStatus.dwell = (configPage4.dwellRun * 100); //use fixed running dwell
currentStatus.dwell = (configPage4.dwellRun * 100U); //use fixed running dwell
}
}
currentStatus.dwell = correctionsDwell(currentStatus.dwell);
int dwellAngle = timeToAngleDegPerMicroSec(currentStatus.dwell); //Convert the dwell time to dwell angle based on the current engine speed
calculateIgnitionAngles(dwellAngle);
// 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
@ -1323,10 +1322,8 @@ byte getAdvance1(void)
* 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(int dwellAngle)
void calculateIgnitionAngles(uint16_t dwellAngle)
{
//This test for more cylinders and do the same thing
switch (configPage2.nCylinders)
{

View File

@ -63,7 +63,7 @@ void test_maths_div100_S16(void)
void test_maths_div100_S32(void)
{
//Check both the signed and unsigned results
#if defined(__arm__)
#if defined(__arm__) && !defined(CORE_TEENSY)
test_div100_Seed<int>(100U);
test_div100_Seed<int>(10000U);
test_div100_Seed<int>(100000000UL);
@ -107,6 +107,7 @@ void assert_udiv_32_16(uint32_t dividend, uint16_t divisor) {
void test_maths_udiv_32_16(void)
{
#if defined(ARDUINO_ARCH_AVR)
// Divide by zero
TEST_ASSERT_EQUAL_UINT16(UINT16_MAX, udiv_32_16(0, 0));
@ -121,6 +122,7 @@ void test_maths_udiv_32_16(void)
assert_udiv_32_16(MICROS_PER_MIN, 7590); // 7905 RPM
assert_udiv_32_16(MICROS_PER_MIN, 7715); // 7777 RPM
assert_udiv_32_16(MICROS_PER_MIN, 3333); // 18000 RPM
#endif
}
@ -130,6 +132,7 @@ void assert_udiv_32_16_closest(uint32_t dividend, uint16_t divisor) {
void test_maths_udiv_32_16_closest(void)
{
#if defined(ARDUINO_ARCH_AVR)
// Divide by zero
TEST_ASSERT_EQUAL_UINT16(UINT16_MAX, udiv_32_16_closest(0, 0));
@ -145,6 +148,7 @@ void test_maths_udiv_32_16_closest(void)
assert_udiv_32_16(MICROS_PER_MIN, 7590); // 7905 RPM
assert_udiv_32_16(MICROS_PER_MIN, 7715); // 7777 RPM
assert_udiv_32_16(MICROS_PER_MIN, 3333); // 18000 RPM
#endif
}
static uint32_t indexToDividend(int16_t index) {
@ -152,6 +156,7 @@ static uint32_t indexToDividend(int16_t index) {
}
void test_maths_udiv_32_16_perf(void)
{
#if defined(ARDUINO_ARCH_AVR)
uint16_t iters = 32;
uint16_t start_index = UINT16_MAX/3;
uint16_t end_index = UINT16_MAX/3*2;
@ -167,10 +172,12 @@ void test_maths_udiv_32_16_perf(void)
TEST_ASSERT_INT32_WITHIN(UINT32_MAX/2, comparison.timeA.result, comparison.timeB.result);
TEST_ASSERT_LESS_THAN(comparison.timeA.durationMicros, comparison.timeB.durationMicros);
#endif
}
void test_maths_div100_s16_perf(void)
{
#if defined(ARDUINO_ARCH_AVR)
constexpr int16_t iters = 1;
constexpr int16_t start_index = -10000;
constexpr int16_t end_index = -1;
@ -186,11 +193,13 @@ void test_maths_div100_s16_perf(void)
TEST_ASSERT_INT32_WITHIN(UINT32_MAX/2, comparison.timeA.result, comparison.timeB.result);
TEST_ASSERT_LESS_THAN(comparison.timeA.durationMicros, comparison.timeB.durationMicros);
#endif
}
void test_maths_div100_s32_perf(void)
{
#if defined(ARDUINO_ARCH_AVR)
constexpr int32_t iters = 1;
constexpr int32_t start_index = -1439190;
constexpr int32_t end_index = -1;
@ -206,6 +215,7 @@ void test_maths_div100_s32_perf(void)
TEST_ASSERT_INT32_WITHIN(UINT32_MAX/2, comparison.timeA.result, comparison.timeB.result);
TEST_ASSERT_LESS_THAN(comparison.timeA.durationMicros, comparison.timeB.durationMicros);
#endif
}
void testDivision(void) {

View File

@ -1,14 +1,37 @@
#include <stdio.h>
#include <unity.h>
#include "test_fp_support.h"
float64_t floatDivision(int32_t a, int32_t b) {
#if defined(ARDUINO_ARCH_AVR)
#include <fp64lib.h>
using test_float_t = float64_t;
#else
using test_float_t = double;
#endif
test_float_t floatDivision(int32_t a, int32_t b) {
#if defined(ARDUINO_ARCH_AVR)
return fp64_div(fp64_int32_to_float64(a), fp64_int32_to_float64(b));
#else
return (double)a/(double)b;
#endif
}
void assert_rounded_div(int32_t a, int32_t b, int32_t actual) {
float64_t fExpected = floatDivision(a, b);
int32_t expected = fp64_lround(fExpected);
int32_t round_float(test_float_t f) {
#if defined(ARDUINO_ARCH_AVR)
return fp64_lround(f);
#else
return round(f);
#endif
}
char msg[64];
sprintf(msg, "a: %" PRIi32 ", b: %" PRIi32 " fExpected: %s", a, b, fp64_to_string(fExpected, 17, 15));
TEST_ASSERT_EQUAL_MESSAGE(expected, actual, msg);
void assert_rounded_div(int32_t a, int32_t b, int32_t actual) {
test_float_t fExpected = floatDivision(a, b);
int32_t expected = round_float(fExpected);
// char msg[64];
// sprintf(msg, "a: %" PRIi32 ", b: %" PRIi32 " fExpected: %s", a, b, fp64_to_string(fExpected, 17, 15));
// TEST_ASSERT_EQUAL_MESSAGE(expected, actual, msg);
TEST_ASSERT_EQUAL(expected, actual);
}

View File

@ -1,8 +1,4 @@
#pragma once
#include <stdio.h>
#include <unity.h>
#include <fp64lib.h>
float64_t floatDivision(int32_t a, int32_t b);
#include <stdint.h>
void assert_rounded_div(int32_t a, int32_t b, int32_t actual);

View File

@ -62,6 +62,7 @@ void test_maths_halfpercent_U16(void)
void test_maths_halfPercentage_perf(void)
{
#if defined(ARDUINO_ARCH_AVR)
constexpr int16_t iters = 4;
constexpr uint8_t start_index = 3;
constexpr uint8_t end_index = 99;
@ -78,11 +79,13 @@ void test_maths_halfPercentage_perf(void)
TEST_ASSERT_INT32_WITHIN(UINT32_MAX/2, comparison.timeA.result, comparison.timeB.result);
TEST_ASSERT_LESS_THAN(comparison.timeA.durationMicros, comparison.timeB.durationMicros);
#endif
}
void test_maths_percentage_perf(void)
{
#if defined(ARDUINO_ARCH_AVR)
constexpr uint16_t iters = 4;
constexpr uint8_t start_index = 3;
constexpr uint8_t end_index = 99;
@ -99,6 +102,7 @@ void test_maths_percentage_perf(void)
TEST_ASSERT_INT32_WITHIN(UINT32_MAX/2, comparison.timeA.result, comparison.timeB.result);
TEST_ASSERT_LESS_THAN(comparison.timeA.durationMicros, comparison.timeB.durationMicros);
#endif
}
void testPercent()