Skip to content

Commit e8d3df5

Browse files
projectgusdpgeorge
authored andcommitted
stm32/pyb_can: Make pyb.CAN baud calculation a little more forgiving.
Not every baudrate or sample point combination has an exact match, but getting within 1% on sample point and .1% on baud rate should always be good enough. Because the search goes from shorter bit periods (lowest brp) and increases, the first match which meets this criteria should still mostly be the best available. This work was funded through GitHub Sponsors. Signed-off-by: Angus Gratton <[email protected]>
1 parent 1d8943a commit e8d3df5

File tree

2 files changed

+24
-9
lines changed

2 files changed

+24
-9
lines changed

docs/library/pyb.CAN.rst

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,11 +67,17 @@ Methods
6767
:meth:`~CAN.restart()` can be used to leave the bus-off state
6868
- *baudrate* if a baudrate other than 0 is provided, this function will try to automatically
6969
calculate the CAN nominal bit time (overriding *prescaler*, *bs1* and *bs2*) that satisfies
70-
both the baudrate and the desired *sample_point*.
71-
- *sample_point* given in a percentage of the nominal bit time, the *sample_point* specifies the position
72-
of the bit sample with respect to the whole nominal bit time. The default *sample_point* is 75%.
70+
both the *baudrate* (within .1%) and the desired *sample_point* (to the nearest 1%). For more precise
71+
control over the CAN timing, set the *prescaler*, *bs1* and *bs2* parameters directly.
72+
- *sample_point* specifies the position of the bit sample with respect to the whole nominal bit time,
73+
expressed as an integer percentage of the nominal bit time. The default *sample_point* is 75%.
74+
This parameter is ignored unless *baudrate* is set.
7375
- *num_filter_banks* for classic CAN, this is the number of banks that will be assigned to CAN(1),
7476
the rest of the 28 are assigned to CAN(2).
77+
78+
The remaining parameters are only present on boards with CAN FD support, and configure the optional CAN FD
79+
Bit Rate Switch (BRS) feature:
80+
7581
- *brs_prescaler* is the value by which the CAN FD input clock is divided to generate the
7682
data bit time quanta. The prescaler can be a value between 1 and 32 inclusive.
7783
- *brs_sjw* is the resynchronisation jump width in units of time quanta for data bits;
@@ -82,10 +88,11 @@ Methods
8288
it can be a value between 1 and 16 inclusive
8389
- *brs_baudrate* if a baudrate other than 0 is provided, this function will try to automatically
8490
calculate the CAN data bit time (overriding *brs_prescaler*, *brs_bs1* and *brs_bs2*) that satisfies
85-
both the baudrate and the desired *brs_sample_point*.
86-
- *brs_sample_point* given in a percentage of the data bit time, the *brs_sample_point* specifies the position
87-
of the bit sample with respect to the whole data bit time. The default *brs_sample_point* is 75%.
88-
91+
both the *brs_baudrate* (within .1%) and the desired *brs_sample_point* (to the nearest 1%). For more
92+
precise control over the BRS timing, set the *brs_prescaler*, *brs_bs1* and *brs_bs2* parameters directly.
93+
- *brs_sample_point* specifies the position of the bit sample with respect to the whole nominal bit time,
94+
expressed as an integer percentage of the nominal bit time. The default *brs_sample_point* is 75%.
95+
This parameter is ignored unless *brs_baudrate* is set.
8996

9097
The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN
9198
prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1);

ports/stm32/pyb_can.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
*/
2626

2727
#include <string.h>
28+
#include <stdlib.h>
2829

2930
#include "py/objarray.h"
3031
#include "py/runtime.h"
@@ -199,12 +200,19 @@ static void pyb_can_get_bit_timing(mp_uint_t baudrate, mp_uint_t sample_point,
199200
uint32_t max_brp, uint32_t max_bs1, uint32_t max_bs2, uint32_t min_tseg,
200201
mp_int_t *bs1_out, mp_int_t *bs2_out, mp_int_t *prescaler_out) {
201202
uint32_t can_kern_clk = pyb_can_get_source_freq();
203+
mp_uint_t max_baud_error = baudrate / 1000; // Allow .1% deviation
204+
const mp_uint_t MAX_SAMPLE_ERROR = 5; // round to nearest 1%, which is the param resolution
205+
sample_point *= 10;
202206
// Calculate CAN bit timing.
203207
for (uint32_t brp = 1; brp < max_brp; brp++) {
204208
for (uint32_t bs1 = min_tseg; bs1 < max_bs1; bs1++) {
205209
for (uint32_t bs2 = min_tseg; bs2 < max_bs2; bs2++) {
206-
if ((baudrate == (can_kern_clk / (brp * (1 + bs1 + bs2)))) &&
207-
((sample_point * 10) == (((1 + bs1) * 1000) / (1 + bs1 + bs2)))) {
210+
mp_int_t calc_baud = can_kern_clk / (brp * (1 + bs1 + bs2));
211+
mp_int_t calc_sample = ((1 + bs1) * 1000) / (1 + bs1 + bs2);
212+
mp_int_t baud_err = baudrate - calc_baud;
213+
mp_int_t sample_err = sample_point - calc_sample;
214+
if (abs(baud_err) < max_baud_error &&
215+
abs(sample_err) < MAX_SAMPLE_ERROR) {
208216
*bs1_out = bs1;
209217
*bs2_out = bs2;
210218
*prescaler_out = brp;

0 commit comments

Comments
 (0)