stmhal: Add support for CAN rx callbacks.

This commit is contained in:
Henrik Sölver 2015-01-15 23:16:57 +01:00 committed by Damien George
parent ed8b4da0db
commit f80f1a7077
9 changed files with 345 additions and 34 deletions

View File

@ -26,30 +26,30 @@ Constructors
initialised (it has the settings from the last initialisation of initialised (it has the settings from the last initialisation of
the bus, if any). If extra arguments are given, the bus is initialised. the bus, if any). If extra arguments are given, the bus is initialised.
See ``init`` for parameters of initialisation. See ``init`` for parameters of initialisation.
The physical pins of the CAN busses are: The physical pins of the CAN busses are:
- ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)`` - ``CAN(1)`` is on ``YA``: ``(RX, TX) = (Y3, Y4) = (PB8, PB9)``
- ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)`` - ``CAN(2)`` is on ``YB``: ``(RX, TX) = (Y5, Y6) = (PB12, PB13)``
Class Methods Class Methods
------------- -------------
.. method:: CAN.initfilterbanks(nr) .. method:: CAN.initfilterbanks(nr)
Reset and disable all filter banks and assign how many banks should be available for CAN(1). Reset and disable all filter banks and assign how many banks should be available for CAN(1).
STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers. STM32F405 has 28 filter banks that are shared between the two available CAN bus controllers.
This function configures how many filter banks should be assigned to each. ``nr`` is the number of banks This function configures how many filter banks should be assigned to each. ``nr`` is the number of banks
that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2). that will be assigned to CAN(1), the rest of the 28 are assigned to CAN(2).
At boot, 14 banks are assigned to each controller. At boot, 14 banks are assigned to each controller.
Methods Methods
------- -------
.. method:: can.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8) .. method:: can.init(mode, extframe=False, prescaler=100, \*, sjw=1, bs1=6, bs2=8)
Initialise the CAN bus with the given parameters: Initialise the CAN bus with the given parameters:
- ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK - ``mode`` is one of: NORMAL, LOOPBACK, SILENT, SILENT_LOOPBACK
- if ``extframe`` is True then the bus uses extended identifiers in the frames - if ``extframe`` is True then the bus uses extended identifiers in the frames
(29 bits); otherwise it uses standard 11 bit identifiers (29 bits); otherwise it uses standard 11 bit identifiers
@ -83,14 +83,14 @@ Methods
Turn off the CAN bus. Turn off the CAN bus.
.. method:: can.setfilter(bank, mode, fifo, params) .. method:: can.setfilter(bank, mode, fifo, params)
Configure a filter bank: Configure a filter bank:
- ``bank`` is the filter bank that is to be configured. - ``bank`` is the filter bank that is to be configured.
- ``mode`` is the mode the filter should operate in. - ``mode`` is the mode the filter should operate in.
- ``fifo`` is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter. - ``fifo`` is which fifo (0 or 1) a message should be stored in, if it is accepted by this filter.
- ``params`` is an array of values the defines the filter. The contents of the array depends on the ``mode`` argument. - ``params`` is an array of values the defines the filter. The contents of the array depends on the ``mode`` argument.
+-----------+---------------------------------------------------------+ +-----------+---------------------------------------------------------+
|``mode`` |contents of parameter array | |``mode`` |contents of parameter array |
+===========+=========================================================+ +===========+=========================================================+
@ -106,11 +106,11 @@ Methods
+-----------+---------------------------------------------------------+ +-----------+---------------------------------------------------------+
|CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.| |CAN.MASK32 |As with CAN.MASK16 but with only one 32 bit id/mask pair.|
+-----------+---------------------------------------------------------+ +-----------+---------------------------------------------------------+
.. method:: can.clearfilter(bank) .. method:: can.clearfilter(bank)
Clear and disables a filter bank: Clear and disables a filter bank:
- ``bank`` is the filter bank that is to be cleared. - ``bank`` is the filter bank that is to be cleared.
.. method:: can.any(fifo) .. method:: can.any(fifo)
@ -120,22 +120,56 @@ Methods
.. method:: can.recv(fifo, \*, timeout=5000) .. method:: can.recv(fifo, \*, timeout=5000)
Receive data on the bus: Receive data on the bus:
- ``fifo`` is an integer, which is the FIFO to receive on - ``fifo`` is an integer, which is the FIFO to receive on
- ``timeout`` is the timeout in milliseconds to wait for the receive. - ``timeout`` is the timeout in milliseconds to wait for the receive.
Return value: buffer of data bytes. Return value: buffer of data bytes.
.. method:: can.send(send, addr, \*, timeout=5000) .. method:: can.send(send, addr, \*, timeout=5000)
Send a message on the bus: Send a message on the bus:
- ``send`` is the data to send (an integer to send, or a buffer object). - ``send`` is the data to send (an integer to send, or a buffer object).
- ``addr`` is the address to send to - ``addr`` is the address to send to
- ``timeout`` is the timeout in milliseconds to wait for the send. - ``timeout`` is the timeout in milliseconds to wait for the send.
Return value: ``None``. Return value: ``None``.
.. method:: can.rxcallback(fifo, fun)
Register a function to be called when a message is accepted into a empty fifo:
- ``fifo`` is the receiving fifo.
- ``fun`` is the function to be called when the fifo becomes non empty.
The callback function takes two arguments the first is the can object it self the second is
a integer that indicates the reason for the callback.
+--------+------------------------------------------------+
| Reason | |
+========+================================================+
| 0 | A message has been accepted into a empty FIFO. |
+--------+------------------------------------------------+
| 1 | The FIFO is full |
+--------+------------------------------------------------+
| 2 | A message has been lost due to a full FIFO |
+--------+------------------------------------------------+
Example use of rxcallback::
def cb0(bus, reason):
print('cb0')
if reason == 0:
print('pending')
if reason == 1:
print('full')
if reason == 2:
print('overflow')
can = CAN(1, CAN.LOOPBACK)
can.rxcallback(0, cb0)
Constants Constants
--------- ---------
@ -151,4 +185,4 @@ Constants
.. data:: CAN.LIST32 .. data:: CAN.LIST32
.. data:: CAN.MASK32 .. data:: CAN.MASK32
the operation mode of a filter the operation mode of a filter

View File

@ -32,6 +32,8 @@
#include "py/nlr.h" #include "py/nlr.h"
#include "py/objtuple.h" #include "py/objtuple.h"
#include "py/runtime.h" #include "py/runtime.h"
#include "py/gc.h"
#include "py/pfenv.h"
#include "bufhelper.h" #include "bufhelper.h"
#include "can.h" #include "can.h"
#include "pybioctl.h" #include "pybioctl.h"
@ -64,14 +66,27 @@
/// can.send('message!', 123) # send message with id 123 /// can.send('message!', 123) # send message with id 123
/// can.recv(0) # receive message on FIFO 0 /// can.recv(0) # receive message on FIFO 0
typedef enum _rx_state_t {
RX_STATE_FIFO_EMPTY = 0,
RX_STATE_MESSAGE_PENDING,
RX_STATE_FIFO_FULL,
RX_STATE_FIFO_OVERFLOW,
} rx_state_t;
typedef struct _pyb_can_obj_t { typedef struct _pyb_can_obj_t {
mp_obj_base_t base; mp_obj_base_t base;
mp_obj_t rxcallback0;
mp_obj_t rxcallback1;
mp_uint_t can_id : 8; mp_uint_t can_id : 8;
bool is_enabled : 1; bool is_enabled : 1;
bool extframe : 1; bool extframe : 1;
byte rx_state0;
byte rx_state1;
CAN_HandleTypeDef can; CAN_HandleTypeDef can;
} pyb_can_obj_t; } pyb_can_obj_t;
STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in);
STATIC uint8_t can2_start_bank = 14; STATIC uint8_t can2_start_bank = 14;
// assumes Init parameters have been set up correctly // assumes Init parameters have been set up correctly
@ -124,18 +139,18 @@ STATIC bool can_init(pyb_can_obj_t *can_obj) {
return true; return true;
} }
STATIC void can_deinit(pyb_can_obj_t *can_obj) { void can_init0(void) {
can_obj->is_enabled = false; for (uint i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) {
CAN_HandleTypeDef *can = &can_obj->can; MP_STATE_PORT(pyb_can_obj_all)[i] = NULL;
HAL_CAN_DeInit(can); }
if (can->Instance == CAN1) { }
__CAN1_FORCE_RESET();
__CAN1_RELEASE_RESET(); void can_deinit(void) {
__CAN1_CLK_DISABLE(); for (int i = 0; i < MP_ARRAY_SIZE(MP_STATE_PORT(pyb_can_obj_all)); i++) {
} else if (can->Instance == CAN2) { pyb_can_obj_t *can_obj = MP_STATE_PORT(pyb_can_obj_all)[i];
__CAN2_FORCE_RESET(); if (can_obj != NULL) {
__CAN2_RELEASE_RESET(); pyb_can_deinit(can_obj);
__CAN2_CLK_DISABLE(); }
} }
} }
@ -260,6 +275,11 @@ STATIC mp_obj_t pyb_can_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n
} else { } else {
o->can_id = mp_obj_get_int(args[0]); o->can_id = mp_obj_get_int(args[0]);
} }
o->rxcallback0 = mp_const_none;
o->rxcallback1 = mp_const_none;
MP_STATE_PORT(pyb_can_obj_all)[o->can_id - 1] = o;
o->rx_state0 = RX_STATE_FIFO_EMPTY;
o->rx_state1 = RX_STATE_FIFO_EMPTY;
if (n_args > 1 || n_kw > 0) { if (n_args > 1 || n_kw > 0) {
// start the peripheral // start the peripheral
@ -280,7 +300,21 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_init_obj, 1, pyb_can_init);
/// Turn off the CAN bus. /// Turn off the CAN bus.
STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) { STATIC mp_obj_t pyb_can_deinit(mp_obj_t self_in) {
pyb_can_obj_t *self = self_in; pyb_can_obj_t *self = self_in;
can_deinit(self); self->is_enabled = false;
HAL_CAN_DeInit(&self->can);
if (self->can.Instance == CAN1) {
HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
__CAN1_FORCE_RESET();
__CAN1_RELEASE_RESET();
__CAN1_CLK_DISABLE();
} else if (self->can.Instance == CAN2) {
HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
__CAN2_FORCE_RESET();
__CAN2_RELEASE_RESET();
__CAN2_CLK_DISABLE();
}
return mp_const_none; return mp_const_none;
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit); STATIC MP_DEFINE_CONST_FUN_OBJ_1(pyb_can_deinit_obj, pyb_can_deinit);
@ -334,7 +368,7 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
// send the data // send the data
CanTxMsgTypeDef tx_msg; CanTxMsgTypeDef tx_msg;
if (self->extframe){ if (self->extframe) {
tx_msg.ExtId = args[1].u_int & 0x1FFFFFFF; tx_msg.ExtId = args[1].u_int & 0x1FFFFFFF;
tx_msg.IDE = CAN_ID_EXT; tx_msg.IDE = CAN_ID_EXT;
} else { } else {
@ -385,6 +419,33 @@ STATIC mp_obj_t pyb_can_recv(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
mp_hal_raise(status); mp_hal_raise(status);
} }
// Manage the rx state machine
if ((args[0].u_int == CAN_FIFO0 && self->rxcallback0 != mp_const_none) ||
(args[0].u_int == CAN_FIFO1 && self->rxcallback1 != mp_const_none)) {
byte *state = (args[0].u_int == CAN_FIFO0) ? &self->rx_state0 : &self->rx_state1;
switch (*state) {
case RX_STATE_FIFO_EMPTY:
break;
case RX_STATE_MESSAGE_PENDING:
if (__HAL_CAN_MSG_PENDING(&self->can, args[0].u_int) == 0) {
// Fifo is empty
__HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
*state = RX_STATE_FIFO_EMPTY;
}
break;
case RX_STATE_FIFO_FULL:
__HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
*state = RX_STATE_MESSAGE_PENDING;
break;
case RX_STATE_FIFO_OVERFLOW:
__HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
__HAL_CAN_ENABLE_IT(&self->can, (args[0].u_int == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
*state = RX_STATE_MESSAGE_PENDING;
break;
}
}
// return the received data // return the received data
// TODO use a namedtuple (when namedtuple types can be stored in ROM) // TODO use a namedtuple (when namedtuple types can be stored in ROM)
mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL); mp_obj_tuple_t *tuple = mp_obj_new_tuple(4, NULL);
@ -525,6 +586,39 @@ error:
} }
STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_setfilter_obj, 1, pyb_can_setfilter); STATIC MP_DEFINE_CONST_FUN_OBJ_KW(pyb_can_setfilter_obj, 1, pyb_can_setfilter);
STATIC mp_obj_t pyb_can_rxcallback(mp_obj_t self_in, mp_obj_t fifo_in, mp_obj_t callback_in) {
pyb_can_obj_t *self = self_in;
mp_int_t fifo = mp_obj_get_int(fifo_in);
mp_obj_t *callback;
callback = (fifo == 0) ? &self->rxcallback0 : &self->rxcallback1;
if (callback_in == mp_const_none) {
__HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
__HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1);
__HAL_CAN_DISABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
*callback = mp_const_none;
} else if (*callback != mp_const_none) {
// Rx call backs has already been initialized
// only the callback function should be changed
*callback = callback_in;
} else if (mp_obj_is_callable(callback_in)) {
*callback = callback_in;
uint32_t irq;
if (self->can_id == PYB_CAN_1) {
irq = (fifo == 0) ? CAN1_RX0_IRQn : CAN1_RX1_IRQn;
} else {
irq = (fifo == 0) ? CAN2_RX0_IRQn : CAN2_RX1_IRQn;
}
HAL_NVIC_SetPriority(irq, 7, 0);
HAL_NVIC_EnableIRQ(irq);
__HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
__HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FF0 : CAN_IT_FF1);
__HAL_CAN_ENABLE_IT(&self->can, (fifo == 0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
}
return mp_const_none;
}
STATIC MP_DEFINE_CONST_FUN_OBJ_3(pyb_can_rxcallback_obj, pyb_can_rxcallback);
STATIC const mp_map_elem_t pyb_can_locals_dict_table[] = { STATIC const mp_map_elem_t pyb_can_locals_dict_table[] = {
// instance methods // instance methods
{ MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_can_init_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_init), (mp_obj_t)&pyb_can_init_obj },
@ -535,6 +629,7 @@ STATIC const mp_map_elem_t pyb_can_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_initfilterbanks), (mp_obj_t)&pyb_can_initfilterbanks_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_initfilterbanks), (mp_obj_t)&pyb_can_initfilterbanks_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_setfilter), (mp_obj_t)&pyb_can_setfilter_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_setfilter), (mp_obj_t)&pyb_can_setfilter_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_clearfilter), (mp_obj_t)&pyb_can_clearfilter_obj }, { MP_OBJ_NEW_QSTR(MP_QSTR_clearfilter), (mp_obj_t)&pyb_can_clearfilter_obj },
{ MP_OBJ_NEW_QSTR(MP_QSTR_rxcallback), (mp_obj_t)&pyb_can_rxcallback_obj },
// class constants // class constants
// Note: we use the ST constants >> 4 so they fit in a small-int. The // Note: we use the ST constants >> 4 so they fit in a small-int. The
@ -543,7 +638,6 @@ STATIC const mp_map_elem_t pyb_can_locals_dict_table[] = {
{ MP_OBJ_NEW_QSTR(MP_QSTR_LOOPBACK), MP_OBJ_NEW_SMALL_INT(CAN_MODE_LOOPBACK >> 4) }, { MP_OBJ_NEW_QSTR(MP_QSTR_LOOPBACK), MP_OBJ_NEW_SMALL_INT(CAN_MODE_LOOPBACK >> 4) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SILENT), MP_OBJ_NEW_SMALL_INT(CAN_MODE_SILENT >> 4) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SILENT), MP_OBJ_NEW_SMALL_INT(CAN_MODE_SILENT >> 4) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_SILENT_LOOPBACK), MP_OBJ_NEW_SMALL_INT(CAN_MODE_SILENT_LOOPBACK >> 4) }, { MP_OBJ_NEW_QSTR(MP_QSTR_SILENT_LOOPBACK), MP_OBJ_NEW_SMALL_INT(CAN_MODE_SILENT_LOOPBACK >> 4) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASK16), MP_OBJ_NEW_SMALL_INT(MASK16) }, { MP_OBJ_NEW_QSTR(MP_QSTR_MASK16), MP_OBJ_NEW_SMALL_INT(MASK16) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_LIST16), MP_OBJ_NEW_SMALL_INT(LIST16) }, { MP_OBJ_NEW_QSTR(MP_QSTR_LIST16), MP_OBJ_NEW_SMALL_INT(LIST16) },
{ MP_OBJ_NEW_QSTR(MP_QSTR_MASK32), MP_OBJ_NEW_SMALL_INT(MASK32) }, { MP_OBJ_NEW_QSTR(MP_QSTR_MASK32), MP_OBJ_NEW_SMALL_INT(MASK32) },
@ -573,6 +667,59 @@ mp_uint_t can_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *err
return ret; return ret;
} }
void can_rx_irq_handler(uint can_id, uint fifo_id) {
mp_obj_t callback;
pyb_can_obj_t *self;
mp_obj_t irq_reason = MP_OBJ_NEW_SMALL_INT(0);
byte *state;
self = MP_STATE_PORT(pyb_can_obj_all)[can_id - 1];
if (fifo_id == CAN_FIFO0) {
callback = self->rxcallback0;
state = &self->rx_state0;
} else {
callback = self->rxcallback1;
state = &self->rx_state1;
}
switch (*state) {
case RX_STATE_FIFO_EMPTY:
__HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FMP0 : CAN_IT_FMP1);
irq_reason = MP_OBJ_NEW_SMALL_INT(0);
*state = RX_STATE_MESSAGE_PENDING;
break;
case RX_STATE_MESSAGE_PENDING:
__HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FF0 : CAN_IT_FF1);
irq_reason = MP_OBJ_NEW_SMALL_INT(1);
*state = RX_STATE_FIFO_FULL;
break;
case RX_STATE_FIFO_FULL:
__HAL_CAN_DISABLE_IT(&self->can, (fifo_id == CAN_FIFO0) ? CAN_IT_FOV0 : CAN_IT_FOV1);
irq_reason = MP_OBJ_NEW_SMALL_INT(2);
*state = RX_STATE_FIFO_OVERFLOW;
break;
case RX_STATE_FIFO_OVERFLOW:
// This should never happen
break;
}
if (callback != mp_const_none) {
gc_lock();
nlr_buf_t nlr;
if (nlr_push(&nlr) == 0) {
mp_call_function_2(callback, self, irq_reason);
nlr_pop();
} else {
// Uncaught exception; disable the callback so it doesn't run again.
pyb_can_rxcallback(self, MP_OBJ_NEW_SMALL_INT(fifo_id), mp_const_none);
printf("uncaught exception in CAN(%u) rx interrupt handler\n", self->can_id);
mp_obj_print_exception(printf_wrapper, NULL, (mp_obj_t)nlr.ret_val);
}
gc_unlock();
}
}
STATIC const mp_stream_p_t can_stream_p = { STATIC const mp_stream_p_t can_stream_p = {
//.read = can_read, // is read sensible for CAN? //.read = can_read, // is read sensible for CAN?
//.write = can_write, // is write sensible for CAN? //.write = can_write, // is write sensible for CAN?

View File

@ -34,3 +34,7 @@
#endif #endif
extern const mp_obj_type_t pyb_can_type; 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);

View File

@ -57,6 +57,7 @@
#include "accel.h" #include "accel.h"
#include "servo.h" #include "servo.h"
#include "dac.h" #include "dac.h"
#include "can.h"
#include "modnetwork.h" #include "modnetwork.h"
#include MICROPY_HAL_H #include MICROPY_HAL_H
@ -399,6 +400,9 @@ soft_reset:
extint_init0(); extint_init0();
timer_init0(); timer_init0();
uart_init0(); uart_init0();
#if MICROPY_HW_ENABLE_CAN
can_init0();
#endif
#if MICROPY_HW_ENABLE_RNG #if MICROPY_HW_ENABLE_RNG
rng_init0(); rng_init0();
@ -540,6 +544,9 @@ soft_reset_exit:
printf("PYB: soft reboot\n"); printf("PYB: soft reboot\n");
timer_deinit(); timer_deinit();
uart_deinit(); uart_deinit();
#if MICROPY_HW_ENABLE_CAN
can_deinit();
#endif
first_soft_reset = false; first_soft_reset = false;
goto soft_reset; goto soft_reset;

View File

@ -153,6 +153,9 @@ extern const struct _mp_obj_module_t mp_module_network;
/* pointers to all UART objects (if they have been created) */ \ /* pointers to all UART objects (if they have been created) */ \
struct _pyb_uart_obj_t *pyb_uart_obj_all[6]; \ struct _pyb_uart_obj_t *pyb_uart_obj_all[6]; \
\ \
/* pointers to all CAN objects (if they have been created) */ \
struct _pyb_can_obj_t *pyb_can_obj_all[2]; \
\
/* list of registered NICs */ \ /* list of registered NICs */ \
mp_obj_list_t mod_network_nic_list; \ mp_obj_list_t mod_network_nic_list; \

View File

@ -211,6 +211,7 @@ Q(params)
Q(initfilterbanks) Q(initfilterbanks)
Q(clearfilter) Q(clearfilter)
Q(setfilter) Q(setfilter)
Q(rxcallback)
Q(NORMAL) Q(NORMAL)
Q(LOOPBACK) Q(LOOPBACK)
Q(SILENT) Q(SILENT)

View File

@ -75,6 +75,7 @@
#include "timer.h" #include "timer.h"
#include "uart.h" #include "uart.h"
#include "storage.h" #include "storage.h"
#include "can.h"
extern void __fatal_error(const char*); extern void __fatal_error(const char*);
extern PCD_HandleTypeDef pcd_handle; extern PCD_HandleTypeDef pcd_handle;
@ -414,3 +415,21 @@ void UART4_IRQHandler(void) {
void USART6_IRQHandler(void) { void USART6_IRQHandler(void) {
uart_irq_handler(6); uart_irq_handler(6);
} }
#if MICROPY_HW_ENABLE_CAN
void CAN1_RX0_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO0);
}
void CAN1_RX1_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_1, CAN_FIFO1);
}
void CAN2_RX0_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO0);
}
void CAN2_RX1_IRQHandler(void) {
can_rx_irq_handler(PYB_CAN_2, CAN_FIFO1);
}
#endif // MICROPY_HW_ENABLE_CAN

View File

@ -48,3 +48,75 @@ else:
print('passed') print('passed')
else: else:
print('failed, wrong data received') print('failed, wrong data received')
del can
# Test RxCallbacks
can = CAN(1, CAN.LOOPBACK)
can.setfilter(0, CAN.LIST16, 0, (1, 2, 3, 4))
can.setfilter(1, CAN.LIST16, 1, (5, 6, 7, 8))
def cb0(bus, reason):
print('cb0')
if reason == 0:
print('pending')
if reason == 1:
print('full')
if reason == 2:
print('overflow')
def cb1(bus, reason):
print('cb1')
if reason == 0:
print('pending')
if reason == 1:
print('full')
if reason == 2:
print('overflow')
def cb0a(bus, reason):
print('cb0a')
if reason == 0:
print('pending')
if reason == 1:
print('full')
if reason == 2:
print('overflow')
def cb1a(bus, reason):
print('cb1a')
if reason == 0:
print('pending')
if reason == 1:
print('full')
if reason == 2:
print('overflow')
can.rxcallback(0, cb0)
can.rxcallback(1, cb1)
can.send('11111111',1)
can.send('22222222',2)
can.send('33333333',3)
can.rxcallback(0, cb0a)
can.send('44444444',4)
can.send('55555555',5)
can.send('66666666',6)
can.send('77777777',7)
can.rxcallback(1, cb1a)
can.send('88888888',8)
print(can.recv(0))
print(can.recv(0))
print(can.recv(0))
print(can.recv(1))
print(can.recv(1))
print(can.recv(1))
can.send('11111111',1)
can.send('55555555',5)
print(can.recv(0))
print(can.recv(1))

View File

@ -8,3 +8,27 @@ True
passed passed
CAN(1, CAN.LOOPBACK, extframe=True) CAN(1, CAN.LOOPBACK, extframe=True)
passed passed
cb0
pending
cb0
full
cb0a
overflow
cb1
pending
cb1
full
cb1a
overflow
(1, 0, 0, b'11111111')
(2, 0, 1, b'22222222')
(4, 0, 3, b'44444444')
(5, 0, 0, b'55555555')
(6, 0, 1, b'66666666')
(8, 0, 3, b'88888888')
cb0a
pending
cb1a
pending
(1, 0, 0, b'11111111')
(5, 0, 0, b'55555555')