[1] CAN_DeInit
描述
将外设 CAN 的全部寄存器重设为缺省值。
函数源代码
void CAN_DeInit(CAN_TypeDef* CANx)
{
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
if (CANx == CAN1)
{
/* Enable CAN1 reset state */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN1, ENABLE); //强制或释放APB1挂载的外设
/* Release CAN1 from reset state */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN1, DISABLE);
}
else
{
/* Enable CAN2 reset state */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN2, ENABLE);
/* Release CAN2 from reset state */
RCC_APB1PeriphResetCmd(RCC_APB1Periph_CAN2, DISABLE);
}
}
分析
入参类型为CAN_TypeDef*,该数据类型是对CAN外设寄存器的抽象,具体如下。结构体成员与STM32参考手册中CAN章节列出的CAN寄存器逐一对应。
typedef struct
{
__IO uint32_t MCR;
__IO uint32_t MSR;
__IO uint32_t TSR;
__IO uint32_t RF0R;
__IO uint32_t RF1R;
__IO uint32_t IER;
__IO uint32_t ESR;
__IO uint32_t BTR;
uint32_t RESERVED0[88];
CAN_TxMailBox_TypeDef sTxMailBox[3];
CAN_FIFOMailBox_TypeDef sFIFOMailBox[2];
uint32_t RESERVED1[12];
__IO uint32_t FMR;
__IO uint32_t FM1R;
uint32_t RESERVED2;
__IO uint32_t FS1R;
uint32_t RESERVED3;
__IO uint32_t FFA1R;
uint32_t RESERVED4;
__IO uint32_t FA1R;
uint32_t RESERVED5[8];
#ifndef STM32F10X_CL
CAN_FilterRegister_TypeDef sFilterRegister[14];
#else
CAN_FilterRegister_TypeDef sFilterRegister[28];
#endif /* STM32F10X_CL */
} CAN_TypeDef;
函数内部首先利用断言机制assert_param判定入参是否合理,断言在标准库代码中随处可见,其主要用于代码调试阶段来debug,实现如下:
#ifdef USE_FULL_ASSERT
#define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
/* Exported functions ------------------------------------------------------- */
void assert_failed(uint8_t* file, uint32_t line);
#else
#define assert_param(expr) ((void)0)
#endif /* USE_FULL_ASSERT */
可见只有在宏USE_FULL_ASSERT有效时才真正起到“断言”的作用,而标准库一般默认将该宏屏蔽,所以在这里不起作用。而宏IS_CAN_ALL_PERIPH(PERIPH)的作用是判断外设PERIPH是否为CAN1或CAN2,是则返回1否则返回0,实现如下:
#define IS_CAN_ALL_PERIPH(PERIPH) (((PERIPH) == CAN1) || \
((PERIPH) == CAN2))
然后具体设置CAN外设的复位,先强制复位再释放复位,无论是CAN1还是CAN2都一样。这里调用了库函数RCC_APB1PeriphResetCmd,它的含义是“强制或者释放低速 APB(APB1)外设复位”,其实现如下:
void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
RCC->APB1RSTR |= RCC_APB1Periph; //把寄存器APB1RSTR中要复位的外设对应位置1
}
else
{
RCC->APB1RSTR &= ~RCC_APB1Periph; //把寄存器APB1RSTR中要复位的外设对应位置0
}
}
该函数的核心是操作RCC的APB1RSTR寄存器的相关位以实现强制复位或释放复位。查阅参考手册可知,该32位寄存器的不同位代表挂载在APB1下的各外设的复位情况,以CAN1为例,要想将其复位则函数实际执行的操作如下:
#define RCC_APB1Periph_CAN1 ((uint32_t)0x02000000)
RCC->APB1RSTR |= RCC_APB1Periph_CAN1;
意味着将APB1RSTR的第25位CAN1RST置1,实现CAN1的复位。释放复位则是将APB1RSTR对应位置0。
[2] CAN_StructInit
描述
把 CAN_InitStruct 中的每一个参数按缺省值填入。
函数源代码
void CAN_StructInit(CAN_InitTypeDef* CAN_InitStruct)
{
/* Reset CAN init structure parameters values */
/* Initialize the time triggered communication mode */
CAN_InitStruct->CAN_TTCM = DISABLE;
/* Initialize the automatic bus-off management */
CAN_InitStruct->CAN_ABOM = DISABLE;
/* Initialize the automatic wake-up mode */
CAN_InitStruct->CAN_AWUM = DISABLE;
/* Initialize the no automatic retransmission */
CAN_InitStruct->CAN_NART = DISABLE;
/* Initialize the receive FIFO locked mode */
CAN_InitStruct->CAN_RFLM = DISABLE;
/* Initialize the transmit FIFO priority */
CAN_InitStruct->CAN_TXFP = DISABLE;
/* Initialize the CAN_Mode member */
CAN_InitStruct->CAN_Mode = CAN_Mode_Normal;
/* Initialize the CAN_SJW member */
CAN_InitStruct->CAN_SJW = CAN_SJW_1tq;
/* Initialize the CAN_BS1 member */
CAN_InitStruct->CAN_BS1 = CAN_BS1_4tq;
/* Initialize the CAN_BS2 member */
CAN_InitStruct->CAN_BS2 = CAN_BS2_3tq;
/* Initialize the CAN_Prescaler member */
CAN_InitStruct->CAN_Prescaler = 1;
}
分析
函数入参CAN_InitTypeDef*即CAN初始化结构体,包含了CAN相关的重要参数配置,包括外设时钟分频、工作模式、同步跳跃宽度、位段1和位段2宽度、时间触发模式开关、自动唤醒模式开关等等,结构体如下:
typedef struct
{
uint16_t CAN_Prescaler; /*!< Specifies the length of a time quantum.
It ranges from 1 to 1024. */
uint8_t CAN_Mode; /*!< Specifies the CAN operating mode.
This parameter can be a value of
@ref CAN_operating_mode */
uint8_t CAN_SJW; /*!< Specifies the maximum number of time quanta
the CAN hardware is allowed to lengthen or
shorten a bit to perform resynchronization.
This parameter can be a value of
@ref CAN_synchronisation_jump_width */
uint8_t CAN_BS1; /*!< Specifies the number of time quanta in Bit
Segment 1. This parameter can be a value of
@ref CAN_time_quantum_in_bit_segment_1 */
uint8_t CAN_BS2; /*!< Specifies the number of time quanta in Bit
Segment 2.
This parameter can be a value of
@ref CAN_time_quantum_in_bit_segment_2 */
FunctionalState CAN_TTCM; /*!< Enable or disable the time triggered
communication mode. This parameter can be set
either to ENABLE or DISABLE. */
FunctionalState CAN_ABOM; /*!< Enable or disable the automatic bus-off
management. This parameter can be set either
to ENABLE or DISABLE. */
FunctionalState CAN_AWUM; /*!< Enable or disable the automatic wake-up mode.
This parameter can be set either to ENABLE or
DISABLE. */
FunctionalState CAN_NART; /*!< Enable or disable the no-automatic
retransmission mode. This parameter can be
set either to ENABLE or DISABLE. */
FunctionalState CAN_RFLM; /*!< Enable or disable the Receive FIFO Locked mode.
This parameter can be set either to ENABLE
or DISABLE. */
FunctionalState CAN_TXFP; /*!< Enable or disable the transmit FIFO priority.
This parameter can be set either to ENABLE
or DISABLE. */
} CAN_InitTypeDef;
函数内部实现很简单,仅仅是给初始化结构体的各个成员赋默认值而已。
[3] CAN_Init
描述
根据 CAN_InitStruct 中指定的参数初始化外设 CAN 的寄存器。
函数源代码
uint8_t CAN_Init(CAN_TypeDef* CANx, CAN_InitTypeDef* CAN_InitStruct)
{
uint8_t InitStatus = CAN_InitStatus_Failed;
uint32_t wait_ack = 0x00000000;
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_TTCM));
assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_ABOM));
assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_AWUM));
assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_NART));
assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_RFLM));
assert_param(IS_FUNCTIONAL_STATE(CAN_InitStruct->CAN_TXFP));
assert_param(IS_CAN_MODE(CAN_InitStruct->CAN_Mode));
assert_param(IS_CAN_SJW(CAN_InitStruct->CAN_SJW));
assert_param(IS_CAN_BS1(CAN_InitStruct->CAN_BS1));
assert_param(IS_CAN_BS2(CAN_InitStruct->CAN_BS2));
assert_param(IS_CAN_PRESCALER(CAN_InitStruct->CAN_Prescaler));
/* Exit from sleep mode */
CANx->MCR &= (~(uint32_t)CAN_MCR_SLEEP); //清零CAN主控制寄存器CAN_MCR的第1位SLEEP,CAN退出睡眠模式
/* Request initialisation */
CANx->MCR |= CAN_MCR_INRQ ; //设置CAN主控制寄存器CAN_MCR的第0位INRQ,CAN进入初始化模式
/* Wait the acknowledge */
while (((CANx->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT)) //读取CAN主状态寄存器CAN_MSR的第0位INAK,若为1则确认CAN进入初始化模式
{
wait_ack++;
}
/* Check acknowledge */
if ((CANx->MSR & CAN_MSR_INAK) != CAN_MSR_INAK) //CAN初始化失败返回
{
InitStatus = CAN_InitStatus_Failed;
}
else //CAN进入了初始化模式
{
/* Set the time triggered communication mode */
if (CAN_InitStruct->CAN_TTCM == ENABLE)
{
CANx->MCR |= CAN_MCR_TTCM;
}
else
{
CANx->MCR &= ~(uint32_t)CAN_MCR_TTCM;
}
/* Set the automatic bus-off management */
if (CAN_InitStruct->CAN_ABOM == ENABLE)
{
CANx->MCR |= CAN_MCR_ABOM;
}
else
{
CANx->MCR &= ~(uint32_t)CAN_MCR_ABOM;
}
/* Set the automatic wake-up mode */
if (CAN_InitStruct->CAN_AWUM == ENABLE)
{
CANx->MCR |= CAN_MCR_AWUM;
}
else
{
CANx->MCR &= ~(uint32_t)CAN_MCR_AWUM;
}
/* Set the no automatic retransmission */
if (CAN_InitStruct->CAN_NART == ENABLE)
{
CANx->MCR |= CAN_MCR_NART;
}
else
{
CANx->MCR &= ~(uint32_t)CAN_MCR_NART;
}
/* Set the receive FIFO locked mode */
if (CAN_InitStruct->CAN_RFLM == ENABLE)
{
CANx->MCR |= CAN_MCR_RFLM;
}
else
{
CANx->MCR &= ~(uint32_t)CAN_MCR_RFLM;
}
/* Set the transmit FIFO priority */
if (CAN_InitStruct->CAN_TXFP == ENABLE)
{
CANx->MCR |= CAN_MCR_TXFP;
}
else
{
CANx->MCR &= ~(uint32_t)CAN_MCR_TXFP;
}
/* Set the bit timing register */
CANx->BTR = (uint32_t)((uint32_t)CAN_InitStruct->CAN_Mode << 30) | \
((uint32_t)CAN_InitStruct->CAN_SJW << 24) | \
((uint32_t)CAN_InitStruct->CAN_BS1 << 16) | \
((uint32_t)CAN_InitStruct->CAN_BS2 << 20) | \
((uint32_t)CAN_InitStruct->CAN_Prescaler - 1);
/* Request leave initialisation */
CANx->MCR &= ~(uint32_t)CAN_MCR_INRQ; //CAN从初始化模式进入正常模式
/* Wait the acknowledge */
wait_ack = 0;
while (((CANx->MSR & CAN_MSR_INAK) == CAN_MSR_INAK) && (wait_ack != INAK_TIMEOUT))
{
wait_ack++;
}
/* ...and check acknowledged */
if ((CANx->MSR & CAN_MSR_INAK) == CAN_MSR_INAK)
{
InitStatus = CAN_InitStatus_Failed;
}
else
{
InitStatus = CAN_InitStatus_Success ;
}
}
/* At this step, return the status of initialization */
return InitStatus;
}
分析
通过清零CAN主控制寄存器CAN_MCR的第1位SLEEP,CAN退出睡眠模式,因为CAN在复位后就处于睡眠模式了。设置CAN主控制寄存器CAN_MCR的第0位INRQ,CAN进入初始化模式。接下来是初始化的确认,因为在上一步中设置INRQ后,相应地硬件会对CAN主状态寄存器CAN_MSR的INAK位置1,所以通过读取该位来判断CAN是否真正进入初始化模式。为保证判断准确此处进行了while循环等待处理。紧接着判断INAK,若初始化失败则返回失败状态,否则继续配置其它寄存器。对于初始化结构体中开关型的成员,设置或清零CAN_MCR寄存器中的对应位。对于其它数值型的成员,根据它们各自在CAN位时序寄存器CAN_BTR中的对应位置,经过不同的移位和按位或运算后写入CAN_BTR。
配置完毕相关的寄存器后,CAN要从初始化模式进入正常模式,方法就是清零CAN_MCR的位INRQ,相应地硬件会把CAN_MSR的位INAK清零,同样的紧接着读取检查INAK位,若该位未能从1变成0则意味失败,若为0则说明CAN进入了正常模式,整个初始化过程成功,返回成功标志。
[4] CAN_FilterInit
描述
根据 CAN_FilterInitStruct 中指定的参数初始化外设CAN的寄存器。
函数源代码
void CAN_FilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
uint32_t filter_number_bit_pos = 0;
/* Check the parameters */
assert_param(IS_CAN_FILTER_NUMBER(CAN_FilterInitStruct->CAN_FilterNumber));
assert_param(IS_CAN_FILTER_MODE(CAN_FilterInitStruct->CAN_FilterMode));
assert_param(IS_CAN_FILTER_SCALE(CAN_FilterInitStruct->CAN_FilterScale));
assert_param(IS_CAN_FILTER_FIFO(CAN_FilterInitStruct->CAN_FilterFIFOAssignment));
assert_param(IS_FUNCTIONAL_STATE(CAN_FilterInitStruct->CAN_FilterActivation));
filter_number_bit_pos = ((uint32_t)1) << CAN_FilterInitStruct->CAN_FilterNumber; //过滤器序号为x则把x位置1
/* Initialisation mode for the filter */
CAN1->FMR |= FMR_FINIT; //使过滤器组工作在初始化模式
/* Filter Deactivation */
CAN1->FA1R &= ~(uint32_t)filter_number_bit_pos; //所选的过滤器被禁用
/* Filter Scale */
if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_16bit) //16位模式
{
/* 16-bit scale for the filter */
CAN1->FS1R &= ~(uint32_t)filter_number_bit_pos; //设置当前过滤器位宽为2个16位
/* First 16-bit identifier and First 16-bit mask */
/* Or First 16-bit identifier and Second 16-bit identifier */
CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow); //若为列表模式,设置FR1存储两条过滤ID;若为掩码模式,设置FR1存储一条ID及其掩码
/* Second 16-bit identifier and Second 16-bit mask */
/* Or Third 16-bit identifier and Fourth 16-bit identifier */
CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh); //若为列表模式,设置FR2存储另两条过滤ID;若为掩码模式,设置FR2存储另一条ID及其掩码
}
if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_32bit) //32位模式
{
/* 32-bit scale for the filter */
CAN1->FS1R |= filter_number_bit_pos; //设置当前过滤器位宽为32位
/* 32-bit identifier or First 32-bit identifier */
CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow); //设置FR1为ID
/* 32-bit mask or Second 32-bit identifier */
CAN1->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 =
((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
(0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow); //若为列表模式,设置FR2为另一个ID;若为掩码模式,设置FR2为FR1中的ID的掩码
}
/* Filter Mode */
if (CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdMask)
{
/*Id/Mask mode for the filter*/
CAN1->FM1R &= ~(uint32_t)filter_number_bit_pos; //设置当前过滤器组工作在掩码模式
}
else /* CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdList */
{
/*Identifier list mode for the filter*/
CAN1->FM1R |= (uint32_t)filter_number_bit_pos; //设置当前过滤器组工作在列表模式
}
/* Filter FIFO assignment */
if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO0)
{
/* FIFO 0 assignation for the filter */
CAN1->FFA1R &= ~(uint32_t)filter_number_bit_pos; //当前过滤器关联到FIFO0
}
if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO1)
{
/* FIFO 1 assignation for the filter */
CAN1->FFA1R |= (uint32_t)filter_number_bit_pos; //当前过滤器关联到FIFO1
}
/* Filter activation */
if (CAN_FilterInitStruct->CAN_FilterActivation == ENABLE)
{
CAN1->FA1R |= filter_number_bit_pos; //使过滤器被激活
}
/* Leave the initialisation mode for the filter */
CAN1->FMR &= ~FMR_FINIT; //使过滤器组工作在正常模式
}
分析
入参的结构体即CAN过滤器初始化结构体,其成员包括ID模式的高低位、掩码模式的高低位、过滤器关联的FIFO序号、过滤器序号、过滤器模式等参数,具体如下:
typedef struct
{
uint16_t CAN_FilterIdHigh; /*!< Specifies the filter identification number (MSBs for a 32-bit
configuration, first one for a 16-bit configuration).
This parameter can be a value between 0x0000 and 0xFFFF */
uint16_t CAN_FilterIdLow; /*!< Specifies the filter identification number (LSBs for a 32-bit
configuration, second one for a 16-bit configuration).
This parameter can be a value between 0x0000 and 0xFFFF */
uint16_t CAN_FilterMaskIdHigh; /*!< Specifies the filter mask number or identification number,
according to the mode (MSBs for a 32-bit configuration,
first one for a 16-bit configuration).
This parameter can be a value between 0x0000 and 0xFFFF */
uint16_t CAN_FilterMaskIdLow; /*!< Specifies the filter mask number or identification number,
according to the mode (LSBs for a 32-bit configuration,
second one for a 16-bit configuration).
This parameter can be a value between 0x0000 and 0xFFFF */
uint16_t CAN_FilterFIFOAssignment; /*!< Specifies the FIFO (0 or 1) which will be assigned to the filter.
This parameter can be a value of @ref CAN_filter_FIFO */
uint8_t CAN_FilterNumber; /*!< Specifies the filter which will be initialized. It ranges from 0 to 13. */
uint8_t CAN_FilterMode; /*!< Specifies the filter mode to be initialized.
This parameter can be a value of @ref CAN_filter_mode */
uint8_t CAN_FilterScale; /*!< Specifies the filter scale.
This parameter can be a value of @ref CAN_filter_scale */
FunctionalState CAN_FilterActivation; /*!< Enable or disable the filter.
This parameter can be set either to ENABLE or DISABLE. */
} CAN_FilterInitTypeDef;
代码中有先进行过滤器的禁用操作CAN1->FA1R &= ~(uint32_t)filter_number_bit_pos,就是把CAN过滤器激活寄存器中,当前过滤器序号的对应位清零,实现禁用。参考手册中指明:只有对FACTx位清’0’,或对CAN_FMR寄存器的FINIT位设置’1’后,才能修改相应的过滤器寄存器x(CAN_FxR[0:1])。对过滤模式而言,无论是列表模式还是掩码模式,都有16位和32位两种位长度。如果为16位模式,则过滤器组的寄存器FR1的高位存CAN_FilterMaskIdLow、低位存CAN_FilterIdLow,FR2的高位存CAN_FilterMaskIdHigh、低位存CAN_FilterIdHigh。在列表模式下,CAN_FilterMaskIdLow和CAN_FilterIdLow分别为两个ID,CAN_FilterMaskIdHigh和CAN_FilterIdHigh分别为另外两个ID。在掩码模式下则不同,CAN_FilterIdLow和CAN_FilterMaskIdLow分别为一个ID及其掩码,CAN_FilterIdHigh和CAN_FilterMaskIdHigh分别为另一个ID及其掩码。如果为32位模式,则FR1高位存入CAN_FilterIdHigh、低位存入CAN_FilterIdLow,FR2高位存入CAN_FilterMaskIdHigh、低位存入CAN_FilterMaskIdLow。在列表模式下,FR1和FR2表示两个ID,而在掩码模式下它们分别表示ID及其掩码。
[5] CAN_ITConfig
描述
使能或者失能指定的CAN中断。
函数源代码
void CAN_ITConfig(CAN_TypeDef* CANx, uint32_t CAN_IT, FunctionalState NewState)
{
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_IT(CAN_IT));
assert_param(IS_FUNCTIONAL_STATE(NewState));
if (NewState != DISABLE)
{
/* Enable the selected CANx interrupt */
CANx->IER |= CAN_IT;
}
else
{
/* Disable the selected CANx interrupt */
CANx->IER &= ~CAN_IT;
}
}
分析
对于给定的中断类型,函数通过对CAN中断使能寄存器CAN_IER的各中断类型相应位设置或清零,以实现中断使能或失能。CAN的中断类型如下:
#define CAN_IT_TME ((uint32_t)0x00000001) /*!< Transmit mailbox empty Interrupt*/
/* Receive Interrupts */
#define CAN_IT_FMP0 ((uint32_t)0x00000002) /*!< FIFO 0 message pending Interrupt*/
#define CAN_IT_FF0 ((uint32_t)0x00000004) /*!< FIFO 0 full Interrupt*/
#define CAN_IT_FOV0 ((uint32_t)0x00000008) /*!< FIFO 0 overrun Interrupt*/
#define CAN_IT_FMP1 ((uint32_t)0x00000010) /*!< FIFO 1 message pending Interrupt*/
#define CAN_IT_FF1 ((uint32_t)0x00000020) /*!< FIFO 1 full Interrupt*/
#define CAN_IT_FOV1 ((uint32_t)0x00000040) /*!< FIFO 1 overrun Interrupt*/
/* Operating Mode Interrupts */
#define CAN_IT_WKU ((uint32_t)0x00010000) /*!< Wake-up Interrupt*/
#define CAN_IT_SLK ((uint32_t)0x00020000) /*!< Sleep acknowledge Interrupt*/
/* Error Interrupts */
#define CAN_IT_EWG ((uint32_t)0x00000100) /*!< Error warning Interrupt*/
#define CAN_IT_EPV ((uint32_t)0x00000200) /*!< Error passive Interrupt*/
#define CAN_IT_BOF ((uint32_t)0x00000400) /*!< Bus-off Interrupt*/
#define CAN_IT_LEC ((uint32_t)0x00000800) /*!< Last error code Interrupt*/
#define CAN_IT_ERR ((uint32_t)0x00008000) /*!< Error Interrupt*/
[6] CAN_Transmit
描述
开始一个消息的传输。
函数源代码
uint8_t CAN_Transmit(CAN_TypeDef* CANx, CanTxMsg* TxMessage)
{
uint8_t transmit_mailbox = 0;
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_IDTYPE(TxMessage->IDE));
assert_param(IS_CAN_RTR(TxMessage->RTR));
assert_param(IS_CAN_DLC(TxMessage->DLC));
/* Select one empty transmit mailbox */
if ((CANx->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)
{
transmit_mailbox = 0;
}
else if ((CANx->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)
{
transmit_mailbox = 1;
}
else if ((CANx->TSR&CAN_TSR_TME2) == CAN_TSR_TME2)
{
transmit_mailbox = 2;
}
else
{
transmit_mailbox = CAN_TxStatus_NoMailBox;
}
if (transmit_mailbox != CAN_TxStatus_NoMailBox)
{
/* Set up the Id */
CANx->sTxMailBox[transmit_mailbox].TIR &= TMIDxR_TXRQ; //请求发送邮箱的数据
if (TxMessage->IDE == CAN_Id_Standard)
{
assert_param(IS_CAN_STDID(TxMessage->StdId));
CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->StdId << 21) | \
TxMessage->RTR);
}
else
{
assert_param(IS_CAN_EXTID(TxMessage->ExtId));
CANx->sTxMailBox[transmit_mailbox].TIR |= ((TxMessage->ExtId << 3) | \
TxMessage->IDE | \
TxMessage->RTR);
}
/* Set up the DLC */
TxMessage->DLC &= (uint8_t)0x0000000F;
CANx->sTxMailBox[transmit_mailbox].TDTR &= (uint32_t)0xFFFFFFF0;
CANx->sTxMailBox[transmit_mailbox].TDTR |= TxMessage->DLC;
/* Set up the data field */
CANx->sTxMailBox[transmit_mailbox].TDLR = (((uint32_t)TxMessage->Data[3] << 24) |
((uint32_t)TxMessage->Data[2] << 16) |
((uint32_t)TxMessage->Data[1] << 8) |
((uint32_t)TxMessage->Data[0]));
CANx->sTxMailBox[transmit_mailbox].TDHR = (((uint32_t)TxMessage->Data[7] << 24) |
((uint32_t)TxMessage->Data[6] << 16) |
((uint32_t)TxMessage->Data[5] << 8) |
((uint32_t)TxMessage->Data[4]));
/* Request transmission */
CANx->sTxMailBox[transmit_mailbox].TIR |= TMIDxR_TXRQ;
}
return transmit_mailbox;
}
分析
第二个入参的结构体为CAN发送消息结构体,如下:
typedef struct
{
uint32_t StdId; /*!< Specifies the standard identifier.
This parameter can be a value between 0 to 0x7FF. */
uint32_t ExtId; /*!< Specifies the extended identifier.
This parameter can be a value between 0 to 0x1FFFFFFF. */
uint8_t IDE; /*!< Specifies the type of identifier for the message that
will be transmitted. This parameter can be a value
of @ref CAN_identifier_type */
uint8_t RTR; /*!< Specifies the type of frame for the message that will
be transmitted. This parameter can be a value of
@ref CAN_remote_transmission_request */
uint8_t DLC; /*!< Specifies the length of the frame that will be
transmitted. This parameter can be a value between
0 to 8 */
uint8_t Data[8]; /*!< Contains the data to be transmitted. It ranges from 0
to 0xFF. */
} CanTxMsg;
这几个成员分别是标准ID、扩展ID、ID类型标识、帧类型(数据帧或扩展帧)标识、数据长度和要发送的数据内容。函数内部,先要选择可用的发送邮箱,通过依次读CAN发送状态寄存器CAN_TSR的26、27和28位,若找到置1的位,说明该位对应的邮箱没有需要等待发送的报文,硬件对其置1了,这就是可选的发送邮箱。否则,未找到可用的发送邮箱,本次发送无法进行。选择了邮箱序号后,主要的工作就是设置CAN邮箱寄存器。根据标识符类型、帧类型等参数配置发送邮箱标识符寄存器CAN_TIR。根据要发送的数据长度DLC配置发送邮箱数据长度和时间戳寄存器CAN_TDTR。根据要发送的一帧数据内容,分低位字节和高位字节分别存入发送邮箱低字节数据寄存器CAN_TDLR和发送邮箱高字节数据寄存器CAN_TDHR。最后设置CAN_TIR的TXRQ位请求发送。
[7] CAN_TransmitStatus
描述
检查消息传输的状态。
函数源代码
uint8_t CAN_TransmitStatus(CAN_TypeDef* CANx, uint8_t TransmitMailbox)
{
uint32_t state = 0;
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_TRANSMITMAILBOX(TransmitMailbox));
switch (TransmitMailbox)
{
case (CAN_TXMAILBOX_0):
state = CANx->TSR & (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0); //检查TSR寄存器的位RQCP、TXOK和TME
break;
case (CAN_TXMAILBOX_1):
state = CANx->TSR & (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1);
break;
case (CAN_TXMAILBOX_2):
state = CANx->TSR & (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2);
break;
default:
state = CAN_TxStatus_Failed;
break;
}
switch (state)
{
/* transmit pending */
case (0x0): state = CAN_TxStatus_Pending;
break;
/* transmit failed */
case (CAN_TSR_RQCP0 | CAN_TSR_TME0): state = CAN_TxStatus_Failed;
break;
case (CAN_TSR_RQCP1 | CAN_TSR_TME1): state = CAN_TxStatus_Failed;
break;
case (CAN_TSR_RQCP2 | CAN_TSR_TME2): state = CAN_TxStatus_Failed;
break;
/* transmit succeeded */
case (CAN_TSR_RQCP0 | CAN_TSR_TXOK0 | CAN_TSR_TME0):state = CAN_TxStatus_Ok;
break;
case (CAN_TSR_RQCP1 | CAN_TSR_TXOK1 | CAN_TSR_TME1):state = CAN_TxStatus_Ok;
break;
case (CAN_TSR_RQCP2 | CAN_TSR_TXOK2 | CAN_TSR_TME2):state = CAN_TxStatus_Ok;
break;
default: state = CAN_TxStatus_Failed;
break;
}
return (uint8_t) state;
}
分析
对于当前正在使用的邮箱,检查其在CAN发送状态寄存器CAN_TSR所对应的RQCP、TXOK和TME这3个标志位,这些位被硬件置1时,RQCP表示上次传输请求完成(这里说的上次传输即指本次传输已完成),TXOK表示上次传输成功,TME意为当前发送邮箱为空,这3种状态同时存在则表明CAN外设的一次消息传输是没问题的。如果3个标志位均为0,表明本次传输仍在进行中,至于结果如何还未知,故函数返回一个pending状态。如果本次传输失败了,则一般TXOK位就不会被硬件置1。
[8] CAN_CancelTransmit
描述
取消一个传输请求。
函数源代码
void CAN_CancelTransmit(CAN_TypeDef* CANx, uint8_t Mailbox)
{
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_TRANSMITMAILBOX(Mailbox));
/* abort transmission */
switch (Mailbox)
{
case (CAN_TXMAILBOX_0): CANx->TSR |= CAN_TSR_ABRQ0;
break;
case (CAN_TXMAILBOX_1): CANx->TSR |= CAN_TSR_ABRQ1;
break;
case (CAN_TXMAILBOX_2): CANx->TSR |= CAN_TSR_ABRQ2;
break;
default:
break;
}
}
分析
对于当前正在使用的邮箱,设置其在CAN_TSR所对应的ABRQ位,即可中止该邮箱的发送请求。
[9] CAN_FIFORelease
描述
释放一个 FIFO。
函数源代码
void CAN_FIFORelease(CAN_TypeDef* CANx, uint8_t FIFONumber)
{
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_FIFO(FIFONumber));
/* Release FIFO0 */
if (FIFONumber == CAN_FIFO0)
{
CANx->RF0R |= CAN_RF0R_RFOM0;
}
/* Release FIFO1 */
else /* FIFONumber == CAN_FIFO1 */
{
CANx->RF1R |= CAN_RF1R_RFOM1;
}
}
分析
当接收邮箱中存在多条报文时,为了连续获取报文,设置CAN接收FIFO寄存器的位RFOM以释放邮箱,从而访问下一条接收报文。
[10] CAN_MessagePending
描述
返回挂号的信息数量。
函数源代码
uint8_t CAN_MessagePending(CAN_TypeDef* CANx, uint8_t FIFONumber)
{
uint8_t message_pending=0;
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_FIFO(FIFONumber));
if (FIFONumber == CAN_FIFO0)
{
message_pending = (uint8_t)(CANx->RF0R&(uint32_t)0x03);
}
else if (FIFONumber == CAN_FIFO1)
{
message_pending = (uint8_t)(CANx->RF1R&(uint32_t)0x03);
}
else
{
message_pending = 0;
}
return message_pending;
}
分析
函数返回接收FIFO中当前存在的报文数量,通过读CAN接收FIFO寄存器的位FMP获得。每释放一次FIFO,该位表示的数值就减一,FIFO中的报文数减一。
[11] CAN_Receive
描述
接收一个消息。
函数源代码
void CAN_Receive(CAN_TypeDef* CANx, uint8_t FIFONumber, CanRxMsg* RxMessage)
{
/* Check the parameters */
assert_param(IS_CAN_ALL_PERIPH(CANx));
assert_param(IS_CAN_FIFO(FIFONumber));
/* Get the Id */
RxMessage->IDE = (uint8_t)0x04 & CANx->sFIFOMailBox[FIFONumber].RIR;
if (RxMessage->IDE == CAN_Id_Standard)
{
RxMessage->StdId = (uint32_t)0x000007FF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 21);
}
else
{
RxMessage->ExtId = (uint32_t)0x1FFFFFFF & (CANx->sFIFOMailBox[FIFONumber].RIR >> 3);
}
RxMessage->RTR = (uint8_t)0x02 & CANx->sFIFOMailBox[FIFONumber].RIR;
/* Get the DLC */
RxMessage->DLC = (uint8_t)0x0F & CANx->sFIFOMailBox[FIFONumber].RDTR;
/* Get the FMI */
RxMessage->FMI = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDTR >> 8);
/* Get the data field */
RxMessage->Data[0] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDLR;
RxMessage->Data[1] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 8);
RxMessage->Data[2] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 16);
RxMessage->Data[3] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDLR >> 24);
RxMessage->Data[4] = (uint8_t)0xFF & CANx->sFIFOMailBox[FIFONumber].RDHR;
RxMessage->Data[5] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 8);
RxMessage->Data[6] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 16);
RxMessage->Data[7] = (uint8_t)0xFF & (CANx->sFIFOMailBox[FIFONumber].RDHR >> 24);
/* Release the FIFO */
/* Release FIFO0 */
if (FIFONumber == CAN_FIFO0)
{
CANx->RF0R |= CAN_RF0R_RFOM0;
}
/* Release FIFO1 */
else /* FIFONumber == CAN_FIFO1 */
{
CANx->RF1R |= CAN_RF1R_RFOM1;
}
}
分析
获取接收消息的标识符类型,通过读取接收FIFO邮箱标识符寄存器CAN_RIR的位IDE获得。如果是标准帧,则取CAN_RIR的STID共11位为标准ID;如果是扩展帧,则取CAN_RIR的EXID共29位为扩展ID。数据长度DLC由接收FIFO邮箱数据长度和时间戳寄存器CAN_RDTR的位DLC获得。数据内容从接收FIFO邮箱低字节数据寄存器CAN_RDLR和高字节数据寄存器CAN_RDHR获得。最后进行释放邮箱的操作,这一步很重要,否则邮箱中有多条消息时无法读到第二条、第三条消息。