Reading successive CANbus frames; where does it stop?

Postfix:
The very short story here is, that the code listed, no matter what variation, actually works (despite the small coding mistake at the beginning of setup()). However, after spending significant time (`30h) 'debugging' it, it turned out that the cause of trouble was a faulty Arduino UNO, which, when replaced, flawlessly produced the desired results.


Sorry, I didn't come up with a better title; this post is probably for someone who understands CANbus and MCP2515 and or its library.

I have a Daly BMS (Battery Mgmt System) where I'd like to read the data from by using an Arduino UNO R3 and a MCP2515 CAN module.

It took me a while to get a handle of it, and eventually figured I have to send an empty frame (as in frame w/o data bytes) in order to get a response.

This works well so far where the frame contains the 'complete' data, as in, not more related data. To explain:
These return frames have an ID|DLC|DATA(8 bytes) and that's it.
However, there are a couple responses that have more than one frame to build the whole picture.
More precise: the 8 bytes can carry 3 16-bit values, which can relate to 3 battery cells. Here I have 16 cells, hence, 6 frames need to be read to get all 16 values.

My simplest of code returns these replies when querying a specific CAN ID:

     DLC | | Frame number
CAN ID   | |
|        | | |----------- Data--------------|
98954001 8 1 | D | 1C | D | 17 | D | 1B | 0 | 
98954001 8 1 | D | 21 | D | 15 | D | 1E | 0 | 
98954001 8 1 | D | 1E | D | 16 | D | 1C | 0 | 
98954001 8 1 | D | 1C | D | 19 | D | 1A | 0 | 
98954001 8 1 | D | 1B | D | 18 | D | 1A | 0 |
98954001 8 1 | D | 21 | D | 16 | D | 1E | 0 |
98954001 8 1 | D | 1E | D | 17 | D | 1A | 0 |
98954001 8 1 | D | 1B | D | 1A | D | 1A | 0 |
98954001 8 1 | D | 1C | D | 18 | D | 19 | 0 |

This is correct.
So D blah, D blah, D blah stands for 6 bytes = three 16 bit values. The last byte is ignored (0).
The 1 represents the frame number.

Now... let's look at the result when I loop 5 times in order to catch 5 frames.
(Please note: I issue the query once, but read it twice, just see if a) reading multiple times works, and b) if I get the same result in each read):

i: 4 98954001 8 2 | D | 5E | D | 22 | D | 20 | 0 |
i: 5 98954001 8 4 | D | 4E | D | 32 | D | 55 | 0 |
i: 0 98954001 8 5 | D | 4E | D | 57 | D | 53 | 0 | 
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...
Message sent ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 98954001 8 1 | D | 18 | D | 16 | D | 17 | 0 |
i: 4 98954001 8 2 | D | 5C | D | 22 | D | 1F | 0 | 
i: 5 98954001 8 4 | D | 4E | D | 32 | D | 55 | 0 |
i: 0 98954001 8 5 | D | 4C | D | 56 | D | 53 | 0 |
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...
Message sent ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 98954001 8 1 | D | 1D | D | 14 | D | 1C | 0 |
i: 4 98954001 8 3 | D | 61 | D | 5D | D | 59 | 0 |
i: 5 98954001 8 2 | D | 5A | D | 24 | D | 1E | 0 | 
i: 0 98954001 8 4 | D | 47 | D | 39 | D | 51 | 0 |
i: 1 98954001 8 5 | D | 53 | D | 53 | D | 58 | 0 |
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...
Message sent ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 98954001 8 1 | D | 1A | D | 18 | D | 18 | 0 |
i: 4 98954001 8 2 | D | 5E | D | 22 | D | 21 | 0 | 
i: 5 98954001 8 3 | D | 5B | D | 67 | D | 53 | 0 |
i: 0 98954001 8 4 | D | 51 | D | 32 | D | 59 | 0 |
i: 1 98954001 8 5 | D | 4D | D | 59 | D | 52 | 0 |
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...
Message sent ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 98954001 8 1 | D | 1B | D | 15 | D | 1A | 0 | 
i: 5 98954001 8 2 | D | 5A | D | 24 | D | 1E | 0 |
i: 0 98954001 8 4 | D | 4A | D | 35 | D | 53 | 0 |
i: 1 98954001 8 5 | D | 51 | D | 55 | D | 55 | 0 | 
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...

This is what the documentation says:
image

this is what my program looks like:

#include <Arduino.h>
#include <SPI.h>
#include <mcp2515.h>

struct can_frame can_query;
struct can_frame can_reply;

MCP2515 mcp2515(10);

void send_can_query();
void read_can_reply();


void send_can_query()
{
    can_query.can_id  = 0x18950140 | CAN_EFF_FLAG;
    can_query.can_dlc = 8;

    for (uint8_t i = 0; i < 8; i++)
    {
        can_query.data[i] = 0x00;
    }

    mcp2515.sendMessage(&can_query);

    Serial.println("Message sent ...");
}


void read_can_reply()
{
    const uint8_t NUMBER_OF_LOOPS = 6;

    for (uint8_t i = 0; i < NUMBER_OF_LOOPS; i++)
    {
        Serial.print("i: ");
        Serial.print(i);
        Serial.print(" ");

        if (mcp2515.readMessage(&can_reply) == MCP2515::ERROR_OK)
        {
            Serial.print(can_reply.can_id, HEX);
            Serial.print(" ");

            Serial.print(can_reply.can_dlc, HEX);
            Serial.print(" ");

            for (int i = 0; i < can_reply.can_dlc; i++)
            {
                Serial.print(can_reply.data[i], HEX);
                Serial.print(" | ");
            }
            Serial.println();

        }
        else
        {
            Serial.println("... reading reply failed ...");
        }
    }
}


void setup()
{
    while (!Serial);
    Serial.begin(115200);
    delay(500);

    mcp2515.reset();
    mcp2515.setBitrate(CAN_250KBPS, MCP_8MHZ);
    mcp2515.setNormalMode();

    Serial.println("Query and interpet CAN msg...");
    Serial.println("ID  DLC   DATA");
}

void loop()
{
    send_can_query();
    read_can_reply();
    read_can_reply();
    delay(3000);
}

So, this result has puzzled me, and here are my questions (not having much of an idea about how this protocol really works):

  1. Why am I getting the read errors? Is this normal? It would be a bad protocol to use in automotive, where it is heavily used.
    So, I assume the problem sits elsewhere. My wires are short, and there is no AC source near the cables and Arduino/MCP2515 to potentially interfere with the signal.
  2. How do I know or test if there are more than the six frames?
  3. Assuming I have only 8 battery cells (= 3 frames to query); in fact no matter how many cells there are, how do I know how many (follow-up ) frames there are?
    I reckon I have to somehow find out with test routines.
  4. I also wondered where are frames 2..6? Are these in memory, or does readMessage send out another request?
    I only send one query to the CAN ID. Each mcp2515.readMessage(&can_reply) seemingly progresses to the next frame when issued... but some have read errors. The frame IDs are not always in order.
  5. And last, what is the best way to work around the errors? Not asking to write the code for me, but comment on my suggested idea...

Idea: it looks like I could use an array or a byte to hold a successful "frame read" and either store its number in the array, or when using a byte in its bit position, or sum up the frame numbers to 136 or however many frames I want to catch.

Any hints/answers appreciated.


I have checked the hardware:

  1. I have an 8Mhz crystal on the MCP2515
  2. I have 5.0 V on the MCP2515; as the TJA1050 CAN chip requires >4.75 V to operate properly
  3. the library examples work
  4. the bus is terminated (tried un-terminated which made no difference)

IMHO ur probably polling too quick...

maybe try something like this:
(compiles, NOT tested!)

#include <Arduino.h>
#include <SPI.h>
#include <mcp2515.h>

struct can_frame can_query;
struct can_frame can_reply;

MCP2515 mcp2515(10);

void send_can_query();
void read_can_reply();

const uint8_t NUMBER_OF_LOOPS = 6;
uint8_t i = 0;


void send_can_query()
{
    can_query.can_id  = 0x18950140 | CAN_EFF_FLAG;
    can_query.can_dlc = 8;

    for (uint8_t i = 0; i < 8; i++)
    {
        can_query.data[i] = 0x00;
    }

    mcp2515.sendMessage(&can_query);

    Serial.println("Message sent ...");
}


void read_can_reply()
{
    if(i < NUMBER_OF_LOOPS)
    {
        if (mcp2515.readMessage(&can_reply) == MCP2515::ERROR_OK)
        {
            Serial.print("i: ");
            Serial.print(i);
            Serial.print(" ");
            Serial.print(can_reply.can_id, HEX);
            Serial.print(" ");

            Serial.print(can_reply.can_dlc, HEX);
            Serial.print(" ");

            for (int i = 0; i < can_reply.can_dlc; i++)
            {
                Serial.print(can_reply.data[i], HEX);
                Serial.print(" | ");
            }
            Serial.println();
            i++;
        }
        /*
        else
        {
            Serial.println("... reading reply failed ...");
        }
        */
    }
}


void setup()
{
    while (!Serial);
    Serial.begin(115200);
    delay(500);

    mcp2515.reset();
    mcp2515.setBitrate(CAN_250KBPS, MCP_8MHZ);
    mcp2515.setNormalMode();

    Serial.println("Query and interpet CAN msg...");
    Serial.println("ID  DLC   DATA");
}

void loop()
{
  if(i==0)
  {  
    send_can_query();
  }
  else{
    read_can_reply();
    delay(10);
  }

  if(i==NUMBER_OF_LOOPS){
    i=0;
    delay(3000);
  }
}

hope that helps...

1 Like

Thank you for looking into this...

Firstly, I changed the for loop from:

for (uint8_t i = 0; i < NUMBER_OF_LOOPS; i++)

... to ...

for (uint8_t i = 0; i <= NUMBER_OF_LOOPS; i++)

... to get the envisaged 6 frames. However, it is irrelevant for this exercise.

Secondly, if it is poll speed issue as you suspect... I have added a delay(500); just before the closing bracket of the for() loop... and made an interesting observation:

Message sent ...
i: 0 ... reading reply failed ...
i: 1 98954001 8 1 | C | F2 | C | F5 | C | F8 | 0 | 
i: 2 98954001 8 2 | C | F4 | C | F8 | C | FA | 0 | 
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...
i: 6 ... reading reply failed ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...
i: 6 ... reading reply failed ...

... is always the same; "always" being watching this for over ten minutes; always the same result pattern.
I am still using my O.P. code (with the aforementioned changes) to continue playing with 'timings'... (and report back).
I also noticed in tests made with my full program, that inserting Serial.prints into the readMessage() loop, changes the number of iterations required to see results, which are also different in composition and order.

I am still interested in answers to my questions, and with further thinking, maybe more suspicion than thinking, that possibly the Arduino Uno is too slow for this project?!


Further playing with different delays and removal of Serial create random outcomes, but do not provide any improvement.
I am not checking your code suggestion to understand what it does, as it compiles but does not produce any output (other than "Message sent".)


I have since modified the global and local variable i, to clearly distinguish between them... but still no output.

Try again, @maxG - that will loop 7 times. 0,1,2,3,4,5,6

Yes, I mentioned that I changed this. However, the number of 'for loop' iterations does not change the output pattern, as in random "failed" reads.

I have also used a different MCP2515 library , which does not produce any output, and makes me suspicious if I am dealing with a BMS problem, rather than Arduino/MCP problem.

... still pottering along :slight_smile:

When you change your code, it's good form to post a new version here, at the bottom of the posts, so those following along can see that you've comprehended and implemented the suggestions of others. At this point, we have no idea what your present code looks like.

1 Like

Updated code (same as originally posted, except for an added = in the for loop):

#include <Arduino.h>
#include <SPI.h>
#include <mcp2515.h>

struct can_frame can_query;
struct can_frame can_reply;

MCP2515 mcp2515(10);


void send_can_query();
void read_can_reply();


void send_can_query()
{
    can_query.can_id  = 0x18950140 | CAN_EFF_FLAG;
    can_query.can_dlc = 8;

    for (uint8_t i = 0; i < 8; i++)
    {
        can_query.data[i] = 0x00;
    }

    mcp2515.sendMessage(&can_query);

    Serial.println("Message sent ...");
}


void read_can_reply()
{
    const uint8_t NUMBER_OF_LOOPS = 6;

    for (uint8_t i = 0; i <= NUMBER_OF_LOOPS; i++)
    {
        //Serial.print("i: ");
        Serial.print(i);
        Serial.print(" ");

        if (mcp2515.readMessage(&can_reply) == MCP2515::ERROR_OK)
        {
            Serial.print(can_reply.can_id, HEX);
            Serial.print(" ");

            Serial.print(can_reply.can_dlc, HEX);
            Serial.print(" ");

            for (int i = 0; i < can_reply.can_dlc; i++)
            {
                Serial.print(can_reply.data[i], HEX);
                Serial.print(" | ");
            }
            Serial.println();
        }
        else
        {
            Serial.println("... reading reply failed ...");
        }
    }
}


void setup()
{
    while (!Serial);
    Serial.begin(115200);
    delay(500);

    mcp2515.reset();
    mcp2515.setBitrate(CAN_250KBPS, MCP_8MHZ);
    mcp2515.setNormalMode();

    Serial.println("Query and interpet CAN msg...");
    Serial.println("ID  DLC   DATA");
}

void loop()
{
    send_can_query();
    read_can_reply();
    read_can_reply();
    delay(5000);
}

/*
Message sent ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 98954001 8 1 | D | 1E | D | 14 | D | 1A | 0 |
i: 0 98954001 8 2 | D | 54 | D | 23 | D | 1E | 0 |
i: 1 98954001 8 4 | D | 49 | D | 3A | D | 52 | 0 |
i: 2 98954001 8 5 | D | 59 | D | 59 | D | 5E | 0 |
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...


DLC | | Frame number
CAN ID   | |
|        | | |----------- Data--------------|
98954001 8 1 | D | 1C | D | 17 | D | 1B | 0 |
98954001 8 1 | D | 21 | D | 15 | D | 1E | 0 |
98954001 8 1 | D | 1E | D | 16 | D | 1C | 0 |
98954001 8 1 | D | 1C | D | 19 | D | 1A | 0 |
98954001 8 1 | D | 1B | D | 18 | D | 1A | 0 |
98954001 8 1 | D | 21 | D | 16 | D | 1E | 0 |
98954001 8 1 | D | 1E | D | 17 | D | 1A | 0 |
98954001 8 1 | D | 1B | D | 1A | D | 1A | 0 |
98954001 8 1 | D | 1C | D | 18 | D | 19 | 0 |
*/

My point exactly. This executes 7 times, not 6 - is that your intent? This is a common form we see here on the forum, and it is rare that the programmer's intent is to actually execute 7 times, so I am asking for clarity.

Could you please point me to the source of this CAN library? Thanks

Thank you for pointing this out...

Corrected code listed further below...

The library can be found at GitHub - autowp/arduino-mcp2515: Arduino MCP2515 CAN interface library

What I wonder most about is, when I send a request that has >1 return message, where are these 'others' located?

Does the sendMessage() return the data into memory, or do further readMessage() calls go and get the messages from the device being queried?

#include <Arduino.h>
#include <SPI.h>
#include <mcp2515.h>

struct can_frame can_query;
struct can_frame can_reply;

MCP2515 mcp2515(10);


void send_can_query();
void read_can_reply();


void send_can_query()
{
    can_query.can_id  = 0x18950140 | CAN_EFF_FLAG;
    can_query.can_dlc = 8;

    for (uint8_t i = 0; i < 8; i++)
    {
        can_query.data[i] = 0x00;
    }

    mcp2515.sendMessage(&can_query);

    Serial.println("Message sent ...");
}


void read_can_reply()
{
    const uint8_t NUMBER_OF_LOOPS = 6;

    for (uint8_t i = 0; i < NUMBER_OF_LOOPS; i++)
    {
        //Serial.print("i: ");
        Serial.print(i);
        Serial.print(" ");

        if (mcp2515.readMessage(&can_reply) == MCP2515::ERROR_OK)
        {
            Serial.print(can_reply.can_id, HEX);
            Serial.print(" ");

            Serial.print(can_reply.can_dlc, HEX);
            Serial.print(" ");

            for (int i = 0; i < can_reply.can_dlc; i++)
            {
                Serial.print(can_reply.data[i], HEX);
                Serial.print(" | ");
            }
            Serial.println();
        }
        else
        {
            Serial.println("... reading reply failed ...");
        }
    }
}


void setup()
{
    while (!Serial);
    Serial.begin(115200);
    delay(500);

    mcp2515.reset();
    mcp2515.setBitrate(CAN_250KBPS, MCP_8MHZ);
    mcp2515.setNormalMode();

    Serial.println("Query and interpet CAN msg...");
    Serial.println("ID  DLC   DATA");
}

void loop()
{
    send_can_query();
    read_can_reply();
    read_can_reply();
    delay(5000);
}

/*
Message sent ...
i: 0 ... reading reply failed ...
i: 1 ... reading reply failed ...
i: 2 ... reading reply failed ...
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 98954001 8 1 | D | 1E | D | 14 | D | 1A | 0 |
i: 0 98954001 8 2 | D | 54 | D | 23 | D | 1E | 0 |
i: 1 98954001 8 4 | D | 49 | D | 3A | D | 52 | 0 |
i: 2 98954001 8 5 | D | 59 | D | 59 | D | 5E | 0 |
i: 3 ... reading reply failed ...
i: 4 ... reading reply failed ...
i: 5 ... reading reply failed ...


DLC | | Frame number
CAN ID   | |
|        | | |----------- Data--------------|
98954001 8 1 | D | 1C | D | 17 | D | 1B | 0 |
98954001 8 1 | D | 21 | D | 15 | D | 1E | 0 |
98954001 8 1 | D | 1E | D | 16 | D | 1C | 0 |
98954001 8 1 | D | 1C | D | 19 | D | 1A | 0 |
98954001 8 1 | D | 1B | D | 18 | D | 1A | 0 |
98954001 8 1 | D | 21 | D | 16 | D | 1E | 0 |
98954001 8 1 | D | 1E | D | 17 | D | 1A | 0 |
98954001 8 1 | D | 1B | D | 1A | D | 1A | 0 |
98954001 8 1 | D | 1C | D | 18 | D | 19 | 0 |
*/

FWIW, try the following. It's not robust, but may give you an alternate perspective:

#include <Arduino.h>
#include <SPI.h>
#include <mcp2515.h>

struct can_frame can_query;
struct can_frame can_reply;

MCP2515 mcp2515(10);

void send_can_query();
void read_can_reply();

void send_can_query() {
  can_query.can_id  = 0x18950140 | CAN_EFF_FLAG;
  can_query.can_dlc = 8;
  for (uint8_t i = 0; i < 8; i++)   can_query.data[i] = 0x00;
  mcp2515.sendMessage(&can_query);
  Serial.println("Message sent ...");
}

void read_can_reply() {
  const uint8_t NUMBER_OF_LOOPS = 6;
  for (uint8_t i = 0; i < NUMBER_OF_LOOPS; i++)
  {
    while ((&can_reply) != MCP2515::ERROR_OK);
    Serial.print(i);
    Serial.print(" ");
    Serial.print(can_reply.can_id, HEX);
    Serial.print(" ");
    Serial.print(can_reply.can_dlc, HEX);
    Serial.print(" ");
    for (int i = 0; i < can_reply.can_dlc; i++)   {
      Serial.print(can_reply.data[i], HEX);
      Serial.print(" | ");
    }
    Serial.println();
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  delay(500);
  mcp2515.reset();
  mcp2515.setBitrate(CAN_250KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  Serial.println("Query and interpet CAN msg...");
  Serial.println("ID  DLC   DATA");
}

void loop() {
  send_can_query();
  read_can_reply();
  delay(5000);
}
1 Like

Thank you for 'checking' and improving...

Other than removing blank lines and compressing code :slight_smile:
All stayed the same except:

  1. setup() swapped first two lines... oops.
  2. loop() removed one of the read_can_reply()
  3. read_can_reply() is where the changes are...

It compiles after I changed this line from:

    while (&can_reply != MCP2515::ERROR_OK);

... to ...

    while (mcp2515.readMessage(&can_reply) != MCP2515::ERROR_OK);

The result has seemingly less read errors... (no idea why) :slight_smile:
Again, frame 6 is rarely seen. Weird.
... but there is one '6' in the last response, which is almost complete, but has frame 4 in there twice.

Message sent ...
0 ... reading reply failed ... 
1 ... reading reply failed ... 
2 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 | 
3 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 | 
4 98954001 8 4 | C | CD | C | EB | C | D9 | 0 | 
5 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 | 
Message sent ...
0 ... reading reply failed ...
1 ... reading reply failed ...
2 ... reading reply failed ...
3 ... reading reply failed ...
4 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 | 
5 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 |
Message sent ...
0 98954001 8 4 | C | CD | C | EB | C | D9 | 0 |
1 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 |
2 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 | 
3 98954001 8 3 | C | D7 | C | CC | C | DB | 0 |
4 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 |
5 98954001 8 4 | C | CD | C | EB | C | D9 | 0 | 
Message sent ...
0 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 |
1 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 |
2 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 | 
3 98954001 8 4 | C | CD | C | EB | C | D9 | 0 |
4 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 |
5 ... reading reply failed ...
Message sent ...
0 ... reading reply failed ...
1 ... reading reply failed ...
2 ... reading reply failed ...
3 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 |
4 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 | 
5 98954001 8 4 | C | CD | C | EB | C | D9 | 0 |
Message sent ...
0 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 |
1 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 | 
2 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 |
3 ... reading reply failed ...
4 98954001 8 4 | C | CD | C | EB | C | D9 | 0 |
5 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 | 
Message sent ...
0 ... reading reply failed ...
1 ... reading reply failed ...
2 ... reading reply failed ...
3 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 | 
4 98954001 8 3 | C | D7 | C | CC | C | DB | 0 |
5 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 |
Message sent ...
0 98954001 8 4 | C | CD | C | EB | C | D9 | 0 |
1 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 | 
2 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 |
3 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 |
4 98954001 8 4 | C | CD | C | EB | C | D9 | 0 | 
5 98954001 8 5 | C | E5 | C | DD | C | E6 | 0 |
Message sent ...
0 ... reading reply failed ...
1 ... reading reply failed ...
2 ... reading reply failed ...
3 98954001 8 1 | C | DB | C | D5 | C | E1 | 0 | 
4 98954001 8 2 | C | E7 | C | F4 | C | F3 | 0 |
5 98954001 8 3 | C | D7 | C | CC | C | DB | 0 |
Message sent ...
0 98954001 8 4 | C | CF | C | E9 | C | DA | 0 |
1 98954001 8 5 | C | E2 | C | DF | C | E5 | 0 |
2 98954001 8 1 | C | DB | C | D7 | C | DE | 0 |
3 98954001 8 2 | C | E8 | C | F3 | C | F3 | 0 | 
4 98954001 8 4 | C | CF | C | E9 | C | DA | 0 |
5 98954001 8 6 | C | E1 | C | DF | C | E5 | 0 |

No time to dig deeper, but I was hoping to avoid incrementing the index when there's nothing to read, which is what you're doing.
To me, you should only attempt to read out a message when the library says there's something there. The syntax may not be (test if no error), but I don't see any other indicator there's a frame available.
Good luck. Maybe, repost your present code, as no one is going to go through your list of changes and assume you made them all correctly, especially since it's obvious you didn't remove some things I did, so my code and your code have diverged.
Good luck!

1 Like

I really appreciate your input, and it seems the problem has been solved.

I sort of had it after two full days dabbling in this, and changed the hardware to a Arduino R4 Minima ... and ...

drum roll...

This works!!! Arrrghhh.

No read errors! Awesome...

Thank you, thank you, thank you... :slight_smile:


Why did I not do this earlier?
Well, I have a program reading all single reply BMS parameters, except for this multi-response one. Hence, I had a hunch, but ruled it out, based on single replies working without a problem. I then isolated the non-working part and posted here.
I have seen post from camsysca before, which looked to me of better quality than what produce, hence, him positing the improvement, I trusted it to work, and then ditched the Uno R3, as I had no other choice left. I could rule out the MCP2515, as I connected it to another Arduino UNO where I loaded code that is running for years and connected it to its respective device, working just fine.
Lesson learned: if after checking your code 100+ times, believing it to be correct, swap the hardware and try again :slight_smile:

Message sent ...
0 98954001 8 4 | C | C9 | C | EA | C | D6 | 0 | 
1 98954001 8 5 | C | E2 | C | D9 | C | E5 | 0 | 
2 98954001 8 1 | C | D2 | C | DB | C | D9 | 0 | 
3 98954001 8 2 | C | EC | C | F1 | C | F5 | 0 | 
4 98954001 8 6 | C | DE | C | D9 | C | E5 | 0 | 
5 98954001 8 4 | C | DB | C | DE | C | E1 | 0 |
Message sent ...
0 98954001 8 5 | C | D7 | C | E4 | C | DD | 0 |
1 98954001 8 6 | C | E5 | C | E4 | C | DD | 0 |
2 98954001 8 1 | C | D9 | C | D3 | C | DF | 0 |
3 98954001 8 2 | C | E4 | C | F3 | C | F3 | 0 |
4 98954001 8 3 | C | D7 | C | C6 | C | D8 | 0 |
5 98954001 8 4 | C | C7 | C | E8 | C | D3 | 0 |
Message sent ...
0 98954001 8 5 | C | E0 | C | D8 | C | E3 | 0 |
1 98954001 8 6 | C | DD | C | D8 | C | E3 | 0 |
2 98954001 8 1 | C | D3 | C | D9 | C | DA | 0 | 
3 98954001 8 2 | C | EA | C | F1 | C | F4 | 0 |
4 98954001 8 3 | C | CE | C | D3 | C | CF | 0 |
5 98954001 8 4 | C | D6 | C | DF | C | DD | 0 |

Plus updated code that produced the result:

#include <Arduino.h>
#include <SPI.h>
#include <mcp2515.h>

struct can_frame can_query;
struct can_frame can_reply;

MCP2515 mcp2515(10);

void send_can_query();
void read_can_reply();

void send_can_query() {
  can_query.can_id  = 0x18950140 | CAN_EFF_FLAG;
  can_query.can_dlc = 8;
  for (uint8_t i = 0; i < 8; i++)   can_query.data[i] = 0x00;
  mcp2515.sendMessage(&can_query);
  Serial.println("Message sent ...");
}

void read_can_reply() {
  const uint8_t NUMBER_OF_LOOPS = 6;
  for (uint8_t i = 0; i < NUMBER_OF_LOOPS; i++)
  {
    while (mcp2515.readMessage(&can_reply) != MCP2515::ERROR_OK);
    //while (&can_reply != MCP2515::ERROR_OK);
    Serial.print(i);
    Serial.print(" ");
    Serial.print(can_reply.can_id, HEX);
    Serial.print(" ");
    Serial.print(can_reply.can_dlc, HEX);
    Serial.print(" ");
    for (int i = 0; i < can_reply.can_dlc; i++)   {
      Serial.print(can_reply.data[i], HEX);
      Serial.print(" | ");
    }
    Serial.println();
  }
}

void setup() {
  Serial.begin(115200);
  while (!Serial);
  delay(500);
  mcp2515.reset();
  mcp2515.setBitrate(CAN_250KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  Serial.println("Query and interpet CAN msg...");
  Serial.println("ID  DLC   DATA");
}

void loop() {
  send_can_query();
  read_can_reply();
  delay(5000);
}

@MaxG confession time - I know so little about CAN, I shouldn't have been replying, but I thought you were'nt getting any other bites, so WTH. Thing is, I said what I posted wasn't robust, and it isn't. You'll have to look further at CAN to see what to do when things go wrong, because that while() statement I inserted will hang happily forever, which is not a good thing.
But, glad we've made some progress, anyway.

1 Like

Maybe my initial sentence was limiting the punters...
but, my questions, rather than the code, I thought was something someone who worked a bit more in depth with this protocol could answer.
I had a while() before in my trial, which returned nothing to a bit; had a do while, an if, and whatever else could be varied.

So... after all, thanks for having a crack at it. :slight_smile:

Yes... a simple counter, if over returning nothing and moving on, should do the trick.


I actually started developing this program with the Minima, because, the received data will be packaged as MQTT messages to my automation system, which also creates graphs, which allows me to see quickly which cells deviate over time.
However, after a few uploads it would not release the monitor, and I replaced it with the Uno.

And while I had the suspicion the Uno is not the right hardware, I was wrong... I just (after a night's sleep) connected another Uno, and it too, works flawlessly.

1 Like