stmhal: Allow sending CAN messages with timeout=0.

Thanks to Henrik Sölver for this patch.
This commit is contained in:
Damien George 2015-04-16 23:52:43 +01:00
parent 4c45921349
commit 7d5e34287c
4 changed files with 151 additions and 18 deletions

View File

@ -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)

View File

@ -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);

View File

@ -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))

View File

@ -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')