#include <string.h>
#include "cmsis_os.h"
#include "driver_HAL/driver.h"
#include "utils/utils.h"
#include "utils/ring_fifo.h"
#define CAN1_TX_GPIO_PORT GPIOA
#define CAN1_TX_PIN GPIO_PIN_12
#define CAN1_RX_GPIO_PORT GPIOA
#define CAN1_RX_PIN GPIO_PIN_11
#define CAN1_TX_AF GPIO_AF9_CAN1
#define CAN1_RX_AF GPIO_AF9_CAN1
#define RXBUF_SIZE power_of_2(9) /* 512 bytes */
uint32_t tx_mailbox;
CAN_HandleTypeDef hcan1;
static CAN_RxHeaderTypeDef rx_header;
static struct can_frame rxfr;
static CAN_TxHeaderTypeDef tx_header;
static struct can_frame txfr;
static struct ring_fifo can_fifo;
static uint8_t rxbuf[RXBUF_SIZE];
static osMutexId can_mutex;
/**
* @brief Rx FIFO 0 callback.
* @param hfdcan: pointer to an FDCAN_HandleTypeDef structure that contains
* the configuration information for the specified FDCAN.
* @param RxFifo0ITs: indicates which Rx FIFO 0 interrupts are signalled.
* This parameter can be any combination of @arg
* FDCAN_Rx_Fifo0_Interrupts.
* @retval None
*/
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
if (HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &rx_header, rxfr.data) != HAL_OK)
return;
rxfr.can_id = rx_header.StdId;
if (rx_header.IDE == CAN_ID_EXT)
rxfr.can_id |= CAN_EFF_FLAG;
if (rx_header.RTR == CAN_RTR_REMOTE)
rxfr.can_id |= CAN_RTR_FLAG;
rxfr.can_dlc = rx_header.DLC;
ring_fifo_element_put(&can_fifo, &rxfr, sizeof(rxfr), 1);
//HAL_CAN_ActivateNotification(hcan, CAN_IT_RX_FIFO0_MSG_PENDING);
}
/***************************************************************
** 函数名: can1_read
** 函数描述: can1读取
** 输入参数:
** 输出参数:
** 返回值:
****************************************************************/
static int32_t can1_read(int32_t inode, void *buff, int32_t size, int32_t offset)
{
int32_t cnt;
if (CAN1_INODE != inode)
return -1;
if (size < sizeof(struct can_frame))
return 0;
osMutexWait(can_mutex, osWaitForever);
cnt = size / sizeof(struct can_frame);
size = ring_fifo_element_get(&can_fifo, buff, sizeof(struct can_frame), cnt);
osMutexRelease(can_mutex);
return size;
}
/***************************************************************
** 函数名: can1_write
** 函数描述: can1写入
** 输入参数:
** 输出参数:
** 返回值:
****************************************************************/
static int32_t can1_write(int32_t inode, const void *buff, int32_t size, int32_t offset)
{
int32_t ret = 0;
if (CAN1_INODE != inode)
return -1;
if (size < sizeof(txfr))
return 0;
osMutexWait(can_mutex, osWaitForever);
memcpy(&txfr, buff, sizeof(txfr));
tx_header.StdId = txfr.can_id & 0x7ff;
if (txfr.can_dlc > 8) {
ret = -1;
goto wr_out;
}
tx_header.DLC = (uint32_t)txfr.can_dlc;
HAL_CAN_ActivateNotification(&hcan1, CAN_IT_TX_MAILBOX_EMPTY);//开启中断
if (HAL_CAN_AddTxMessage(&hcan1, &tx_header, txfr.data, &tx_mailbox) != HAL_OK)
ret = -1;
else
ret = sizeof(txfr);
wr_out:
osMutexRelease(can_mutex);
return ret;
}
static struct file_operations can1_dev = {
.llseek = NULL,
.read = can1_read,
.write = can1_write,
.ioctl = NULL,
.open = NULL,
.release = NULL,
};
/***************************************************************
** 函数名: can1_config
** 函数描述: can1参数配置
** 输入参数:
** 输出参数:
** 返回值:
****************************************************************/
static void can1_config(void)
{
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 12;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_5TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_1TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
/* 必须使能,防止从机掉线重连时主机发送邮箱满 */
hcan1.Init.AutoBusOff = ENABLE;
/* 必须使能,防止从机掉线重连时主机发送邮箱满 */
hcan1.Init.AutoWakeUp = ENABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
error_handler();
}
}
/***************************************************************
** 函数名: can1_msp_init
** 函数描述: can1引脚配置
** 输入参数:
** 输出参数:
** 返回值:
****************************************************************/
void can1_msp_init(void)
{
GPIO_InitTypeDef gpio_conf;
/* Enable GPIO TX/RX clock */
__CAN1_CLK_ENABLE();
__GPIOA_CLK_ENABLE();
/**CAN1 GPIO Configuration
PA11 ------> CAN1_RX
PA12 ------> CAN1_TX
*/
gpio_conf.Pin = GPIO_PIN_11 | GPIO_PIN_12;
gpio_conf.Mode = GPIO_MODE_AF_PP;
gpio_conf.Pull = GPIO_NOPULL;
gpio_conf.Speed = GPIO_SPEED_HIGH;
gpio_conf.Alternate = GPIO_AF9_CAN1;
HAL_GPIO_Init(GPIOA, &gpio_conf);
/* CAN interrupt Init */
HAL_NVIC_SetPriority(CAN1_TX_IRQn, 0x0F, 1);
HAL_NVIC_EnableIRQ(CAN1_TX_IRQn);
HAL_NVIC_SetPriority(CAN1_RX0_IRQn, 0x0F, 2);
HAL_NVIC_EnableIRQ(CAN1_RX0_IRQn);
HAL_NVIC_SetPriority(CAN1_RX1_IRQn, 0x0F, 3);
HAL_NVIC_EnableIRQ(CAN1_RX1_IRQn);
}
/***************************************************************
** 函数名: can1_filter_config
** 函数描述: can1滤波配置
** 输入参数:
** 输出参数:
** 返回值:
****************************************************************/
static void can1_filter_config(void)
{
CAN_FilterTypeDef filter_conf;
/*##-2- Configure the CAN Filter #############*/
filter_conf.FilterBank = 0;
filter_conf.FilterFIFOAssignment = CAN_RX_FIFO0;
filter_conf.FilterMode = CAN_FILTERMODE_IDMASK;
filter_conf.FilterScale = CAN_FILTERSCALE_32BIT;
filter_conf.FilterIdHigh = 0x0000;
filter_conf.FilterIdLow = 0x0000;
filter_conf.FilterMaskIdHigh = 0x0000;
filter_conf.FilterMaskIdLow = 0x0000;
filter_conf.FilterActivation = ENABLE;
filter_conf.SlaveStartFilterBank = 14;
if (HAL_CAN_ConfigFilter(&hcan1, &filter_conf) != HAL_OK)
{
error_handler();
}
}
/***************************************************************
** 函数名: init_can1
** 函数描述: can1初始化
** 输入参数:
** 输出参数:
** 返回值:
****************************************************************/
void init_can1(void)
{
can1_config();
can1_filter_config();
/*##-3- Start the CAN peripheral #############*/
if (HAL_CAN_Start(&hcan1) != HAL_OK)
{
error_handler();
}
/*##-4- Activate CAN RX notification ##########*/
if (HAL_CAN_ActivateNotification(&hcan1,
CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK)
{
error_handler();
}
/* Activate CAN TX notification */
if (HAL_CAN_ActivateNotification(&hcan1,
CAN_IT_TX_MAILBOX_EMPTY) != HAL_OK)
{
error_handler();
}
osMutexDef(Can_mutex); //实时数据操作互斥信号量
can_mutex = osMutexCreate(osMutex(Can_mutex));
ring_fifo_init(&can_fifo, rxbuf, RXBUF_SIZE);
/* register the driver function */
register_dev(CAN1_INODE, &can1_dev);
}
/* ================================== EOF =================================== */