Panic, hard_fault, problems continue

While there are multiple posts with the (panic, hard_fault) error, none of them relates to the issue I am having.

I am running the same program on mulitple Xenons. Each Xenon is connected to a laser sensor. Some sensors are i2c and others are UART.

In the case of i2c sensors, program runs without problems.

But in the case of UART sensors, I am getting “panic, hard_fault” on average once an hour! The program keeps reading distances from the sensor then suddenly reboots.

I have (over more than a year now!) been trying different firmwares and different baud rates but the problem persists. I am running OS firmware 1.5.1 (but same problem happened with 1.5.0). I have reduced the baud rate to 57,600 (from 115200) but this did not help.

Is there anyway I can find out what causes this error?

Thanks in advance for the community’s help.

Minimize your program down to the simplest version that still reproduces. That might help pinpoint a programming/logic error on your end that could be causing the hard-fault. Might also try posting that version here to see if anyone can see something wrong.

It’s possible to debug but can be painful. I’ve had reasonable success debugging hard-faults in the past using a JLINK and https://www.segger.com/products/development-tools/ozone-j-link-debugger/. Letting your code run with a breakpoint in the hard-fault handler will let you catch where it is hard-faulting from. You can do the same thing from Workbench using the Particle mesh debugger, but GDB doesn’t seem to always follow the stack trace out of the hard fault handler very well.

Thank you @joel.

I will try your recommendations by posting a smaller version of the program and also using JLINK although I have no experience using those types of tools.

Hard faults are often caused by overshooting buffer boundaries.
With UART I guess you are gradually filling a buffer till you get a full message you are looking for and in that it’s often easy to forget to check the buffer index while receiving data :wink:

Thank you @ScruffR.

Do you mean something like:

if (Serial1.available() > x) Serial1.flush();

What should the value of x be?

Thanks again.

Serial1.flush() will only make sure the TX buffer is empty but doesn’t do anything to the RX buffer.

We don’t know how you use Serial1.read() but that would be what could cause the issue.

BTW, the RX and TX buffers won’t overflow as they are circular buffers - it’s more likely your own strings.

Thank you @ScruffR.

Here is the code I am using. I took out all “String” usage.

===============================================

int debug1;

char responseData[40];
int responseDataSize = 0;

uint16_t distance;
uint32_t distanceP;
int distanceCM;             //laser distance(CM)
int distIN = 0;                //Distance in inches
int distFT = 0;              //Distance in feet

void loop()
{
   readLW20();
} 

void  readLW20();
{
    if (lw20GetStreamResponse())
    {
      float distanceM = getNumberFromResponse(responseData);
      
      distanceCM = distanceM * 100;
      distIN = distanceM * 100 * 0.394;
      
      distance = distanceCM;
      distanceP = distance;
      
      //Serial.print(distance);
      //Serial.println(" cm");
    }
    else
    {
      debug1 ++;
      //Serial.println("No streamed data within timeout");
    }
    //delay(2);
}

bool lw20GetStreamResponse() {
  // Only have 1 second timeout.
  unsigned long timeoutTime = millis() + 1000;

  responseDataSize = 0;

  // Wait for the full response.
  while (millis() < timeoutTime)
  {
    if (Serial1.available() < 150)
    {
      int c = Serial1.read();
      if (c == '\n')
      {
        responseData[responseDataSize] = 0;
        return true;
      }
      else if (c != '\r')
      {
        if (responseDataSize == sizeof(responseData) - 1)
        {
          responseDataSize = 0;
        }
        responseData[responseDataSize++] = (char)c;
      }
    }
  }
  return false;
}


float getNumberFromResponse(char* ResponseStr) {
  // Find the ':' character.
  int index = 0;

  while (true) {
    if (ResponseStr[index] == 0)
      break;

    if (ResponseStr[index] == ':') {
      return atof(ResponseStr + index + 1);
    }

    ++index;
  }

  return 0.0f;
}

One possible place to look at is here since you are not checking for ResponseStr+index+1 being within bounds.

Also in your lw20GetStreamResponse() I’d rather go for the safe route and change

  if (responseDataSize == sizeof(responseData) - 1)

to

  if (responseDataSize >= sizeof(responseData) - 1)

BTW, Serial1.available() will never be more than 64 since the RX buffer is limited to that :wink:
and since you are reading even when Serial1.available() is less than 0 you will be reading 0xFF characters till you get a \n or run into timeout.

You might be better off with using a good and tested function like Serial1.readBytesUntil() and/or Serial1.find() instead of using some half baked “solution” that doesn’t take into account the actual behaviour of the interface object.

Thank you @ScruffR.

On your recommendation, I placed some Publish statements (publishQueue) library.

One of them yielded for Serial1.available() = 128. How can this happen if the maximum should be 64?

Is there a way to prevent that?

Thanks.

Opps, my bad, for Gen3 that limit is 128. 64 byte is the limit for Photon and Electron.

However for USB Serial it’s 64 on Gen3 too.