diff --git a/comms.ino b/comms.ino index 363f9cc..86c28ac 100644 --- a/comms.ino +++ b/comms.ino @@ -80,9 +80,9 @@ void sendValues(int length) boolean a = 0; //inj_port1.status; boolean b = 0; //inj_port2.status; - response[1] = ((a & 0x01) << 0) | ((a & 0x02) << 1) | ((a & 0x04) << 1) | ((b & 0x01) << 1) | ((b & 0x02) << 3) | ((b & 0x04) << 3); //squirt NOT YET WORKING + response[1] = currentStatus.squirt; //((a & 0x01) << 0) | ((a & 0x02) << 1) | ((a & 0x04) << 1) | ((b & 0x01) << 1) | ((b & 0x02) << 3) | ((b & 0x04) << 3); //squirt NOT YET WORKING - response[2] = (byte)128; // Engine Status NOT YET WORKING + response[2] = currentStatus.engine; // Engine Status NOT YET WORKING response[3] = 0x00; //baro response[4] = currentStatus.MAP; //map response[5] = 0x00; //mat @@ -126,13 +126,15 @@ void receiveValue(byte offset, byte newValue) if (offset < 72) { //X Axis - *(pnt_configPage + offset) = newValue * 100; //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct + //*(pnt_configPage + offset) = newValue * 100; //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct + fuelTable.axisX[(offset-64)] = newValue * 100; //The RPM values sent by megasquirt are divided by 100, need to multiple it back by 100 to make it correct } else { //Y Axis offset = 7-(offset-72); //Need to do a translation to flip the order (Due to us using (0,0) in the top left rather than bottom right - *(pnt_configPage + offset) = newValue; + //*(pnt_configPage + offset) = newValue; + fuelTable.axisY[offset] = newValue; } } else //New value is one of the remaining config items @@ -174,6 +176,11 @@ void receiveValue(byte offset, byte newValue) } } +/* +sendPage() packs the data within the current page (As set with the 'P' command) +into a buffer and sends it. +Note that some translation of the data is required to lay it out in the way Megasqurit / TunerStudio expect it +*/ void sendPage() { byte response[page_size]; @@ -185,7 +192,7 @@ void sendPage() case vePage: //Need to perform a translation of the values[MAP/TPS][RPM] into the MS expected format //MS format has origin (0,0) in the bottom left corner, we use the top left for efficiency reasons - for(byte x=0;x<64;x++) { response[x] = fuelTable.values[7-x/8][x%8]; } + for(byte x=0;x<64;x++) { response[x] = fuelTable.values[7-x/8][x%8]; } //This is slightly non-intuitive, but essentially just flips the table vertically (IE top line becomes the bottom line etc). Columns are unchanged for(byte x=64;x<72;x++) { response[x] = fuelTable.axisX[(x-64)] / 100; } //RPM Bins for VE table (Need to be dvidied by 100) for(byte y=72;y<80;y++) { response[y] = fuelTable.axisY[7-(y-72)]; } //MAP or TPS bins for VE table @@ -196,44 +203,6 @@ void sendPage() { response[offset] = *(pnt_configPage + offset + x); //Each byte is simply the location in memory of configPage1 + the offset + the variable number (x) } - /* - response[80] = configPage1.crankCold; //Cold cranking pulsewidth. This is added to the fuel pulsewidth when cranking under a temp threshold (ms) - response[81] = configPage1.crankHot; //Warm cranking pulsewidth. This is added to the fuel pulsewidth when cranking (ms) - response[82] = configPage1.asePct; //Afterstart enrichment (%) - response[83] = configPage1.aseCount; //Afterstart enrichment cycles. This is the number of ignition cycles that the afterstart enrichment % lasts for - for(byte x=84;x<94;x++) { response[x] = configPage1.wueBins[x-84]; } //Warm up enrichment array (10 bytes, % values) - response[94] = configPage1.taeBins1; //TPS based acceleration enrichment bin 1 of 4 (ms) - response[95] = configPage1.taeBins2; //TPS based acceleration enrichment bin 2 of 4 (ms) - response[96] = configPage1.taeBins3; //TPS based acceleration enrichment bin 3 of 4 (ms) - response[97] = configPage1.taeBins4; //TPS based acceleration enrichment bin 4 of 4 (ms) - response[98] = 0; - response[99] = 0; - response[100] = 0; - response[101] = 0; - response[102] = 0; - response[103] = 0; - response[104] = 0; - response[105] = 0; - response[106] = configPage1.reqFuel; - response[107] = 0; - response[108] = 0; - response[109] = 0; - response[110] = 0; - response[111] = 0; - response[112] = 0; - response[113] = 0; - response[114] = 0; //rpmk (16 bits) - response[116] = ((configPage1.nCylinders-1) * 16) + (1 * 8) + ((configPage1.strokes / 4) * 4) + 2; // (engineCylinders * 16) + (1 * 8) + ((engineStrokes / 4) * 4) + 4 - response[117] = 0; - response[118] = 0; - response[119] = 0; - response[120] = 0; - response[121] = 0; - response[122] = 0; - response[123] = 0; - response[124] = 0; - */ - Serial.write((byte *)&response, sizeof(response)); break; diff --git a/globals.h b/globals.h index 5eb6967..fe1a110 100644 --- a/globals.h +++ b/globals.h @@ -12,8 +12,16 @@ struct statuses { byte MAP; byte TPS; byte VE; + byte squirt; + byte engine; unsigned long PW; //In uS + //Helpful bitwise operations: + //Useful reference: http://playground.arduino.cc/Code/BitMath + // y = (x >> n) & 1; // n=0..15. stores nth bit of x in y. y becomes 0 or 1. + // x &= ~(1 << n); // forces nth bit of x to be 0. all other bits left alone. + // x |= (1 << n); // forces nth bit of x to be 1. all other bits left alone. + }; diff --git a/kartduino.ino b/kartduino.ino index cf2bc32..322ed3c 100644 --- a/kartduino.ino +++ b/kartduino.ino @@ -28,7 +28,7 @@ Need to calculate the req_fuel figure here, preferably in pre-processor macro #include "comms.h" #include "fastAnalog.h" -#include "digitalIOPerformance.h" +//#include "digitalIOPerformance.h" //NEED TO LOAD FROM EEPROM HERE struct config1 configPage1; @@ -45,6 +45,8 @@ int triggerToothAngle = 360 / configPage2.triggerTeeth; //The number of degrees volatile int toothCurrentCount = 0; //The current number of teeth (Onec sync has been achieved, this can never actually be 0 volatile unsigned long toothLastToothTime = 0; //The time (micros()) that the last tooth was registered volatile unsigned long toothLastMinusOneToothTime = 0; //The time (micros()) that the tooth before the last tooth was registered +volatile unsigned long toothOneTime = 0; //The time (micros()) that tooth 1 last triggered +volatile unsigned long toothOneMinusOneTime = 0; //The 2nd to last time (micros()) that tooth 1 last triggered struct table fuelTable; struct table ignitionTable; @@ -69,7 +71,6 @@ void setup() { switch (pinTrigger) { //Arduino Mega 2560 mapping (Uncomment to use) - /* case 2: triggerInterrupt = 0; break; case 3: @@ -82,9 +83,10 @@ void setup() { triggerInterrupt = 3; break; case 21: triggerInterrupt = 2; break; - */ + //Arduino Leo(nardo/stick) mapping (Comment this section if using a mega) + /* case 3: triggerInterrupt = 0; break; case 2: @@ -95,8 +97,11 @@ void setup() { triggerInterrupt = 3; break; case 7: triggerInterrupt = 4; break; + */ } - attachInterrupt(triggerInterrupt, trigger, FALLING); // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) + pinMode(pinTrigger, INPUT); + digitalWrite(pinTrigger, HIGH); + attachInterrupt(triggerInterrupt, trigger, RISING); // Attach the crank trigger wheel interrupt (Hall sensor drags to ground when triggering) //End crank triger interrupt attachment req_fuel_uS = req_fuel_uS / engineSquirtsPerCycle; //The req_fuel calculation above gives the total required fuel (At VE 100%) in the full cycle. If we're doing more than 1 squirt per cycle then we need to split the amount accordingly. (Note that in a non-sequential 4-stroke setup you cannot have less than 2 squirts as you cannot determine the stroke to make the single squirt on) @@ -120,6 +125,11 @@ void setup() { initialiseScheduler(); counter = 0; + configPage2.triggerTeeth = 12; //TESTING ONLY! + configPage2.triggerMissingTeeth = 1; //TESTING ONLY! + triggerActualTeeth = configPage2.triggerTeeth - configPage2.triggerMissingTeeth; //The number of physical teeth on the wheel. Doing this here saves us a calculation each time in the interrupt + triggerToothAngle = 360 / configPage2.triggerTeeth; + //Setup some LEDs for testing pinMode(10, OUTPUT); pinMode(9, OUTPUT); @@ -127,6 +137,31 @@ void setup() { void loop() { + + //Check for any requets from serial + //Serial.println(toothCurrentCount); + //if (toothCurrentCount == 1) //Only check the serial buffer (And hence process serial commands) once per revolution + //{ + if (Serial.available() > 0) + { + command(); + } + + //Serial.print("Trigger Teeth: "); + //Serial.println(configPage2.triggerTeeth); + /* + Serial.print("Tooth last time: "); + Serial.println(toothLastToothTime); + Serial.print("Tooth last minus one time: "); + Serial.println(toothLastMinusOneToothTime); + */ + Serial.print("RPM: "); + Serial.println(currentStatus.RPM); + /* + //Serial.print("toothLastToothTime: "); + //Serial.println(toothLastToothTime); + */ + //} //delay(2500); //Always check for sync //Main loop runs within this clause @@ -134,15 +169,19 @@ void loop() { //Calculate the RPM based on the time between the last 2 teeth. I have no idea whether this will be accurate AT ALL, but it's fairly efficient and means there doesn't need to be another variable placed into the trigger interrupt - if (toothCurrentCount != 1) //We can't perform the RPM calculation if we're at the first tooth as the timing would be double (Well, we can, but it would need a different calculation and I don't think it's worth it, just use the last RPM value) + if (toothCurrentCount != 1 && toothLastMinusOneToothTime != 0) //We can't perform the RPM calculation if we're at the first tooth as the timing would be double (Well, we can, but it would need a different calculation and I don't think it's worth it, just use the last RPM value) { - long revolutionTime = (configPage2.triggerTeeth * (toothLastToothTime - toothLastMinusOneToothTime)); //The time in uS that one revolution would take at current speed + //unsigned long revolutionTime = ((long)configPage2.triggerTeeth * (toothLastToothTime - toothLastMinusOneToothTime)); //The time in uS that one revolution would take at current speed + unsigned long revolutionTime = (toothOneTime - toothOneMinusOneTime); //The time in uS that one revolution would take at current speed + //Serial.println((toothLastToothTime - toothLastMinusOneToothTime)); currentStatus.RPM = US_IN_MINUTE / revolutionTime; } + if ( (micros() - toothLastToothTime) > 100000L ) { currentStatus.RPM = 0; toothLastMinusOneToothTime = 0;} //Get the current MAP value //currentStatus.MAP = 100; //Placeholder currentStatus.MAP = map(analogRead(pinMAP), 0, 1023, 0, 100); currentStatus.TPS = 20; //Placeholder + //currentStatus.TPS = map(analogRead(pinTPS), 0, 1023, 0, 100); //Begin the fuel calculation //Perform lookup into fuel map for RPM vs MAP value @@ -189,53 +228,9 @@ void loop() ); } - //Check for any requets from serial - //Serial.println(toothCurrentCount); - if (toothCurrentCount == 1) //Only check the serial buffer (And hence process serial commands) once per revolution - { - if (Serial.available() > 0) - { - command(); - } - } - - - //Serial.println(VE); - //Serial.print("VE: "); - //Serial.println(VE); - - //Serial.print("Injector pulsewidth: "); - //Serial.println(pulseWidth); - //Serial.println(req_fuel * (float)(VE/100.0) * (float)(MAP/100.0) * (float)(100/100.0) + engineInjectorDeadTime); - //Serial.println( (float)(req_fuel * (float)(VE/100)) ); - //Serial.println( (float)(VE/100.0)); - - /* - if (counter > 100000) { - scheduleStart = micros(); - setSchedule1(openInjector2, 1000000); - counter = 0; - } - counter++; - - - if (scheduleEnd != 0) { - Serial.print("The schedule took (uS): "); - Serial.println(scheduleEnd - scheduleStart); - scheduleEnd = 0; - } - */ - trigger(); - delay(1); } else { getSync(); } - - - //Serial.println(toothLastToothTime); - //Serial.println(toothLastMinusOneToothTime); - //Serial.println(rpm); - //delay(100); } @@ -254,7 +249,7 @@ void getSync() //The are some placeholder values so we can get a fake RPM toothLastMinusOneToothTime = micros(); - delay(1); //A 1000us delay should make for about a 5000rpm test speed with a 12 tooth wheel(60000000us / (1000us * triggerTeeth) + //delay(1); //A 1000us delay should make for about a 5000rpm test speed with a 12 tooth wheel(60000000us / (1000us * triggerTeeth) toothLastToothTime = micros(); currentStatus.hasSync = true; @@ -275,18 +270,28 @@ void trigger() { // http://www.msextra.com/forums/viewtopic.php?f=94&t=22976 // http://www.megamanual.com/ms2/wheel.htm + unsigned long curTime = micros(); - toothCurrentCount++; //Increment the tooth counter + if ( (curTime - toothLastToothTime) < 500) { return; } //Debounce check. Pulses should never be less than 100uS, so if they are it means a false trigger. (A 36-1 wheel at 8000pm will have triggers approx. every 200uS) + toothCurrentCount++; //Increment the tooth counter + //Serial.println("Got trigger"); //Begin the missing tooth detection //If the time between the current tooth and the last is greater than 1.5x the time between the last tooth and the tooth before that, we make the assertion that we must be at the first tooth after the gap //if ( (curTime - toothLastToothTime) > (1.5 * (toothLastToothTime - toothLastMinusOneToothTime))) { toothCurrentCount = 1; } - if ( (curTime - toothLastToothTime) > ((3 * (toothLastToothTime - toothLastMinusOneToothTime))>>1)) { toothCurrentCount = 1; } //Same as above, but uses bitshift instead of multiplying by 1.5 - if (toothCurrentCount > triggerActualTeeth) { toothCurrentCount = 1; } //For testing ONLY + //if ( (curTime - toothLastToothTime) > ((3 * (toothLastToothTime - toothLastMinusOneToothTime))>>1)) { toothCurrentCount = 1; } //Same as above, but uses bitshift instead of multiplying by 1.5 + if (toothCurrentCount > triggerActualTeeth) + { + toothCurrentCount = 1; + toothOneMinusOneTime = toothOneTime; + toothOneTime = curTime; + } //For testing ONLY - // Update the last few tooth times toothLastMinusOneToothTime = toothLastToothTime; toothLastToothTime = curTime; + // Update the last few tooth times + //toothLastMinusOneToothTime = toothLastToothTime; + //toothLastToothTime = curTime; } diff --git a/storage.h b/storage.h index 0de2654..9944623 100644 --- a/storage.h +++ b/storage.h @@ -30,7 +30,7 @@ Current layout of EEPROM data (Version 1) is as follows (All sizes are in bytes) #define EEPROM_CONFIG1_MAP 3 #define EEPROM_CONFIG1_XBINS 67 #define EEPROM_CONFIG1_YBINS 75 -#define EEPROM_CONFIG1_SETTINGS 85 +#define EEPROM_CONFIG1_SETTINGS 83 #define EEPROM_CONFIG2_XSIZE 128 #define EEPROM_CONFIG2_YSIZE 129 #define EEPROM_CONFIG2_MAP 130 diff --git a/storage.ino b/storage.ino index f8778b3..c0c5b40 100644 --- a/storage.ino +++ b/storage.ino @@ -1,5 +1,9 @@ #include +/* +Takes the current configuration (config pages and maps) +and writes the to EEPROM in the layout defined in storage.h +*/ void writeConfig() { /* @@ -7,16 +11,37 @@ void writeConfig() This is due to the limited write life of the EEPROM (Approximately 100,000 writes) */ + int offset; + //Create a pointer to the config page + byte* pnt_configPage; + pnt_configPage = (byte *)&configPage1; //Create a pointer to Page 1 in memory + if(EEPROM.read(0) != data_structure_version) { EEPROM.write(0,data_structure_version); } //Write the data structure version + + //Fuel table (See storage.h for data layout) if(EEPROM.read(EEPROM_CONFIG1_XSIZE) != fuelTable.xSize) { EEPROM.write(EEPROM_CONFIG1_XSIZE, fuelTable.xSize); } //Write the VE Tables RPM dimension size if(EEPROM.read(EEPROM_CONFIG1_YSIZE) != fuelTable.ySize) { EEPROM.write(EEPROM_CONFIG1_YSIZE, fuelTable.ySize); } //Write the VE Tables MAP/TPS dimension size - - byte* pnt_configPage; - //The next 125 bytes can simply be pulled straight from the fuelTable - pnt_configPage = (byte *)&configPage1; //Create a pointer to Page 1 in memory - for(int x=EEPROM_CONFIG1_MAP; x