stmhal: Add support for CAN rx callbacks.
This commit is contained in:
parent
ed8b4da0db
commit
f80f1a7077
|
@ -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
|
||||||
|
|
177
stmhal/can.c
177
stmhal/can.c
|
@ -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?
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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; \
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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))
|
||||||
|
|
||||||
|
|
|
@ -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')
|
||||||
|
|
Loading…
Reference in New Issue