mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2026-05-16 19:57:52 +08:00
feat[can]: Implement non-blocking send mechanism and enhance CAN driver functionality
- Added support for non-blocking mode CAN message sending, including software ring buffer management and dynamic memory allocation options. - Improved related comments and error handling. - Updated example code to demonstrate the usage of both blocking and non-blocking sending modes, and corrected some structure field naming and macro definitions.
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2006-2024 RT-Thread Development Team
|
||||
* Copyright (c) 2006-2025, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
@@ -14,6 +14,7 @@
|
||||
* 2021-02-02 YuZhe XU fix bug in filter config
|
||||
* 2021-8-25 SVCHAO The baud rate is configured according to the different APB1 frequencies.
|
||||
f4-series only.
|
||||
* 2025-09-20 wdfk_prog Implemented sendmsg_nonblocking op to support framework's async TX.
|
||||
*/
|
||||
|
||||
#include "drv_can.h"
|
||||
@@ -484,6 +485,21 @@ static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Low-level function to send a CAN message to a specific hardware mailbox.
|
||||
*
|
||||
* This function is part of the **blocking** send mechanism. It is called by
|
||||
* `_can_int_tx` after a hardware mailbox has already been acquired. Its role is
|
||||
* to format the message according to the STM32 hardware requirements and place
|
||||
* it into the specified mailbox for transmission.
|
||||
*
|
||||
* @param[in] can A pointer to the CAN device structure.
|
||||
* @param[in] buf A pointer to the `rt_can_msg` to be sent.
|
||||
* @param[in] box_num The specific hardware mailbox index (0, 1, or 2) to use for this tran
|
||||
*
|
||||
* @return `RT_EOK` on success, or an error code on failure.
|
||||
*/
|
||||
static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num)
|
||||
{
|
||||
CAN_HandleTypeDef *hcan;
|
||||
@@ -586,6 +602,53 @@ static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Low-level, hardware-specific non-blocking function to send a CAN message.
|
||||
*
|
||||
* This function interacts directly with the STM32 HAL library to add a message
|
||||
* to a hardware TX mailbox. It returns immediately and does not wait for the
|
||||
* transmission to complete.
|
||||
*
|
||||
* @param[in] can A pointer to the CAN device structure.
|
||||
* @param[in] buf A pointer to the `rt_can_msg` to be sent.
|
||||
*
|
||||
* @return
|
||||
* - `RT_EOK` if the message was successfully accepted by the hardware.
|
||||
* - `-RT_EBUSY` if all hardware mailboxes are currently full.
|
||||
* - `-RT_ERROR` on other HAL failures.
|
||||
*/
|
||||
static rt_ssize_t _can_sendmsg_nonblocking(struct rt_can_device *can, const void *buf)
|
||||
{
|
||||
CAN_HandleTypeDef *hcan = &((struct stm32_can *) can->parent.user_data)->CanHandle;
|
||||
struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
|
||||
CAN_TxHeaderTypeDef txheader = {0};
|
||||
uint32_t tx_mailbox;
|
||||
|
||||
if ((hcan->State != HAL_CAN_STATE_READY) && (hcan->State != HAL_CAN_STATE_LISTENING))
|
||||
return -RT_ERROR;
|
||||
|
||||
if (HAL_CAN_GetTxMailboxesFreeLevel(hcan) == 0)
|
||||
return -RT_EBUSY;
|
||||
|
||||
txheader.DLC = pmsg->len;
|
||||
txheader.RTR = (pmsg->rtr == RT_CAN_RTR) ? CAN_RTR_REMOTE : CAN_RTR_DATA;
|
||||
txheader.IDE = (pmsg->ide == RT_CAN_STDID) ? CAN_ID_STD : CAN_ID_EXT;
|
||||
if (txheader.IDE == CAN_ID_STD)
|
||||
txheader.StdId = pmsg->id;
|
||||
else
|
||||
txheader.ExtId = pmsg->id;
|
||||
|
||||
HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(hcan, &txheader, pmsg->data, &tx_mailbox);
|
||||
if (status != HAL_OK)
|
||||
{
|
||||
LOG_W("can sendmsg nonblocking send error %d", status);
|
||||
return -RT_ERROR;
|
||||
}
|
||||
|
||||
return RT_EOK;
|
||||
}
|
||||
|
||||
static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
|
||||
{
|
||||
HAL_StatusTypeDef status;
|
||||
@@ -645,10 +708,11 @@ static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo)
|
||||
|
||||
static const struct rt_can_ops _can_ops =
|
||||
{
|
||||
_can_config,
|
||||
_can_control,
|
||||
_can_sendmsg,
|
||||
_can_recvmsg,
|
||||
.configure = _can_config,
|
||||
.control = _can_control,
|
||||
.sendmsg = _can_sendmsg,
|
||||
.recvmsg = _can_recvmsg,
|
||||
.sendmsg_nonblocking = _can_sendmsg_nonblocking,
|
||||
};
|
||||
|
||||
static void _can_rx_isr(struct rt_can_device *can, rt_uint32_t fifo)
|
||||
@@ -788,6 +852,22 @@ static void _can_sce_isr(struct rt_can_device *can)
|
||||
hcan->Instance->MSR |= CAN_MSR_ERRI;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief The low-level ISR for CAN TX events on STM32.
|
||||
*
|
||||
* This function's sole responsibility is to check the hardware status flags
|
||||
* to determine which mailbox completed a transmission and whether it was
|
||||
* successful or failed. It then reports the specific event to the upper
|
||||
* framework layer via `rt_hw_can_isr()`.
|
||||
*
|
||||
* @note This ISR contains NO framework-level logic (e.g., buffer handling).
|
||||
* It is a pure hardware event reporter, ensuring a clean separation
|
||||
* of concerns between the driver and the framework.
|
||||
*
|
||||
* @param[in] can A pointer to the CAN device structure.
|
||||
* @return void
|
||||
*/
|
||||
static void _can_tx_isr(struct rt_can_device *can)
|
||||
{
|
||||
CAN_HandleTypeDef *hcan;
|
||||
|
||||
@@ -1,31 +1,76 @@
|
||||
config RT_USING_CAN
|
||||
bool "Using CAN device drivers"
|
||||
default n
|
||||
help
|
||||
Enable this option to include the CAN device driver framework.
|
||||
|
||||
if RT_USING_CAN
|
||||
|
||||
config RT_CAN_USING_HDR
|
||||
bool "Enable CAN hardware filter"
|
||||
bool "Enable CAN hardware filter support"
|
||||
default n
|
||||
|
||||
help
|
||||
If your CAN controller supports hardware filtering, and you want to
|
||||
use the framework to configure these filters, enable this option.
|
||||
|
||||
config RT_CAN_USING_CANFD
|
||||
bool "Enable CANFD support"
|
||||
bool "Enable CAN-FD support"
|
||||
default n
|
||||
|
||||
help
|
||||
Enable this to support CAN with Flexible Data-Rate. This will
|
||||
increase the size of the rt_can_msg structure.
|
||||
|
||||
config RT_CANMSG_BOX_SZ
|
||||
int "CAN message box size"
|
||||
int "Software RX message box size (in messages)"
|
||||
default 16
|
||||
help
|
||||
Set the size of the CAN message box.
|
||||
|
||||
This sets the capacity of the software buffer (FIFO) for incoming
|
||||
CAN messages. It defines how many messages can be buffered by the
|
||||
driver before the application must read them.
|
||||
|
||||
config RT_CANSND_BOX_NUM
|
||||
int "Number of CAN send queues"
|
||||
int "Number of mailboxes for blocking send"
|
||||
default 1
|
||||
help
|
||||
Set the number of CAN send queues.
|
||||
|
||||
This sets the number of concurrent blocking send operations that
|
||||
can be in flight. It is typically matched to the number of
|
||||
hardware transmission mailboxes on the CAN controller.
|
||||
|
||||
config RT_CANSND_MSG_TIMEOUT
|
||||
int "CAN send message timeout"
|
||||
int "Timeout for blocking send (in OS ticks)"
|
||||
default 100
|
||||
help
|
||||
Set the timeout for CAN send messages.
|
||||
This sets the default time a thread will wait for a hardware
|
||||
mailbox to become available when sending in blocking mode.
|
||||
|
||||
config RT_CAN_NB_TX_FIFO_SIZE
|
||||
int "Non-blocking send buffer size (in bytes)"
|
||||
default 256
|
||||
help
|
||||
This defines the size of the software ring buffer used for
|
||||
non-blocking and ISR-based transmissions. When the hardware
|
||||
mailboxes are full, outgoing messages are temporarily stored
|
||||
in this buffer.
|
||||
|
||||
To calculate a suitable size, use:
|
||||
(number of messages to buffer) * sizeof(struct rt_can_msg).
|
||||
For standard CAN, sizeof(struct rt_can_msg) is typically 16 bytes.
|
||||
The default of 256 bytes can buffer 16 standard CAN messages.
|
||||
If using CAN-FD, you will need to increase this size significantly.
|
||||
|
||||
config RT_CAN_MALLOC_NB_TX_BUFFER
|
||||
bool "Dynamically allocate the non-blocking send buffer"
|
||||
depends on RT_USING_HEAP
|
||||
default n
|
||||
help
|
||||
If this option is enabled (y), the non-blocking send buffer will
|
||||
be allocated from the system heap at runtime when the CAN device
|
||||
is opened (using rt_malloc). This saves static RAM but requires
|
||||
a heap to be available.
|
||||
|
||||
If this option is disabled (n), the buffer will be allocated
|
||||
as a static array within the rt_can_device structure. This
|
||||
consumes static RAM but guarantees the memory is always available
|
||||
and avoids heap fragmentation.
|
||||
|
||||
endif
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user