Browse Source

Merge pull request #1716 from xeonxu/stm32hal_can

[STM32 BSP]CAN driver for stm32f4xx HAL.
ZYH 6 năm trước cách đây
mục cha
commit
d06f9ac9df

+ 11 - 1
bsp/stm32f4xx-HAL/Kconfig

@@ -308,7 +308,17 @@ config RT_USING_UART2
 config RT_USING_UART6
     bool "Using UART6"
     default n   
-	
+
+if RT_USING_CAN
+config USING_BXCAN1
+    bool "Enable CAN1 RX:PD0 TX:PD1. Do not select HDR."
+    default n
+
+config USING_BXCAN2
+    bool "Enable CAN2 RX:PB12 TX:PB6. Do not select HDR."
+    default n
+endif
+
 if RT_USING_SPI
 
 config RT_USING_SPI1

+ 4 - 1
bsp/stm32f4xx-HAL/drivers/SConscript

@@ -35,7 +35,10 @@ if GetDepend(['RT_USING_USB_HOST']):
     src += ['drv_usbh.c']
 
 if GetDepend(['RT_USING_I2C']):
-	src += ['drv_i2c.c']
+    src += ['drv_i2c.c']
+
+if GetDepend(['RT_USING_CAN']):
+    src += ['drv_can.c']
 
 if GetDepend(['RT_USING_PWM']):
     src += ['drv_pwm.c']

+ 868 - 0
bsp/stm32f4xx-HAL/drivers/drv_can.c

@@ -0,0 +1,868 @@
+/*
+ * File      : drv_can.c
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with this program; if not, write to the Free Software Foundation, Inc.,
+ *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-05     Xeon Xu      the first version
+ */
+
+/* Includes ------------------------------------------------------------------*/
+#include "drv_can.h"
+#include "board.h"
+#include <rtdevice.h>
+#include <rthw.h>
+#include <rtthread.h>
+
+#define BS1SHIFT 16
+#define BS2SHIFT 20
+#define RRESCLSHIFT 0
+#define SJWSHIFT 24
+#define BS1MASK ( (0x0F) << BS1SHIFT )
+#define BS2MASK ( (0x07) << BS2SHIFT )
+#define RRESCLMASK ( 0x3FF << RRESCLSHIFT )
+#define SJWMASK ( 0x3 << SJWSHIFT )
+
+struct stm_baud_rate_tab
+{
+    rt_uint32_t baud_rate;
+    rt_uint32_t confdata;
+};
+
+/* STM32 can driver */
+struct stm32_drv_can
+{
+    CAN_HandleTypeDef CanHandle;
+    CanTxMsgTypeDef TxMessage;
+    CanRxMsgTypeDef RxMessage;
+    CAN_FilterConfTypeDef FilterConfig;
+};
+
+static const struct stm_baud_rate_tab can_baud_rate_tab[] =
+{
+    {CAN1MBaud  , (CAN_SJW_1TQ | CAN_BS1_2TQ  | CAN_BS2_4TQ | 6)},
+    {CAN800kBaud, (CAN_SJW_1TQ | CAN_BS1_5TQ  | CAN_BS2_7TQ | 4)},
+    {CAN500kBaud, (CAN_SJW_1TQ | CAN_BS1_14TQ | CAN_BS2_6TQ | 4)},
+    {CAN250kBaud, (CAN_SJW_1TQ | CAN_BS1_1TQ  | CAN_BS2_2TQ | 42)},
+    {CAN125kBaud, (CAN_SJW_1TQ | CAN_BS1_1TQ  | CAN_BS2_2TQ | 84)},
+    {CAN100kBaud, (CAN_SJW_1TQ | CAN_BS1_1TQ  | CAN_BS2_1TQ | 140)},
+    {CAN50kBaud , (CAN_SJW_1TQ | CAN_BS1_1TQ  | CAN_BS2_1TQ | 280)},
+    {CAN20kBaud , (CAN_SJW_1TQ | CAN_BS1_1TQ  | CAN_BS2_1TQ | 700)},
+    {CAN10kBaud , (CAN_SJW_1TQ | CAN_BS1_3TQ  | CAN_BS2_4TQ | 525)}
+};
+
+#define BAUD_DATA(TYPE,NO)                              \
+    ((can_baud_rate_tab[NO].confdata & TYPE##MASK))
+
+static rt_uint32_t get_can_baud_index(rt_uint32_t baud)
+{
+    rt_uint32_t len, index, default_index;
+
+    len = sizeof(can_baud_rate_tab)/sizeof(can_baud_rate_tab[0]);
+    default_index = len;
+
+    for(index = 0; index < len; index++)
+    {
+        if(can_baud_rate_tab[index].baud_rate == baud)
+            return index;
+
+        if(can_baud_rate_tab[index].baud_rate == 1000UL * 250)
+            default_index = index;
+    }
+
+    if(default_index != len)
+        return default_index;
+
+    return 0;
+}
+
+#ifdef USING_BXCAN1
+static struct stm32_drv_can drv_can1;
+struct rt_can_device dev_can1;
+void CAN1_TX_IRQHandler(void)
+{
+    CAN_HandleTypeDef *hcan;
+
+    rt_interrupt_enter();
+    hcan = &drv_can1.CanHandle;
+
+    HAL_CAN_IRQHandler(hcan);
+
+    if (__HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_0))
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_DONE | 0 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_FAIL | 0 << 8);
+    }
+
+    if (__HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_1))
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_DONE | 1 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_FAIL | 1 << 8);
+    }
+
+    if (__HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_2))
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_DONE | 2 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_TX_FAIL | 2 << 8);
+    }
+
+    rt_interrupt_leave();
+}
+
+/**
+ * @brief This function handles CAN1 RX0 interrupts.
+ */
+void CAN1_RX0_IRQHandler(void)
+{
+    CAN_HandleTypeDef *hcan;
+
+    hcan = &drv_can1.CanHandle;
+
+    rt_interrupt_enter();
+    HAL_CAN_IRQHandler(hcan);
+
+    if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0))
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_RXOF_IND | 0 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_RX_IND | 0 << 8);
+    }
+
+    rt_interrupt_leave();
+}
+
+/**
+ * @brief This function handles CAN1 RX1 interrupts.
+ */
+void CAN1_RX1_IRQHandler(void)
+{
+    CAN_HandleTypeDef *hcan;
+
+    hcan = &drv_can1.CanHandle;
+
+    rt_interrupt_enter();
+    HAL_CAN_IRQHandler(hcan);
+
+    if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV1))
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_RXOF_IND | 1 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can1, RT_CAN_EVENT_RX_IND | 1 << 8);
+    }
+
+    rt_interrupt_leave();
+}
+
+/**
+ * @brief This function handles CAN1 SCE interrupts.
+ */
+void CAN1_SCE_IRQHandler(void)
+{
+    rt_uint32_t errtype;
+    CAN_HandleTypeDef *hcan;
+
+    hcan = &drv_can1.CanHandle;
+    errtype = hcan->Instance->ESR;
+
+    rt_interrupt_enter();
+    HAL_CAN_IRQHandler(hcan);
+
+    if (errtype & 0x70 && dev_can1.status.lasterrtype == (errtype & 0x70))
+    {
+        switch ((errtype & 0x70) >> 4)
+        {
+        case RT_CAN_BUS_BIT_PAD_ERR:
+            dev_can1.status.bitpaderrcnt++;
+            break;
+        case RT_CAN_BUS_FORMAT_ERR:
+            dev_can1.status.formaterrcnt++;
+            break;
+        case RT_CAN_BUS_ACK_ERR:
+            dev_can1.status.ackerrcnt++;
+            break;
+        case RT_CAN_BUS_IMPLICIT_BIT_ERR:
+        case RT_CAN_BUS_EXPLICIT_BIT_ERR:
+            dev_can1.status.biterrcnt++;
+            break;
+        case RT_CAN_BUS_CRC_ERR:
+            dev_can1.status.crcerrcnt++;
+            break;
+        }
+        dev_can1.status.lasterrtype = errtype & 0x70;
+        hcan->Instance->ESR &= ~0x70;
+    }
+    dev_can1.status.rcverrcnt = errtype >> 24;
+    dev_can1.status.snderrcnt = (errtype >> 16 & 0xFF);
+    dev_can1.status.errcode = errtype & 0x07;
+    hcan->Instance->MSR |= CAN_MSR_ERRI;
+    rt_interrupt_leave();
+}
+#endif // USING_BXCAN1
+
+#ifdef USING_BXCAN2
+static struct stm32_drv_can drv_can2;
+struct rt_can_device dev_can2;
+/**
+ * @brief This function handles CAN2 TX interrupts.
+ */
+void CAN2_TX_IRQHandler(void)
+{
+    CAN_HandleTypeDef *hcan;
+
+    rt_interrupt_enter();
+    hcan = &drv_can2.CanHandle;
+
+    HAL_CAN_IRQHandler(hcan);
+
+    if (__HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_0))
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_DONE | 0 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_FAIL | 0 << 8);
+    }
+
+    if (__HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_1))
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_DONE | 1 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_FAIL | 1 << 8);
+    }
+
+    if (__HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_2))
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_DONE | 2 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_TX_FAIL | 2 << 8);
+    }
+
+    rt_interrupt_leave();
+}
+
+/**
+ * @brief This function handles CAN2 RX0 interrupts.
+ */
+void CAN2_RX0_IRQHandler(void)
+{
+    CAN_HandleTypeDef *hcan;
+
+    hcan = &drv_can2.CanHandle;
+
+    rt_interrupt_enter();
+    HAL_CAN_IRQHandler(hcan);
+
+    if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV0))
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_RXOF_IND | 0 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_RX_IND | 0 << 8);
+    }
+
+    rt_interrupt_leave();
+
+}
+
+/**
+ * @brief This function handles CAN2 RX1 interrupts.
+ */
+void CAN2_RX1_IRQHandler(void)
+{
+    CAN_HandleTypeDef *hcan;
+
+    hcan = &drv_can2.CanHandle;
+
+    rt_interrupt_enter();
+    HAL_CAN_IRQHandler(hcan);
+
+    if (__HAL_CAN_GET_FLAG(hcan, CAN_FLAG_FOV1))
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_RXOF_IND | 1 << 8);
+    }
+    else
+    {
+        rt_hw_can_isr(&dev_can2, RT_CAN_EVENT_RX_IND | 1 << 8);
+    }
+
+    rt_interrupt_leave();
+}
+
+/**
+ * @brief This function handles CAN2 SCE interrupts.
+ */
+void CAN2_SCE_IRQHandler(void)
+{
+    rt_uint32_t errtype;
+    CAN_HandleTypeDef *hcan;
+
+    hcan = &drv_can2.CanHandle;
+    errtype = hcan->Instance->ESR;
+
+    rt_interrupt_enter();
+    HAL_CAN_IRQHandler(hcan);
+
+    if (errtype & 0x70 && dev_can2.status.lasterrtype == (errtype & 0x70))
+    {
+        switch ((errtype & 0x70) >> 4)
+        {
+        case RT_CAN_BUS_BIT_PAD_ERR:
+            dev_can2.status.bitpaderrcnt++;
+            break;
+        case RT_CAN_BUS_FORMAT_ERR:
+            dev_can2.status.formaterrcnt++;
+            break;
+        case RT_CAN_BUS_ACK_ERR:
+            dev_can2.status.ackerrcnt++;
+            break;
+        case RT_CAN_BUS_IMPLICIT_BIT_ERR:
+        case RT_CAN_BUS_EXPLICIT_BIT_ERR:
+            dev_can2.status.biterrcnt++;
+            break;
+        case RT_CAN_BUS_CRC_ERR:
+            dev_can2.status.crcerrcnt++;
+            break;
+        }
+        dev_can2.status.lasterrtype = errtype & 0x70;
+        hcan->Instance->ESR &= ~0x70;
+    }
+    dev_can2.status.rcverrcnt = errtype >> 24;
+    dev_can2.status.snderrcnt = (errtype >> 16 & 0xFF);
+    dev_can2.status.errcode = errtype & 0x07;
+    hcan->Instance->MSR |= CAN_MSR_ERRI;
+    rt_interrupt_leave();
+}
+
+#endif // USING_BXCAN2
+
+/**
+ * @brief  Error CAN callback.
+ * @param  hcan pointer to a CAN_HandleTypeDef structure that contains
+ *         the configuration information for the specified CAN.
+ * @retval None
+ */
+void HAL_CAN_ErrorCallback(CAN_HandleTypeDef *hcan)
+{
+    /* TODO Error Callback */
+    /* Prevent unused argument(s) compilation warning */
+    UNUSED(hcan);
+    /* NOTE : This function Should not be modified, when the callback is needed,
+       the HAL_CAN_ErrorCallback could be implemented in the user file
+    */
+}
+
+/**
+ * @brief  Transmission  complete callback in non blocking mode
+ * @param  hcan: pointer to a CAN_HandleTypeDef structure that contains
+ *         the configuration information for the specified CAN.
+ * @retval None
+ */
+void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
+{
+    switch((int)hcan->Instance)
+    {
+    case (int)CAN1:
+        /* User define */
+        break;
+    case (int)CAN2:
+        /* User define */
+        break;
+    }
+}
+
+/**
+ * @brief  Transmission  complete callback in non blocking mode
+ * @param  hcan: pointer to a CAN_HandleTypeDef structure that contains
+ *         the configuration information for the specified CAN.
+ * @retval None
+ */
+void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan)
+{
+    HAL_CAN_Receive_IT(hcan, CAN_FIFO0);
+    HAL_CAN_Receive_IT(hcan, CAN_FIFO1);
+}
+
+static rt_err_t drv_configure(struct rt_can_device *dev_can,
+                              struct can_configure *cfg)
+{
+    struct stm32_drv_can *drv_can;
+    rt_uint32_t baud_index;
+    CAN_InitTypeDef *drv_init;
+    CAN_FilterConfTypeDef *filterConf;
+
+    RT_ASSERT(dev_can);
+    RT_ASSERT(cfg);
+
+    drv_can = (struct stm32_drv_can *)dev_can->parent.user_data;
+    drv_init = &drv_can->CanHandle.Init;
+
+    drv_init->TTCM = DISABLE;
+    drv_init->ABOM = DISABLE;
+    drv_init->AWUM = DISABLE;
+    drv_init->NART = DISABLE;
+    drv_init->RFLM = DISABLE;
+    drv_init->TXFP = DISABLE;
+
+    switch (cfg->mode)
+    {
+    case RT_CAN_MODE_NORMAL:
+        drv_init->Mode = CAN_MODE_NORMAL;
+        break;
+    case RT_CAN_MODE_LISEN:
+        drv_init->Mode = CAN_MODE_SILENT;
+        break;
+    case RT_CAN_MODE_LOOPBACK:
+        drv_init->Mode = CAN_MODE_LOOPBACK;
+        break;
+    case RT_CAN_MODE_LOOPBACKANLISEN:
+        drv_init->Mode = CAN_MODE_SILENT_LOOPBACK;
+        break;
+    }
+
+    baud_index = get_can_baud_index(cfg->baud_rate);
+    drv_init->SJW = BAUD_DATA(SJW, baud_index);
+    drv_init->BS1 = BAUD_DATA(BS1, baud_index);
+    drv_init->BS2 = BAUD_DATA(BS2, baud_index);
+    drv_init->Prescaler = BAUD_DATA(RRESCL, baud_index);
+    if (HAL_CAN_Init(&drv_can->CanHandle) != HAL_OK)
+    {
+        return RT_ERROR;
+    }
+
+    /* Filter conf */
+    filterConf = &drv_can->FilterConfig;
+    filterConf->FilterNumber = 0;
+    filterConf->FilterMode = CAN_FILTERMODE_IDMASK;
+    filterConf->FilterScale = CAN_FILTERSCALE_32BIT;
+    filterConf->FilterIdHigh = 0x0000;
+    filterConf->FilterIdLow = 0x0000;
+    filterConf->FilterMaskIdHigh = 0x0000;
+    filterConf->FilterMaskIdLow = 0x0000;
+    filterConf->FilterFIFOAssignment = 0;
+    filterConf->FilterActivation = ENABLE;
+    filterConf->BankNumber = 14;
+    HAL_CAN_ConfigFilter(&drv_can->CanHandle, filterConf);
+
+    return RT_EOK;
+}
+
+static rt_err_t drv_control(struct rt_can_device *can, int cmd, void *arg)
+{
+    struct stm32_drv_can *drv_can;
+    rt_uint32_t argval;
+
+    drv_can = (struct stm32_drv_can *) can->parent.user_data;
+    assert_param(drv_can != RT_NULL);
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_CLR_INT:
+        argval = (rt_uint32_t) arg;
+        if (argval == RT_DEVICE_FLAG_INT_RX)
+        {
+            if (CAN1 == drv_can->CanHandle.Instance) {
+                HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
+                HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
+            }
+            else
+            {
+                HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
+                HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
+            }
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_FMP0);
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_FF0 );
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_FOV0);
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_FMP1);
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_FF1 );
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_FOV1);
+        }
+        else if (argval == RT_DEVICE_FLAG_INT_TX)
+        {
+            if (CAN1 == drv_can->CanHandle.Instance)
+            {
+                HAL_NVIC_DisableIRQ(CAN1_TX_IRQn);
+            }
+            else
+            {
+                HAL_NVIC_DisableIRQ(CAN2_TX_IRQn);
+            }
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_TME);
+        }
+        else if (argval == RT_DEVICE_CAN_INT_ERR)
+        {
+            if (CAN1 == drv_can->CanHandle.Instance)
+            {
+                NVIC_DisableIRQ(CAN1_SCE_IRQn);
+            }
+            else
+            {
+                NVIC_DisableIRQ(CAN2_SCE_IRQn);
+            }
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_BOF);
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_LEC);
+            __HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_ERR);
+        }
+        break;
+    case RT_DEVICE_CTRL_SET_INT:
+        argval = (rt_uint32_t) arg;
+        if (argval == RT_DEVICE_FLAG_INT_RX)
+        {
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_FMP0);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_FF0);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_FOV0);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_FMP1);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_FF1);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_FOV1);
+
+            if (CAN1 == drv_can->CanHandle.Instance)
+            {
+                HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
+                HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
+            }
+            else
+            {
+                HAL_NVIC_SetPriority(CAN2_RX0_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN2_RX0_IRQn);
+                HAL_NVIC_SetPriority(CAN2_RX1_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN2_RX1_IRQn);
+            }
+        }
+        else if (argval == RT_DEVICE_FLAG_INT_TX)
+        {
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_TME);
+
+            if (CAN1 == drv_can->CanHandle.Instance)
+            {
+                HAL_NVIC_SetPriority(CAN1_TX_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
+            }
+            else
+            {
+                HAL_NVIC_SetPriority(CAN2_TX_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN2_TX_IRQn);
+            }
+        }
+        else if (argval == RT_DEVICE_CAN_INT_ERR)
+        {
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_BOF);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_LEC);
+            __HAL_CAN_ENABLE_IT(&drv_can->CanHandle, CAN_IT_ERR);
+
+            if (CAN1 == drv_can->CanHandle.Instance)
+            {
+                HAL_NVIC_SetPriority(CAN1_SCE_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN1_SCE_IRQn);
+            }
+            else
+            {
+                HAL_NVIC_SetPriority(CAN2_SCE_IRQn, 1, 0);
+                HAL_NVIC_EnableIRQ(CAN2_SCE_IRQn);
+            }
+        }
+        break;
+    case RT_CAN_CMD_SET_FILTER:
+        /* TODO: filter*/
+        break;
+    case RT_CAN_CMD_SET_MODE:
+        argval = (rt_uint32_t) arg;
+        if (argval != RT_CAN_MODE_NORMAL ||
+            argval != RT_CAN_MODE_LISEN ||
+            argval != RT_CAN_MODE_LOOPBACK ||
+            argval != RT_CAN_MODE_LOOPBACKANLISEN)
+        {
+            return RT_ERROR;
+        }
+        if (argval != can->config.mode)
+        {
+            can->config.mode = argval;
+            if (HAL_CAN_Init(&drv_can->CanHandle) != HAL_OK)
+            {
+                return RT_ERROR;
+            }
+        }
+        break;
+    case RT_CAN_CMD_SET_BAUD:
+        argval = (rt_uint32_t) arg;
+        if (argval != CAN1MBaud &&
+            argval != CAN800kBaud &&
+            argval != CAN500kBaud &&
+            argval != CAN250kBaud &&
+            argval != CAN125kBaud &&
+            argval != CAN100kBaud &&
+            argval != CAN50kBaud  &&
+            argval != CAN20kBaud  &&
+            argval != CAN10kBaud)
+        {
+            return RT_ERROR;
+        }
+        if (argval != can->config.baud_rate)
+        {
+            CAN_InitTypeDef *drv_init;
+            rt_uint32_t baud_index;
+
+            can->config.baud_rate = argval;
+
+            drv_init = &drv_can->CanHandle.Init;
+
+            drv_init->TTCM = DISABLE;
+            drv_init->ABOM = DISABLE;
+            drv_init->AWUM = DISABLE;
+            drv_init->NART = DISABLE;
+            drv_init->RFLM = DISABLE;
+            drv_init->TXFP = DISABLE;
+            baud_index = get_can_baud_index(can->config.baud_rate);
+            drv_init->SJW = BAUD_DATA(SJW, baud_index);
+            drv_init->BS1 = BAUD_DATA(BS1, baud_index);
+            drv_init->BS2 = BAUD_DATA(BS2, baud_index);
+            drv_init->Prescaler = BAUD_DATA(RRESCL, baud_index);
+
+            if (HAL_CAN_Init(&drv_can->CanHandle) != HAL_OK)
+            {
+                return RT_ERROR;
+            }
+        }
+        break;
+    case RT_CAN_CMD_SET_PRIV:
+        argval = (rt_uint32_t) arg;
+        if (argval != RT_CAN_MODE_PRIV ||
+            argval != RT_CAN_MODE_NOPRIV)
+        {
+            return RT_ERROR;
+        }
+        if (argval != can->config.privmode)
+        {
+            can->config.privmode = argval;
+            if (HAL_CAN_Init(&drv_can->CanHandle) != HAL_OK)
+            {
+                return RT_ERROR;
+            }
+        }
+        break;
+    case RT_CAN_CMD_GET_STATUS:
+    {
+        rt_uint32_t errtype;
+        errtype = drv_can->CanHandle.Instance->ESR;
+        can->status.rcverrcnt = errtype >> 24;
+        can->status.snderrcnt = (errtype >> 16 & 0xFF);
+        can->status.errcode = errtype & 0x07;
+        if (arg != &can->status)
+        {
+            rt_memcpy(arg, &can->status, sizeof(can->status));
+        }
+    }
+    break;
+    }
+
+    return RT_EOK;
+}
+
+static int drv_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno)
+{
+    CAN_HandleTypeDef *hcan;
+    struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
+
+    hcan = &((struct stm32_drv_can *) can->parent.user_data)->CanHandle;
+    hcan->pTxMsg->StdId = pmsg->id;
+    hcan->pTxMsg->RTR = pmsg->rtr;
+    hcan->pTxMsg->IDE = pmsg->ide;
+    hcan->pTxMsg->DLC = pmsg->len;
+    rt_memset(&hcan->pTxMsg->Data, 0x00, 8);
+    /* rt_memcpy(&hcan->pTxMsg->Data, &pmsg->data, 8); */
+    hcan->pTxMsg->Data[0] = pmsg->data[0];
+    hcan->pTxMsg->Data[1] = pmsg->data[1];
+    hcan->pTxMsg->Data[2] = pmsg->data[2];
+    hcan->pTxMsg->Data[3] = pmsg->data[3];
+    hcan->pTxMsg->Data[4] = pmsg->data[4];
+    hcan->pTxMsg->Data[5] = pmsg->data[5];
+    hcan->pTxMsg->Data[6] = pmsg->data[6];
+    hcan->pTxMsg->Data[7] = pmsg->data[7];
+    HAL_CAN_Transmit_IT(hcan);
+
+    return RT_EOK;
+}
+
+static int drv_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno)
+{
+    CAN_HandleTypeDef *hcan;
+    struct rt_can_msg *pmsg = (struct rt_can_msg *) buf;
+    hcan = &((struct stm32_drv_can *) can->parent.user_data)->CanHandle;
+
+    pmsg->id = hcan->pRxMsg->StdId;
+    pmsg->rtr = hcan->pRxMsg->RTR;
+    pmsg->ide = hcan->pRxMsg->IDE;
+    pmsg->len = hcan->pRxMsg->DLC;
+    /* rt_memcpy(&pmsg->data, &hcan->pRxMsg->Data, 8); */
+    pmsg->data[0] = hcan->pRxMsg->Data[0];
+    pmsg->data[1] = hcan->pRxMsg->Data[1];
+    pmsg->data[2] = hcan->pRxMsg->Data[2];
+    pmsg->data[3] = hcan->pRxMsg->Data[3];
+    pmsg->data[4] = hcan->pRxMsg->Data[4];
+    pmsg->data[5] = hcan->pRxMsg->Data[5];
+    pmsg->data[6] = hcan->pRxMsg->Data[6];
+    pmsg->data[7] = hcan->pRxMsg->Data[7];
+
+    return RT_EOK;
+}
+
+static const struct rt_can_ops drv_can_ops =
+{
+    drv_configure,
+    drv_control,
+    drv_sendmsg,
+    drv_recvmsg,
+};
+
+void HAL_CAN_MspInit(CAN_HandleTypeDef* canHandle)
+{
+    GPIO_InitTypeDef GPIO_InitStruct;
+    if(canHandle->Instance==CAN1)
+    {
+        /* CAN1 clock enable */
+        __HAL_RCC_CAN1_CLK_ENABLE();
+        __HAL_RCC_GPIOD_CLK_ENABLE();
+
+        /**CAN1 GPIO Configuration
+           PD0     ------> CAN1_RX
+           PD1     ------> CAN1_TX
+        */
+        GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
+        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+        GPIO_InitStruct.Alternate = GPIO_AF9_CAN1;
+        HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
+
+
+    }
+    else if(canHandle->Instance==CAN2)
+    {
+        /* CAN2 clock enable */
+        __HAL_RCC_CAN2_CLK_ENABLE();
+        __HAL_RCC_GPIOB_CLK_ENABLE();
+
+        /**CAN2 GPIO Configuration
+           PB12     ------> CAN2_RX
+           PB6     ------> CAN2_TX
+        */
+        GPIO_InitStruct.Pin = GPIO_PIN_12|GPIO_PIN_6;
+        GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
+        GPIO_InitStruct.Pull = GPIO_NOPULL;
+        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
+        GPIO_InitStruct.Alternate = GPIO_AF9_CAN2;
+        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
+
+
+    }
+}
+
+void HAL_CAN_MspDeInit(CAN_HandleTypeDef* canHandle)
+{
+
+    if(canHandle->Instance==CAN1)
+    {
+        /* Peripheral clock disable */
+        __HAL_RCC_CAN1_CLK_DISABLE();
+
+        /**CAN1 GPIO Configuration
+           PD0     ------> CAN1_RX
+           PD1     ------> CAN1_TX
+        */
+        HAL_GPIO_DeInit(GPIOD, GPIO_PIN_0|GPIO_PIN_2);
+        HAL_NVIC_DisableIRQ(CAN1_TX_IRQn);
+        HAL_NVIC_DisableIRQ(CAN1_RX0_IRQn);
+        HAL_NVIC_DisableIRQ(CAN1_RX1_IRQn);
+    }
+    else if(canHandle->Instance==CAN2)
+    {
+        __HAL_RCC_CAN2_CLK_DISABLE();
+
+        /**CAN2 GPIO Configuration
+           PB12     ------> CAN2_RX
+           PB6     ------> CAN2_TX
+        */
+        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_12|GPIO_PIN_6);
+
+        HAL_NVIC_DisableIRQ(CAN2_TX_IRQn);
+        HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
+        HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
+    }
+}
+
+int hw_can_init(void)
+{
+    struct stm32_drv_can *drv_can;
+    struct can_configure config = CANDEFAULTCONFIG;
+
+    config.privmode = 0;
+    config.ticks = 50;
+    config.sndboxnumber = 3;
+#ifdef RT_CAN_USING_HDR
+    config.maxhdr = 28;
+#endif
+
+#ifdef USING_BXCAN1
+    drv_can = &drv_can1;
+    drv_can->CanHandle.Instance = CAN1;
+    drv_can->CanHandle.pTxMsg = &drv_can->TxMessage;
+    drv_can->CanHandle.pRxMsg = &drv_can->RxMessage;
+    dev_can1.ops    = &drv_can_ops;
+    dev_can1.config = config;
+    /* register CAN1 device */
+    rt_hw_can_register(&dev_can1, "can1",
+                       &drv_can_ops,
+                       drv_can);
+#endif /* USING_BXCAN1 */
+
+#ifdef USING_BXCAN2
+    drv_can = &drv_can2;
+    drv_can->CanHandle.Instance = CAN2;
+    drv_can->CanHandle.pTxMsg = &drv_can->TxMessage;
+    drv_can->CanHandle.pRxMsg = &drv_can->RxMessage;
+    dev_can2.ops    = &drv_can_ops;
+    dev_can2.config = config;
+    /* register CAN2 device */
+    rt_hw_can_register(&dev_can2, "can2",
+                       &drv_can_ops,
+                       drv_can);
+#endif /* USING_BXCAN2 */
+
+    return 0;
+}
+
+INIT_BOARD_EXPORT(hw_can_init);
+

+ 23 - 0
bsp/stm32f4xx-HAL/drivers/drv_can.h

@@ -0,0 +1,23 @@
+/*
+ * File      : drv_can.h
+ * This file is part of RT-Thread RTOS
+ * COPYRIGHT (C) 2018, RT-Thread Development Team
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rt-thread.org/license/LICENSE
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2018-08-05     Xeon Xu      the first version
+ */
+#ifndef __CAN_H__
+#define __CAN_H__
+#ifdef __cplusplus
+ extern "C" {
+#endif
+extern int hw_can_init(void);
+#ifdef __cplusplus
+ }
+#endif
+#endif /*__CAN_H__ */

+ 3 - 1
bsp/stm32f4xx-HAL/drivers/stm32f4xx_hal_conf.h

@@ -52,7 +52,9 @@ extern "C" {
   */
 #define HAL_MODULE_ENABLED
 /* #define HAL_ADC_MODULE_ENABLED      */
-/* #define HAL_CAN_MODULE_ENABLED      */
+#ifdef RT_USING_CAN
+#define HAL_CAN_MODULE_ENABLED
+#endif
 /* #define HAL_CRC_MODULE_ENABLED      */
 /* #define HAL_CRYP_MODULE_ENABLED     */
 /* #define HAL_DAC_MODULE_ENABLED      */