diff options
| -rw-r--r-- | docs/library/pyb.CAN.rst | 21 | ||||
| -rw-r--r-- | ports/stm32/pyb_can.c | 12 |
2 files changed, 24 insertions, 9 deletions
diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst index 57a85d54b..eb21d8223 100644 --- a/docs/library/pyb.CAN.rst +++ b/docs/library/pyb.CAN.rst @@ -67,11 +67,17 @@ Methods :meth:`~CAN.restart()` can be used to leave the bus-off state - *baudrate* if a baudrate other than 0 is provided, this function will try to automatically calculate the CAN nominal bit time (overriding *prescaler*, *bs1* and *bs2*) that satisfies - both the baudrate and the desired *sample_point*. - - *sample_point* given in a percentage of the nominal bit time, the *sample_point* specifies the position - of the bit sample with respect to the whole nominal bit time. The default *sample_point* is 75%. + both the *baudrate* (within .1%) and the desired *sample_point* (to the nearest 1%). For more precise + control over the CAN timing, set the *prescaler*, *bs1* and *bs2* parameters directly. + - *sample_point* specifies the position of the bit sample with respect to the whole nominal bit time, + expressed as an integer percentage of the nominal bit time. The default *sample_point* is 75%. + This parameter is ignored unless *baudrate* is set. - *num_filter_banks* for classic CAN, this is the number of banks that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). + + The remaining parameters are only present on boards with CAN FD support, and configure the optional CAN FD + Bit Rate Switch (BRS) feature: + - *brs_prescaler* is the value by which the CAN FD input clock is divided to generate the data bit time quanta. The prescaler can be a value between 1 and 32 inclusive. - *brs_sjw* is the resynchronisation jump width in units of time quanta for data bits; @@ -82,10 +88,11 @@ Methods it can be a value between 1 and 16 inclusive - *brs_baudrate* if a baudrate other than 0 is provided, this function will try to automatically calculate the CAN data bit time (overriding *brs_prescaler*, *brs_bs1* and *brs_bs2*) that satisfies - both the baudrate and the desired *brs_sample_point*. - - *brs_sample_point* given in a percentage of the data bit time, the *brs_sample_point* specifies the position - of the bit sample with respect to the whole data bit time. The default *brs_sample_point* is 75%. - + both the *brs_baudrate* (within .1%) and the desired *brs_sample_point* (to the nearest 1%). For more + precise control over the BRS timing, set the *brs_prescaler*, *brs_bs1* and *brs_bs2* parameters directly. + - *brs_sample_point* specifies the position of the bit sample with respect to the whole nominal bit time, + expressed as an integer percentage of the nominal bit time. The default *brs_sample_point* is 75%. + This parameter is ignored unless *brs_baudrate* is set. The time quanta tq is the basic unit of time for the CAN bus. tq is the CAN prescaler value divided by PCLK1 (the frequency of internal peripheral bus 1); diff --git a/ports/stm32/pyb_can.c b/ports/stm32/pyb_can.c index dc05f965d..723ff6f9d 100644 --- a/ports/stm32/pyb_can.c +++ b/ports/stm32/pyb_can.c @@ -25,6 +25,7 @@ */ #include <string.h> +#include <stdlib.h> #include "py/objarray.h" #include "py/runtime.h" @@ -199,12 +200,19 @@ static void pyb_can_get_bit_timing(mp_uint_t baudrate, mp_uint_t sample_point, uint32_t max_brp, uint32_t max_bs1, uint32_t max_bs2, uint32_t min_tseg, mp_int_t *bs1_out, mp_int_t *bs2_out, mp_int_t *prescaler_out) { uint32_t can_kern_clk = pyb_can_get_source_freq(); + mp_uint_t max_baud_error = baudrate / 1000; // Allow .1% deviation + const mp_uint_t MAX_SAMPLE_ERROR = 5; // round to nearest 1%, which is the param resolution + sample_point *= 10; // Calculate CAN bit timing. for (uint32_t brp = 1; brp < max_brp; brp++) { for (uint32_t bs1 = min_tseg; bs1 < max_bs1; bs1++) { for (uint32_t bs2 = min_tseg; bs2 < max_bs2; bs2++) { - if ((baudrate == (can_kern_clk / (brp * (1 + bs1 + bs2)))) && - ((sample_point * 10) == (((1 + bs1) * 1000) / (1 + bs1 + bs2)))) { + mp_int_t calc_baud = can_kern_clk / (brp * (1 + bs1 + bs2)); + mp_int_t calc_sample = ((1 + bs1) * 1000) / (1 + bs1 + bs2); + mp_int_t baud_err = baudrate - calc_baud; + mp_int_t sample_err = sample_point - calc_sample; + if (abs(baud_err) < max_baud_error && + abs(sample_err) < MAX_SAMPLE_ERROR) { *bs1_out = bs1; *bs2_out = bs2; *prescaler_out = brp; |
