_canio.CAN: add error handling & bus state
This commit is contained in:
parent
f8dcf2118e
commit
635fcadb59
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user