summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2018-03-16 18:28:35 +1100
committerDamien George <damien.p.george@gmail.com>2018-03-16 18:28:35 +1100
commita25e6c6b650acf3af742920c1d3a024054c986cb (patch)
treeefcc17316c7238761b32ed1f907ef29eddcfbe9c
parentd7e67fb1b40c40ba24e3a17e73e5f1b5b96f3914 (diff)
stm32/can: Add CAN.info() method to retrieve error and tx/rx buf info.
-rw-r--r--docs/library/pyb.CAN.rst22
-rw-r--r--ports/stm32/can.c62
-rw-r--r--ports/stm32/can.h1
-rw-r--r--ports/stm32/stm32_it.c12
4 files changed, 97 insertions, 0 deletions
diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst
index 484a00f36..e1ce90d60 100644
--- a/docs/library/pyb.CAN.rst
+++ b/docs/library/pyb.CAN.rst
@@ -113,6 +113,28 @@ Methods
- ``CAN.BUS_OFF`` -- the controller is on but not participating in bus activity
(TEC overflowed beyond 255).
+.. method:: CAN.info([list])
+
+ Get information about the controller's error states and TX and RX buffers.
+ If *list* is provided then it should be a list object with at least 8 entries,
+ which will be filled in with the information. Otherwise a new list will be
+ created and filled in. In both cases the return value of the method is the
+ populated list.
+
+ The values in the list are:
+
+ - TEC value
+ - REC value
+ - number of times the controller enterted the Error Warning state (wrapped
+ around to 0 after 65535)
+ - number of times the controller enterted the Error Passive state (wrapped
+ around to 0 after 65535)
+ - number of times the controller enterted the Bus Off state (wrapped
+ around to 0 after 65535)
+ - number of pending TX messages
+ - number of pending RX messages on fifo 0
+ - number of pending RX messages on fifo 1
+
.. method:: CAN.setfilter(bank, mode, fifo, params, \*, rtr)
Configure a filter bank:
diff --git a/ports/stm32/can.c b/ports/stm32/can.c
index 563d15dab..b1bcd1c3e 100644
--- a/ports/stm32/can.c
+++ b/ports/stm32/can.c
@@ -89,6 +89,9 @@ typedef struct _pyb_can_obj_t {
bool extframe : 1;
byte rx_state0;
byte rx_state1;
+ uint16_t num_error_warning;
+ uint16_t num_error_passive;
+ uint16_t num_bus_off;
CAN_HandleTypeDef can;
} pyb_can_obj_t;
@@ -103,6 +106,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) {
uint32_t GPIO_Pin = 0;
uint8_t GPIO_AF_CANx = 0;
GPIO_TypeDef* GPIO_Port = NULL;
+ uint32_t sce_irq = 0;
switch (can_obj->can_id) {
// CAN1 is on RX,TX = Y3,Y4 = PB9,PB9
@@ -111,6 +115,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) {
GPIO_AF_CANx = GPIO_AF9_CAN1;
GPIO_Port = GPIOB;
GPIO_Pin = GPIO_PIN_8 | GPIO_PIN_9;
+ sce_irq = CAN1_SCE_IRQn;
__CAN1_CLK_ENABLE();
break;
@@ -121,6 +126,7 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) {
GPIO_AF_CANx = GPIO_AF9_CAN2;
GPIO_Port = GPIOB;
GPIO_Pin = GPIO_PIN_12 | GPIO_PIN_13;
+ sce_irq = CAN2_SCE_IRQn;
__CAN1_CLK_ENABLE(); // CAN2 is a "slave" and needs CAN1 enabled as well
__CAN2_CLK_ENABLE();
break;
@@ -144,6 +150,14 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) {
HAL_CAN_Init(&can_obj->can);
can_obj->is_enabled = true;
+ can_obj->num_error_warning = 0;
+ can_obj->num_error_passive = 0;
+ can_obj->num_bus_off = 0;
+
+ __HAL_CAN_ENABLE_IT(&can_obj->can, CAN_IT_ERR | CAN_IT_BOF | CAN_IT_EPV | CAN_IT_EWG);
+
+ HAL_NVIC_SetPriority(sce_irq, IRQ_PRI_CAN, IRQ_SUBPRI_CAN);
+ HAL_NVIC_EnableIRQ(sce_irq);
return true;
}
@@ -459,6 +473,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) {
if (self->can.Instance == CAN1) {
HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
+ HAL_NVIC_DisableIRQ(CAN1_SCE_IRQn);
__CAN1_FORCE_RESET();
__CAN1_RELEASE_RESET();
__CAN1_CLK_DISABLE();
@@ -466,6 +481,7 @@ STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) {
} else if (self->can.Instance == CAN2) {
HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
+ HAL_NVIC_DisableIRQ(CAN2_SCE_IRQn);
__CAN2_FORCE_RESET();
__CAN2_RELEASE_RESET();
__CAN2_CLK_DISABLE();
@@ -512,6 +528,36 @@ STATIC mp_obj_t pyb_can_state(mp_obj_t self_in) {
}
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_state_obj, pyb_can_state);
+// Get info about error states and TX/RX buffers
+STATIC mp_obj_t pyb_can_info(size_t n_args, const mp_obj_t *args) {
+ pyb_can_obj_t *self = MP_OBJ_TO_PTR(args[0]);
+ mp_obj_list_t *list;
+ if (n_args == 1) {
+ list = MP_OBJ_TO_PTR(mp_obj_new_list(8, NULL));
+ } else {
+ if (!MP_OBJ_IS_TYPE(args[1], &mp_type_list)) {
+ mp_raise_TypeError(NULL);
+ }
+ list = MP_OBJ_TO_PTR(args[1]);
+ if (list->len < 8) {
+ mp_raise_ValueError(NULL);
+ }
+ }
+ CAN_TypeDef *can = self->can.Instance;
+ uint32_t esr = can->ESR;
+ list->items[0] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_TEC_Pos & 0xff);
+ list->items[1] = MP_OBJ_NEW_SMALL_INT(esr >> CAN_ESR_REC_Pos & 0xff);
+ list->items[2] = MP_OBJ_NEW_SMALL_INT(self->num_error_warning);
+ list->items[3] = MP_OBJ_NEW_SMALL_INT(self->num_error_passive);
+ list->items[4] = MP_OBJ_NEW_SMALL_INT(self->num_bus_off);
+ int n_tx_pending = 0x01121223 >> ((can->TSR >> CAN_TSR_TME_Pos & 7) << 2) & 0xf;
+ list->items[5] = MP_OBJ_NEW_SMALL_INT(n_tx_pending);
+ list->items[6] = MP_OBJ_NEW_SMALL_INT(can->RF0R >> CAN_RF0R_FMP0_Pos & 3);
+ list->items[7] = MP_OBJ_NEW_SMALL_INT(can->RF1R >> CAN_RF1R_FMP1_Pos & 3);
+ return MP_OBJ_FROM_PTR(list);
+}
+STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(pyb_can_info_obj, 1, 2, pyb_can_info);
+
/// \method any(fifo)
/// Return `True` if any message waiting on the FIFO, else `False`.
STATIC mp_obj_t pyb_can_any(mp_obj_t self_in, mp_obj_t fifo_in) {
@@ -871,6 +917,7 @@ STATIC const mp_rom_map_elem_t pyb_can_locals_dict_table[] = {
{ MP_ROM_QSTR(MP_QSTR_deinit), MP_ROM_PTR(&pyb_can_deinit_obj) },
{ MP_ROM_QSTR(MP_QSTR_restart), MP_ROM_PTR(&pyb_can_restart_obj) },
{ MP_ROM_QSTR(MP_QSTR_state), MP_ROM_PTR(&pyb_can_state_obj) },
+ { MP_ROM_QSTR(MP_QSTR_info), MP_ROM_PTR(&pyb_can_info_obj) },
{ MP_ROM_QSTR(MP_QSTR_any), MP_ROM_PTR(&pyb_can_any_obj) },
{ MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&pyb_can_send_obj) },
{ MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&pyb_can_recv_obj) },
@@ -979,6 +1026,21 @@ void can_rx_irq_handler(uint can_id, uint fifo_id) {
}
}
+void can_sce_irq_handler(uint can_id) {
+ pyb_can_obj_t *self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1];
+ if (self) {
+ self->can.Instance->MSR = CAN_MSR_ERRI;
+ uint32_t esr = self->can.Instance->ESR;
+ if (esr & CAN_ESR_BOFF) {
+ ++self->num_bus_off;
+ } else if (esr & CAN_ESR_EPVF) {
+ ++self->num_error_passive;
+ } else if (esr & CAN_ESR_EWGF) {
+ ++self->num_error_warning;
+ }
+ }
+}
+
STATIC const mp_stream_p_t can_stream_p = {
//.read = can_read, // is read sensible for CAN?
//.write = can_write, // is write sensible for CAN?
diff --git a/ports/stm32/can.h b/ports/stm32/can.h
index b725b5924..54e7deaa5 100644
--- a/ports/stm32/can.h
+++ b/ports/stm32/can.h
@@ -34,5 +34,6 @@ extern const mp_obj_type_t pyb_can_type;
void can_init0(void);
void can_deinit(void);
void can_rx_irq_handler(uint can_id, uint fifo_id);
+void can_sce_irq_handler(uint can_id);
#endif // MICROPY_INCLUDED_STM32_CAN_H
diff --git a/ports/stm32/stm32_it.c b/ports/stm32/stm32_it.c
index 0ad71771c..77cfcc580 100644
--- a/ports/stm32/stm32_it.c
+++ b/ports/stm32/stm32_it.c
@@ -749,6 +749,12 @@ void CAN1_RX1_IRQHandler(void) {
IRQ_EXIT(CAN1_RX1_IRQn);
}
+void CAN1_SCE_IRQHandler(void) {
+ IRQ_ENTER(CAN1_SCE_IRQn);
+ can_sce_irq_handler(PYB_CAN_1);
+ IRQ_EXIT(CAN1_SCE_IRQn);
+}
+
void CAN2_RX0_IRQHandler(void) {
IRQ_ENTER(CAN2_RX0_IRQn);
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
@@ -760,6 +766,12 @@ void CAN2_RX1_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
IRQ_EXIT(CAN2_RX1_IRQn);
}
+
+void CAN2_SCE_IRQHandler(void) {
+ IRQ_ENTER(CAN2_SCE_IRQn);
+ can_sce_irq_handler(PYB_CAN_2);
+ IRQ_EXIT(CAN2_SCE_IRQn);
+}
#endif // MICROPY_HW_ENABLE_CAN
#if defined(MICROPY_HW_I2C1_SCL)