Hardfault : segmentation fault?

Hello,

This is my first time using mbed, so I am sorry for the mistake i will make. I will update the subject based on your suggestions. For example, i didn’t find a proper way to share my code.

I am trying to get data from a Lidar using the STM Nucleo-F401RG.

It used to be able to see the data using a serial bus, output in mbed console, using RawSerial :
RawSerial se_lidar(PA_11, PA_12, BAUDERATE); Serial PC(SERIAL_TX,SERIAL_RX);

I am using rplidar(lidar supplier) functions to use the lidar :

//Getting data
buf = tim.read_ms();
while(tim.read_ms()-buf<=readTime){//Crashes after around 400
_PC.printf(“tim.read_ms() : %d\n”,tim.read_ms());
lidar.waitPoint(0);//Causes the crash
}

But as i have written in the comment, the program crashes after a while, giving me an hardfault error. Looking at the fault registers, the only fault bit set to 1 is UFSR[2] : integrity check error.

I tried to find posts with similar problem but i got no result.

On the other hand, the debugger led me to SIGSEGV fault (top left of the picture, which relates to a segmentation fault) and the error message :
except.S: No such file or directory

I couldn’t actually find where this error came from.

I obviously understand that you need more of my code to help me out here. I am looking for a proper way to attach it.

In short, i am using the RPLidar method “waitpoint” to get the data,

RPLidar lidar;

lidar.waitPoint(0);//Causes the crash

then i used the stored data :

lidar.Data[j]

“waitpoint” is defined by the supplier as :

u_result RPLidar::waitPoint(uint32_t timeout){
    uint8_t recvPos = 0;
	uint32_t startTs = timers.read_ms();

	uint32_t waitTime;
	rplidar_response_measurement_node_t node;
	uint8_t* nodebuf = (uint8_t*)&node;

	
    uint8_t currentByte;
	while ((waitTime = timers.read_ms() - startTs) <= timeout) {
		if(_binded_serialdev->readable()) 
            currentByte = _binded_serialdev->getc();
        else
            continue;
		
		switch (recvPos) {
		case 0: // expect the sync bit and its reverse in this byte          {
		{
			uint8_t tmp = (currentByte >> 1);
			if ((tmp ^ currentByte) & 0x1) {
				// pass
			}
			else {
				continue;
			}

		}
		break;
		case 1: // expect the Check bit to be 1
		{
			if (currentByte & RPLIDAR_RESP_MEASUREMENT_CHECKBIT) {
				// pass
			}
			else {
				recvPos = 0;
				continue;
			}
		}
		break;
		}
		nodebuf[recvPos++] = currentByte;

		if (recvPos == sizeof(rplidar_response_measurement_node_t)) {
			// store the data ...
			_currentMeasurement.distance = node.distance_q2 / 4.0f;
			_currentMeasurement.angle = (node.angle_q6_checkbit >> RPLIDAR_RESP_MEASUREMENT_ANGLE_SHIFT) / 64.0f;
			_currentMeasurement.quality = (node.sync_quality >> RPLIDAR_RESP_MEASUREMENT_QUALITY_SHIFT);
			_currentMeasurement.startBit = (node.sync_quality & RPLIDAR_RESP_MEASUREMENT_SYNCBIT);
			ang = (int)_currentMeasurement.angle;
			//dis = _currentMeasurement.distance;

            if (ang >= angMin && ang <= angMax) Data[ang] =  _currentMeasurement;
            //.distance;// (float) ang;
            //wait_ms(200);
           /* for(int i = 0; i < size_t(nodebuf); i++)
                Data[i] = nodebuf[i]*/
			//if (ang >= angMin && ang <= angMax)Data[ang] = 12.0;//_currentMeasurement.distance;
//continue;
			return RESULT_OK;
		}


	}

	return RESULT_OPERATION_TIMEOUT;
}

If you can lead me to a related topic, help me on my specific error or help me with the code upload to the forum, that would be awesome.

Thanks in advance, i will update this post as much as possible.

Hello Pierre-Yves,

“Segmentation fault” usually means the program is trying to use an uninitialized pointer (which is pointing to a random memory location). In the RPLidar::waitPoint function, the _binded_serialdev pointer seems to me the main candidate for that. Make sure it has been assigned to a variable (i.e. it’s pointing to memory location of a serial object) before the RPLidar::waitPoint function is called.

help me with the code upload to the forum

  • Create a new program with the online compiler running in your web browser.
  • Drag&drop your program and library files from the file manager to the new program in the web browser.
  • Publish the program: Right click the program name and in the popup window select the Publish option.
  • Make a hyperlink to your published program in your post here on the forum (copy&paste the program location to your post).

Best regards, Zoltan

1 Like

Hello Zoltan,

Thanks a lot for your answer. Following the code, this is what happens to _binded_serialdev

RawSerial se_lidar(PA_11, PA_12, BAUDERATE); 
lidar.begin(se_lidar); //Initialize the serial port used for the lidar
lidar.waitPoint(0);//Causes the crash

with

void RPLidar::begin(RawSerial& serialobj)
{
_binded_serialdev = &serialobj;
timers.start();
_binded_serialdev->baud(RPLIDAR_SERIAL_BAUDRATE);
}

It looks like the variable is initialized. I also used the debugger, and checked the value of the pointer you mentioned. It points to an address indeed, so it doesn’t seem to be the problem. I then checked for other variables but nothing seemed odd to me.

I went further. For context ; the famous “RPLidar::waitpoint()” method is used i a method I created. This method only gets data from the lidar the prints the value as I explained in the first message.

Just in case, I did copy past the whole method and put it in the main file. It kind of looks like when i first tried this way. And it works.

I forgot to mention that this is also my first program in cpp (i have used c and c# before). I’m guessing something is wrong with the syntax. It’s weird the compiler didn’t find any problem though.

To update my code, i actually have already tried what you mentioned, but i never could import or “drag & drop” my program to the online compiler. But now that I know this is the way to do it, i will try again and update my post as soon as possible.

I guess you will not be able to help until I publish my code.

Thanks for your help !

UPDATE :
I have published the way i could. I struggled a lot with the “drag & drop” because it only accepts files and not folders. And in mbed, the BUILD and “mbed-os” folders contain a ton of subfolders.

So, i ignored those two folders and recreated the hierarchy. You can find the “inc”, “src” and main.cpp containing mainly what I did alongside the “rplidar” folder containing the supplier methods.

I also tried to import the mbed-os.lib file, which never worked. mbed returns a server error.

I am pretty sure there is a better way to do this, so i’m open to recommendations.

Here is the link : https://os.mbed.com/users/pymal/code/Lidar/

You can zip your folders and then drag&drop the xxx.zip file.

1 Like

Thanks again !

I dropped the zip file as you explained. But it returns an error message : “Your browser aborted the previous request”.

Well, even without the zip, you should have the needed files (i hope so).
In main.cpp[117], i used a method I created that gets the print data :

printer.getPrintData(angle, sizeOfPrint, lidar, readTime);//This one does everything in one go (gets data then prints it)

this method is defined in src/print.cpp [31] :

void Print::getPrintData(int angle, int sizeOfPrint, RPLidar lidar, int readTime)
{
    int startAngle=0;
    int buf=0;
    int step = angle/sizeOfPrint;
    Timer tim;
    //tim.start();
    _PC.printf("Timer started\n");

    while(startAngle<360)
    {                
        lidar.setAngle(startAngle, startAngle+angle);
        lidar.setLidar();

        //Getting data
        buf = tim.read_ms();
        while(tim.read_ms()-buf<=readTime){//Crashes after around 400
            _PC.printf("tim.read_ms() : %d\n",tim.read_ms());
            lidar.waitPoint(0);//Causes the crash
        }

        //Printing
        _PC.printf("Distance\t");
        for(int j = startAngle; j < startAngle + angle; j+=step) _PC.printf("%.0f\t", lidar.Data[j].distance); //in cm 
        _PC.printf("\nAngle\t\t");
        for(int j = startAngle; j < startAngle + angle; j+=step) _PC.printf("%.0f\t",lidar.Data[j].angle);
        _PC.printf("\n");
            
        startAngle+=angle;
        _PC.printf("\n\n");

    }
} 

All I did was copy paste the whole method and put it directly i the main instead. And it works just fine.
Which means it should be my cpp syntax that it isn’t correct. Again, this is my first time coding in cpp so there might be mistakes due to some rules i’m not aware of.

Thanks a lot !

Yes, I have got all files. Which release of Mbed do you use?

I think the problem is caused by passing an instance of the RPLidar class to the Print::getPrintData function by value. In such case the compiler creates a local copy of the RPLidar object and that one is used inside the function’s body rather than the passed one. To make a copy of the RPLidar class the compiler uses the copy constructor of that class. Since there is no copy constructor, such as

RPLidar(RPLidar& instance);  // copy constructor

defined for the RPLidar class, the compiler creates one by itself. However, such default copy constructor is a very simple one and instead of a full initialization of the object it makes only a so called bitcopy. As a result, pointer members (like RawSerial* _binded_serialdev) remain uninitialized.

To fix it, try to pass either a reference or a pointer of the RPLidar object.

For example:

void Print::getPrintData(int angle, int sizeOfPrint, RPLidar &lidar, int readTime)
{
    ...
    lidar.waitPoint(0); // lidar is referring directly to the passed parameter rather than an uninitialized copy of it
    ...
}

or

void Print::getPrintData(int angle, int sizeOfPrint, RPLidar *lidar, int readTime)
{
    ...
    lidar->waitPoint(0); // lidar is pointing to the instance of the passed parameter
    ...
}

Another solution is to define a copy constructor for the RPLidar class. But that’s more complex than passing a reference or a pointer. In addition, making a copy of larger objects requires more resources and makes the program run slower.

However, be cautious when passing parameters by reference or pointer. As opposed to when “passing by value”, if such parameter is modified inside the function’s body at the same time the passed variable becomes modified also outside the function’s body!

NOTE:
After you copied the body of the Print::getPrintData function to the main function rather than making a call to it, no copying was involved and that’s why the code worked.

Best regards, Zoltan

1 Like

Hello,

Thanks a lot for all the time you spent answering here.
I guess it is not needed anymore, but to answer your question, i am using mbed-os 5.15.4.

Not only your solution works just fine, but also your explanations are very clear. This is wonderful !
I am truly amazed by how fast and well you have been answering to all my messages.

I wish you all the best things that can happen to a person.

Thank you,

Pierre-Yves