cancel
Showing results for 
Search instead for 
Did you mean: 

In CAN_ERR what is "Stuff Error" and what is "Form Error"?

KiptonM
Lead

I have a can bus operating between a PC and a Motor, where the PC can control the motor.

Eventually I want the STM32 to control the motor. For now all I want to do is read what is on the bus.

Looking at thedata with a CAN bus sniffer it looks like there are two messages going back and forth. About every millisecond the PC sends a command to the motor and the motor responds almost immediately. The bus sniffer says the two addresses are 0x05A0 and 0x0620.

I set up a 16-bit List filter with 05A0, 0620, 0000, 0000.

At this point I am only looking to see if the FIFO is not empty. It is always empty.

The CAN_ERR register changes. it is either 0xFF000023 or 0xFF000013 which tells me that the LEC (Last error code) is either 001 Stuff error, or 010 Form Error.

I have searched the entire 1347 page RM0390 Reference Manual and the only place Stuff error or Form error is mentioned is in the Error Status Register.

Where is Stuff error or Form error defined? If I do not know what it is how do I fix it?

Of course I would like to also know how to fix them.

I am programming a STM32 Nucleo-F446RE and the CAN bus is running at 1 MHz

I think my SW is upto date:

STM32CubeIDE

Version: 1.6.1

Build: 9958_20210326_1446 (UTC)

STM32CubeMX - STM32 Device Configuration Tool

Version: 6.2.1-RC2

Build: 20210324-1236 (UTC)

Attached is a screen shot of the MX Setup

1 ACCEPTED SOLUTION

Accepted Solutions
KiptonM
Lead

I think I figured it out. Not by reading RM0390, but by reading TI documentation. https://www.ti.com/lit/an/slla270/slla270.pdf Section 4.10.

No where in the documentation did it mention the target of the sample point should be 75%.

I tried to find the solutions with a spread sheet but soon decided a C program would be faster.

/*
 * This was easier to do in C than in a spread sheet.
 * The default values for BRP, TS1, and TS2 in the CAN MX program are not good.
 * This calculates all of the usable combinations of BRP, TS1, and TS2.
 * In an ideal world you want the error to be 0.00%
 * And I am thinking you want the sum of TS1 + TS2 to be larger if the error is 0.
 * According to the TI documentation you want the sample point TS1+2 to be 75% of 3 + TS1 + TS2
 * https://www.ti.com/lit/an/slla270/slla270.pdf Page 11
 */
#define TARGET 0.0
#define TARGET_ERROR (0.02)
#define SAMPLE_POINT_ERROR (0.075)
#define SAMPLE_POINT (0.75)
 
void search_baudrate2(uint32_t clk, uint32_t baud_rate)
{
	float baud_period_ns;
	float clock_period_ns;
	uint16_t BRP;
	int16_t TS1;
	int16_t TS2;
	float Tq_ns; // Time Quanta
	float Tbs1_ns; //
	float Tbs2_ns;
	float bit_time_ns;
	float baud_rate_f = baud_rate;
	float baud_rate_calc;
	float error;
	float sample_point;
 
	char buf[120];
 
	sprintf(buf,"Starting search_baudrate(clk: %lu, target baud_rate: %lu\r\n", clk, baud_rate );
	write_debug_str(buf);
 
	sprintf(buf,"Target is %4.1f +//- %4.1f %% error and %4.1f +//- %4.1f %% Sample Point\r\n", 
TARGET*100, TARGET_ERROR*100, SAMPLE_POINT*100, SAMPLE_POINT_ERROR*100);
	write_debug_str(buf);
 
	clock_period_ns = (1.0 / clk) * 1000000000.0;
	baud_period_ns = ((1.0 / baud_rate) * 1000000000.0) * (1.0 + TARGET_ERROR);
 
	for (BRP=0;BRP<512;BRP++)
	{
		Tq_ns = (BRP + 1) * clock_period_ns;
		if ((Tq_ns * 3) > baud_period_ns) break; // quit searching when there is no way you will have a good solution.
 
		for (TS1=15;TS1>=0;TS1--)
		{
			Tbs1_ns = (TS1 + 1) * Tq_ns;
			for (TS2=7;TS2>=0;TS2--)
			{
				Tbs2_ns = (TS2 + 1) * Tq_ns;
				bit_time_ns = Tq_ns + Tbs1_ns + Tbs2_ns;
				baud_rate_calc = 1000000000.0 / bit_time_ns;
				error = (baud_rate_calc - baud_rate_f) / baud_rate_f;
				sample_point = (Tq_ns + Tbs1_ns)  / bit_time_ns;
 
				if (fabs(error) < TARGET_ERROR)
				{
					if ((sample_point < (SAMPLE_POINT + SAMPLE_POINT_ERROR)) && (sample_point > (SAMPLE_POINT - SAMPLE_POINT_ERROR))) // If sample point between 0.7 and 0.8
					{
						// Close enough maybe
 
						sprintf(buf,"BRP: %4u, TS1: %2u, TS2: %2u, Tq(ns): %7.2f, Baudrate: %9.1f, error(%%): %6.2f, Sample_Point(%%): %6.1f\r\n",
								BRP, TS1, TS2, Tq_ns, baud_rate_calc, error*100.0, sample_point*100.0);
						HAL_Delay(100);
						write_debug_str(buf);
					}
				}
			}
		}
	}
    write_debug_str("Done search_baudrate()\r\n");
}

You call it with the peripheral clock (in Hz) for the CAN interface. For the STM32F446RM that is APB1 in the Clock Configuration Tab of the MX program. (In my case 45000000.)

And the Baudrate (or bits per second) that you want. (In my case 1000000 bits/s)

In an ideal case you want the baudrate to match exactly. So the error should 0.00%

And the Sample point should be 75%. But I do not think that is as critical as the baudrate.

So the program with brute force tries all the combinations and prints the ones that match the criteria set in the # define.

TARGET is the baudrate target, you want that to be 0.

TARGET_ERROR is how far off you are willing to go from the target. 0.02 is 2%. If it is not exact I would test it like crazy to see if it works in all situations.

SAMPLE_POINT is 0.75 for 75% That is what the TI documentation says the target should be.

SAMPLE_POINT error is 0.075 or 7.5%. So it will print results from 67.5% to 82.5%

I am a beginner at this but I think you should use the solution with the lowest BRP, with an exact baud, and the closest to 75% Sample Point (favoring maybe greater than 75% versus less than 75%).

I ran the program on my STM32 processor. You will have to tell the program to use the floating point sprint library and write the write_debug_str() subroutine to take a string and write it to the serial port of your choosing. I write to the UART at 921600 bits/s, and was exceeding the terminal program buffer, so I had to slow it down with some HAL_Delay(); It ran in less than a minute.

In my case the output was:

Starting search_baudrate(clk: 45000000, target baud_rate: 1000000

Target is 0.0 +//- 2.0 % error and 75.0 +//- 7.5 % Sample Point

BRP:   2, TS1: 10, TS2: 2, Tq(ns):  66.67, Baudrate: 1000000.0, error(%):  0.00, Sample_Point(%):  80.0

BRP:   2, TS1: 9, TS2: 3, Tq(ns):  66.67, Baudrate: 1000000.0, error(%):  0.00, Sample_Point(%):  73.3

BRP:   4, TS1: 5, TS2: 1, Tq(ns): 111.11, Baudrate: 1000000.1, error(%):  0.00, Sample_Point(%):  77.8

BRP:   8, TS1: 2, TS2: 0, Tq(ns): 200.00, Baudrate: 1000000.0, error(%):  0.00, Sample_Point(%):  80.0

Done search_baudrate()

So I plan to use the second one because the BRP was the lowest, the baud rate error was 0, and the sample point 73.3 was the closest to 75%

BRP, TS1, TS2 are the values in the CAN_BTR register.

When you are in the MX program setting up the parameters for the CAN interface

The Prescaler (for Time Quantum) is BRP+1

Time Quanta in Bit Segment 1 is TS1+1

Time Quanta in Bit Segment 2 is TS2+1

And I do not know what the ReSynchronization Jump Width should be. I am trying 1, since the baud rate error is 0.

View solution in original post

6 REPLIES 6
TDK
Guru

Bit stuffing is used to ensure a signal has enough edges in order for the clock to be recovered/sync at the receiving end.

https://en.wikipedia.org/wiki/CAN_bus#Bit_stuffing

A bit stuffing error means one of these added bits was the incorrect value.

Not sure what a form error would mean offhand.

Seems like there could be a clock mismatch between what the sniffer expects and what is actually on the line.

If you feel a post has answered your question, please click "Accept as Solution".
KiptonM
Lead

I wondered if it was a problem with the PC or the motor.

So I tried a filter with just 0x0620, or with just 0x05A0 and then with no valid value, 0000. Did not seem to make a difference.

I do not know how to check for a clock mismatch as I am just receiving at the moment.

I tried to slow it down from 1 Mb/s to 100 kb/s and I have the same errors.

The MX program says the speed is right. But that is not the same as measuring it.

KiptonM
Lead

TDK suggested it may be a clock mismatch.

The oscilloscope tends to say it is correct,

So I changed the baud rate from 1 Mbit/sec to 100kbit/sec a tenth of the speed.

Surprisingly when I changed it on the Crouzet control program, and power cycled the motor it worked at the slower rate. So there must be some autobaud at the beginning of the motor driver power up.

On the STM32 it was a matter of changing the CAN prescaler from 15 to 150 in the MX program, and it said the baud rate went from 1 Mbits/s to 100 kbits/s.

It then generated the code and I was back in operation. But the errors still persist. 

If it is a baud rate error from the clock being a little off, then by walking through the baud rates, I should be able to make it work. So I tried all prescalers from 130 through 170. In each case I was only seeing "Form Errors" and did not see any "Stuff Errors". But it never went away at any of the 21 baud rates I tried.

KiptonM
Lead

I think I figured it out. Not by reading RM0390, but by reading TI documentation. https://www.ti.com/lit/an/slla270/slla270.pdf Section 4.10.

No where in the documentation did it mention the target of the sample point should be 75%.

I tried to find the solutions with a spread sheet but soon decided a C program would be faster.

/*
 * This was easier to do in C than in a spread sheet.
 * The default values for BRP, TS1, and TS2 in the CAN MX program are not good.
 * This calculates all of the usable combinations of BRP, TS1, and TS2.
 * In an ideal world you want the error to be 0.00%
 * And I am thinking you want the sum of TS1 + TS2 to be larger if the error is 0.
 * According to the TI documentation you want the sample point TS1+2 to be 75% of 3 + TS1 + TS2
 * https://www.ti.com/lit/an/slla270/slla270.pdf Page 11
 */
#define TARGET 0.0
#define TARGET_ERROR (0.02)
#define SAMPLE_POINT_ERROR (0.075)
#define SAMPLE_POINT (0.75)
 
void search_baudrate2(uint32_t clk, uint32_t baud_rate)
{
	float baud_period_ns;
	float clock_period_ns;
	uint16_t BRP;
	int16_t TS1;
	int16_t TS2;
	float Tq_ns; // Time Quanta
	float Tbs1_ns; //
	float Tbs2_ns;
	float bit_time_ns;
	float baud_rate_f = baud_rate;
	float baud_rate_calc;
	float error;
	float sample_point;
 
	char buf[120];
 
	sprintf(buf,"Starting search_baudrate(clk: %lu, target baud_rate: %lu\r\n", clk, baud_rate );
	write_debug_str(buf);
 
	sprintf(buf,"Target is %4.1f +//- %4.1f %% error and %4.1f +//- %4.1f %% Sample Point\r\n", 
TARGET*100, TARGET_ERROR*100, SAMPLE_POINT*100, SAMPLE_POINT_ERROR*100);
	write_debug_str(buf);
 
	clock_period_ns = (1.0 / clk) * 1000000000.0;
	baud_period_ns = ((1.0 / baud_rate) * 1000000000.0) * (1.0 + TARGET_ERROR);
 
	for (BRP=0;BRP<512;BRP++)
	{
		Tq_ns = (BRP + 1) * clock_period_ns;
		if ((Tq_ns * 3) > baud_period_ns) break; // quit searching when there is no way you will have a good solution.
 
		for (TS1=15;TS1>=0;TS1--)
		{
			Tbs1_ns = (TS1 + 1) * Tq_ns;
			for (TS2=7;TS2>=0;TS2--)
			{
				Tbs2_ns = (TS2 + 1) * Tq_ns;
				bit_time_ns = Tq_ns + Tbs1_ns + Tbs2_ns;
				baud_rate_calc = 1000000000.0 / bit_time_ns;
				error = (baud_rate_calc - baud_rate_f) / baud_rate_f;
				sample_point = (Tq_ns + Tbs1_ns)  / bit_time_ns;
 
				if (fabs(error) < TARGET_ERROR)
				{
					if ((sample_point < (SAMPLE_POINT + SAMPLE_POINT_ERROR)) && (sample_point > (SAMPLE_POINT - SAMPLE_POINT_ERROR))) // If sample point between 0.7 and 0.8
					{
						// Close enough maybe
 
						sprintf(buf,"BRP: %4u, TS1: %2u, TS2: %2u, Tq(ns): %7.2f, Baudrate: %9.1f, error(%%): %6.2f, Sample_Point(%%): %6.1f\r\n",
								BRP, TS1, TS2, Tq_ns, baud_rate_calc, error*100.0, sample_point*100.0);
						HAL_Delay(100);
						write_debug_str(buf);
					}
				}
			}
		}
	}
    write_debug_str("Done search_baudrate()\r\n");
}

You call it with the peripheral clock (in Hz) for the CAN interface. For the STM32F446RM that is APB1 in the Clock Configuration Tab of the MX program. (In my case 45000000.)

And the Baudrate (or bits per second) that you want. (In my case 1000000 bits/s)

In an ideal case you want the baudrate to match exactly. So the error should 0.00%

And the Sample point should be 75%. But I do not think that is as critical as the baudrate.

So the program with brute force tries all the combinations and prints the ones that match the criteria set in the # define.

TARGET is the baudrate target, you want that to be 0.

TARGET_ERROR is how far off you are willing to go from the target. 0.02 is 2%. If it is not exact I would test it like crazy to see if it works in all situations.

SAMPLE_POINT is 0.75 for 75% That is what the TI documentation says the target should be.

SAMPLE_POINT error is 0.075 or 7.5%. So it will print results from 67.5% to 82.5%

I am a beginner at this but I think you should use the solution with the lowest BRP, with an exact baud, and the closest to 75% Sample Point (favoring maybe greater than 75% versus less than 75%).

I ran the program on my STM32 processor. You will have to tell the program to use the floating point sprint library and write the write_debug_str() subroutine to take a string and write it to the serial port of your choosing. I write to the UART at 921600 bits/s, and was exceeding the terminal program buffer, so I had to slow it down with some HAL_Delay(); It ran in less than a minute.

In my case the output was:

Starting search_baudrate(clk: 45000000, target baud_rate: 1000000

Target is 0.0 +//- 2.0 % error and 75.0 +//- 7.5 % Sample Point

BRP:   2, TS1: 10, TS2: 2, Tq(ns):  66.67, Baudrate: 1000000.0, error(%):  0.00, Sample_Point(%):  80.0

BRP:   2, TS1: 9, TS2: 3, Tq(ns):  66.67, Baudrate: 1000000.0, error(%):  0.00, Sample_Point(%):  73.3

BRP:   4, TS1: 5, TS2: 1, Tq(ns): 111.11, Baudrate: 1000000.1, error(%):  0.00, Sample_Point(%):  77.8

BRP:   8, TS1: 2, TS2: 0, Tq(ns): 200.00, Baudrate: 1000000.0, error(%):  0.00, Sample_Point(%):  80.0

Done search_baudrate()

So I plan to use the second one because the BRP was the lowest, the baud rate error was 0, and the sample point 73.3 was the closest to 75%

BRP, TS1, TS2 are the values in the CAN_BTR register.

When you are in the MX program setting up the parameters for the CAN interface

The Prescaler (for Time Quantum) is BRP+1

Time Quanta in Bit Segment 1 is TS1+1

Time Quanta in Bit Segment 2 is TS2+1

And I do not know what the ReSynchronization Jump Width should be. I am trying 1, since the baud rate error is 0.

KiptonM
Lead
/*
 * This was easier to do in C than in a spread sheet.
 * The default values for BRP, TS1, and TS2 in the CAN MX program are not good.
 * This calculates all of the usable combinations of BRP, TS1, and TS2.
 * In an ideal world you want the baudrate error to be 0.00%
 * And I am thinking you want the sum of TS1 + TS2 to be larger if the error is 0.
 * According to the TI documentation you want the sample point TS1+2 to be 75% of 3 + TS1 + TS2
 * https://www.ti.com/lit/an/slla270/slla270.pdf Page 11
 */
#define TARGET 0.0
#define TARGET_ERROR (0.02)
#define SAMPLE_POINT_ERROR (0.075)
#define SAMPLE_POINT (0.75)
 
void search_baudrate2(uint32_t clk, uint32_t baud_rate)
{
    float baud_period_ns;
    float clock_period_ns;
    uint16_t BRP;
    int16_t TS1;
    int16_t TS2;
    float Tq_ns; // Time Quanta
    float Tbs1_ns; //
    float Tbs2_ns;
    float bit_time_ns;
    float baud_rate_f = baud_rate;
    float baud_rate_calc;
    float error;
    float sample_point;
 
    char buf[120];
 
    sprintf(buf,"Starting search_baudrate(clk: %lu, target baud_rate: %lu\r\n", clk, baud_rate );
    write_debug_str(buf);
 
    sprintf(buf,"Target is %4.1f +//- %4.1f %% error and %4.1f +//- %4.1f %% Sample Point\r\n",
        TARGET*100, TARGET_ERROR*100, SAMPLE_POINT*100, SAMPLE_POINT_ERROR*100);
	
    write_debug_str(buf);
 
    clock_period_ns = (1.0 / clk) * 1000000000.0;
    baud_period_ns = ((1.0 / baud_rate) * 1000000000.0) * (1.0 + TARGET_ERROR);
 
    for (BRP=0;BRP<512;BRP++)
    {
        Tq_ns = (BRP + 1) * clock_period_ns;
        if ((Tq_ns * 3) > baud_period_ns) break; // quit searching when there is no way 
                                                                    // you will have a good solution.
 
        for (TS1=15;TS1>=0;TS1--)
        {
            Tbs1_ns = (TS1 + 1) * Tq_ns;
            for (TS2=7;TS2>=0;TS2--)
            {
                Tbs2_ns = (TS2 + 1) * Tq_ns;
                bit_time_ns = Tq_ns + Tbs1_ns + Tbs2_ns;
                baud_rate_calc = 1000000000.0 / bit_time_ns;
                error = (baud_rate_calc - baud_rate_f) / baud_rate_f;
                sample_point = (Tq_ns + Tbs1_ns)  / bit_time_ns;
 
                if (fabs(error) < TARGET_ERROR)
                {
                    // If sample point between 0.67.5% and 0.82.5% for default case
                    if ((sample_point < (SAMPLE_POINT + SAMPLE_POINT_ERROR)) && 
                        (sample_point > (SAMPLE_POINT - SAMPLE_POINT_ERROR))) 
                    {
                        // Close enough maybe
                        sprintf(buf,"BRP: %4u, TS1: %2u, TS2: %2u, Tq(ns): %7.2f,"
                            "Baudrate: %9.1f, error(%%): %6.2f, Sample_Point(%%): %6.1f\r\n",
                            BRP, TS1, TS2, Tq_ns, baud_rate_calc, error*100.0, sample_point*100.0);
                            HAL_Delay(100);
                            write_debug_str(buf);
                    }
                }
            }
        }
    }
    write_debug_str("Done search_baudrate()\r\n");
}

I took out the tabs so the program would be easier to read. My program has 4 space tabs, this system has 8 space tabs.