Skip to content

Commit a9389f3

Browse files
Tinyu-Zhaolbuque
authored andcommitted
cmodules: Compatible with the new TWAI configuration method.
Signed-off-by: tinyu <tinyu@m5stack.com>
1 parent a270c78 commit a9389f3

File tree

4 files changed

+341
-134
lines changed

4 files changed

+341
-134
lines changed

m5stack/cmodules/m5can/modcan.c

Lines changed: 253 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,19 +16,23 @@
1616
#include "py/mperrno.h"
1717
#include "py/mphal.h"
1818
#include "driver/twai.h"
19+
#include "esp_clk_tree.h"
20+
#include "esp_private/esp_clk.h"
1921

20-
#define DEBUG 0
22+
#define DEBUG 1
2123
#if DEBUG
2224
#define DEBUG_printf(...) mp_printf(&mp_plat_print, __VA_ARGS__)
2325
#else
2426
#define DEBUG_printf(...) (void)0
2527
#endif
2628

2729
// Default timings; 125Kbps
28-
#define CAN_DEFAULT_PRESCALER (32)
29-
#define CAN_DEFAULT_SJW (3)
30-
#define CAN_DEFAULT_BS1 (15)
31-
#define CAN_DEFAULT_BS2 (4)
30+
#define CAN_DEFAULT_CLK_SRC TWAI_CLK_SRC_DEFAULT
31+
#define CAN_DEFAULT_QUANTA_RESOLUTION_HZ (2500000)
32+
#define CAN_DEFAULT_BRP (0)
33+
#define CAN_DEFAULT_TSEG1 (15)
34+
#define CAN_DEFAULT_TSEG2 (4)
35+
#define CAN_DEFAULT_SJW (3)
3236

3337
#define CAN_MAXIMUM_NBRP (512)
3438
#define CAN_MAXIMUM_NBS1 (256)
@@ -58,6 +62,172 @@
5862
#define CAN_STATE_RECOVERING 5
5963
#define CAN_STATE_RUNNING 6
6064

65+
typedef struct {
66+
int xtal; // MHz
67+
int bitrate; // kbit
68+
twai_timing_config_t config;
69+
} twai_timing_entry_t;
70+
71+
static const twai_timing_entry_t timing_table[] = {
72+
// XTAL = 32 MHz
73+
{32,
74+
25,
75+
{.clk_src = CAN_DEFAULT_CLK_SRC,
76+
.quanta_resolution_hz = 400000,
77+
.brp = 0,
78+
.tseg_1 = 11,
79+
.tseg_2 = 4,
80+
.sjw = 3,
81+
.triple_sampling = false}},
82+
{32,
83+
50,
84+
{.clk_src = CAN_DEFAULT_CLK_SRC,
85+
.quanta_resolution_hz = 1000000,
86+
.brp = 0,
87+
.tseg_1 = 15,
88+
.tseg_2 = 4,
89+
.sjw = 3,
90+
.triple_sampling = false}},
91+
{32,
92+
100,
93+
{.clk_src = CAN_DEFAULT_CLK_SRC,
94+
.quanta_resolution_hz = 2000000,
95+
.brp = 0,
96+
.tseg_1 = 15,
97+
.tseg_2 = 4,
98+
.sjw = 3,
99+
.triple_sampling = false}},
100+
{32,
101+
125,
102+
{.clk_src = CAN_DEFAULT_CLK_SRC,
103+
.quanta_resolution_hz = 4000000,
104+
.brp = 0,
105+
.tseg_1 = 23,
106+
.tseg_2 = 8,
107+
.sjw = 3,
108+
.triple_sampling = false}},
109+
{32,
110+
250,
111+
{.clk_src = CAN_DEFAULT_CLK_SRC,
112+
.quanta_resolution_hz = 4000000,
113+
.brp = 0,
114+
.tseg_1 = 11,
115+
.tseg_2 = 4,
116+
.sjw = 3,
117+
.triple_sampling = false}},
118+
{32,
119+
500,
120+
{.clk_src = CAN_DEFAULT_CLK_SRC,
121+
.quanta_resolution_hz = 8000000,
122+
.brp = 0,
123+
.tseg_1 = 11,
124+
.tseg_2 = 4,
125+
.sjw = 3,
126+
.triple_sampling = false}},
127+
{32,
128+
800,
129+
{.clk_src = CAN_DEFAULT_CLK_SRC,
130+
.quanta_resolution_hz = 16000000,
131+
.brp = 0,
132+
.tseg_1 = 15,
133+
.tseg_2 = 4,
134+
.sjw = 3,
135+
.triple_sampling = false}},
136+
{32,
137+
1000,
138+
{.clk_src = CAN_DEFAULT_CLK_SRC,
139+
.quanta_resolution_hz = 16000000,
140+
.brp = 0,
141+
.tseg_1 = 11,
142+
.tseg_2 = 4,
143+
.sjw = 3,
144+
.triple_sampling = false}},
145+
146+
// XTAL = 40 MHz
147+
{40,
148+
25,
149+
{.clk_src = CAN_DEFAULT_CLK_SRC,
150+
.quanta_resolution_hz = 625000,
151+
.brp = 0,
152+
.tseg_1 = 16,
153+
.tseg_2 = 8,
154+
.sjw = 3,
155+
.triple_sampling = false}},
156+
{40,
157+
50,
158+
{.clk_src = CAN_DEFAULT_CLK_SRC,
159+
.quanta_resolution_hz = 1000000,
160+
.brp = 0,
161+
.tseg_1 = 15,
162+
.tseg_2 = 4,
163+
.sjw = 3,
164+
.triple_sampling = false}},
165+
{40,
166+
100,
167+
{.clk_src = CAN_DEFAULT_CLK_SRC,
168+
.quanta_resolution_hz = 2000000,
169+
.brp = 0,
170+
.tseg_1 = 15,
171+
.tseg_2 = 4,
172+
.sjw = 3,
173+
.triple_sampling = false}},
174+
{40,
175+
125,
176+
{.clk_src = CAN_DEFAULT_CLK_SRC,
177+
.quanta_resolution_hz = 2500000,
178+
.brp = 0,
179+
.tseg_1 = 15,
180+
.tseg_2 = 4,
181+
.sjw = 3,
182+
.triple_sampling = false}},
183+
{40,
184+
250,
185+
{.clk_src = CAN_DEFAULT_CLK_SRC,
186+
.quanta_resolution_hz = 5000000,
187+
.brp = 0,
188+
.tseg_1 = 15,
189+
.tseg_2 = 4,
190+
.sjw = 3,
191+
.triple_sampling = false}},
192+
{40,
193+
500,
194+
{.clk_src = CAN_DEFAULT_CLK_SRC,
195+
.quanta_resolution_hz = 10000000,
196+
.brp = 0,
197+
.tseg_1 = 15,
198+
.tseg_2 = 4,
199+
.sjw = 3,
200+
.triple_sampling = false}},
201+
{40,
202+
800,
203+
{.clk_src = CAN_DEFAULT_CLK_SRC,
204+
.quanta_resolution_hz = 20000000,
205+
.brp = 0,
206+
.tseg_1 = 16,
207+
.tseg_2 = 8,
208+
.sjw = 3,
209+
.triple_sampling = false}},
210+
{40,
211+
1000,
212+
{.clk_src = CAN_DEFAULT_CLK_SRC,
213+
.quanta_resolution_hz = 20000000,
214+
.brp = 0,
215+
.tseg_1 = 15,
216+
.tseg_2 = 4,
217+
.sjw = 3,
218+
.triple_sampling = false}},
219+
};
220+
221+
static int find_timing_config(int xtal, int bitrate, twai_timing_config_t *out) {
222+
for (size_t i = 0; i < sizeof(timing_table) / sizeof(timing_table[0]); ++i) {
223+
if (timing_table[i].bitrate == bitrate && timing_table[i].xtal == xtal) {
224+
*out = timing_table[i].config;
225+
return 0;
226+
}
227+
}
228+
return -1;
229+
}
230+
61231
typedef struct _pyb_can_obj_t {
62232
mp_obj_base_t base;
63233
mp_uint_t can_id;
@@ -96,36 +266,74 @@ static void pyb_can_print(const mp_print_t *print, mp_obj_t self_in, mp_print_ki
96266

97267
// init(mode, prescaler=100, *, sjw=1, bs1=6, bs2=8)
98268
static 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) {
99-
enum { ARG_mode, ARG_tx, ARG_rx, ARG_prescaler, ARG_sjw, ARG_bs1, ARG_bs2, ARG_triple_sampling };
269+
enum {
270+
ARG_mode,
271+
ARG_tx,
272+
ARG_rx,
273+
ARG_quanta_resolution_hz,
274+
ARG_brp,
275+
ARG_tseg_1,
276+
ARG_tseg_2,
277+
ARG_sjw,
278+
ARG_triple_sampling,
279+
ARG_baudrate,
280+
};
100281
static const mp_arg_t allowed_args[] = {
101282
{MP_QSTR_mode, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = CAN_MODE_NORMAL}},
102283
{MP_QSTR_tx, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 2}},
103284
{MP_QSTR_rx, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 1}},
104-
{MP_QSTR_prescaler, MP_ARG_INT, {.u_int = CAN_DEFAULT_PRESCALER}},
285+
{MP_QSTR_quanta_resolution_hz, MP_ARG_INT, {.u_int = CAN_DEFAULT_QUANTA_RESOLUTION_HZ}},
286+
{MP_QSTR_brp, MP_ARG_INT, {.u_int = CAN_DEFAULT_BRP}},
287+
{MP_QSTR_tseg_1, MP_ARG_INT, {.u_int = CAN_DEFAULT_TSEG1}},
288+
{MP_QSTR_tseg_2, MP_ARG_INT, {.u_int = CAN_DEFAULT_TSEG2}},
105289
{MP_QSTR_sjw, MP_ARG_INT, {.u_int = CAN_DEFAULT_SJW}},
106-
{MP_QSTR_bs1, MP_ARG_INT, {.u_int = CAN_DEFAULT_BS1}},
107-
{MP_QSTR_bs2, MP_ARG_INT, {.u_int = CAN_DEFAULT_BS2}},
108290
{MP_QSTR_triple_sampling, MP_ARG_BOOL, {.u_bool = false}},
291+
{MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 0}},
109292
};
110293

111294
// parse args
112295
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
113296
mp_arg_parse_all(n_args, pos_args, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
114297

115-
self->t_config.brp = args[ARG_prescaler].u_int;
116-
self->t_config.tseg_1 = args[ARG_bs1].u_int;
117-
self->t_config.tseg_2 = args[ARG_bs2].u_int;
118-
self->t_config.sjw = args[ARG_sjw].u_int;
119-
self->t_config.triple_sampling = args[ARG_triple_sampling].u_bool;
120-
121298
self->g_config.tx_io = args[ARG_tx].u_int;
122299
self->g_config.rx_io = args[ARG_rx].u_int;
123300
self->g_config.mode = args[ARG_mode].u_int;
124301

125-
DEBUG_printf(&mp_plat_print, "prescaler=%u, sjw=%u, bs1=%u, bs2=%u, triple_sampling=%u\n", self->t_config.brp,
126-
self->t_config.tseg_1, self->t_config.tseg_2, self->t_config.sjw, self->t_config.triple_sampling);
127-
DEBUG_printf(&mp_plat_print, "mode=%u, tx=%u, rx=%u\n", self->g_config.mode, self->g_config.tx_io,
128-
self->g_config.rx_io);
302+
if (args[ARG_baudrate].u_int != 0) {
303+
int xtal = esp_clk_xtal_freq() / 1000000;
304+
DEBUG_printf("XTAL frequency: %d MHz\n", xtal);
305+
DEBUG_printf("find_timing_config: xtal=%d MHz, baudrate=%d kbps\n", xtal, args[ARG_baudrate].u_int);
306+
if (find_timing_config(xtal, args[ARG_baudrate].u_int, &self->t_config) != 0) {
307+
DEBUG_printf("Timing config not found for baudrate %d kbps\n", args[ARG_baudrate].u_int);
308+
mp_raise_msg_varg(&mp_type_ValueError,
309+
MP_ERROR_TEXT("Unsupported baudrate %d kbps for %d MHz crystal. Supported: 25, 50, 100, "
310+
"125, 250, 500, 800, 1000"),
311+
args[ARG_baudrate].u_int, xtal);
312+
}
313+
} else {
314+
self->t_config.clk_src = CAN_DEFAULT_CLK_SRC;
315+
if (args[ARG_quanta_resolution_hz].u_int == 0 && args[ARG_brp].u_int != 0) {
316+
uint32_t xtal_apb_freq_hz;
317+
318+
esp_clk_tree_src_get_freq_hz(CAN_DEFAULT_CLK_SRC, ESP_CLK_TREE_SRC_FREQ_PRECISION_EXACT, &xtal_apb_freq_hz);
319+
DEBUG_printf("XTAL APB frequency: %d MHz\n", xtal_apb_freq_hz / 1000000);
320+
args[ARG_quanta_resolution_hz].u_int = xtal_apb_freq_hz / args[ARG_brp].u_int;
321+
DEBUG_printf("Using quanta_resolution_hz=%u based on brp=%u\n", args[ARG_quanta_resolution_hz].u_int,
322+
args[ARG_brp].u_int);
323+
args[ARG_brp].u_int = 0;
324+
}
325+
self->t_config.quanta_resolution_hz = args[ARG_quanta_resolution_hz].u_int;
326+
self->t_config.brp = args[ARG_brp].u_int;
327+
self->t_config.tseg_1 = args[ARG_tseg_1].u_int;
328+
self->t_config.tseg_2 = args[ARG_tseg_2].u_int;
329+
self->t_config.sjw = args[ARG_sjw].u_int;
330+
self->t_config.triple_sampling = args[ARG_triple_sampling].u_bool;
331+
}
332+
333+
DEBUG_printf("tx=%u, rx=%u, mode=%u\n", self->g_config.tx_io, self->g_config.rx_io, self->g_config.mode);
334+
DEBUG_printf("quanta_resolution_hz=%u brp=%u, tseg_1=%u, tseg_2=%u, sjw=%u, triple_sampling=%u\n",
335+
self->t_config.quanta_resolution_hz, self->t_config.brp, self->t_config.tseg_1, self->t_config.tseg_2,
336+
self->t_config.sjw, self->t_config.triple_sampling);
129337

130338
check_esp_err(twai_driver_install(&self->g_config, &self->t_config, &self->f_config));
131339
check_esp_err(twai_start());
@@ -157,9 +365,11 @@ static mp_obj_t pyb_can_make_new(const mp_obj_type_t *type, size_t n_args, size_
157365
}
158366

159367
{
160-
self->t_config.brp = CAN_DEFAULT_PRESCALER;
161-
self->t_config.tseg_1 = CAN_DEFAULT_BS1;
162-
self->t_config.tseg_2 = CAN_DEFAULT_BS2;
368+
self->t_config.clk_src = CAN_DEFAULT_CLK_SRC;
369+
self->t_config.quanta_resolution_hz = CAN_DEFAULT_QUANTA_RESOLUTION_HZ;
370+
self->t_config.brp = CAN_DEFAULT_BRP;
371+
self->t_config.tseg_1 = CAN_DEFAULT_TSEG1;
372+
self->t_config.tseg_2 = CAN_DEFAULT_TSEG2;
163373
self->t_config.sjw = CAN_DEFAULT_SJW;
164374
self->t_config.triple_sampling = false;
165375
};
@@ -187,7 +397,7 @@ static mp_obj_t pyb_can_make_new(const mp_obj_type_t *type, size_t n_args, size_
187397
twai_stop();
188398
// check_esp_err(twai_driver_uninstall());
189399
int err = twai_driver_uninstall();
190-
mp_printf(&mp_plat_print, "twai_driver_uninstall() returned %d\n", err);
400+
DEBUG_printf("twai_driver_uninstall() returned %d\n", (int)err);
191401

192402
vTaskDelay(10 / portTICK_PERIOD_MS);
193403
self->is_enabled = false;
@@ -340,24 +550,24 @@ static mp_obj_t pyb_can_send(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
340550
tx_msg.rtr = args[ARG_rtr].u_bool;
341551
tx_msg.extd = args[ARG_extframe].u_bool;
342552
#if DEBUG
343-
DEBUG_printf(&mp_plat_print, "Income Data:");
553+
DEBUG_printf("Send Data:");
344554
for (size_t i = 0; i < bufinfo.len; i++) {
345-
DEBUG_printf(&mp_plat_print, "0x%02X ", ((uint8_t *)bufinfo.buf)[i]);
555+
DEBUG_printf("0x%02X ", ((uint8_t *)bufinfo.buf)[i]);
346556
}
347-
DEBUG_printf(&mp_plat_print, "\n - extd: %d\n", tx_msg.extd);
348-
DEBUG_printf(&mp_plat_print, " - rtr: %d\n", tx_msg.rtr);
349-
DEBUG_printf(&mp_plat_print, " - ss: %d\n", tx_msg.ss);
350-
DEBUG_printf(&mp_plat_print, " - self: %d\n", tx_msg.self);
351-
DEBUG_printf(&mp_plat_print, " - dlc_non_comp: %d\n", tx_msg.dlc_non_comp);
352-
DEBUG_printf(&mp_plat_print, "Complete tx_msg:\n");
353-
DEBUG_printf(&mp_plat_print, " flags: 0x%08X\n", tx_msg.flags);
354-
DEBUG_printf(&mp_plat_print, " identifier: 0x%08X\n", tx_msg.identifier);
355-
DEBUG_printf(&mp_plat_print, " data_length_code: %d\n", tx_msg.data_length_code);
356-
DEBUG_printf(&mp_plat_print, " data: ");
557+
DEBUG_printf("\n - extd: %d\n", tx_msg.extd);
558+
DEBUG_printf(" - rtr: %d\n", tx_msg.rtr);
559+
DEBUG_printf(" - ss: %d\n", tx_msg.ss);
560+
DEBUG_printf(" - self: %d\n", tx_msg.self);
561+
DEBUG_printf(" - dlc_non_comp: %d\n", tx_msg.dlc_non_comp);
562+
DEBUG_printf("Complete tx_msg:\n");
563+
DEBUG_printf(" flags: 0x%08X\n", tx_msg.flags);
564+
DEBUG_printf(" identifier: 0x%08X\n", tx_msg.identifier);
565+
DEBUG_printf(" data_length_code: %d\n", tx_msg.data_length_code);
566+
DEBUG_printf(" data: ");
357567
for (int i = 0; i < bufinfo.len; i++) {
358-
DEBUG_printf(&mp_plat_print, "0x%02X ", tx_msg.data[i]);
568+
DEBUG_printf("0x%02X ", tx_msg.data[i]);
359569
}
360-
DEBUG_printf(&mp_plat_print, "\n\n");
570+
DEBUG_printf("\n\n");
361571
#endif
362572
check_esp_err(twai_transmit(&tx_msg, args[ARG_timeout].u_int));
363573
return mp_const_none;
@@ -382,12 +592,12 @@ static mp_obj_t pyb_can_recv(size_t n_args, const mp_obj_t *pos_args, mp_map_t *
382592
twai_message_t rx_msg;
383593
esp_err_t ret = twai_receive(&rx_msg, args[ARG_timeout].u_int);
384594
#if DEBUG
385-
DEBUG_printf(&mp_plat_print, "Received identifier: 0x%08X\n", rx_msg.identifier);
386-
DEBUG_printf(&mp_plat_print, "received data: ");
595+
DEBUG_printf("Received identifier: 0x%08X\n", rx_msg.identifier);
596+
DEBUG_printf("received data: ");
387597
for (int i = 0; i < rx_msg.data_length_code; i++) {
388-
DEBUG_printf(&mp_plat_print, "0x%02X ", rx_msg.data[i]);
598+
DEBUG_printf("0x%02X ", rx_msg.data[i]);
389599
}
390-
DEBUG_printf(&mp_plat_print, "\r\n");
600+
DEBUG_printf("\r\n");
391601
#endif
392602
if (ret != ESP_OK || rx_msg.data_length_code > 8) {
393603
return mp_const_none;
@@ -540,8 +750,8 @@ MP_DEFINE_CONST_OBJ_TYPE(pyb_can_type, MP_QSTR_CAN, MP_TYPE_FLAG_NONE, make_new,
540750
MP_REGISTER_ROOT_POINTER(struct _pyb_can_obj_t *pyb_can_obj_all[1]);
541751

542752
static const mp_rom_map_elem_t m5can_module_globals_table[] = {
543-
{ MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_m5can) },
544-
{ MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type) },
753+
{MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_m5can)},
754+
{MP_ROM_QSTR(MP_QSTR_CAN), MP_ROM_PTR(&pyb_can_type)},
545755
};
546756

547757
static MP_DEFINE_CONST_DICT(m5can_module_globals, m5can_module_globals_table);

0 commit comments

Comments
 (0)