|
1 | 1 | /* |
2 | | - * Copyright (c) 2006-2024 RT-Thread Development Team |
| 2 | + * Copyright (c) 2006-2025, RT-Thread Development Team |
3 | 3 | * |
4 | 4 | * SPDX-License-Identifier: Apache-2.0 |
5 | 5 | * |
|
14 | 14 | * 2021-02-02 YuZhe XU fix bug in filter config |
15 | 15 | * 2021-8-25 SVCHAO The baud rate is configured according to the different APB1 frequencies. |
16 | 16 | f4-series only. |
| 17 | + * 2025-09-20 wdfk_prog Implemented sendmsg_nonblocking op to support framework's async TX. |
17 | 18 | */ |
18 | 19 |
|
19 | 20 | #include "drv_can.h" |
@@ -484,6 +485,21 @@ static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg) |
484 | 485 | return RT_EOK; |
485 | 486 | } |
486 | 487 |
|
| 488 | +/** |
| 489 | + * @internal |
| 490 | + * @brief Low-level function to send a CAN message to a specific hardware mailbox. |
| 491 | + * |
| 492 | + * This function is part of the **blocking** send mechanism. It is called by |
| 493 | + * `_can_int_tx` after a hardware mailbox has already been acquired. Its role is |
| 494 | + * to format the message according to the STM32 hardware requirements and place |
| 495 | + * it into the specified mailbox for transmission. |
| 496 | + * |
| 497 | + * @param can A pointer to the CAN device structure. |
| 498 | + * @param buf A pointer to the `rt_can_msg` to be sent. |
| 499 | + * @param box_num The specific hardware mailbox index (0, 1, or 2) to use for this transmission. |
| 500 | + * |
| 501 | + * @return `RT_EOK` on success, or an error code on failure. |
| 502 | + */ |
487 | 503 | static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t box_num) |
488 | 504 | { |
489 | 505 | CAN_HandleTypeDef *hcan; |
@@ -586,6 +602,53 @@ static int _can_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t |
586 | 602 | } |
587 | 603 | } |
588 | 604 |
|
| 605 | +/** |
| 606 | + * @internal |
| 607 | + * @brief Low-level, hardware-specific non-blocking function to send a CAN message. |
| 608 | + * |
| 609 | + * This function interacts directly with the STM32 HAL library to add a message |
| 610 | + * to a hardware TX mailbox. It returns immediately and does not wait for the |
| 611 | + * transmission to complete. |
| 612 | + * |
| 613 | + * @param can A pointer to the CAN device structure. |
| 614 | + * @param buf A pointer to the `rt_can_msg` to be sent. |
| 615 | + * |
| 616 | + * @return |
| 617 | + * - `RT_EOK` if the message was successfully accepted by the hardware. |
| 618 | + * - `-RT_EBUSY` if all hardware mailboxes are currently full. |
| 619 | + * - `-RT_ERROR` on other HAL failures. |
| 620 | + */ |
| 621 | +static rt_ssize_t _can_sendmsg_nonblocking(struct rt_can_device *can, const void *buf) |
| 622 | +{ |
| 623 | + CAN_HandleTypeDef *hcan = &((struct stm32_can *) can->parent.user_data)->CanHandle; |
| 624 | + struct rt_can_msg *pmsg = (struct rt_can_msg *) buf; |
| 625 | + CAN_TxHeaderTypeDef txheader = {0}; |
| 626 | + uint32_t tx_mailbox; |
| 627 | + |
| 628 | + if ((hcan->State != HAL_CAN_STATE_READY) && (hcan->State != HAL_CAN_STATE_LISTENING)) |
| 629 | + return -RT_ERROR; |
| 630 | + |
| 631 | + if (HAL_CAN_GetTxMailboxesFreeLevel(hcan) == 0) |
| 632 | + return -RT_EBUSY; |
| 633 | + |
| 634 | + txheader.DLC = pmsg->len; |
| 635 | + txheader.RTR = (pmsg->rtr == RT_CAN_RTR) ? CAN_RTR_REMOTE : CAN_RTR_DATA; |
| 636 | + txheader.IDE = (pmsg->ide == RT_CAN_STDID) ? CAN_ID_STD : CAN_ID_EXT; |
| 637 | + if (txheader.IDE == CAN_ID_STD) |
| 638 | + txheader.StdId = pmsg->id; |
| 639 | + else |
| 640 | + txheader.ExtId = pmsg->id; |
| 641 | + |
| 642 | + HAL_StatusTypeDef status = HAL_CAN_AddTxMessage(hcan, &txheader, pmsg->data, &tx_mailbox); |
| 643 | + if (status != HAL_OK) |
| 644 | + { |
| 645 | + LOG_W("can sendmsg nonblocking send error %d", status); |
| 646 | + return -RT_ERROR; |
| 647 | + } |
| 648 | + |
| 649 | + return RT_EOK; |
| 650 | +} |
| 651 | + |
589 | 652 | static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo) |
590 | 653 | { |
591 | 654 | HAL_StatusTypeDef status; |
@@ -645,10 +708,11 @@ static int _can_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t fifo) |
645 | 708 |
|
646 | 709 | static const struct rt_can_ops _can_ops = |
647 | 710 | { |
648 | | - _can_config, |
649 | | - _can_control, |
650 | | - _can_sendmsg, |
651 | | - _can_recvmsg, |
| 711 | + .configure = _can_config, |
| 712 | + .control = _can_control, |
| 713 | + .sendmsg = _can_sendmsg, |
| 714 | + .recvmsg = _can_recvmsg, |
| 715 | + .sendmsg_nonblocking = _can_sendmsg_nonblocking, |
652 | 716 | }; |
653 | 717 |
|
654 | 718 | static void _can_rx_isr(struct rt_can_device *can, rt_uint32_t fifo) |
@@ -788,6 +852,21 @@ static void _can_sce_isr(struct rt_can_device *can) |
788 | 852 | hcan->Instance->MSR |= CAN_MSR_ERRI; |
789 | 853 | } |
790 | 854 |
|
| 855 | +/** |
| 856 | + * @internal |
| 857 | + * @brief The low-level ISR for CAN TX events on STM32. |
| 858 | + * |
| 859 | + * This function's sole responsibility is to check the hardware status flags |
| 860 | + * to determine which mailbox completed a transmission and whether it was |
| 861 | + * successful or failed. It then reports the specific event to the upper |
| 862 | + * framework layer via `rt_hw_can_isr()`. |
| 863 | + * |
| 864 | + * @note This ISR contains NO framework-level logic (e.g., buffer handling). |
| 865 | + * It is a pure hardware event reporter, ensuring a clean separation |
| 866 | + * of concerns between the driver and the framework. |
| 867 | + * |
| 868 | + * @param can A pointer to the CAN device structure. |
| 869 | + */ |
791 | 870 | static void _can_tx_isr(struct rt_can_device *can) |
792 | 871 | { |
793 | 872 | CAN_HandleTypeDef *hcan; |
|
0 commit comments