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.