IFCT - Improved Flexcan Teensy Library

Status
Not open for further replies.
Ok, after work I'll give it a try removing the 120ohm resistor and if still not works I'll also try to use Can0...

I've checked the code and I'm sending the OBD request every 5 seconds just to poll if the connection is ok... after sendig the first request I'm waiting for 15msec before call while(Can1.read()) { ... }
Are that timing ok? 15msec is enough to get response?

I'm sending 3 ODB requests with ID 0x7DF to get (RPM, TPC and ECT) and I expect 3 OBD responses with ID 0x7E8.... how can I configure the filters to receive just that messages?
 
you do not need a while loop on read, if a frame is available then u can read it right away otherwise continue the rest of your code. You also dont need to read if you’re using interrupts. they goto the callback automatically. If you don’t use interrupts you can poll read(), if it has something you can read it.

i would first make sure you can operate send/receive working properly before going to filter but for filtering its simple
mailbox mode:
Can1.setMBFilter(MB0, 0x7DF, 0x7E8); // mailbox 0 and 2 IDs
fifo mode:
Can1.setFIFOFilter(0, 0x7DF, 0x7E8); // fifo filter 0, and 2 IDs

Do not forget to block all frames before applying filters:
Can1.setMBFilter(REJECT_ALL); //mailbox mode
Can1.setFIFOFilter(REJECT_ALL); //fifo mode
 
Hey tonton81, thank you so much for all you've done!
I've removed the 120ohm resistor and now it seems to work fine!
I'm able to read all the CAN messges and I can also send the OBD request and get the response... great!!!! :)

Now I think I need some help to fine tune my code:
I want my Datalogger to poll the ECU when startup (every 5 seconds?) and if the ECU reply (switch ing. ON on my bike) it will start acquiring "realtime" data via OBD request (RPM, ECT, TPS)...
I'm starting using the RPM OBD request as "poll" msg every 5 seconds but maybe I can ask for the supported CAN IDs or ...
After sending the OBD request I wait 15ms and after that I'm using the while(Can1.read(rxMsg)) but my while loop exit after just one read message... I was supposed that the while will loop for all the messages including my OBD request.
Can you explain me the better why to send one or more OBD requests and then wait with a reasonable timeout for the response? If I can't get the response I have to manage this with retry and so on...

I'd also like to receive only the messages I need but still not clear if would be better to use MB or FIFO or ... and how to filter in the best way.


Thank you so much and keep up the great job!
 
you send one you read one usually, you can set a flag when you send one and poll the read(), if you get a read unset the flag so the write can send another request again, no need to do a while loop, while loops are bad for datalogging, just replace while with if, if theres nothing there your code can continue doing other stuff but not write. you can set a timer if you want to resend again if nothing happened in like 2 seconds to request again, millis() and flags are your friend here :)
 
Hi guys,
I've made some tests but still got soem issues:
If I just send the OBD request for RPM everithing seems to works fine but if I send also the ODB request for TPS and ECT it seems to freeze or became unresponsive..,

Here there is the code, can you please help me?

#include <IFCT.h>

#define CLEAR_SCREEN F("\033[0H\033[0J")

#define SERIAL_BAUD 115200 // Serial Monitor baud
#define CANBUS_SPEED 500000 // 500Kpbs

#define OBD_DIAG_ID 0x7DF
#define OBD_DIAG_RESP_ID 0x7E8

#define OBD_PID_SUPP 0x00 // Request for supported PIDs
#define OBD_PID_LOAD 0x04 // ???
#define OBD_PID_ECT 0x05
#define OBD_PID_TPS 0x11
#define OBD_PID_RPM 0x0C
#define OBD_PID_VBAT 0x42

static unsigned long previousMillis = 0;

static float tps = 0.0;
static uint16_t rpm = 0;
static uint8_t ect = 0;

static char response[32];
static char str_temp[6];

void setup() {

Serial.begin(SERIAL_BAUD);
delay(2000);

pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, HIGH);

Can1.setBaudRate(CANBUS_SPEED);
Can1.enableFIFO();
Can1.setFIFOFilter(REJECT_ALL);
Can1.setFIFOFilter(MB0, OBD_DIAG_ID, OBD_DIAG_RESP_ID, STD);
Can0.enhanceFilter(FIFO);

Serial.println("Starting IFTC sniffer...");
}

void loop() {
CAN_message_t msg;

// Send OBD request every 100ms
if (millis() - previousMillis >= 100) {
if (!sendObdRequest(OBD_PID_RPM)) {
Serial.println("Error sending RPM ODB request!");
}

/////////////////////////////////////////////////////////
// IF I UNCOMMENT THIS CODE EVERITHING GET FREEZED
// AND NOT RESPONSIVE!!!
// if (!sendObdRequest(OBD_PID_TPS)) {
// Serial.println("Error sending TPS ODB request!");
// }
// if (!sendObdRequest(OBD_PID_ECT)) {
// Serial.println("Error sending ECT ODB request!");
// }

previousMillis = millis();
}

if (Can1.read(msg)) canSniff(msg);

}

bool sendObdRequest(unsigned long id) {

CAN_message_t reqMsg;
reqMsg.flags.extended = 0;
reqMsg.flags.remote = 0;
reqMsg.len = 8;
reqMsg.id = OBD_DIAG_ID;
reqMsg.buf[0] = 0x02;
reqMsg.buf[1] = 0x01;
reqMsg.buf[2] = id;
reqMsg.buf[3] = 0x00;
reqMsg.buf[4] = 0x00;
reqMsg.buf[5] = 0x00;
reqMsg.buf[6] = 0x00;
reqMsg.buf[7] = 0x00;
Can1.write(reqMsg); // Need to check ret val?

return true;
}

void canSniff(const CAN_message_t &rxMsg) {

if(rxMsg.id == OBD_DIAG_RESP_ID) {
switch (rxMsg.buf[2]) {
case OBD_PID_RPM:
rpm = ((256 * rxMsg.buf[3]) + rxMsg.buf[4]) / 4;
break;
case OBD_PID_TPS:
tps = (100.0 / 255.0) * rxMsg.buf[3];
break;
case OBD_PID_ECT:
ect = rxMsg.buf[3] - 40;
break;
}
}

Serial.print(CLEAR_SCREEN);
/* 4 is mininum width, 2 is precision; float value is copied onto str_temp*/
dtostrf(tps, 4, 1, str_temp);
sprintf(response, "TPS: %s RPM: %d ECT: %d", str_temp, rpm, ect);
Serial.println(response);

}
 
I am pretty sure the ECU needs some time between requests, @tonton81 can confirm. I did a little google search and came across this link: https://stackoverflow.com/questions...ands-together-and-get-response-simultaneously. To make a long story short
The OBD-II default settings are responsible for this. The default waiting time, (as far as I can recognize) 200 ms. So you can only send 5 commands each second. This is somewhat slow, and some applications manage to get 20 request each second.
You may have to play with the delay time though.
 
Thanks for response!
The first think I’ve tried was just add a delay of 10ms and also tried with 50ms but... 200ms it’s realiy slow!!!!

How can the diagnostic tool handle all the parameters with such slow delay between requests?
 
Thanks for response!
The first think I’ve tried was just add a delay of 10ms and also tried with 50ms but... 200ms it’s realiy slow!!!!

How can the diagnostic tool handle all the parameters with such slow delay between requests?
If you read the link I posted it also said about adding another parameter to the send request for timing? Don't know much about that one but take a read. Also maybe @tonton81 can help here.
 
the reason you can get more requests is you can ask for multiple pids, like RPM and speed, and receive them in one frame, provided they can fit in one 8-byte datafield, if not, it will come in 2 frames. Obviously you’d have to know where to parse it based on what order you requested them
 
the reason you can get more requests is you can ask for multiple pids, like RPM and speed, and receive them in one frame, provided they can fit in one 8-byte datafield, if not, it will come in 2 frames. Obviously you’d have to know where to parse it based on what order you requested them

That’s really interesting!
Can you help me to find a way to ask for RPM, TPS and ECT with just one OBD request? That would be the best approach for my datalogger but I’m not expert on CAN and/or OBD....

I’ve also checked my test code made for Arduino Nano and MCP2515 and I was able to send 3 OBD request and get response without issue!
I just have to wait about 10ms between every request so it seem it is not an issue related to the ECU.... mmmhhh....
 
im curious, does it still freeze when you disable using dtostrf and sprintf and uncomment the above lines?

ill have to check my old code for multiple PID request but I’m sure it can be found all over google
 
yes disabling using dtostrf and sprintf doesn't fix the isssue.
I've tryied asking every 200ms all the 3 request with a 10ms delay between each of them but it seems that I receive pnly the ECT and the serial monitor is not so responsive... seems like freezing but not sure if freeze or...

The strange think is that with Arduino + MCP2515 I was able to send 3 request with 10ms delay and get all responses with no issue in the same ECU.
I'll try to move to Can0 but no other idea.

If you could let us know how to request multiple IDs and manage multiple responses it will be very usefull because for my applciation that's should be the best way to go.


Thanks for your help!
 
Hey guys, sorry to bother you again but I think I found my issue:
after some more tests I saw that if I send all the 3 requests and after that I gonna read from the CAN... I just receive the response for the last request I sent!
Don't know if this is expected behavior but I need a "snapshot" of RPM, TPS and ECT taken in the same time because just before or just after I get all the responses I can read the analog input voltage corresponding to the AFR and store all of them in a table. To be accurate I think I'll need to do this "read procedure" at least 10/20 times per sec.
Any idea on how to solve my issue?
 
Try to see if you receive them without using filters, try to see if you can call one at a time, to see if you catch them. only call one to see if it works, then try another, confirm you see them. Also try reposting your sketch if you changed anything

On another note:

The ELM327 datasheet gives the following information on page 45:

Multiple PID Requests The SAE J1979 (ISO 15031-5) standard allows requesting multiple PIDs with one message, but only if you connect to the vehicle with CAN (ISO 15765-4). Up to six parameters may be requested at once, and the reply is one message that contains all of the responses. For example, let us say that you need to know engine load (04), engine coolant temperature (05), manifold pressure (0B), and engine rpm (0C) on a regular basis. You could send four separate requests for them (01 04, then 01 05, then 01 0B, etc.) or you could put them all into one message like this:

01 04 05 0B 0C to which, a typical reply might be:
0: 41 04 3F 05 44 0B
1: 21 0C 17 B8 00 00 00

For the above, the example shows reception of 2 frames for a single request.
 
Hi guys,
can you please help me understand which is the best way to configure the FIFO filter with setFIFOFilter() if I'd like to receive just 3 CAN IDs?
I can't get it working.... :(
 
Can0.setFIFOFilter(0,0x01);
Can0.setFIFOFilter(1,0x02);
Can0.setFIFOFilter(2,0x03);

This should allow IDs 1 2 and 3 to pass FIFO, rest blocked.
Be sure to run Can0.setFIFOFilter(REJECT_ALL); to block everything before setting the filters above to let only those frames through
 
Thanks for fast response!
That means that the every time I call setFIFOFilter it will be added to the filters (+=) instead of reset and add (=), correct?
What about the first parameter? Is that the mailbox? Can you explain me how does the mailbox works?
 
mailboxes are not FIFO, but FIFO has 8 filters by default 0-7, if you want specific mailbox as reception in a sepearate callback you can use a mailbox for that
 
Can0.setFIFOFilter(0,0x01);
Can0.setFIFOFilter(1,0x02);
Can0.setFIFOFilter(2,0x03);

This should allow IDs 1 2 and 3 to pass FIFO, rest blocked.
Be sure to run Can0.setFIFOFilter(REJECT_ALL); to block everything before setting the filters above to let only those frames through

I'm trying but I'm getting a compiler error:
error: no matching function for call to 'IFCT::setFIFOFilter(int, int)'

I've had a look at the lib examples but it seems there is no filtering example code... can you please add a working example code to the lib?
 
sorry I forgot the extra frame info you need to add
EXT for extended, STD for standard frame:

Can0.setFIFOFilter(0, 0x05, STD);

filter 0, ID 5, Standard frame
 
Hey, I have a project that I am starting here shortly and don't even really know where to start. I have 1 device that I can send data over with any address as any bit length from unsigned8bit to a signed 32bit.

I need to send values from -99.99 to 99.99 so a signed 8 bit should be perfectly fine correct?

I am using the Teensy 3.6 and have a the Dual Can board on the way. Currently I just need to read values from it, but I see a need to send some messages out as a 1 or 0 for turning things on and off.

1st how do I get the message to read in as a number and then can I assign that number as a variable? It will be coming in at 100hz, and I will more than likely have up to 20 addresses that I need to read.

Does this seem doable?

Is there a decent example of just reading a particular address?

Thanks for the help.
 
Status
Not open for further replies.
Back
Top