Added Trigger for the Yamaha Vmax motorcycle, 1990 and up. (#823)

* Test 1

* Added the Vmax decoder option

* Added the Yamaha Vmax decoder

Co-authored-by: RempageR1 <unconfigured@null.spigotmc.org>
Co-authored-by: Josh Stewart <josh@noisymime.org>
This commit is contained in:
RempageR1 2022-04-11 03:08:22 +02:00 committed by GitHub
parent 7020705dbe
commit d8be3f56e8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 208 additions and 1 deletions

View File

@ -168,6 +168,7 @@
#define trigger_FordST170 = 20
#define trigger_DRZ400 = 21
#define trigger_NGC = 22
#define trigger_VMAX = 23
[Constants]
@ -479,7 +480,7 @@ page = 4
TrigEdge = bits, U08, 5,[0:0], "RISING", "FALLING"
TrigSpeed = bits, U08, 5,[1:1], "Crank Speed", "Cam Speed"
IgInv = bits, U08, 5,[2:2], "Going Low", "Going High"
TrigPattern= bits, U08, 5,[3:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata / 3000GT", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "Subaru 6/7", "Daihatsu +1", "Harley EVO", "36-2-2-2", "36-2-1", "DSM 420a", "Weber-Marelli", "Ford ST170", "DRZ400", "Chrysler NGC", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
TrigPattern= bits, U08, 5,[3:7], "Missing Tooth", "Basic Distributor", "Dual Wheel", "GM 7X", "4G63 / Miata / 3000GT", "GM 24X", "Jeep 2000", "Audi 135", "Honda D17", "Miata 99-05", "Mazda AU", "Non-360 Dual", "Nissan 360", "Subaru 6/7", "Daihatsu +1", "Harley EVO", "36-2-2-2", "36-2-1", "DSM 420a", "Weber-Marelli", "Ford ST170", "DRZ400", "Chrysler NGC", "Yamaha Vmax 1990+", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID", "INVALID"
TrigEdgeSec= bits, U08, 6,[0:0], "RISING", "FALLING"
fuelPumpPin= bits , U08, 6,[1:6], "Board Default", "INVALID", "INVALID", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "50", "51", "52", "53", "INVALID", "A8", "A9", "A10", "A11", "A12", "A13", "A14", "A15", "INVALID"
useResync = bits, U08, 6,[7:7], "No", "Yes"

View File

@ -34,6 +34,7 @@
#define DECODER_ST170 20
#define DECODER_DRZ400 21
#define DECODER_NGC 22
#define DECODER_VMAX 23
//This isn't to to filter out wrong pulses on triggers, but just to smooth out the cam angle reading for better closed loop VVT control.
#define ANGLE_FILTER(input, alpha, prior) (((long)input * (256 - alpha) + ((long)prior * alpha))) >> 8

View File

@ -4568,4 +4568,196 @@ void triggerSetEndTeeth_NGC()
lastToothCalcAdvance = currentStatus.advance;
}
/** Yamaha Vmax 1990+ with 6 uneven teeth, triggering on the wide lobe.
Within the decoder code, the sync tooth is referred to as tooth #1. Derived from Harley and made to work on the Yamah Vmax.
Trigger is based on 'CHANGE' so we get a signal on the up and downward edges of the lobe. This is required to identify the wide lobe.
* @defgroup dec_vmax Yamaha Vmax
* @{
*/
void triggerSetup_Vmax()
{
triggerToothAngle = 0; // The number of degrees that passes from tooth to tooth, ev. 0. It alternates uneven
secondDerivEnabled = false;
decoderIsSequential = false;
MAX_STALL_TIME = (3333UL * 60); //Minimum 50rpm. (3333uS is the time per degree at 50rpm)
if(initialisationComplete == false) { toothLastToothTime = micros(); } //Set a startup value here to avoid filter errors when starting. This MUST have the initi check to prevent the fuel pump just staying on all the time
triggerFilterTime = 1500;
validTrigger = true; // We must start with a valid trigger or we cannot start measuring the lobe width. We only have a false trigger on the lobe up event when it doesn't pass the filter. Then, the lobe width will also not be beasured.
toothAngles[1] = 0; //tooth #1, these are the absolute tooth positions
toothAngles[2] = 40; //tooth #2
toothAngles[3] = 110; //tooth #3
toothAngles[4] = 180; //tooth #4
toothAngles[5] = 220; //tooth #5
toothAngles[6] = 290; //tooth #6
}
//curGap = The difference between the rising lobes.
//curGap2 = the time in micros when the rising lobe is seen
//curGap3 = the time in micros when the falling lobe is seen
//toothCurrentCount = the current number for the end of a lobe
//secondaryToothCount = the current number of the beginning of a lobe
//We measure the width of a lobe so on the end of a lobe, but want to trigger on the beginning. Variable toothCurrentCount tracks the downward events, and secondaryToothCount updates on the upward events. Ideally, it should be the other way round but the engine stall routine resets secondaryToothCount, so it would not sync again after an engine stall.
void triggerPri_Vmax()
{
curTime = micros();
if(READ_PRI_TRIGGER() == primaryTriggerEdge){// Forwarded from the config page to setup the primary trigger edge (rising or falling). Inverting VR-conditioners require FALLING, non-inverting VR-conditioners require RISING in the Trigger edge setup.
curGap2 = curTime;
curGap = curTime - toothLastToothTime;
if ( (curGap >= triggerFilterTime) ){
validTrigger = true;
if (toothCurrentCount > 0) // We have sync based on the tooth width.
{
validTrigger = true; //Flag this pulse as being a valid trigger (ie that it passed filters)
if (toothCurrentCount==1)
{
secondaryToothCount = 1;
triggerToothAngle = 70;// Has to be equal to Angle Routine, and describe the delta between two teeth.
toothOneMinusOneTime = toothOneTime;
toothOneTime = curTime;
currentStatus.hasSync = true;
setFilter((curGap/1.75));//Angle to this tooth is 70, next is in 40, compensating.
}
else if (toothCurrentCount==2)
{
secondaryToothCount = 2;
triggerToothAngle = 40;
setFilter((curGap*1.75));//Angle to this tooth is 40, next is in 70, compensating.
}
else if (toothCurrentCount==3)
{
secondaryToothCount = 3;
triggerToothAngle = 70;
setFilter(curGap);//Angle to this tooth is 70, next is in 70. No need to compensate.
}
else if (toothCurrentCount==4)
{
secondaryToothCount = 4;
triggerToothAngle = 70;
setFilter((curGap/1.75));//Angle to this tooth is 70, next is in 40, compensating.
}
else if (toothCurrentCount==5)
{
secondaryToothCount = 5;
triggerToothAngle = 40;
setFilter((curGap*1.75));//Angle to this tooth is 40, next is in 70, compensating.
}
else if (toothCurrentCount==6)
{
secondaryToothCount = 6;
triggerToothAngle = 70;
setFilter(curGap);//Angle to this tooth is 70, next is in 70. No need to compensate.
}
toothLastMinusOneToothTime = toothLastToothTime;
toothLastToothTime = curTime;
currentStatus.startRevolutions++; //Counter
if (triggerFilterTime > 50000){//The first pulse seen
triggerFilterTime = 0;
}
}
else{
triggerFilterTime = 0;
return;//Zero, no sync yet.
}
}
else{
validTrigger = false;
}
}
else if (validTrigger == true){// Inverted due to vr conditioner. So this is the falling lobe. We only process if there was a valid trigger.
curGap3 = curTime - curGap2;
if (curGap3 > (lastGap * 2)){// Small lobe is 5 degrees, big lobe is 45 degrees. So this should be the wide lobe.
if (toothCurrentCount == 0 || toothCurrentCount == 6){//Wide should be seen with toothCurrentCount = 0, when there is no sync yet, or toothCurrentCount = 6 when we have done a full revolution.
currentStatus.hasSync = true;
}
else{//Wide lobe seen where it shouldn't, adding a sync error.
currentStatus.syncLossCounter++;
}
toothCurrentCount = 1;
}
else if(toothCurrentCount == 6){//The 6th lobe should be wide, adding a sync error.
toothCurrentCount = 1;
currentStatus.syncLossCounter++;
}
else{// Small lobe, just add 1 to the toothCurrentCount.
toothCurrentCount++;
}
lastGap = curGap3;
return;
}
else if (validTrigger == false){
validTrigger == true;//We reset this every time to ensure we only filter when needed.
}
}
void triggerSec_Vmax()
// Needs to be enabled in main()
{
return;// No need for now. The only thing it could help to sync more quikly or confirm position.
} // End Sec Trigger
uint16_t getRPM_Vmax()
{
uint16_t tempRPM = 0;
if (currentStatus.hasSync == true)
{
if ( currentStatus.RPM < (unsigned int)(configPage4.crankRPM * 100) )
{
int tempToothAngle;
unsigned long toothTime;
if ( (toothLastToothTime == 0) || (toothLastMinusOneToothTime == 0) ) { tempRPM = 0; }
else
{
noInterrupts();
tempToothAngle = triggerToothAngle;
revolutionTime = (toothOneTime - toothOneMinusOneTime); //The time in uS that one revolution would take at current speed (The time tooth 1 was last seen, minus the time it was seen prior to that)
toothTime = (toothLastToothTime - toothLastMinusOneToothTime);
interrupts();
toothTime = toothTime * 36;
tempRPM = ((unsigned long)tempToothAngle * 6000000UL) / toothTime;
}
}
else {
tempRPM = stdGetRPM(360);
}
}
return tempRPM;
}
int getCrankAngle_Vmax()
{
//This is the current angle ATDC the engine is at. This is the last known position based on what tooth was last 'seen'. It is only accurate to the resolution of the trigger wheel (Eg 36-1 is 10 degrees)
unsigned long tempToothLastToothTime;
int tempsecondaryToothCount;
//Grab some variables that are used in the trigger code and assign them to temp variables.
noInterrupts();
tempsecondaryToothCount = secondaryToothCount;
tempToothLastToothTime = toothLastToothTime;
lastCrankAngleCalc = micros(); //micros() is no longer interrupt safe
interrupts();
//Check if the last tooth seen was the reference tooth (Number 3). All others can be calculated, but tooth 3 has a unique angle
int crankAngle;
crankAngle=toothAngles[tempsecondaryToothCount] + configPage4.triggerAngle;
//Estimate the number of degrees travelled since the last tooth}
elapsedTime = (lastCrankAngleCalc - tempToothLastToothTime);
crankAngle += timeToAngle(elapsedTime, CRANKMATH_METHOD_INTERVAL_REV);
if (crankAngle >= 720) { crankAngle -= 720; }
if (crankAngle > CRANK_ANGLE_MAX) { crankAngle -= CRANK_ANGLE_MAX; }
if (crankAngle < 0) { crankAngle += 360; }
return crankAngle;
}
void triggerSetEndTeeth_Vmax()
{
lastToothCalcAdvance = currentStatus.advance;
}
/** @} */

View File

@ -3275,6 +3275,19 @@ void initialiseTriggers()
attachInterrupt(triggerInterrupt2, triggerSecondaryHandler, secondaryTriggerEdge);
break;
case DECODER_VMAX:
triggerSetup_Vmax();
triggerHandler = triggerPri_Vmax;
getRPM = getRPM_Vmax;
getCrankAngle = getCrankAngle_Vmax;
triggerSetEndTeeth = triggerSetEndTeeth_Vmax;
if(configPage4.TrigEdge == 0) { primaryTriggerEdge = true; } // set as boolean so we can directly use it in decoder.
else { primaryTriggerEdge = false; }
attachInterrupt(triggerInterrupt, triggerHandler, CHANGE); //Hardcoded change, the primaryTriggerEdge will be used in the decoder to select if it`s an inverted or non-inverted signal.
break;
default:
triggerHandler = triggerPri_missingTooth;
getRPM = getRPM_missingTooth;