I have a program that is polling data from another micro at 20Hz at 115200 baud rate. Each packet of data is 112 bytes long. I'm receiving the data into an array and then parse out the high and low byte and turn the data back into human values. From there I do a for loop and write all the data I just placed in the array to the SD card. I'm also creating CAN messages to transmit along with receiving messages. Everything work like it should as long as the SD card is not installed into it's slot. The CAN messages are producing the desired outputs into a GUI. Once the project is powered down and the SD card placed in the holder and powered back up, I get a couple seconds of good CAN data on the GUI then it all goes to crap. I can pull the SD card and view the .csv file and see where all the serial referenced values get shifted to the right or to the left a few spots.
I expanded the size of the RX buffer in the serial3.h file to 128 bytes. I also change the priority from 64 to 2.
I'm on a Teensy3.2, SDfat, and FlexCAN, Serial3.
What sucks the most is I had this all working really well months back and now I'm having to fight it so bad.
I expanded the size of the RX buffer in the serial3.h file to 128 bytes. I also change the priority from 64 to 2.
I'm on a Teensy3.2, SDfat, and FlexCAN, Serial3.
What sucks the most is I had this all working really well months back and now I'm having to fight it so bad.
Code:
#include <FlexCAN.h>
#include <kinetis_flexcan.h>
#include <SPI.h>
#include "SdFat.h"
#include <Servo.h>
#include <FreqMeasureMulti.h> // Used to measure input pulses from the ECU for tach signal RPM.
#include <EEPROM.h>
elapsedMillis duration;
Servo ThrottleServo;
IntervalTimer Halfsec;
IntervalTimer Tenthsec;
IntervalTimer Tenhz;
FreqMeasureMulti RPMin;
FreqMeasureMulti CH3in;
///////////////pin assignment////////////////////////////////////////////////
//0- RX1 to RS232 IC
//1- TX1 to RS232 IC
//2- unused
//3- CAN tx
//4- CAN rx
//5- Ch3 input
int EnableIN = 6; // from 14pin input harness
//7- RX3 to uSquirt Mod
//8- TX3 to uSquirt Mod
//9- Servo Out
//10- CS to uSD Card-2
//11- DOUT to uSD Card-3
//12- DIN to uSD Card-7
//13- SCK/LED to uSD Card-5
int EnableOUT = 14;// to HT0440 for 12/5v power enable
int FPsignal = 15; // from uSquirt FP output
int BatVolt = A2; //pin 16
int FPaIN = A3; //pin 17 from JST14-2
int PM5 = 18; // I2C SDA
int PM4 = 19; // I2C SCL
//20- Measure RPM from uSquirt
int IgnPwr = A7; // 21
int Fault = 22; // fault light
int FPOUT = 23; // PWM or digital on for fuelpump relay
//ThrottleA = DAC; // analog TPS signal, representive of PWM input.
float SdValue[32]; // holds data to write to SD card.
uint8_t serbuff[113]; // holds serial data from MS2
uint8_t setbuff[2]; // settings buffer for changing EEPROM settings.
uint16_t value[5]; //place to hold HOBS values, time and file number
uint8_t serialBlast[32]; // place to hold for serial blast to AP.
String hobs = ""; // a way to receive ascii characters from the text doc.
//int baudr = 1000000; //1Mb rate
FlexCAN CANbus(1000000);
static CAN_message_t txmsg,rxmsg;
#define ECUOUT 0x8
#define ECUIN 0x9
#define CANFAST 0x00
#define CANSLOW0 0x01
#define CANSLOW1 0x02
#define CANSLOW2 0x03
#define THROTTLECAL 0x05
#define THROTTLECMD 0x06
#define HARDCONFIG 0x0A
#define TOTALENGINETIME 0x13
#define POWERCYCLES 0x10
#define SWVERSION 0x0B
#define USERSETTING 0x14
#define USERDATA 0x60
uint8_t serial = 0;
uint8_t k = 0;
uint8_t SdGood, seconds, CAN_seconds, i, fault, TPS8, ServoOUT_H, ServoOUT_L, Input_type, IGN8, flow;
uint8_t counter1, counter2, counter3, count, CANinput, CHT8c, BATV8, baroH, baroL, SDfull;
uint32_t Eminutes, engineRev, EngineTime, steps; // engine minutes
int inChar, inchar, number;
int b = 1; // sets fuel pump on during power up.
int location = 0;
uint16_t fuelUsed, RPM, ServoIN, ServoOUT, powercycles, firstFile, PWraw;
uint16_t ECUID, CAN_Throttle, TPSadc;
uint8_t ENABLE, CANBUS, TPSINPUT, FUELPUMP, MAP8;
uint32_t CANinputMessage;
uint8_t Status, ChargTemp, InjDutyH, InjDutyL; // ECU condition enable and serial mode.
int8_t MAT8c;
uint8_t EngineTime0, EngineTime1, EngineTime2, syscmd,g_hrH,g_hrL;
uint16_t FuelUsedDiv,ThrottleClosed, ThrottleOpen;
float slope, yint, g_hr;
uint8_t gramsL, gramsML, gramsMH, gramsH;
uint16_t deadtime, grams;
//File object
//SD chip select pin.
const uint8_t chipSelect = SS;
SdFat sd;
SdFile file; // for test.txt file
SdFile logfile; // for .csv file
//char newfile[13] = "D0000.csv"; // base name for .csv file. updat positions 1,2,3,4 from .txt file
char newfile[13]; // base name for .csv file. updat positions 1,2,3,4 from .txt file
char firstfile[13]; // array for the first file to be deleted.
/////////////////////////////////////////////Set Up///////////////////////////////////////////////////
void setup() {
pinMode(EnableIN, INPUT); // read input state for Enable
pinMode(EnableOUT, OUTPUT); // drive the HT0440 to power Inj and Ign.
pinMode(FPsignal, INPUT); // read state of FP drive pin from uSquirt Module
pinMode(BatVolt, INPUT); // measure battery voltage level
pinMode(FPaIN, INPUT); // measure fuel pressure
pinMode(PM5, INPUT); // read state of ECU pin
pinMode(PM4, INPUT); // read state of ECU pin
pinMode(IgnPwr, INPUT); // measure 5v reg voltage level
pinMode(Fault, OUTPUT); // drive fualt lamp
pinMode(FPOUT, OUTPUT); // drive fuel pump relay
digitalWrite(FPOUT,b); // on power up turn on Fuel Pump relay.
SDfull = EEPROM.read(12); // check for prior SD car volume with less than 750MiB
IntSdCard(); // start SD card.
if(SdGood){ //if sd card good then open some files
OpenHobs(); // open test.txt and get engine run time and current file name for logging
NewFile(); // create new .csv file for logging
writeHeader(); // write header info
}
Read_Eeprom();// Grab setting values from EEPROM.
Do_Math();
Halfsec.begin(HalfSec, 500000);
RPMin.begin(20,FREQMEASUREMULTI_RAISING);// capture RPM input signal
CH3in.begin(5, FREQMEASUREMULTI_MARK_ONLY);// capture incoming throttle command.
Tenthsec.begin(TenthSec, 100000);// Serial3 output to AP.
delay(50);
Tenhz.begin(TwentyHZ, 50000); // 20 hz CAN fast out and ECU data request
Serial1.begin(115200); // to RS232 then to JST14 connector for external tuning
Serial.begin(115200); // for COM cummunication to laptop for setting EEPROM values
Serial3.begin(115200); // UART lines to uSquirt module
CANbus.begin();
}
////////////////////////////////////////Main Loop/////////////////////////////////////////////////////
void loop() {
checkSerial();
readRPM();
Channel3();
GetCAN();
////////////Read FP signal from uSquirtModule/////////
if (!FUELPUMP){
int c = digitalRead(FPsignal);
digitalWrite(FPOUT,c);
}else{
//Insert PWM code or subroutines here//////////
}
uint16_t w = analogRead(BatVolt); // 47k to 6.8k zero to 26.1 volts
float batteryVolt = w * 0.0255; // convert ADC to volts. ie. 512 adc X 0.0255 is 13.05V
SdValue[29] = batteryVolt;
uint16_t z = analogRead(FPaIN); //1k to 1k v-divid 6.6v max.
SdValue[22] = z;
uint16_t d = analogRead(IgnPwr); //1k to 1k v-divid. 6.6V max input.
SdValue[25] = d;
if (d <= 690){
fault = fault | 2; ;
}
}
////////////////////////////////Read EEPROM settings/////////////////////////////////////////////////
void Read_Eeprom(){// read eeprom data for settings options
ECUID = (EEPROM.read(0)<<8) | EEPROM.read(1); // get stored ECU ID/address
ENABLE = EEPROM.read(2); // 0= TPSenable, 1= Digital Enable, 2, TPS_CAN, 3= CAN/Digital Enable
CANBUS = EEPROM.read(3); // 0= off, 1=on(fast,slow0,slow1,slow2)
TPSINPUT = EEPROM.read(4); // 0=PWM(50hz), 1=CAN, 2=CAN/PWM
FUELPUMP = EEPROM.read(5); // 0= on/off, 1= PWM w/CL pressure feedback
FuelUsedDiv = (EEPROM.read(6)<<8) | EEPROM.read(7); // need to sort this out. Call out injector, 50, 150, 250, 450.
ThrottleClosed = (EEPROM.read(8)<<8) | EEPROM.read(9); // Throttle Closed pulse 800 to 1100. (3,132)=900
ThrottleOpen = (EEPROM.read(10)<<8) | EEPROM.read(11); // Throttle Open Pulse 1800 to 2200. (8,52)= 2100
//CANinputMessage = 0x906 << 16 | ECUID; // From AP for throttle command Group 9, FrameID 6, ECUID.
ThrottleServo.attach(9, ThrottleClosed, ThrottleOpen); // set min to 900us and max to 2100us SERVO out
}
///////////////////////////////Do Math for pulsein to analog out./////////////////////////////////////
void Do_Math(){
uint16_t delta = ThrottleOpen - ThrottleClosed;
slope = 1000/(float)delta;
yint = ThrottleClosed * slope;
// y = mx+b
//throttle% = inputpulse(slope) + yint.
//outputpulse = inputpulse.
}
/////////////////////////////////Record input pulse from AP or RX//////////////////////////////////////
void Channel3(){
if (CH3in.available()){
unsigned long a = CH3in.read();
ServoIN = a/24 - 10; // commanded throttle
counter2 = 0;
}
if(!TPSINPUT){ // PWM in only
if (counter2 >= 5){
fault = fault | 16;
ServoIN = 0;
Input_type = 0x00;
}
SdValue[21] = ServoIN;
ServoOUT = ServoIN;
Input_type = 0x20;
}else if(TPSINPUT == 1){// CAN only
SdValue[21] = CAN_Throttle; // zero to 255. 0.39% per step
float candelta = ThrottleOpen-ThrottleClosed;
ServoOUT = ((candelta/256) * CAN_Throttle)+ ThrottleClosed;
Input_type = 0x80;
}else if(TPSINPUT == 2){// CAN with backup PWM
}
if(ServoOUT >= ThrottleOpen){
ServoOUT = ThrottleOpen;
}else if(ServoOUT <= ThrottleClosed){
ServoOUT = ThrottleClosed;
}else {
//SerovOUT = ServoIN;
}
uint16_t throttle = ((float)ServoOUT * slope) - yint; // y=mx-b
TPSadc = throttle * 4; // convert xx.x to 0to4000.
analogWriteResolution(12); // zero to 4095
analogWrite(A14, TPSadc); // send new DAC value
ThrottleServo.writeMicroseconds(ServoOUT); //Update the servo position
ServoOUT_L = ServoOUT & 0xFF;// just grab and keep the low byte
ServoOUT_H = (ServoOUT >> 8 | Input_type); // just keep the high byte and or in "Input_type"
if(!ENABLE){
if(ServoIN >= (ThrottleClosed + 50)){
digitalWrite(EnableOUT, HIGH);
Status = 0x01;
}else{
digitalWrite(EnableOUT, LOW);
Status = 0x00;
}
}else if (ENABLE == 1){// Digital in ENABLE here/////////////
int h = digitalRead(EnableIN);
if(h){
digitalWrite(EnableOUT,HIGH);
Status = 0x01;
}else{
digitalWrite(EnableOUT, LOW);
Status = 0x00;
}
}else if(ENABLE == 2){// Digital and/or CAN input here////////
if(ServoOUT >= (ThrottleClosed + 50)){
digitalWrite(EnableOUT, HIGH);
Status = 0x01;
}else{
digitalWrite(EnableOUT, LOW);
Status = 0x00;
}
}
}
////////////////////Get RPM if present/////////////////////////////////////
void readRPM (){//Set up for 24Mhz
int batcor;
if (RPMin.available()){
unsigned long a = RPMin.read();// have to read the captured measement.
counter1 = 0;
engineRev++;
//Read PW.. find fuel amount for single pulse at that PW.. Maybe assign a value 0 to 1023 for the pulse. 9.77us per step.
//add the value to itself, then divide by a diviser to get true fuel used.
//
if(SdValue[8] >= 8.0){
batcor = (13.2 - SdValue[8]) * 100; // solve deatime of injector.
deadtime = 700 + batcor;
steps += (PWraw - deadtime); // keep adding PWraw minus deatime value to steps
uint16_t math2 = PWraw - deadtime;
}
float flowrate = (PWraw-deadtime) / (float)FuelUsedDiv; // instant flow of fuel in g/min...
g_hr = flowrate * 30; // go from g/min to g/hr
SdValue[28] = g_hr;
g_hrH = (uint16_t)g_hr >> 8; // grab high byte
g_hrL = (uint16_t)g_hr & 0xFF; // grab low byte
if(steps >= (FuelUsedDiv * 6000)){
grams++; // add one more gram used once steps adds up to more than fuelused(us) * 6000. 1 mintes worth of PW.
steps = 0;
SdValue[19] = grams;
}
gramsL = (uint16_t)grams & 0xFF; //grab the low byte
gramsML = (uint16_t)grams>>8 ; // grab the 2nd byte good to 144lbs of fuel
gramsMH = 0;
gramsH = 0;
if (counter1 >= 10){
RPM = 0;
}
if(SdValue[0] == 0){
SdValue[28] = 0;
SdValue[23] = 0;
//SdValue[] = 0;
}
}
}
//////////////////////////get serial data/////////////////////////////////////
void checkSerial(){
if (counter3 >= 100){ // check if JST14 COM port has been inactive for 5 sec
serial = 0; // resume data request from MS2
}
///////////////////USB serial input for changing settings////////////////////////////
if(Serial.available() > 0){ // setting input from teensy COM port.
inChar = Serial.read(); // only used to write new values into eeprom
setbuff[i] = inChar;
i++;
}
if(i >= 2){
if(setbuff[1] == 255){
for (int y=0; y<20; y++){
int val = EEPROM.read(y);
Serial.print(y);
Serial.print("\t");
Serial.println(val);
}
}else{
EEPROM.write(setbuff[0], setbuff[1]); //address then value to write to that address.
}
setbuff[0] = 0;
setbuff[1] = 0;
i = 0;
}
///////////////////End of USB serial checking/////////////////////////////////////////
//////////////////JST14 pin Serial input check///////////////////////////////////////
if(Serial1.available() > 0){ // check for data being used from JST14 COM port
serial = 1; // stops teensy from requesting data from MS2
counter3 = 0; // keep track of when data is nolonger being sent from and to JST14 COM port
}
///////////////////Receive data from MS2//////////////////////////////////////////
if(!serial){ // receive data from MS2
// if (Serial3.available() >0){
// inChar = Serial3.read(); // read data into array serbuff
// serbuff[k] = inChar;
// k++; // keep track of number fo bytes received.
// }
while(Serial3.available() && k <= 112){
inChar = Serial3.read(); // read data into array serbuff
serbuff[k] = inChar;
k++; // keep track of number fo bytes received.
}
}else{ // used for passing data in and out of JST14 COM port.
if (Serial3.available() >0 ){ // read from MS2
inChar = Serial3.read();
Serial1.write(inChar); // to JST14
}
if (Serial1.available() > 0){ // read from JST14
inChar = Serial1.read();
Serial3.write(inChar); // to MS2
}
}
if(!serial){
if (k >= 112){
Serial3.clear(); // serial3 buffer, clear buffer
pickdata();
storeData();
k = 0;
}else{
//Serial.println("K not counting");
}
} else{
//Serial.println("Serial = 1");
}
}
///////////////////////////pick out data from serial buffer/////////////////////////////////////
void pickdata(){
SdValue[0] = (serbuff[6]<<8) | (serbuff[7]); //rpm
serialBlast[0] = serbuff[6]; //rpm high
serialBlast[1] = serbuff[7]; //rpm low
short tps = ((serbuff[24]<<8) | serbuff[25]); //tps
serialBlast[2] = serbuff[24]; //tps high
serialBlast[3] = serbuff[25]; //tps low
TPS8 = tps / 3.921; // converts float to 8bit 0-255 value for CAN bus.
SdValue[1] = (float) tps / 10.0;
SdValue[2] = (((serbuff[18]<<8) | serbuff[19]) / 10.0); //map
serialBlast[8] = serbuff[18]; // map high
serialBlast[9] = serbuff[19]; // map low
MAP8 = SdValue[2]/SdValue[3] * 100; // MAP/BARO x 100. give ratio zer to 100%
SdValue[3] = (((serbuff[16]<<8) | serbuff[17]) / 10.0); // baro
serialBlast[10] = serbuff[16]; //baro high
serialBlast[11] = serbuff[17]; //baro low
uint16_t baro = ((serbuff[16]<<8) | serbuff[17])* 50;
baroH = baro >>8;
baroL = baro & 0xFF;
short cht = ((serbuff[22]<<8) | serbuff[23]); // CHT
//short CHT8 = cht / 10;
CHT8c = (((cht - 320) * 5/90)+10); // converts F to C and in 8-bit scale -10C to 245C.
SdValue[4] = (float) cht / 10.0;
short mat = ((serbuff[20]<<8) | serbuff[21]); // mat
short MAT = mat / 10;
MAT8c = (MAT - 32) *5/9; //int8-t value for -128 to 127C for IAT
ChargTemp = ((MAT8c + 128)*2/3);// weird charge temp math here...
SdValue[5] = (float) mat / 10.0;
SdValue[6] = (((serbuff[2]<<8) | serbuff[3]) / 1000.0); // PW
PWraw = ((serbuff[2]<<8) | serbuff[3]); // PW raw uint16_t value
serialBlast[15] = serbuff[2]; // PW high
serialBlast[16] = serbuff[3]; // PW low
SdValue[7] = (((serbuff[8]<<8) | serbuff[9]) / 10.0); // ign advance
serialBlast[13] = serbuff[8]; // ign advance high
serialBlast[14] = serbuff[9]; // ign advance low
IGN8 = ((serbuff[8]<<8) | serbuff[9])/5;// work this, output on CAN wrong.
SdValue[8] = (((serbuff[26]<<8) | serbuff[27]) / 10.0);//batv
BATV8 = serbuff[27];
serialBlast[17] = serbuff[27]; // bat volt 255 is 25.5 volts
SdValue[9] = (((serbuff[38]<<8) | serbuff[39]) / 10.0); // air correction
SdValue[10] = ((serbuff[40]<<8) | serbuff[41]) ; // warmup correction
SdValue[11] = (((serbuff[46]<<8) | serbuff[47]) / 10.0); // baro correction
short tpsdot = ((serbuff[58]<<8) | serbuff[59]); // TPSdot
SdValue[12] = (float) tpsdot / 10.0;
short mapdot = ((serbuff[60]<<8) | serbuff[61]); //MAPdot
SdValue[13] = (float) mapdot / 10.0;
SdValue[14] = (((serbuff[50]<<8) | serbuff[51]) / 10.0); // VE1
SdValue[15] = (((serbuff[28]<<8) | serbuff[29]) / 10.0); //AFR
serialBlast[12] = serbuff[29]; // AFR in 8 bit form. 10 to 20 AFR 100 to 200..
SdValue[16] = (((serbuff[34]<<8) | serbuff[35]) / 10.0); //EGO correction
SdValue[17] = (((serbuff[74]<<8) | serbuff[75]) / 10.0); // egoV
SdValue[18] = ((serbuff[48]<<8) | serbuff[49]); // gammeEnrich
//SdValue[19] = fuelUsed; // grams total
SdValue[20] = Eminutes; //
serialBlast[25] = Eminutes >> 8; // Engine run time High byte
serialBlast[26] = Eminutes | 0xFF; // Engine run time Low byte
// EngineTime2 = Eminutes >> 16;
// EngineTime1 = (Eminutes >> 8) & 0xFF;
// EngineTime0 = Eminutes & 0xFF;
//SdValue[21] = ServoIN; // uS 900 to 2100
//SdValue[22] = Fuelpressure; // 0 to 100... maybe.. //SdValue[22] = c; // 0 to 100... maybe.. 0 - 1023
//SdValue[23] = Flowrate; //lbs_hr..
// int c = analogRead(FPaIN);
SdValue[24] = engineRev;
//SdValue[25] = ignition voltage;
SdValue[26] = Status;
//long InjDuty = (((serbuff[2]<<8) | serbuff[3]) * SdValue[0]) / 60000; //PW x Rpm / 600.
SdValue[27] = SdValue[6] * SdValue[0] / 600; // solves injector duty cycle.//
uint16_t InjDuty = SdValue[27] * 10;
InjDutyH = InjDuty >> 8;
InjDutyL = InjDuty & 0xFF;
//SdValue[28] = grams/hr;
//SdValue[29] = batteryVolts;
//SdValue[30] = freeSpace;
}
///////////////////////////////////Receive CAN///////////////////////////////////////////////
void GetCAN(){
while ( CANbus.read(rxmsg) ) {
//when message available
if(rxmsg.id == (ECUIN<<24 | THROTTLECMD<<16 | ECUID)){
CAN_Throttle = rxmsg.buf[0]; // need to sort this to servo limits...
CANinput = 1;
}
else if(rxmsg.id == (ECUIN<<24 | HARDCONFIG<<16 | ECUID)) { //Request ECU ID and fuel divisor value
if (rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | HARDCONFIG<<16 | ECUID);
txmsg.buf[0] = EEPROM.read(0); // ECU Id high
txmsg.buf[1] = EEPROM.read(1); // ECU low
txmsg.buf[2] = EEPROM.read(6);
txmsg.buf[3] = EEPROM.read(7); //Fuel used H work on this later. Maybe have the 4 injector flow rates sorted 1-4 in EEPROM
txmsg.buf[4] = 0; //
txmsg.buf[5] = 0; //
txmsg.buf[6] = 0; //
txmsg.buf[7] = 0; //
CANbus.write(txmsg); //SEND IT!
}
}
else if (rxmsg.id == (ECUIN<<24 | THROTTLECAL<<16 | ECUID)){ // throttle calibration stuff.
if (rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | THROTTLECAL<<16 | ECUID);
txmsg.buf[0] = EEPROM.read(8);
txmsg.buf[1] = EEPROM.read(9);
txmsg.buf[2] = EEPROM.read(10);
txmsg.buf[3] = EEPROM.read(11);
txmsg.buf[4] = 0; //
txmsg.buf[5] = 0; //
CANbus.write(txmsg); //SEND IT!
}
else if(rxmsg.len >= 4){
uint8_t closedH = rxmsg.buf[0];
uint8_t closedL = rxmsg.buf[1];
uint8_t openH = rxmsg.buf[2];
uint8_t openL = rxmsg.buf[3];
EEPROM.write(8,closedH);
EEPROM.write(9,closedL);
EEPROM.write(10,openH);
EEPROM.write(11,openL);
Read_Eeprom();
Do_Math();
}
}
else if (rxmsg.id == (ECUIN<<24 | TOTALENGINETIME<<16 | ECUID)){ // totlat engine time in seconds
if(rxmsg.len == 0){
uint32_t engineseconds = Eminutes * 60;
txmsg.len = 3;
txmsg.id = (ECUOUT<<24 | TOTALENGINETIME<<16 | ECUID);// 90
txmsg.buf[0] = engineseconds >> 16; // seconds for the high byte
txmsg.buf[1] = (engineseconds >> 8 ) & 0x00FF; // seconds for mid byte
txmsg.buf[2] = engineseconds & 0x0000FF; // seconds for low byte.
CANbus.write(txmsg); // SEND IT!
}
}else if(rxmsg.id == (ECUIN<<24 | POWERCYCLES<<16 | ECUID)){ // power cycle count, pull from SD file number
if(rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | POWERCYCLES<<16 | ECUID);
txmsg.buf[0] = powercycles >> 8; // grab high byte
txmsg.buf[1] = powercycles & 0xFF; // grab low byte
txmsg.buf[2] = 0;
txmsg.buf[3] = 0;
txmsg.buf[4] = 0;
txmsg.buf[5] = 0;
txmsg.buf[6] = 0;
txmsg.buf[7] = 0;
CANbus.write(txmsg); // SEND IT!
}
}else if(rxmsg.id == (ECUIN<<24 | SWVERSION<<16 | ECUID)){ // Firmware version request and replay
if(rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | SWVERSION<<16 | ECUID);
txmsg.buf[0] = 1; // major firmware version
txmsg.buf[1] = 12; // minor firmware version
txmsg.buf[2] = 4; // month
txmsg.buf[3] = 19; // day
txmsg.buf[4] = 0x07; // year high byte
txmsg.buf[5] = 0xE2; // year low byte
txmsg.buf[6] = 0xAA; //check sum high
txmsg.buf[7] = 0x55; // check sum low
CANbus.write(txmsg); // SEND IT!
}
}else if(rxmsg.id == (ECUIN<<24 | USERSETTING<<16 | ECUID)){
uint8_t highB;
uint8_t lowB;
syscmd = rxmsg.buf[0];
if(syscmd == 0x11){ // fuel divisor setting
highB = rxmsg.buf[1];
lowB = rxmsg.buf[2];
EEPROM.write(6,highB) ; //Fuel divisor high
EEPROM.write(7,lowB) ; //Fuel divisor low
}else if (syscmd == 0x10){
grams = 0;
}else if(syscmd == 0x50){ // ECU address.
highB = rxmsg.buf[1];
lowB = rxmsg.buf[2];
EEPROM.write(0,highB) ; //ECU ID high
EEPROM.write(1,lowB) ; //ECU ID low
Read_Eeprom();
}else if (syscmd == 0x60){
uint8_t data1 = rxmsg.buf[1]; // address
uint8_t data2 = rxmsg.buf[2]; // data to place into address
EEPROM.write(data1, data2);
}
Read_Eeprom();
}
}
}
///////////////////////////////////////CAN FAST Messages///////////////////////////////////////
void FastCan(){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANFAST<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Fast CAN
txmsg.buf[0] = TPS8;
txmsg.buf[1] = serbuff[6]; //rpm H
txmsg.buf[2] = serbuff[7]; //rpm L
txmsg.buf[3] = gramsH; //Fuel used H work on this later. Maybe have the 4 injector flow rates sorted 1-4 in EEPROM
txmsg.buf[4] = gramsMH; //Fuel used MH
txmsg.buf[5] = gramsML; // fuel used ML
txmsg.buf[6] = gramsL; // fuel used L
txmsg.buf[7] = Status; // status 0x01 when enabled,
CANbus.write(txmsg); //SEND IT!
}
///////////////////////////////////////CAN SLOW_0 Messages///////////////////////////////////////
void Slow0Can(){
txmsg.ext = 1;
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANSLOW0<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Slow0 CAN
txmsg.buf[0] = 0; //commanded RPM 50 rpm count
txmsg.buf[1] = ServoOUT_H; //8-bit TPS 0-100%
txmsg.buf[2] = ServoOUT_L; // 12-bit count of uS pulse to servo
txmsg.buf[3] = CHT8c; // CHT 8-bit -10 to 245 *C
txmsg.buf[4] = 0; // none
txmsg.buf[5] = baroH; // baro H
txmsg.buf[6] = baroL; // baro L unit of 2 pascals
txmsg.buf[7] = MAP8; // MAP ratio 0 - 100% or MAP kpa
CANbus.write(txmsg); //SEND IT!
}
///////////////////////////////////////CAN SLOW_1 Messages///////////////////////////////////////
void Slow1Can(){
txmsg.ext = 1;
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANSLOW1<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Slow1 CAN
uint16_t pressure = SdValue[22] * 6;
txmsg.buf[0] = MAT8c; // IAT *C -128 to 127
txmsg.buf[1] = pressure >> 8; //Fuel Pressure H
txmsg.buf[2] = pressure & 0xFF; //Fuel Pressure L
txmsg.buf[3] = EngineTime2; //Engine Time_2
txmsg.buf[4] = EngineTime1; //Engine Time_1
txmsg.buf[5] = EngineTime0; //Engine Time_0
txmsg.buf[6] = BATV8; //Batv 8-bit xx.x
txmsg.buf[7] = 0; //Status for RPM control, zero = off.
CANbus.write(txmsg); //SEND IT!
}
///////////////////////////////////////CAN SLOW_2 Messages///////////////////////////////////////
void Slow2Can(){
txmsg.ext = 1;
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANSLOW2<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Slow2 CAN
txmsg.buf[0] = 25; //CPU load
txmsg.buf[1] = ChargTemp; //Charge Temp
txmsg.buf[2] = InjDutyH; //Injector duty H
txmsg.buf[3] = InjDutyL; //Injector duty L
txmsg.buf[4] = IGN8; // Ign Angle1
txmsg.buf[5] = 0; // Ign Angle2
txmsg.buf[6] = g_hrH; //Flow Rate H g/hr>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
txmsg.buf[7] = g_hrL; //Flow Rate L g/hr>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CANbus.write(txmsg); //SEND IT!
}
/////////////////////////////////////open engine run time//////////////////////////////////
void OpenHobs(){
file.open("test.txt", O_RDWR); // open test.txt for reading and writing. O_READ
while (file.available()){
inchar = file.read();
if (inchar != '\n'){
hobs += (char)inchar;
}else{
value[location] = hobs.toInt(); // convert read values into int.
location++;
hobs = ""; //clear hobs array.
}
}
Eminutes = value[0]; // pull int value from array Engine time
number = value[1]; // pull int value from array new file name
firstFile = value[2];
powercycles = number;
if(SDfull == 1){ // if less than 750MB left on the card start erase the oldest files.
firstfile[0] = 'D'; // place the 'D' to the beginning.
itoa(firstFile, firstfile+1, 10);
if(firstFile / 10000 >= 1){ // test the value of number and load newfile array in the proper spots.
firstfile[6] = '.';
firstfile[7] = 'c';
firstfile[8] = 's';
firstfile[9] = 'v';
}else if(firstFile / 1000 >= 1){ // if greater than 1000 add .csv
firstfile[5] = '.';
firstfile[6] = 'c';
firstfile[7] = 's';
firstfile[8] = 'v';
}else if(firstFile / 100 >=1){
firstfile[4] = '.';
firstfile[5] = 'c';
firstfile[6] = 's';
firstfile[7] = 'v';
}else if(firstFile / 10 >=1){
firstfile[3] = '.';
firstfile[4] = 'c';
firstfile[5] = 's';
firstfile[6] = 'v';
}else {
firstfile[2] = '.';
firstfile[3] = 'c';
firstfile[4] = 's';
firstfile[5] = 'v';
}
firstFile++;
}
////////////convert int back to array ascii values. not working quite right.
//File name will grow over time and has a fluid length.
newfile[0] = 'D'; // place the 'D' to the beginning.
itoa(number, newfile+1, 10); //converts int to array base 10 after the D..
if(number / 10000 >= 1){ // test the value of number and load newfile array in the proper spots.
newfile[6] = '.';
newfile[7] = 'c';
newfile[8] = 's';
newfile[9] = 'v';
}else if(number / 1000 >= 1){ // if greater than 1000 add .csv
newfile[5] = '.';
newfile[6] = 'c';
newfile[7] = 's';
newfile[8] = 'v';
}else if(number / 100 >=1){
newfile[4] = '.';
newfile[5] = 'c';
newfile[6] = 's';
newfile[7] = 'v';
}else if(number / 10 >=1){
newfile[3] = '.';
newfile[4] = 'c';
newfile[5] = 's';
newfile[6] = 'v';
}else {
newfile[2] = '.';
newfile[3] = 'c';
newfile[4] = 's';
newfile[5] = 'v';
}
number++; // add 1 to make new number name for next power cycle.
file.rewind(); // start at begining of file
file.println(Eminutes); // write engine run time
file.println(number); // write new file name for next power cycle.
file.println(firstFile); // write first file number here.
file.close(); // close file
if(SDfull == 1){
sd.remove(firstfile);// remove
}
}
//////////////////////////////////////////SD card Int/////////////////////////////////////////////////////
void IntSdCard(){
if(!sd.begin(chipSelect, SPI_FULL_SPEED)){
sd.initErrorHalt();
SdGood= 0;
}else{
SdGood = 1;
uint32_t volFree = sd.vol()->freeClusterCount();
SdValue[30] = 0.000512*volFree*sd.vol()->blocksPerCluster(); // find the remaining data left in the sd card. x.xx GB.
if((SDfull == 0) && (SdValue[30] < 2850)){ // check if we have set full bit once we are below 750MB remaining
EEPROM.write(12,1); // write to location 12 a 1.
}else if((SDfull == 1) && (SdValue[30] > 2900)){ // check if full bit is still set and there is more than 1GB free space.
EEPROM.write(12,0); // write zer0 to location 12.
}
}
}
/////////////////////////////////////// Write data header///////////////////////////////////////////////
void writeHeader() {
logfile.println("Engine, Log");
logfile.println("TIME,RPM,TPS,MAP,BARO,CHT,IAT,PW,IgnAdv,BATV,AirCorr,WUE,BaroCor,TPSdot,MAPdot,VE1,AFR,EGOCor,egoV,gaErich,FuelUsed,EngineTime,ServoIN,FuelPressure,LbsHr,CrankRev,IgPwr,Status,InjDuty,g_hr,batV,SDvol");
logfile.close();
}
//////////////////////////////////New File/////////////////////////////////////////////////
void NewFile(){
if(!logfile.open(newfile, O_CREAT | O_WRITE | O_EXCL)){
}
}
//////////////////////////////////////Write to SD card///////////////////////////////////////
void storeData(){
float tenthSec = duration / 1000.00;
if(!logfile.open(newfile, O_WRITE | O_AT_END)){
logfile.print(tenthSec,3);
logfile.print(",");
for(int x = 0; x < 31; x++){
logfile.print(SdValue[x]);
logfile.print(",");
}
logfile.println();
count++;
}
if (count >= 250){ // close reopen every 5 sec.
logfile.close();
count = 0;
}
}
///////////////////////////////////////update minutes of run time//////////////////////////
void WriteNewHOBS(){
logfile.close(); //if log file open then close it before opening the HOBS.csv file
file.open("test.txt", O_WRITE);// Open HOBS.csv
file.rewind();// move to beginning of the file to over write the last minute.
file.print(Eminutes);
file.close();
}
/////////////////////////20hz data request/////////////////////////////////////////////////////
void TwentyHZ(){
if(!serial){
Serial3.write(97);// request/pole data from MS2, send a06.
Serial3.write(0);
Serial3.write(6);
i = 0;
}else{
counter3++;
if(counter3 >= 110)
counter3 = 105;
}
if(CANBUS){
FastCan();
}
}
/////////////////////////////////Serial Blast to AP//////////////////////////////
void BlastSerial(){
int z;
for(z = 0; z < 27; z++){ // write 27 bytes to JST serial out.
Serial1.write(serialBlast[z]);
}
}
////////////////////////request next engine data sample//////////////////////////////////////
void TenthSec(){
counter1++;
counter2++;
if(!serial){
BlastSerial();
}
}
////////////////////////place in side 0.5 sec interval timer/////////////////////////////
void HalfSec (){
if(SdValue[0] >= 500){
seconds++;
CAN_seconds++;
}else{
seconds = 0;
CAN_seconds = 0;
}
if(CANBUS){ // if CAN messages are enabled send them
Slow0Can();
Slow1Can();
Slow2Can();
}
if (seconds >= 119){
seconds = 0;
Eminutes++;
WriteNewHOBS();
//SdValue[20] = Eminutes;
}
if(CAN_seconds >= 2){
EngineTime++; //engine time is seconds for CANSlow1
CAN_seconds = 0;
}
EngineTime2 = EngineTime >> 16;
EngineTime1 = (EngineTime >> 8) & 0xFF;
EngineTime0 = EngineTime & 0xFF;
}