在RT-Thread中给STM32F413添加CAN3
简介
目前最新的RT-Thread v4.0.2并不能直接支持STM32F413的CAN3,从配置项添加的CAN驱动只能够支持CAN1 / CAN2,而F413的CAN3需要我们手动添加。
创建STM32F413工程
首先新建一个工程stm32f413-xxx-xxx
复制模板代码bsp\stm32\libraries\templates\stm32f4xx,在《bsp\stm32\docs\STM32系列BSP制作教程.md》文件中有介绍
在bsp\stm32\stm32f413-xxx-xxx\board\Kconfig文件中修改MCU型号,改为:
config SOC_STM32F413VG
添加CAN3驱动代码
在bsp\stm32\stm32f413-xxx-xxx\board\Kconfig文件中添加CAN配置项
menuconfig BSP_USING_CAN
bool "Enable CAN"
default y
select RT_USING_CAN
if BSP_USING_CAN
config BSP_USING_CAN1
bool "Enable CAN1"
default y
config BSP_USING_CAN2
bool "Enable CAN2"
default y
config BSP_USING_CAN3
bool "Enable CAN3"
default y
endif
添加文件bsp\stm32\stm32f413-xxx-xxx\board\drv_can.c,含CAN3代码
/*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-08-05 Xeon Xu the first version
* 2019-01-22 YLZ port from stm324xx-HAL to bsp stm3210x-HAL
* 2019-02-19 YLZ add support EXTID RTR Frame. modify send, recv functions.
* fix bug.port to BSP [stm32]
* 2019-03-27 YLZ support double can channels, support stm32F4xx (only Legacy mode).
* 2019-06-17 YLZ port to new STM32F1xx HAL V1.1.3.
* 2021-04-19 unit,lhs support 3 can channels, support stm32F413VGTx
*/
#include "drv_can.h"
#ifdef BSP_USING_CAN
#define LOG_TAG "drv_can"
#include <drv_log.h>
/* attention !!! baud calculation example: Tclk / ((ss + bs1 + bs2) * brp) 36 / ((1 + 8 + 3) * 3) = 1MHz*/
#if defined (SOC_SERIES_STM32F1)/* APB1 36MHz(max) */
static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
{
{
CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 3)},
{
CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_5TQ | CAN_BS2_3TQ | 5)},
{
CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 6)},
{
CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 12)},
{
CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 24)},
{
CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 30)},
{
CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 60)},
{
CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 150)},
{
CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_3TQ | 300)}
};
#elif defined (SOC_SERIES_STM32F4)/* APB1 45MHz(max) */
static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
{
{
CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 3)},
{
CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_8TQ | CAN_BS2_5TQ | 4)},
{
CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 6)},
{
CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 12)},
{
CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 24)},
{
CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 30)},
{
CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 60)},
{
CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 150)},
{
CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_5TQ | 300)}
};
#elif defined (SOC_SERIES_STM32F7)/* APB1 54MHz(max) */
static const struct stm32_baud_rate_tab can_baud_rate_tab[] =
{
{
CAN1MBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 3)},
{
CAN800kBaud, (CAN_SJW_2TQ | CAN_BS1_9TQ | CAN_BS2_7TQ | 4)},
{
CAN500kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 6)},
{
CAN250kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 12)},
{
CAN125kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 24)},
{
CAN100kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 30)},
{
CAN50kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 60)},
{
CAN20kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 150)},
{
CAN10kBaud, (CAN_SJW_2TQ | CAN_BS1_10TQ | CAN_BS2_7TQ | 300)}
};
#endif
#ifdef BSP_USING_CAN1
static struct stm32_can drv_can1 =
{
.name = "can1",
.CanHandle.Instance = CAN1,
};
#endif
#ifdef BSP_USING_CAN2
static struct stm32_can drv_can2 =
{
"can2",
.CanHandle.Instance = CAN2,
};
#endif
#ifdef BSP_USING_CAN3
static struct stm32_can drv_can3 =
{
"can3",
.CanHandle.Instance = CAN3,
};
#endif
static rt_uint32_t get_can_baud_index(rt_uint32_t baud)
{
rt_uint32_t len, index;
len = sizeof(can_baud_rate_tab) / sizeof(can_baud_rate_tab[0]);
for (index = 0; index < len; index++)
{
if (can_baud_rate_tab[index].baud_rate == baud)
return index;
}
return 0; /* default baud is CAN1MBaud */
}
static rt_err_t _can_config(struct rt_can_device *can, struct can_configure *cfg)
{
struct stm32_can *drv_can;
rt_uint32_t baud_index;
RT_ASSERT(can);
RT_ASSERT(cfg);
drv_can = (struct stm32_can *)can->parent.user_data;
RT_ASSERT(drv_can);
drv_can->CanHandle.Init.TimeTriggeredMode = DISABLE;
drv_can->CanHandle.Init.AutoBusOff = ENABLE;
drv_can->CanHandle.Init.AutoWakeUp = DISABLE;
drv_can->CanHandle.Init.AutoRetransmission = DISABLE;
drv_can->CanHandle.Init.ReceiveFifoLocked = DISABLE;
drv_can->CanHandle.Init.TransmitFifoPriority = ENABLE;
switch (cfg->mode)
{
case RT_CAN_MODE_NORMAL:
drv_can->CanHandle.Init.Mode = CAN_MODE_NORMAL;
break;
case RT_CAN_MODE_LISEN:
drv_can->CanHandle.Init.Mode = CAN_MODE_SILENT;
break;
case RT_CAN_MODE_LOOPBACK:
drv_can->CanHandle.Init.Mode = CAN_MODE_LOOPBACK;
break;
case RT_CAN_MODE_LOOPBACKANLISEN:
drv_can->CanHandle.Init.Mode = CAN_MODE_SILENT_LOOPBACK;
break;
}
baud_index = get_can_baud_index(cfg->baud_rate);
drv_can->CanHandle.Init.SyncJumpWidth = BAUD_DATA(SJW, baud_index);
drv_can->CanHandle.Init.TimeSeg1 = BAUD_DATA(BS1, baud_index);
drv_can->CanHandle.Init.TimeSeg2 = BAUD_DATA(BS2, baud_index);
drv_can->CanHandle.Init.Prescaler = BAUD_DATA(RRESCL, baud_index);
/* init can */
if (HAL_CAN_Init(&drv_can->CanHandle) != HAL_OK)
{
return -RT_ERROR;
}
/* default filter config */
HAL_CAN_ConfigFilter(&drv_can->CanHandle, &drv_can->FilterConfig);
/* can start */
HAL_CAN_Start(&drv_can->CanHandle);
return RT_EOK;
}
static rt_err_t _can_control(struct rt_can_device *can, int cmd, void *arg)
{
rt_uint32_t argval;
struct stm32_can *drv_can;
struct rt_can_filter_config *filter_cfg;
RT_ASSERT(can != RT_NULL);
drv_can = (struct stm32_can *)can->parent.user_data;
RT_ASSERT(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);
}
#ifdef CAN2
if (CAN2 == drv_can->CanHandle.Instance)
{
HAL_NVIC_DisableIRQ(CAN2_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN2_RX1_IRQn);
}
#endif
#ifdef CAN3
if (CAN3 == drv_can->CanHandle.Instance)
{
HAL_NVIC_DisableIRQ(CAN3_RX0_IRQn);
HAL_NVIC_DisableIRQ(CAN3_RX1_IRQn);
}
#endif
__HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO0_MSG_PENDING);
__HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO0_FULL);
__HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO0_OVERRUN);
__HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO1_MSG_PENDING);
__HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO1_FULL);
__HAL_CAN_DISABLE_IT(&drv_can->CanHandle, CAN_IT_RX_FIFO1_OVERRUN);
}
else if (argval == RT_DEVICE_FLAG_INT_TX)
{
if (CAN1 == drv_can