Debugging panic/hard fault on Photon

I have a Photon that talks to a CANbus module via UART. TBH I’ve not had any problems with it before now and the code hadn’t changed. Things stopped working and I’ve now made many changes in order to debug the system and here’s what I’ve arrived at…

The module is connected to the CANbus fine, and can receive data. If I try and send data I get spark/device/last_reset : panic, hard_fault

The line of code is: can.send(0x7DF, 0, 0, sizeof(data), data);
the data is {0x02, 0x01, 0x0F, 0x55, 0x55, 0x55, 0x55, 0x55}

This calls a class that came with the module https://www.seeedstudio.com/Serial-CAN-BUS-Module-based-on-MCP2551-and-MCP2515.html and the method looks like this:

unsigned char Serial_CAN::send(unsigned long id, uchar ext, uchar rtrBit, uchar len, const uchar *buf) {
unsigned char dta[14] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0};

dta[0] = id>>24;        // id3
dta[1] = id>>16&0xff;   // id2
dta[2] = id>>8&0xff;    // id1
dta[3] = id&0xff;       // id0

dta[4] = ext;
dta[5] = rtrBit;

for(int i=0; i<len; i++)
{
    dta[6+i] = buf[i];
}

for(int i=0; i<14; i++)
{
    Serial1.write(dta[i]);
}
}

All it does is send some data over serial, so I don’t see how a) the status of the CANbus can have any effect on whether this method throws an error or not and b) how this could result in a hard_fault

Bearing in mind all the other can methods just use the same serial interface and work successfully up until this point.

How do I debug this further?

@Nemiah, what is the range of ‘len’? Since you don’t do any range checking (len must be less than 8), dat[6+i] may exceed the size of dta[]. Otherwise, I can’t see any other issues in this part of the code.

Your function signature indicates that your function will return an unsigned char but it doesn’t - which is bad practice to say the least but with 2.0.0 that has become a crashable offence (although I thought it would be a SOS+14 rather than hard fault) :wink:

Add a proper return statement and the SOS panic may go away.

BTW, instead of writing each byte in a loop you could use Serial.write(data, 14);
Or drop the local copy of data entirely and put out the data like this

uint8_t Serial_CAN::send(uint32_t id, uint8_t ext, uint8_t rtrBit, uint8_t len, const uint8_t *buf) {
  uint8_t retVal = 0;
  retVal += Serial.write((uint8_t*)&id, sizeof(id));
  retVal += Serial.write(ext);
  retVal += Serial.write(rtrBit);
  retVal += Serial.write(buf, len); 
  return retVal;                    // return the number of bytes transferred in total
}

Also, why is your len a uchar and not a uint8_t or size_t?
Since it’s supposed to be a number a numeric data type would appear more suitable.

On a side note: Commonly the len parameter is passed after the buffer pointer but I left it as is for compatibility.

1 Like

@ScruffR - I wonder if the reason it “suddenly stopped working” is because I ran particle doctor and part of that process is to update the firmware, maybe this has bumped it to a newer version?

The code is a lib that came with the module BTW, it’s pretty rough and TBH it’s taken me a while to figure out what it actually does. Now that I’ve actually had to look at it in depth I can see how the module works and I think I’ll write my own lib. There’s only a handful of functions and no only will the code be more legible, it will give me a better understanding of what’s going on.

I’ll try your change first though and see if that solves it! (I’m at work now so it will be this evening).

Updating the device OS version can render previously working code invalid - the major version number change 1.x.y->2.x.y allows for breaking changes - especially since the lack of a return value in a function that promises to give one back should always have been a red flag.
The previous device OS was just too forgiving.

1 Like

This was 100% the problem. As a simple test I changed the signature to void and everything worked. I must have been running an earlier firmware version that didn’t mind the missing return value.

@ScruffR This lib was made by Seed for the Seed CANbus UART module. If I have a go a refactoring it and throw it on github, would you be interested in casting an eye over it? I’m sure there’s other particle users wanting to use CANbus.

1 Like

You’re right. I’m not sure as it’s not my lib and I’m only using the CAN bus for specific OBD stuff, so for me it’s max. 8, but I don’t know about other situations. @ScruffR’s answer avoids this issue altogether. I’m going to refactor it and put it on github.

2 Likes