_canio.CAN: add error handling & bus state

This commit is contained in:
Jeff Epler 2020-09-16 11:59:01 -05:00
parent f8dcf2118e
commit 635fcadb59
3 changed files with 156 additions and 45 deletions

View File

@ -218,6 +218,15 @@ void common_hal_canio_can_construct(canio_can_obj_t *self, mcu_pin_obj_t *rx, mc
hri_can_write_XIDFC_reg(self->hw, dfc.reg);
}
{
CAN_IE_Type ie = {
.bit.EWE = 1,
.bit.EPE = 1,
.bit.BOE = 1,
};
hri_can_write_IE_reg(self->hw, ie.reg);
}
hri_can_write_XIDAM_reg(self->hw, CAN_XIDAM_RESETVALUE);
// 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)
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self)
{
return -1;
return self->hw->ECR.bit.TEC;
}
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self)
{
return -1;
return self->hw->ECR.bit.REC;
}
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self)
{
return -1;
return self->error_warning_state_count;
}
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self)
{
return -1;
return self->error_passive_state_count;
}
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self)
{
return -1;
return self->bus_off_state_count;
}
int common_hal_canio_can_state_get(canio_can_obj_t *self) {
return -1;
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self) {
CAN_PSR_Type psr = self->hw->PSR;
if(psr.bit.BO) {
return BUS_STATE_OFF;
}
if(psr.bit.EP) {
return BUS_STATE_ERROR_PASSIVE;
}
if(psr.bit.EW) {
return BUS_STATE_ERROR_WARNING;
}
return BUS_STATE_ERROR_ACTIVE;
}
void common_hal_canio_can_restart(canio_can_obj_t *self) {
if (!self->hw->PSR.bit.BO) {
return;
}
hri_can_clear_CCCR_INIT_bit(self->hw);
while (hri_can_get_CCCR_INIT_bit(self->hw)) {
}
}
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self) {
return self->auto_restart;
}
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool value) {
self->auto_restart = value;
}
static void maybe_auto_restart(canio_can_obj_t *self) {
if(self->auto_restart) {
common_hal_canio_can_restart(self);
}
}
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message)
{
maybe_auto_restart(self);
// We have just one dedicated TX buffer, use it!
canio_can_fifo_t *ent = &self->state->tx_fifo[0];
ent->txb0.bit.ESI = false;
@ -365,7 +410,17 @@ STATIC void can_handler(int i) {
Can *hw = can_insts[i];
uint32_t ir = hri_can_read_IR_reg(hw);
/* Handle various interrupts */
/* Count up errors*/
if (ir & CAN_IE_EWE) {
self->error_warning_state_count += 1;
}
if (ir & CAN_IE_EPE) {
self->error_passive_state_count += 1;
}
if (ir & CAN_IE_BOE) {
self->bus_off_state_count += 1;
}
/* Acknowledge interrupt */
hri_can_write_IR_reg(hw, ir);

View File

@ -27,6 +27,7 @@
#pragma once
#include "py/obj.h"
#include "shared-bindings/_canio/__init__.h"
#include "component/can.h"
#include "common-hal/microcontroller/Pin.h"
#include "common-hal/_canio/__init__.h"
@ -38,25 +39,33 @@
typedef struct {
mp_obj_base_t base;
Can *hw;
int baudrate;
uint8_t rx_pin_number, tx_pin_number;
bool loopback;
bool silent;
canio_can_state_t *state;
volatile uint32_t error_warning_state_count;
volatile uint32_t error_passive_state_count;
volatile uint32_t bus_off_state_count;
int baudrate;
uint8_t rx_pin_number:8;
uint8_t tx_pin_number:8;
bool loopback:1;
bool silent:1;
bool auto_restart:1;
bool fifo0_in_use:1;
bool fifo1_in_use:1;
} canio_can_obj_t;
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);
int common_hal_canio_can_state_get(canio_can_obj_t *self);
int common_hal_canio_can_baudrate_get(canio_can_obj_t *self);
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self);
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self);
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self);
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self);
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self);
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message);
void common_hal_canio_can_deinit(canio_can_obj_t *self);
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self);
bool common_hal_canio_can_auto_restart_get(canio_can_obj_t *self);
bool common_hal_canio_can_deinited(canio_can_obj_t *self);
int common_hal_canio_can_baudrate_get(canio_can_obj_t *self);
int common_hal_canio_can_bus_off_state_count_get(canio_can_obj_t *self);
int common_hal_canio_can_error_passive_state_count_get(canio_can_obj_t *self);
int common_hal_canio_can_error_warning_state_count_get(canio_can_obj_t *self);
int common_hal_canio_can_receive_error_count_get(canio_can_obj_t *self);
canio_bus_state_t common_hal_canio_can_state_get(canio_can_obj_t *self);
int common_hal_canio_can_transmit_error_count_get(canio_can_obj_t *self);
void common_hal_canio_can_auto_restart_set(canio_can_obj_t *self, bool auto_restart);
void common_hal_canio_can_check_for_deinit(canio_can_obj_t *self);
void common_hal_canio_can_deinit(canio_can_obj_t *self);
void common_hal_canio_can_restart(canio_can_obj_t *self);
void common_hal_canio_can_send(canio_can_obj_t *self, canio_message_obj_t *message);
void common_hal_canio_reset(void);

View File

@ -24,8 +24,10 @@
* THE SOFTWARE.
*/
#include "py/enum.h"
#include "common-hal/_canio/CAN.h"
#include "common-hal/_canio/Listener.h"
#include "shared-bindings/_canio/__init__.h"
#include "shared-bindings/_canio/CAN.h"
#include "shared-bindings/_canio/Listener.h"
#include "shared-bindings/_canio/Match.h"
@ -45,6 +47,7 @@
//| *,
//| baudrate: int = 250000,
//| loopback: bool = False,
//| auto_restart: bool = False,
//| ):
//| """A common shared-bus protocol. The rx and tx pins are generally
//| connected to a transceiver which controls the H and L pins on a shared
@ -54,19 +57,19 @@
//| :param ~microcontrller.Pin tx: the pin to transmit with, or None if the peripheral should operate in "silent" mode.
//| :param int baudrate: The bit rate of the bus in Hz. All devices on the bus must agree on this value.
//| :param bool loopback: True if the peripheral will be operated in loopback mode.
//| :param bool auto_restart: If True, will restart communications after entering bus-off state
//| """
//| ...
//|
//## auto_restart: bool = False, # Whether to restart communications after entering bus-off state
//## sample_point: float = .875, # When to sample within bit time (0.0-1.0)
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) {
enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, NUM_ARGS };
enum { ARG_rx, ARG_tx, ARG_baudrate, ARG_loopback, ARG_silent, ARG_auto_restart, NUM_ARGS };
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_rx, MP_ARG_OBJ | MP_ARG_REQUIRED, {.u_obj = 0} },
{ MP_QSTR_tx, MP_ARG_OBJ, {.u_obj = 0} },
{ MP_QSTR_baudrate, MP_ARG_INT, {.u_int = 250000} },
{ MP_QSTR_loopback, MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_silent, MP_ARG_BOOL, {.u_bool = false} },
{ MP_QSTR_auto_restart, MP_ARG_BOOL, {.u_bool = false} },
};
mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
MP_STATIC_ASSERT( MP_ARRAY_SIZE(allowed_args) == NUM_ARGS );
@ -85,12 +88,40 @@ mp_printf(&mp_plat_print, "tx_pin=%p\n", tx_pin);
self->base.type = &canio_can_type;
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);
common_hal_canio_can_auto_restart_set(self, args[ARG_auto_restart].u_bool);
return MP_OBJ_FROM_PTR(self);
}
//| auto_restart: int
//| """If True, will restart communications after entering bus-off state"""
//|
STATIC mp_obj_t canio_can_auto_restart_get(mp_obj_t self_in) {
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_canio_can_check_for_deinit(self);
return mp_obj_new_bool(common_hal_canio_can_auto_restart_get(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_auto_restart_get_obj, canio_can_auto_restart_get);
STATIC mp_obj_t canio_can_auto_restart_set(mp_obj_t self_in, mp_obj_t flag_in) {
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_canio_can_check_for_deinit(self);
common_hal_canio_can_auto_restart_set(self, mp_obj_is_true(flag_in));
return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(canio_can_auto_restart_set_obj, canio_can_auto_restart_set);
STATIC const mp_obj_property_t canio_can_auto_restart_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&canio_can_auto_restart_get_obj,
(mp_obj_t)&canio_can_auto_restart_set_obj,
(mp_obj_t)mp_const_none},
};
//| baudrate: int
//| """The baud rate(read-only)"""
//| """The baud rate (read-only)"""
//|
STATIC mp_obj_t canio_can_baudrate_get(mp_obj_t self_in) {
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
@ -106,23 +137,6 @@ STATIC const mp_obj_property_t canio_can_baudrate_obj = {
(mp_obj_t)mp_const_none},
};
//| state: State
//| """The status of the hardware (read-only)"""
//|
STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) {
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_canio_can_check_for_deinit(self);
return MP_OBJ_NEW_SMALL_INT(common_hal_canio_can_state_get(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get);
STATIC const mp_obj_property_t canio_can_state_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&canio_can_state_get_obj,
(mp_obj_t)mp_const_none,
(mp_obj_t)mp_const_none},
};
//| transmit_error_count: int
//| """The number of transmit errors (read-only). Increased for a detected transmission error, decreased for successful transmission. Limited to the range from 0 to 255 inclusive. Also called TEC."""
//|
@ -208,12 +222,43 @@ STATIC const mp_obj_property_t canio_can_bus_off_state_count_obj = {
(mp_obj_t)mp_const_none},
};
//| state: State
//| """The current state of the bus."""
STATIC mp_obj_t canio_can_state_get(mp_obj_t self_in) {
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_canio_can_check_for_deinit(self);
return cp_enum_find(&canio_bus_state_type, common_hal_canio_can_state_get(self));
}
MP_DEFINE_CONST_FUN_OBJ_1(canio_can_state_get_obj, canio_can_state_get);
STATIC const mp_obj_property_t canio_can_state_obj = {
.base.type = &mp_type_property,
.proxy = {(mp_obj_t)&canio_can_state_get_obj,
(mp_obj_t)mp_const_none,
(mp_obj_t)mp_const_none},
};
#if 0
//| # pending_tx_count: int
//| # """The number of messages waiting to be transmitted. (read-only)"""
//|
#endif
//| def listen(filters: Optional[Sequence[Filter]]=None, *, timeout: float=10) -> Listener:
//| def restart(self) -> None:
//| """If the device is in the bus off state, restart it."""
//| ...
//|
STATIC mp_obj_t canio_can_restart(mp_obj_t self_in) {
canio_can_obj_t *self = MP_OBJ_TO_PTR(self_in);
common_hal_canio_can_check_for_deinit(self);
common_hal_canio_can_restart(self);
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(canio_can_restart_obj, canio_can_restart);
//| def listen(self, filters: Optional[Sequence[Filter]]=None, *, timeout: float=10) -> Listener:
//| """Start receiving messages that match any one of the filters.
//| Creating a listener is an expensive operation and can interfere with reception of messages by other listeners.
//| 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
STATIC const mp_rom_map_elem_t canio_can_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR___enter__), MP_ROM_PTR(&canio_can_enter_obj) },
{ MP_ROM_QSTR(MP_QSTR___exit__), MP_ROM_PTR(&canio_can_exit_obj) },
{ MP_ROM_QSTR(MP_QSTR_auto_restart), MP_ROM_PTR(&canio_can_auto_restart_obj) },
{ MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) },
{ MP_ROM_QSTR(MP_QSTR_bus_off_state_count), MP_ROM_PTR(&canio_can_bus_off_state_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&canio_can_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_error_passive_state_count), MP_ROM_PTR(&canio_can_error_passive_state_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_error_warning_state_count), MP_ROM_PTR(&canio_can_error_warning_state_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&canio_can_listen_obj) },
{ MP_ROM_QSTR(MP_QSTR_receive_error_count), MP_ROM_PTR(&canio_can_receive_error_count_obj) },
{ MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&canio_can_restart_obj) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&canio_can_send_obj) },
{ MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&canio_can_state_obj) },
{ MP_ROM_QSTR(MP_QSTR_baudrate), MP_ROM_PTR(&canio_can_baudrate_obj) },
{ MP_ROM_QSTR(MP_QSTR_transmit_error_count), MP_ROM_PTR(&canio_can_transmit_error_count_obj) },
};
STATIC MP_DEFINE_CONST_DICT(canio_can_locals_dict, canio_can_locals_dict_table);