summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/library/pyb.CAN.rst8
-rw-r--r--stmhal/can.c94
-rw-r--r--tests/pyb/can.py61
-rw-r--r--tests/pyb/can.py.exp6
4 files changed, 151 insertions, 18 deletions
diff --git a/docs/library/pyb.CAN.rst b/docs/library/pyb.CAN.rst
index 8f417f735..46e6d08cf 100644
--- a/docs/library/pyb.CAN.rst
+++ b/docs/library/pyb.CAN.rst
@@ -126,7 +126,7 @@ Methods
Return value: buffer of data bytes.
-.. method:: can.send(send, addr, \*, timeout=5000)
+.. method:: can.send(send, addr, \*, timeout=0)
Send a message on the bus:
@@ -134,6 +134,12 @@ Methods
- ``addr`` is the address to send to
- ``timeout`` is the timeout in milliseconds to wait for the send.
+ If timeout is 0 the message is placed in a buffer in one of three hardware
+ buffers and the method returns immediately. If all three buffers are in use
+ an exception is thrown. If timeout is not 0, the method waits until the
+ message is transmitted. If the message can't be transmitted within the
+ specified time an exception is thrown.
+
Return value: ``None``.
.. method:: can.rxcallback(fifo, fun)
diff --git a/stmhal/can.c b/stmhal/can.c
index 02afbbf82..f60f79532 100644
--- a/stmhal/can.c
+++ b/stmhal/can.c
@@ -170,6 +170,96 @@ STATIC void can_clearfilter(uint32_t f) {
HAL_CAN_ConfigFilter(NULL, &filter);
}
+// We have our own version of CAN transmit so we can handle Timeout=0 correctly.
+STATIC HAL_StatusTypeDef CAN_Transmit(CAN_HandleTypeDef *hcan, uint32_t Timeout) {
+ uint32_t transmitmailbox;
+ uint32_t tickstart;
+ uint32_t rqcpflag;
+ uint32_t txokflag;
+
+ // Check the parameters
+ assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
+ assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
+ assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));
+
+ // Select one empty transmit mailbox
+ if ((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) {
+ transmitmailbox = CAN_TXMAILBOX_0;
+ rqcpflag = CAN_FLAG_RQCP0;
+ txokflag = CAN_FLAG_TXOK0;
+ } else if ((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) {
+ transmitmailbox = CAN_TXMAILBOX_1;
+ rqcpflag = CAN_FLAG_RQCP1;
+ txokflag = CAN_FLAG_TXOK1;
+ } else if ((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2) {
+ transmitmailbox = CAN_TXMAILBOX_2;
+ rqcpflag = CAN_FLAG_RQCP2;
+ txokflag = CAN_FLAG_TXOK2;
+ } else {
+ transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
+ }
+
+ if (transmitmailbox != CAN_TXSTATUS_NOMAILBOX) {
+ // Set up the Id
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
+ if (hcan->pTxMsg->IDE == CAN_ID_STD) {
+ assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << 21) | \
+ hcan->pTxMsg->RTR);
+ } else {
+ assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << 3) | \
+ hcan->pTxMsg->IDE | \
+ hcan->pTxMsg->RTR);
+ }
+
+ // Set up the DLC
+ hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;
+ hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0;
+ hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;
+
+ // Set up the data field
+ hcan->Instance->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)hcan->pTxMsg->Data[3] << 24) |
+ ((uint32_t)hcan->pTxMsg->Data[2] << 16) |
+ ((uint32_t)hcan->pTxMsg->Data[1] << 8) |
+ ((uint32_t)hcan->pTxMsg->Data[0]));
+ hcan->Instance->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)hcan->pTxMsg->Data[7] << 24) |
+ ((uint32_t)hcan->pTxMsg->Data[6] << 16) |
+ ((uint32_t)hcan->pTxMsg->Data[5] << 8) |
+ ((uint32_t)hcan->pTxMsg->Data[4]));
+ // Request transmission
+ hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;
+
+ if (Timeout == 0) {
+ return HAL_OK;
+ }
+
+ // Get tick
+ tickstart = HAL_GetTick();
+ // Check End of transmission flag
+ while (!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox))) {
+ // Check for the Timeout
+ if (Timeout != HAL_MAX_DELAY) {
+ if ((HAL_GetTick() - tickstart) > Timeout) {
+ // When the timeout expires, we try to abort the transmission of the packet
+ __HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox);
+ while (!__HAL_CAN_GET_FLAG(hcan, rqcpflag)) {
+ }
+ if (__HAL_CAN_GET_FLAG(hcan, txokflag)) {
+ // The abort attempt failed and the message was sent properly
+ return HAL_OK;
+ } else {
+ return HAL_TIMEOUT;
+ }
+ }
+ }
+ }
+ return HAL_OK;
+ } else {
+ return HAL_BUSY;
+ }
+}
+
/******************************************************************************/
// Micro Python bindings
@@ -348,7 +438,7 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
static const mp_arg_t allowed_args[] = {
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
{ MP_QSTR_addr, MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
- { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 5000} },
+ { MP_QSTR_timeout, MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = 0} },
};
// parse args
@@ -380,7 +470,7 @@ STATIC mp_obj_t pyb_can_send(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_
tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte
}
self->can.pTxMsg = &tx_msg;
- HAL_StatusTypeDef status = HAL_CAN_Transmit(&self->can, args[2].u_int);
+ HAL_StatusTypeDef status = CAN_Transmit(&self->can, args[2].u_int);
if (status != HAL_OK) {
mp_hal_raise(status);
diff --git a/tests/pyb/can.py b/tests/pyb/can.py
index 132da2306..5fd4d39d0 100644
--- a/tests/pyb/can.py
+++ b/tests/pyb/can.py
@@ -1,4 +1,5 @@
from pyb import CAN
+import pyb
CAN.initfilterbanks(14)
can = CAN(1)
@@ -11,19 +12,19 @@ print(can.any(0))
# Catch all filter
can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0))
-can.send('abcd', 123)
+can.send('abcd', 123, timeout=5000)
print(can.any(0))
print(can.recv(0))
-can.send('abcd', -1)
+can.send('abcd', -1, timeout=5000)
print(can.recv(0))
-can.send('abcd', 0x7FF + 1)
+can.send('abcd', 0x7FF + 1, timeout=5000)
print(can.recv(0))
# Test too long message
try:
- can.send('abcdefghi', 0x7FF)
+ can.send('abcdefghi', 0x7FF, timeout=5000)
except ValueError:
print('passed')
else:
@@ -39,7 +40,7 @@ can.setfilter(0, CAN.MASK32, 0, (0, 0))
print(can)
try:
- can.send('abcde', 0x7FF + 1)
+ can.send('abcde', 0x7FF + 1, timeout=5000)
except ValueError:
print('failed')
else:
@@ -95,17 +96,17 @@ def cb1a(bus, reason):
can.rxcallback(0, cb0)
can.rxcallback(1, cb1)
-can.send('11111111',1)
-can.send('22222222',2)
-can.send('33333333',3)
+can.send('11111111',1, timeout=5000)
+can.send('22222222',2, timeout=5000)
+can.send('33333333',3, timeout=5000)
can.rxcallback(0, cb0a)
-can.send('44444444',4)
+can.send('44444444',4, timeout=5000)
-can.send('55555555',5)
-can.send('66666666',6)
-can.send('77777777',7)
+can.send('55555555',5, timeout=5000)
+can.send('66666666',6, timeout=5000)
+can.send('77777777',7, timeout=5000)
can.rxcallback(1, cb1a)
-can.send('88888888',8)
+can.send('88888888',8, timeout=5000)
print(can.recv(0))
print(can.recv(0))
@@ -114,9 +115,39 @@ print(can.recv(1))
print(can.recv(1))
print(can.recv(1))
-can.send('11111111',1)
-can.send('55555555',5)
+can.send('11111111',1, timeout=5000)
+can.send('55555555',5, timeout=5000)
print(can.recv(0))
print(can.recv(1))
+del can
+
+# Testing asyncronous send
+can = CAN(1, CAN.LOOPBACK)
+can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0))
+
+while can.any(0):
+ can.recv(0)
+
+can.send('abcde', 1, timeout=0)
+print(can.any(0))
+while not can.any(0):
+ pass
+
+print(can.recv(0))
+
+try:
+ can.send('abcde', 2, timeout=0)
+ can.send('abcde', 3, timeout=0)
+ can.send('abcde', 4, timeout=0)
+ can.send('abcde', 5, timeout=0)
+except OSError as e:
+ if str(e) == '16':
+ print('passed')
+ else:
+ print('failed')
+
+pyb.delay(500)
+while can.any(0):
+ print(can.recv(0))
diff --git a/tests/pyb/can.py.exp b/tests/pyb/can.py.exp
index b0ede7b9f..845f6d5ba 100644
--- a/tests/pyb/can.py.exp
+++ b/tests/pyb/can.py.exp
@@ -32,3 +32,9 @@ cb1a
pending
(1, 0, 0, b'11111111')
(5, 0, 0, b'55555555')
+False
+(1, 0, 0, b'abcde')
+passed
+(2, 0, 0, b'abcde')
+(3, 0, 0, b'abcde')
+(4, 0, 0, b'abcde')