Skip to content

Commit 7fec662

Browse files
committed
_canio.CAN: add error handling & bus state
1 parent 8d7f7f1 commit 7fec662

File tree

3 files changed

+151
-40
lines changed

3 files changed

+151
-40
lines changed

ports/atmel-samd/common-hal/_canio/CAN.c

Lines changed: 63 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,15 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mc
218218
hri_can_write_XIDFC_reg(self->hw, dfc.reg);
219219
}
220220

221+
{
222+
CAN_IE_Type ie = {
223+
.bit.EWE = 1,
224+
.bit.EPE = 1,
225+
.bit.BOE = 1,
226+
};
227+
hri_can_write_IE_reg(self->hw, ie.reg);
228+
}
229+
221230
hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE);
222231

223232
// silent: The CAN is set in Bus Monitoring Mode by programming CCCR.MON to '1'. (tx pin unused)
@@ -261,35 +270,71 @@ int common_hal_canio_can_baudrate_get(canio_can_obj_t *self)
261270

262271
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self)
263272
{
264-
return -1;
273+
return self->hw->ECR.bit.TEC;
265274
}
266275

267276
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self)
268277
{
269-
return -1;
278+
return self->hw->ECR.bit.REC;
270279
}
271280

272281
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self)
273282
{
274-
return -1;
283+
return self->error_warning_state_count;
275284
}
276285

277286
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self)
278287
{
279-
return -1;
288+
return self->error_passive_state_count;
280289
}
281290

282291
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self)
283292
{
284-
return -1;
293+
return self->bus_off_state_count;
294+
}
295+
296+
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) {
297+
CAN_PSR_Type psr = self->hw->PSR;
298+
if(psr.bit.BO) {
299+
return BUS_STATE_OFF;
300+
}
301+
if(psr.bit.EP) {
302+
return BUS_STATE_ERROR_PASSIVE;
303+
}
304+
if(psr.bit.EW) {
305+
return BUS_STATE_ERROR_WARNING;
306+
}
307+
return BUS_STATE_ERROR_ACTIVE;
308+
}
309+
310+
void common_hal_canio_can_restart(canio_can_obj_t *self) {
311+
if (!self->hw->PSR.bit.BO) {
312+
return;
313+
}
314+
315+
hri_can_clear_CCCR_INIT_bit(self->hw);
316+
while (hri_can_get_CCCR_INIT_bit(self->hw)) {
317+
}
285318
}
286319

287-
int common_hal_canio_can_state_get(canio_can_obj_t *self) {
288-
return -1;
320+
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) {
321+
return self->auto_restart;
322+
}
323+
324+
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) {
325+
self->auto_restart = value;
326+
}
327+
328+
static void maybe_auto_restart(canio_can_obj_t *self) {
329+
if(self->auto_restart) {
330+
common_hal_canio_can_restart(self);
331+
}
289332
}
290333

291334
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message)
292335
{
336+
maybe_auto_restart(self);
337+
293338
// We have just one dedicated TX buffer, use it!
294339
canio_can_fifo_t *ent = &self->state->tx_fifo[0];
295340
ent->txb0.bit.ESI = false;
@@ -365,7 +410,17 @@ STATIC void can_handler(int i) {
365410

366411
Can *hw = can_insts[i];
367412
uint32_t ir = hri_can_read_IR_reg(hw);
368-
/* Handle various interrupts */
413+
414+
/* Count up errors*/
415+
if (ir & CAN_IE_EWE) {
416+
self->error_warning_state_count += 1;
417+
}
418+
if (ir & CAN_IE_EPE) {
419+
self->error_passive_state_count += 1;
420+
}
421+
if (ir & CAN_IE_BOE) {
422+
self->bus_off_state_count += 1;
423+
}
369424

370425
/* Acknowledge interrupt */
371426
hri_can_write_IR_reg(hw, ir);

ports/atmel-samd/common-hal/_canio/CAN.h

Lines changed: 21 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#pragma once
2828

2929
#include "py/obj.h"
30+
#include "shared-bindings/_canio/__init__.h"
3031
#include "component/can.h"
3132
#include "common-hal/microcontroller/Pin.h"
3233
#include "common-hal/_canio/__init__.h"
@@ -38,25 +39,33 @@
3839
typedef struct {
3940
mp_obj_base_t base;
4041
Can *hw;
41-
int baudrate;
42-
uint8_t rx_pin_number, tx_pin_number;
43-
bool loopback;
44-
bool silent;
4542
canio_can_state_t *state;
43+
volatile uint32_t error_warning_state_count;
44+
volatile uint32_t error_passive_state_count;
45+
volatile uint32_t bus_off_state_count;
46+
int baudrate;
47+
uint8_t rx_pin_number:8;
48+
uint8_t tx_pin_number:8;
49+
bool loopback:1;
50+
bool silent:1;
51+
bool auto_restart:1;
4652
bool fifo0_in_use:1;
4753
bool fifo1_in_use:1;
4854
} canio_can_obj_t;
4955

5056
void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mcu_pin_obj_t *tx, int baudrate, bool loopback, bool silent);
51-
int common_hal_canio_can_state_get(canio_can_obj_t *self);
57+
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self);
58+
bool common_hal_canio_can_deinited(canio_can_obj_t *self);
5259
int common_hal_canio_can_baudrate_get(canio_can_obj_t *self);
53-
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self);
54-
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self);
55-
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self);
56-
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self);
5760
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self);
58-
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message);
59-
void common_hal_canio_can_deinit(canio_can_obj_t *self);
61+
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self);
62+
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self);
63+
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self);
64+
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self);
65+
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self);
66+
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart);
6067
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self);
61-
bool common_hal_canio_can_deinited(canio_can_obj_t *self);
68+
void common_hal_canio_can_deinit(canio_can_obj_t *self);
69+
void common_hal_canio_can_restart(canio_can_obj_t *self);
70+
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message);
6271
void common_hal_canio_reset(void);

shared-bindings/_canio/CAN.c

Lines changed: 67 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,10 @@
2424
* THE SOFTWARE.
2525
*/
2626

27+
#include "py/enum.h"
2728
#include "common-hal/_canio/CAN.h"
2829
#include "common-hal/_canio/Listener.h"
30+
#include "shared-bindings/_canio/__init__.h"
2931
#include "shared-bindings/_canio/CAN.h"
3032
#include "shared-bindings/_canio/Listener.h"
3133
#include "shared-bindings/_canio/Match.h"
@@ -45,6 +47,7 @@
4547
//| *,
4648
//| baudrate: int = 250000,
4749
//| loopback: bool = False,
50+
//| auto_restart: bool = False,
4851
//| ):
4952
//| """A common shared-bus protocol. The rx and tx pins are generally
5053
//| connected to a transceiver which controls the H and L pins on a shared
@@ -54,19 +57,19 @@
5457
//| :param ~microcontrller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode.
5558
//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value.
5659
//| :param bool loopback: True if the peripheral will be operated in loopback mode.
60+
//| :param bool auto_restart: If True, will restart communications after entering bus-off state
5761
//| """
5862
//| ...
5963
//|
60-
//## auto_restart: bool = False, # Whether to restart communications after entering bus-off state
61-
//## sample_point: float = .875, # When to sample within bit time (0.0-1.0)
6264
STATIC mp_obj_t canio_can_make_new(const mp_obj_type_t *type, size_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
63-
enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, NUM_ARGS };
65+
enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS };
6466
static const mp_arg_t allowed_args[] = {
6567
{ MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = 0} },
6668
{ MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = 0} },
6769
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} },
6870
{ MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} },
6971
{ MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} },
72+
{ MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} },
7073
};
7174
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
7275
MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS );
@@ -85,40 +88,51 @@ mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin);
8588
self->base.type = &canio_can_type;
8689
common_hal_canio_can_construct(self, rx_pin, tx_pin, args[ARG_baudrate].u_int, args[ARG_loopback].u_bool, args[ARG_silent].u_bool);
8790

91+
common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool);
92+
8893
return MP_OBJ_FROM_PTR(self);
8994
}
9095

9196

92-
//| baudrate: int
93-
//| """The baud rate(read-only)"""
97+
//| auto_restart: int
98+
//| """If True, will restart communications after entering bus-off state"""
9499
//|
95-
STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) {
100+
STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) {
96101
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
97102
common_hal_canio_can_check_for_deinit(self);
98-
return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self));
103+
return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self));
99104
}
100-
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get);
105+
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get);
101106

102-
STATIC const mp_obj_property_t canio_can_baudrate_obj = {
107+
STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) {
108+
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
109+
common_hal_canio_can_check_for_deinit(self);
110+
common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in));
111+
return mp_const_none;
112+
}
113+
MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set);
114+
115+
STATIC const mp_obj_property_t canio_can_auto_restart_obj = {
103116
.base.type = &mp_type_property,
104-
.proxy = {(mp_obj_t)&canio_can_baudrate_get_obj,
105-
(mp_obj_t)mp_const_none,
117+
.proxy = {(mp_obj_t)&canio_can_auto_restart_get_obj,
118+
(mp_obj_t)&canio_can_auto_restart_set_obj,
106119
(mp_obj_t)mp_const_none},
107120
};
108121

109-
//| state: State
110-
//| """The status of the hardware (read-only)"""
122+
123+
//| baudrate: int
124+
//| """The baud rate (read-only)"""
111125
//|
112-
STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) {
126+
STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) {
113127
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
114128
common_hal_canio_can_check_for_deinit(self);
115-
return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_state_get(self));
129+
return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_baudrate_get(self));
116130
}
117-
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get);
131+
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_baudrate_get_obj, canio_can_baudrate_get);
118132

119-
STATIC const mp_obj_property_t canio_can_state_obj = {
133+
STATIC const mp_obj_property_t canio_can_baudrate_obj = {
120134
.base.type = &mp_type_property,
121-
.proxy = {(mp_obj_t)&canio_can_state_get_obj,
135+
.proxy = {(mp_obj_t)&canio_can_baudrate_get_obj,
122136
(mp_obj_t)mp_const_none,
123137
(mp_obj_t)mp_const_none},
124138
};
@@ -208,12 +222,43 @@ STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = {
208222
(mp_obj_t)mp_const_none},
209223
};
210224

225+
//| state: State
226+
//| """The current state of the bus."""
227+
STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) {
228+
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
229+
common_hal_canio_can_check_for_deinit(self);
230+
return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self));
231+
}
232+
233+
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get);
234+
235+
STATIC const mp_obj_property_t canio_can_state_obj = {
236+
.base.type = &mp_type_property,
237+
.proxy = {(mp_obj_t)&canio_can_state_get_obj,
238+
(mp_obj_t)mp_const_none,
239+
(mp_obj_t)mp_const_none},
240+
};
241+
242+
211243
#if 0
212244
//| # pending_tx_count: int
213245
//| # """The number of messages waiting to be transmitted. (read-only)"""
246+
//|
214247
#endif
215248

216-
//| def listen(filters: Optional[Sequence[Filter]]=None, *, timeout: float=10) -> Listener:
249+
//| def restart(self) -> None:
250+
//| """If the device is in the bus off state, restart it."""
251+
//| ...
252+
//|
253+
STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) {
254+
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
255+
common_hal_canio_can_check_for_deinit(self);
256+
common_hal_canio_can_restart(self);
257+
return mp_const_none;
258+
}
259+
STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart);
260+
261+
//| def listen(self, filters: Optional[Sequence[Filter]]=None, *, timeout: float=10) -> Listener:
217262
//| """Start receiving messages that match any one of the filters.
218263
//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners.
219264
//| There is an implementation-defined maximum number of listeners and limit to the complexity of the filters.
@@ -317,15 +362,17 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(canio_can_exit_obj, 4, 4, canio_can_e
317362
STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = {
318363
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) },
319364
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) },
365+
{ MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) },
366+
{ MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) },
320367
{ MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) },
321368
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) },
322369
{ MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) },
323370
{ MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) },
324371
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) },
325372
{ MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) },
373+
{ MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) },
326374
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) },
327375
{ MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) },
328-
{ MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) },
329376
{ MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) },
330377
};
331378
STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table);

0 commit comments

Comments
 (0)