@@ -140,9 +140,41 @@ STATIC void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
140140 }
141141}
142142
143+ STATIC uint32_t pyb_can_get_source_freq () {
144+ uint32_t can_kern_clk = 0 ;
145+
146+ // Find CAN kernel clock
147+ #if defined(STM32H7 )
148+ switch (__HAL_RCC_GET_FDCAN_SOURCE ()) {
149+ case RCC_FDCANCLKSOURCE_HSE :
150+ can_kern_clk = HSE_VALUE ;
151+ break ;
152+ case RCC_FDCANCLKSOURCE_PLL : {
153+ PLL1_ClocksTypeDef pll1_clocks ;
154+ HAL_RCCEx_GetPLL1ClockFreq (& pll1_clocks );
155+ can_kern_clk = pll1_clocks .PLL1_Q_Frequency ;
156+ break ;
157+ }
158+ case RCC_FDCANCLKSOURCE_PLL2 : {
159+ PLL2_ClocksTypeDef pll2_clocks ;
160+ HAL_RCCEx_GetPLL2ClockFreq (& pll2_clocks );
161+ can_kern_clk = pll2_clocks .PLL2_Q_Frequency ;
162+ break ;
163+ }
164+ }
165+ #else // F4 and F7 and assume other MCUs too.
166+ // CAN1/CAN2/CAN3 on APB1 use GetPCLK1Freq, alternatively use the following:
167+ // can_kern_clk = ((HSE_VALUE / osc_config.PLL.PLLM ) * osc_config.PLL.PLLN) /
168+ // (osc_config.PLL.PLLQ * clk_init.AHBCLKDivider * clk_init.APB1CLKDivider);
169+ can_kern_clk = HAL_RCC_GetPCLK1Freq ();
170+ #endif
171+
172+ return can_kern_clk ;
173+ }
174+
143175// init(mode, extframe=False, prescaler=100, *, sjw=1, bs1=6, bs2=8)
144176STATIC mp_obj_t pyb_can_init_helper (pyb_can_obj_t * self , size_t n_args , const mp_obj_t * pos_args , mp_map_t * kw_args ) {
145- enum { ARG_mode , ARG_extframe , ARG_prescaler , ARG_sjw , ARG_bs1 , ARG_bs2 , ARG_auto_restart };
177+ enum { ARG_mode , ARG_extframe , ARG_prescaler , ARG_sjw , ARG_bs1 , ARG_bs2 , ARG_auto_restart , ARG_baudrate , ARG_sample_point };
146178 static const mp_arg_t allowed_args [] = {
147179 { MP_QSTR_mode , MP_ARG_REQUIRED | MP_ARG_INT , {.u_int = CAN_MODE_NORMAL } },
148180 { MP_QSTR_extframe , MP_ARG_BOOL , {.u_bool = false} },
@@ -151,6 +183,8 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp
151183 { MP_QSTR_bs1 , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = CAN_DEFAULT_BS1 } },
152184 { MP_QSTR_bs2 , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = CAN_DEFAULT_BS2 } },
153185 { MP_QSTR_auto_restart , MP_ARG_KW_ONLY | MP_ARG_BOOL , {.u_bool = false} },
186+ { MP_QSTR_baudrate , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 0 } },
187+ { MP_QSTR_sample_point , MP_ARG_KW_ONLY | MP_ARG_INT , {.u_int = 75 } }, // 75% sampling point
154188 };
155189
156190 // parse args
@@ -162,6 +196,32 @@ STATIC mp_obj_t pyb_can_init_helper(pyb_can_obj_t *self, size_t n_args, const mp
162196 // set the CAN configuration values
163197 memset (& self -> can , 0 , sizeof (self -> can ));
164198
199+ // Calculate CAN bit timing from baudrate if provided
200+ if (args [ARG_baudrate ].u_int != 0 ) {
201+ uint32_t baudrate = args [ARG_baudrate ].u_int ;
202+ uint32_t sampoint = args [ARG_sample_point ].u_int ;
203+ uint32_t can_kern_clk = pyb_can_get_source_freq ();
204+ bool timing_found = false;
205+
206+ // The following max values work on all MCUs for classical CAN.
207+ for (int brp = 1 ; brp < 512 && !timing_found ; brp ++ ) {
208+ for (int bs1 = 1 ; bs1 < 16 && !timing_found ; bs1 ++ ) {
209+ for (int bs2 = 1 ; bs2 < 8 && !timing_found ; bs2 ++ ) {
210+ if ((baudrate == (can_kern_clk / (brp * (1 + bs1 + bs2 )))) &&
211+ ((sampoint * 10 ) == (((1 + bs1 ) * 1000 ) / (1 + bs1 + bs2 )))) {
212+ args [ARG_bs1 ].u_int = bs1 ;
213+ args [ARG_bs2 ].u_int = bs2 ;
214+ args [ARG_prescaler ].u_int = brp ;
215+ timing_found = true;
216+ }
217+ }
218+ }
219+ }
220+ if (!timing_found ) {
221+ mp_raise_msg (& mp_type_ValueError , MP_ERROR_TEXT ("couldn't match baudrate and sample point" ));
222+ }
223+ }
224+
165225 // init CAN (if it fails, it's because the port doesn't exist)
166226 if (!can_init (self , args [ARG_mode ].u_int , args [ARG_prescaler ].u_int , args [ARG_sjw ].u_int ,
167227 args [ARG_bs1 ].u_int , args [ARG_bs2 ].u_int , args [ARG_auto_restart ].u_bool )) {
0 commit comments