Browse Source

Merge pull request #2819 from misonyo/rttdev

[bsp/imxrt]add can driver
Bernard Xiong 6 years ago
parent
commit
c5543593e2

+ 1 - 1
bsp/imxrt/Libraries/MIMXRT1050/SConscript

@@ -55,7 +55,7 @@ if GetDepend(['BSP_USING_LCD']):
 if GetDepend(['RT_USING_USB_HOST']) or GetDepend(['RT_USING_USB_DEVICE']):
     src += ['MIMXRT1052/drivers/fsl_usdhc.c']
 
-if GetDepend(['RT_USING_CAN']):
+if GetDepend(['BSP_USING_CAN']):
     src += ['MIMXRT1052/drivers/fsl_flexcan.c']
 
 if GetDepend(['BSP_USING_ETH']):

+ 3 - 0
bsp/imxrt/Libraries/drivers/SConscript

@@ -31,6 +31,9 @@ if GetDepend('BSP_USING_PWM'):
 if GetDepend('BSP_USING_ADC'):
     src += ['drv_adc.c']
 
+if GetDepend('BSP_USING_CAN'):
+    src += ['drv_can.c']
+    
 if GetDepend('BSP_USING_SDRAM'):
     src += ['drv_sdram.c']
 

+ 461 - 0
bsp/imxrt/Libraries/drivers/drv_can.c

@@ -0,0 +1,461 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-06-27     misonyo     the first version.
+ */
+
+#include <rtthread.h>
+#ifdef BSP_USING_CAN
+
+#include <rtdevice.h>
+#include "drv_can.h"
+#include "fsl_common.h"
+#include "fsl_iomuxc.h"
+#include "fsl_flexcan.h"
+
+#define LOG_TAG    "drv.can"
+#include <drv_log.h>
+
+#if defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL
+    #error "Please don't define 'FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL'!"
+#endif
+
+#define RX_MB_COUNT     32
+static flexcan_frame_t frame[RX_MB_COUNT];    /* one frame buffer per RX MB */
+static rt_uint32_t filter_mask = 0;
+
+enum
+{
+#ifdef BSP_USING_CAN1
+    CAN1_INDEX,
+#endif
+#ifdef BSP_USING_CAN2
+    CAN2_INDEX,
+#endif
+};
+
+struct imxrt_can
+{
+    char *name;
+    CAN_Type *base;
+    IRQn_Type irqn;
+    flexcan_handle_t handle;
+    struct rt_can_device can_dev;
+};
+
+struct imxrt_can flexcans[] =
+{
+#ifdef BSP_USING_CAN1
+    {
+        .name = "can1",
+        .base = CAN1,
+        .irqn = CAN1_IRQn,
+    },
+#endif
+#ifdef BSP_USING_CAN2
+    {
+        .name = "can2",
+        .base = CAN2,
+        .irqn = CAN2_IRQn,
+    },
+#endif
+};
+
+uint32_t GetCanSrcFreq(void)
+{
+    uint32_t freq;
+
+    freq = (CLOCK_GetFreq(kCLOCK_Usb1PllClk) / 6) / (CLOCK_GetDiv(kCLOCK_CanDiv) + 1U);
+
+    return freq;
+}
+
+static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData)
+{
+    struct imxrt_can *can;
+    flexcan_mb_transfer_t rxXfer;
+
+    can = (struct imxrt_can *)userData;
+
+    switch (status)
+    {
+    case kStatus_FLEXCAN_RxIdle:
+        rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_RX_IND | result << 8);
+        rxXfer.frame = &frame[result - 1];
+        rxXfer.mbIdx = result;
+        FLEXCAN_TransferReceiveNonBlocking(can->base, &can->handle, &rxXfer);
+        break;
+
+    case kStatus_FLEXCAN_TxIdle:
+        rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_DONE | (63 - result) << 8);
+        break;
+
+    case kStatus_FLEXCAN_WakeUp:
+
+    case kStatus_FLEXCAN_ErrorStatus:
+        if ((result >= 47) && (result <= 63))
+        {
+            rt_hw_can_isr(&can->can_dev, RT_CAN_EVENT_TX_FAIL | (63 - result) << 8);
+        }
+        break;
+
+    case kStatus_FLEXCAN_TxSwitchToRx:
+        break;
+
+    default:
+        break;
+    }
+}
+
+static rt_err_t can_cfg(struct rt_can_device *can_dev, struct can_configure *cfg)
+{
+    struct imxrt_can *can;
+    flexcan_config_t config;
+    rt_uint32_t res = RT_EOK;
+    flexcan_rx_mb_config_t mbConfig;
+    flexcan_mb_transfer_t rxXfer;
+    rt_uint8_t i, mailbox;
+
+    RT_ASSERT(can_dev != RT_NULL);
+    RT_ASSERT(cfg != RT_NULL);
+
+    can = (struct imxrt_can *)can_dev->parent.user_data;
+    RT_ASSERT(can != RT_NULL);
+
+    FLEXCAN_GetDefaultConfig(&config);
+    config.baudRate = cfg->baud_rate;
+    config.maxMbNum = 64;               /* all series have 64 MB */
+    config.enableIndividMask = true;    /* one filter per MB */
+    switch (cfg->mode)
+    {
+    case RT_CAN_MODE_NORMAL:
+        /* default mode */
+        break;
+    case RT_CAN_MODE_LISEN:
+        break;
+    case RT_CAN_MODE_LOOPBACK:
+        config.enableLoopBack = true;
+        break;
+    case RT_CAN_MODE_LOOPBACKANLISEN:
+        break;
+    }
+    FLEXCAN_Init(can->base, &config, GetCanSrcFreq());
+    FLEXCAN_TransferCreateHandle(can->base, &can->handle, flexcan_callback, can);
+    /* init RX_MB_COUNT RX MB to default status */
+    mbConfig.format = kFLEXCAN_FrameFormatStandard;  /* standard ID */
+    mbConfig.type = kFLEXCAN_FrameTypeData;          /* data frame */
+    mbConfig.id = FLEXCAN_ID_STD(0);                 /* default ID is 0 */
+    for (i = 0; i < RX_MB_COUNT; i++)
+    {
+        /* the used MB index from 1 to RX_MB_COUNT */
+        mailbox = i + 1;
+        /* all ID bit in the filter is "don't care" */
+        FLEXCAN_SetRxIndividualMask(can->base, mailbox, FLEXCAN_RX_MB_STD_MASK(0, 0, 0));
+        FLEXCAN_SetRxMbConfig(can->base, mailbox, &mbConfig, true);
+        /* one frame buffer per MB */
+        rxXfer.frame = &frame[i];
+        rxXfer.mbIdx = mailbox;
+        FLEXCAN_TransferReceiveNonBlocking(can->base, &can->handle, &rxXfer);
+    }
+
+    return res;
+}
+
+static rt_err_t can_control(struct rt_can_device *can_dev, int cmd, void *arg)
+{
+    struct imxrt_can *can;
+    rt_uint32_t argval, mask;
+    rt_uint32_t res = RT_EOK;
+    flexcan_rx_mb_config_t mbConfig;
+    struct rt_can_filter_config  *cfg;
+    struct rt_can_filter_item *item;
+    rt_uint8_t i, count, index;
+
+    RT_ASSERT(can_dev != RT_NULL);
+
+    can = (struct imxrt_can *)can_dev->parent.user_data;
+    RT_ASSERT(can != RT_NULL);
+
+    switch (cmd)
+    {
+    case RT_DEVICE_CTRL_SET_INT:
+        argval = (rt_uint32_t) arg;
+        if (argval == RT_DEVICE_FLAG_INT_RX)
+        {
+            mask = kFLEXCAN_RxWarningInterruptEnable;
+        }
+        else if (argval == RT_DEVICE_FLAG_INT_TX)
+        {
+            mask = kFLEXCAN_TxWarningInterruptEnable;
+        }
+        else if (argval == RT_DEVICE_CAN_INT_ERR)
+        {
+            mask = kFLEXCAN_ErrorInterruptEnable;
+        }
+        FLEXCAN_EnableInterrupts(can->base, mask);
+        NVIC_SetPriority(can->irqn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 5, 0));
+        EnableIRQ(can->irqn);
+        break;
+    case RT_DEVICE_CTRL_CLR_INT:
+        /* each CAN device have one IRQ number. */
+        DisableIRQ(can->irqn);
+        break;
+    case RT_CAN_CMD_SET_FILTER:
+        cfg = (struct rt_can_filter_config *)arg;
+        item = cfg->items;
+        count = cfg->count;
+
+        if (filter_mask == 0xffffffff)
+        {
+            LOG_E("%s filter is full!\n", can->name);
+            res = RT_ERROR;
+            break;
+        }
+        else if (filter_mask == 0)
+        {
+            /* deinit all init RX MB */
+            for (i = 0; i < RX_MB_COUNT; i++)
+            {
+                FLEXCAN_SetRxMbConfig(can->base, i + 1, RT_NULL, false);
+            }
+        }
+
+        while (count)
+        {
+            if (item->ide)
+            {
+                mbConfig.format = kFLEXCAN_FrameFormatExtend;
+                mbConfig.id = FLEXCAN_ID_EXT(item->id);
+                mask = FLEXCAN_RX_MB_EXT_MASK(item->mask, 0, 0);
+            }
+            else
+            {
+                mbConfig.format = kFLEXCAN_FrameFormatStandard;
+                mbConfig.id = FLEXCAN_ID_STD(item->id);
+                mask = FLEXCAN_RX_MB_STD_MASK(item->mask, 0, 0);
+            }
+
+            if (item->rtr)
+            {
+                mbConfig.type = kFLEXCAN_FrameTypeRemote;
+            }
+            else
+            {
+                mbConfig.type = kFLEXCAN_FrameTypeData;
+            }
+
+            /* user does not specify hdr index,set hdr from RX MB 1 */
+            if (item->hdr == -1)
+            {
+
+                for (i = 0; i < 32; i++)
+                {
+                    if (!(filter_mask & (1 << i)))
+                    {
+                        index = i;
+                        break;
+                    }
+                }
+            }
+            else    /* use user specified hdr */
+            {
+                if (filter_mask & (1 << item->hdr))
+                {
+                    res = RT_ERROR;
+                    LOG_E("%s hdr%d filter already set!\n", can->name, item->hdr);
+                    break;
+                }
+                else
+                {
+                    index = item->hdr;
+                }
+            }
+
+            /* RX MB index from 1 to 32,hdr index 0~31 map RX MB index 1~32. */
+            FLEXCAN_SetRxIndividualMask(can->base, index + 1, mask);
+            FLEXCAN_SetRxMbConfig(can->base, index + 1, &mbConfig, true);
+            filter_mask |= 1 << index;
+
+            item++;
+            count--;
+        }
+
+        break;
+
+    case RT_CAN_CMD_SET_BAUD:
+        res = RT_ERROR;
+        break;
+    case RT_CAN_CMD_SET_MODE:
+        res = RT_ERROR;
+        break;
+
+    case RT_CAN_CMD_SET_PRIV:
+        res = RT_ERROR;
+        break;
+    case RT_CAN_CMD_GET_STATUS:
+        FLEXCAN_GetBusErrCount(can->base, (rt_uint8_t *)(&can->can_dev.status.snderrcnt), (rt_uint8_t *)(&can->can_dev.status.rcverrcnt));
+        rt_memcpy(arg, &can->can_dev.status, sizeof(can->can_dev.status));
+        break;
+    default:
+        res = RT_ERROR;
+        break;
+    }
+
+    return res;
+}
+
+static int can_send(struct rt_can_device *can_dev, const void *buf, rt_uint32_t boxno)
+{
+    struct imxrt_can *can;
+    struct rt_can_msg *msg;
+    status_t ret;
+    flexcan_frame_t frame;
+    flexcan_mb_transfer_t txXfer;
+    rt_uint8_t sendMB;
+
+    RT_ASSERT(can_dev != RT_NULL);
+    RT_ASSERT(buf != RT_NULL);
+
+    can = (struct imxrt_can *)can_dev->parent.user_data;
+    msg = (struct rt_can_msg *) buf;
+    RT_ASSERT(can != RT_NULL);
+    RT_ASSERT(msg != RT_NULL);
+
+    /* use the last 16 MB to send msg */
+    sendMB = 63 - boxno;
+    FLEXCAN_SetTxMbConfig(can->base, sendMB, true);
+
+    if (RT_CAN_STDID == msg->ide)
+    {
+        frame.id = FLEXCAN_ID_STD(msg->id);
+        frame.format = kFLEXCAN_FrameFormatStandard;
+    }
+    else if (RT_CAN_EXTID == msg->ide)
+    {
+        frame.id = FLEXCAN_ID_EXT(msg->id);
+        frame.format = kFLEXCAN_FrameFormatExtend;
+    }
+
+    if (RT_CAN_DTR == msg->rtr)
+    {
+        frame.type = kFLEXCAN_FrameTypeData;
+    }
+    else if (RT_CAN_RTR == msg->rtr)
+    {
+        frame.type = kFLEXCAN_FrameTypeRemote;
+    }
+
+    frame.length = msg->len;
+    frame.dataByte0 = msg->data[0];
+    frame.dataByte1 = msg->data[1];
+    frame.dataByte2 = msg->data[2];
+    frame.dataByte3 = msg->data[3];
+    frame.dataByte4 = msg->data[4];
+    frame.dataByte5 = msg->data[5];
+    frame.dataByte6 = msg->data[6];
+    frame.dataByte7 = msg->data[7];
+
+    txXfer.mbIdx = sendMB;
+    txXfer.frame = &frame;
+
+    ret = FLEXCAN_TransferSendNonBlocking(can->base, &can->handle, &txXfer);
+    switch (ret)
+    {
+    case kStatus_Success:
+        ret = RT_EOK;
+        break;
+    case kStatus_Fail:
+        ret = RT_ERROR;
+        break;
+    case kStatus_FLEXCAN_TxBusy:
+        ret = RT_EBUSY;
+        break;
+    }
+    
+    return ret;
+}
+
+static int can_recv(struct rt_can_device *can_dev, void *buf, rt_uint32_t boxno)
+{
+    struct imxrt_can *can;
+    struct rt_can_msg *pmsg;
+    rt_uint8_t index;
+
+    RT_ASSERT(can_dev != RT_NULL);
+
+    can = (struct imxrt_can *)can_dev->parent.user_data;
+    pmsg = (struct rt_can_msg *) buf;
+    RT_ASSERT(can != RT_NULL);
+
+    index = boxno - 1;
+
+    if (frame[index].format == kFLEXCAN_FrameFormatStandard)
+    {
+        pmsg->ide = RT_CAN_STDID;
+        pmsg->id = frame[index].id >> CAN_ID_STD_SHIFT;
+    }
+    else
+    {
+        pmsg->ide = RT_CAN_EXTID;
+        pmsg->id = frame[index].id >> CAN_ID_EXT_SHIFT;
+    }
+
+    if (frame[index].type == kFLEXCAN_FrameTypeData)
+    {
+        pmsg->rtr = RT_CAN_DTR;
+    }
+    else if (frame[index].type == kFLEXCAN_FrameTypeRemote)
+    {
+        pmsg->rtr = RT_CAN_RTR;
+    }
+    pmsg->hdr = index;      /* one hdr filter per MB */
+    pmsg->len = frame[index].length;
+    pmsg->data[0] = frame[index].dataByte0;
+    pmsg->data[1] = frame[index].dataByte1;
+    pmsg->data[2] = frame[index].dataByte2;
+    pmsg->data[3] = frame[index].dataByte3;
+    pmsg->data[4] = frame[index].dataByte4;
+    pmsg->data[5] = frame[index].dataByte5;
+    pmsg->data[6] = frame[index].dataByte6;
+    pmsg->data[7] = frame[index].dataByte7;
+
+    return 0;
+}
+
+static struct rt_can_ops imxrt_can_ops =
+{
+    .configure    = can_cfg,
+    .control      = can_control,
+    .sendmsg      = can_send,
+    .recvmsg      = can_recv,
+};
+
+int rt_hw_can_init(void)
+{
+    int i;
+    rt_err_t ret = RT_EOK;
+    struct can_configure config = CANDEFAULTCONFIG;
+
+    config.privmode = 0;
+    config.ticks = 50;
+    config.sndboxnumber = 16;             /* send Mailbox count */
+    config.msgboxsz = RX_MB_COUNT;        /* RX msg buffer count */
+#ifdef RT_CAN_USING_HDR
+    config.maxhdr = RX_MB_COUNT;          /* filter count,one filter per MB */
+#endif
+
+    for (i = 0; i < sizeof(flexcans) / sizeof(flexcans[0]); i++)
+    {
+        flexcans[i].can_dev.config = config;
+        ret = rt_hw_can_register(&flexcans[i].can_dev, flexcans[i].name, &imxrt_can_ops, &flexcans[i]);
+    }
+
+    return ret;
+}
+INIT_BOARD_EXPORT(rt_hw_can_init);
+
+#endif /* BSP_USING_CAN */

+ 16 - 0
bsp/imxrt/Libraries/drivers/drv_can.h

@@ -0,0 +1,16 @@
+/*
+ * Copyright (c) 2006-2018, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date           Author       Notes
+ * 2019-06-28     misonyo     the first version.
+ */
+ 
+#ifndef DRV_SPI_H__
+#define DRV_SPI_H__
+
+int rt_hw_can_init(void);
+
+#endif /* DRV_SPI_H__ */

+ 1 - 0
bsp/imxrt/imxrt1052-fire-pro/README.md

@@ -54,6 +54,7 @@ i.MX RT1052 EVK Pro 是野火推出的一款基于 ARM Cortex-M7 内核的开发
 | WDT               |     支持     |                                       |
 | PWM               |     支持 |                              |
 | GPT               |     支持 |                              |
+| CAN               |     支持 |        CAN1                      |
 
 ## 使用说明
 

+ 11 - 0
bsp/imxrt/imxrt1052-fire-pro/board/Kconfig

@@ -16,6 +16,17 @@ menu "On-chip Peripheral Drivers"
         select RT_USING_PIN
         default y
 
+    menuconfig BSP_USING_CAN
+        bool "Enable CAN"
+        select RT_USING_CAN
+        default n
+
+        if BSP_USING_CAN
+            config BSP_USING_CAN1
+                bool "Enable CAN1"
+                default y
+        endif
+
     menuconfig BSP_USING_LPUART
         bool "Enable UART"
         select RT_USING_SERIAL

+ 3 - 2
bsp/imxrt/imxrt1052-fire-pro/board/MCUX_Config/clock_config.c

@@ -53,7 +53,7 @@ name: BOARD_BootClockRUN
 called_from_default_init: true
 outputs:
 - {id: AHB_CLK_ROOT.outFreq, value: 600 MHz}
-- {id: CAN_CLK_ROOT.outFreq, value: 40 MHz}
+- {id: CAN_CLK_ROOT.outFreq, value: 20 MHz}
 - {id: CKIL_SYNC_CLK_ROOT.outFreq, value: 32.768 kHz}
 - {id: CLK_1M.outFreq, value: 1 MHz}
 - {id: CLK_24M.outFreq, value: 24 MHz}
@@ -93,6 +93,7 @@ outputs:
 settings:
 - {id: CCM.AHB_PODF.scale, value: '1', locked: true}
 - {id: CCM.ARM_PODF.scale, value: '2', locked: true}
+- {id: CCM.CAN_CLK_PODF.scale, value: '4', locked: true}
 - {id: CCM.FLEXSPI_PODF.scale, value: '1', locked: true}
 - {id: CCM.FLEXSPI_SEL.sel, value: CCM_ANALOG.PLL3_PFD0_CLK}
 - {id: CCM.LCDIF_PODF.scale, value: '8', locked: true}
@@ -297,7 +298,7 @@ void BOARD_BootClockRUN(void)
     CLOCK_DisableClock(kCLOCK_Can1S);
     CLOCK_DisableClock(kCLOCK_Can2S);
     /* Set CAN_CLK_PODF. */
-    CLOCK_SetDiv(kCLOCK_CanDiv, 1);
+    CLOCK_SetDiv(kCLOCK_CanDiv, 3);
     /* Set Can clock source. */
     CLOCK_SetMux(kCLOCK_CanMux, 2);
     /* Disable UART clock gate. */

+ 26 - 0
bsp/imxrt/imxrt1052-fire-pro/board/MCUX_Config/pin_mux.c

@@ -110,6 +110,32 @@ void BOARD_InitPins(void) {
   IOMUXC_SetPinMux(
       IOMUXC_GPIO_B1_13_LPUART5_RX,           /* GPIO_B1_13 is configured as LPUART5_RX */
       0U);                                    /* Software Input On Field: Input Path is determined by functionality */
+  IOMUXC_SetPinMux(
+      IOMUXC_GPIO_AD_B0_14_FLEXCAN2_TX,       /* GPIO_AD_B0_14 is configured as FLEXCAN2_TX */
+      1U);                                    /* Software Input On Field: Force input path of pad GPIO_AD_B0_14 */
+  IOMUXC_SetPinMux(
+      IOMUXC_GPIO_AD_B0_15_FLEXCAN2_RX,       /* GPIO_AD_B0_15 is configured as FLEXCAN2_RX */
+      1U);                                    /* Software Input On Field: Force input path of pad GPIO_AD_B0_15 */
+  IOMUXC_SetPinConfig(
+      IOMUXC_GPIO_AD_B0_14_FLEXCAN2_TX,       /* GPIO_AD_B0_14 PAD functional properties : */
+      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
+                                                 Drive Strength Field: R0/6
+                                                 Speed Field: medium(100MHz)
+                                                 Open Drain Enable Field: Open Drain Disabled
+                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
+                                                 Pull / Keep Select Field: Keeper
+                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
+                                                 Hyst. Enable Field: Hysteresis Disabled */
+  IOMUXC_SetPinConfig(
+      IOMUXC_GPIO_AD_B0_15_FLEXCAN2_RX,       /* GPIO_AD_B0_15 PAD functional properties : */
+      0x10B0u);                               /* Slew Rate Field: Slow Slew Rate
+                                                 Drive Strength Field: R0/6
+                                                 Speed Field: medium(100MHz)
+                                                 Open Drain Enable Field: Open Drain Disabled
+                                                 Pull / Keep Enable Field: Pull/Keeper Enabled
+                                                 Pull / Keep Select Field: Keeper
+                                                 Pull Up / Down Config. Field: 100K Ohm Pull Down
+                                                 Hyst. Enable Field: Hysteresis Disabled */
 }
 
 /***********************************************************************************************************************

+ 4 - 0
bsp/imxrt/imxrt1052-fire-pro/rtconfig.h

@@ -78,6 +78,8 @@
 #define RT_USING_SERIAL
 #define RT_SERIAL_USING_DMA
 #define RT_SERIAL_RB_BUFSZ 64
+#define RT_USING_CAN
+#define RT_CAN_USING_HDR
 #define RT_USING_CPUTIME
 #define RT_USING_PIN
 
@@ -158,6 +160,8 @@
 /* On-chip Peripheral Drivers */
 
 #define BSP_USING_GPIO
+#define BSP_USING_CAN
+#define BSP_USING_CAN2
 #define BSP_USING_LPUART
 #define BSP_USING_LPUART1