stmhal: Allow sending CAN messages with timeout=0.
Thanks to Henrik Sölver for this patch.
This commit is contained in:
parent
4c45921349
commit
7d5e34287c
|
@ -126,7 +126,7 @@ Methods
|
||||||
|
|
||||||
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=0)
|
||||||
|
|
||||||
Send a message on the bus:
|
Send a message on the bus:
|
||||||
|
|
||||||
|
@ -134,6 +134,12 @@ Methods
|
||||||
- ``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.
|
||||||
|
|
||||||
|
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``.
|
Return value: ``None``.
|
||||||
|
|
||||||
.. method:: can.rxcallback(fifo, fun)
|
.. method:: can.rxcallback(fifo, fun)
|
||||||
|
|
94
stmhal/can.c
94
stmhal/can.c
|
@ -170,6 +170,96 @@ STATIC void can_clearfilter(uint32_t f) {
|
||||||
HAL_CAN_ConfigFilter(NULL, &filter);
|
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
|
// 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[] = {
|
static const mp_arg_t allowed_args[] = {
|
||||||
{ MP_QSTR_send, MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
|
{ 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_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
|
// 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
|
tx_msg.Data[i] = ((byte*)bufinfo.buf)[i]; // Data is uint32_t but holds only 1 byte
|
||||||
}
|
}
|
||||||
self->can.pTxMsg = &tx_msg;
|
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) {
|
if (status != HAL_OK) {
|
||||||
mp_hal_raise(status);
|
mp_hal_raise(status);
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
from pyb import CAN
|
from pyb import CAN
|
||||||
|
import pyb
|
||||||
|
|
||||||
CAN.initfilterbanks(14)
|
CAN.initfilterbanks(14)
|
||||||
can = CAN(1)
|
can = CAN(1)
|
||||||
|
@ -11,19 +12,19 @@ print(can.any(0))
|
||||||
# Catch all filter
|
# Catch all filter
|
||||||
can.setfilter(0, CAN.MASK16, 0, (0, 0, 0, 0))
|
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.any(0))
|
||||||
print(can.recv(0))
|
print(can.recv(0))
|
||||||
|
|
||||||
can.send('abcd', -1)
|
can.send('abcd', -1, timeout=5000)
|
||||||
print(can.recv(0))
|
print(can.recv(0))
|
||||||
|
|
||||||
can.send('abcd', 0x7FF + 1)
|
can.send('abcd', 0x7FF + 1, timeout=5000)
|
||||||
print(can.recv(0))
|
print(can.recv(0))
|
||||||
|
|
||||||
# Test too long message
|
# Test too long message
|
||||||
try:
|
try:
|
||||||
can.send('abcdefghi', 0x7FF)
|
can.send('abcdefghi', 0x7FF, timeout=5000)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print('passed')
|
print('passed')
|
||||||
else:
|
else:
|
||||||
|
@ -39,7 +40,7 @@ can.setfilter(0, CAN.MASK32, 0, (0, 0))
|
||||||
print(can)
|
print(can)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
can.send('abcde', 0x7FF + 1)
|
can.send('abcde', 0x7FF + 1, timeout=5000)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
print('failed')
|
print('failed')
|
||||||
else:
|
else:
|
||||||
|
@ -95,17 +96,17 @@ def cb1a(bus, reason):
|
||||||
can.rxcallback(0, cb0)
|
can.rxcallback(0, cb0)
|
||||||
can.rxcallback(1, cb1)
|
can.rxcallback(1, cb1)
|
||||||
|
|
||||||
can.send('11111111',1)
|
can.send('11111111',1, timeout=5000)
|
||||||
can.send('22222222',2)
|
can.send('22222222',2, timeout=5000)
|
||||||
can.send('33333333',3)
|
can.send('33333333',3, timeout=5000)
|
||||||
can.rxcallback(0, cb0a)
|
can.rxcallback(0, cb0a)
|
||||||
can.send('44444444',4)
|
can.send('44444444',4, timeout=5000)
|
||||||
|
|
||||||
can.send('55555555',5)
|
can.send('55555555',5, timeout=5000)
|
||||||
can.send('66666666',6)
|
can.send('66666666',6, timeout=5000)
|
||||||
can.send('77777777',7)
|
can.send('77777777',7, timeout=5000)
|
||||||
can.rxcallback(1, cb1a)
|
can.rxcallback(1, cb1a)
|
||||||
can.send('88888888',8)
|
can.send('88888888',8, timeout=5000)
|
||||||
|
|
||||||
print(can.recv(0))
|
print(can.recv(0))
|
||||||
print(can.recv(0))
|
print(can.recv(0))
|
||||||
|
@ -114,9 +115,39 @@ print(can.recv(1))
|
||||||
print(can.recv(1))
|
print(can.recv(1))
|
||||||
print(can.recv(1))
|
print(can.recv(1))
|
||||||
|
|
||||||
can.send('11111111',1)
|
can.send('11111111',1, timeout=5000)
|
||||||
can.send('55555555',5)
|
can.send('55555555',5, timeout=5000)
|
||||||
|
|
||||||
print(can.recv(0))
|
print(can.recv(0))
|
||||||
print(can.recv(1))
|
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))
|
||||||
|
|
|
@ -32,3 +32,9 @@ cb1a
|
||||||
pending
|
pending
|
||||||
(1, 0, 0, b'11111111')
|
(1, 0, 0, b'11111111')
|
||||||
(5, 0, 0, b'55555555')
|
(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')
|
||||||
|
|
Loading…
Reference in New Issue