记录一下自己学习关于灵动微芯MM32F0系列芯片其中有关FlexCAN的过程,做个笔记!
1、FlexCAN初始化函数:
void MX_CAN_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
NVIC_InitTypeDef NVIC_InitStruct;
flexcan_config_t FlexCAN_ConfigStruct;
flexcan_rx_mb_config_t FlexCAN_RxMB_ConfigStruct;
RCC_ClocksTypeDef RCC_Clocks;
RCC_GetClocksFreq(&RCC_Clocks);
RCC_AHBPeriphClockCmd(RCC_AHBENR_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1ENR_CAN, ENABLE);
//引脚复用,具体查看官方给的芯片手册
GPIO_PinAFConfig(GPIOB, GPIO_PinSource8, GPIO_AF_3);
GPIO_PinAFConfig(GPIOB, GPIO_PinSource9, GPIO_AF_3);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStruct);
GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStruct);
//配置CAN中断优先级
NVIC_InitStruct.NVIC_IRQChannel = FLEX_CAN_IRQn;
NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStruct);
//配置CAN波特率、时钟源等
FLEXCAN_GetDefaultConfig(&FlexCAN_ConfigStruct);
FlexCAN_ConfigStruct.baudRate = 250000; /* 250kbps */
FlexCAN_ConfigStruct.clkSrc = Enum_Flexcan_ClkSrc1;
FlexCAN_ConfigStruct.enableLoopBack = false;
FlexCAN_ConfigStruct.disableSelfReception = true;
FlexCAN_ConfigStruct.enableIndividMask = true;
FLEXCAN_Init(FLEX_CAN1, &FlexCAN_ConfigStruct, RCC_Clocks.PCLK1_Frequency);
//7、8、9为发送邮箱
FLEXCAN_SetTxMbConfig(FLEX_CAN1, 7, true);
FLEXCAN_SetTxMbConfig(FLEX_CAN1, 8, true);
FLEXCAN_SetTxMbConfig(FLEX_CAN1, 9, true);
FLEXCAN_TransferCreateHandle(FLEX_CAN1, &FlexCAN_Handle, FlexCAN_Transfer_Callback, NULL);
//STD不做滤波处理
/* STD */
FlexCAN_RxMB_ConfigStruct.id = FLEXCAN_ID_STD(0x00);
FlexCAN_RxMB_ConfigStruct.format = Enum_Flexcan_FrameFormatStandard;
FlexCAN_RxMB_ConfigStruct.type = Enum_Flexcan_FrameTypeData;
FLEXCAN_SetRxMbConfig(FLEX_CAN1, 10, &FlexCAN_RxMB_ConfigStruct, true);
FLEXCAN_SetRxIndividualMask(FLEX_CAN1, 10, FLEXCAN_RX_MB_STD_MASK(0x000, 0, 0));
FlexCAN_MB10_TransferStruct.mbIdx = 10;
FlexCAN_MB10_TransferStruct.frame = &FlexCAN_MB10_FrameStruct;
FLEXCAN_TransferReceiveNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB10_TransferStruct);
/* STD */
FlexCAN_RxMB_ConfigStruct.id = FLEXCAN_ID_STD(0x000);
FlexCAN_RxMB_ConfigStruct.format = Enum_Flexcan_FrameFormatStandard;
FlexCAN_RxMB_ConfigStruct.type = Enum_Flexcan_FrameTypeData;
FLEXCAN_SetRxMbConfig(FLEX_CAN1, 11, &FlexCAN_RxMB_ConfigStruct, true);
FLEXCAN_SetRxIndividualMask(FLEX_CAN1, 11, FLEXCAN_RX_MB_STD_MASK(0x000, 0, 0));
FlexCAN_MB11_TransferStruct.mbIdx = 11;
FlexCAN_MB11_TransferStruct.frame = &FlexCAN_MB11_FrameStruct;
FLEXCAN_TransferReceiveNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB11_TransferStruct);
/* EXT */
FlexCAN_RxMB_ConfigStruct.id = FLEXCAN_ID_EXT(0x33333);//接收帧ID为0x33333的扩展帧
FlexCAN_RxMB_ConfigStruct.format = Enum_Flexcan_FrameFormatExtend;
FlexCAN_RxMB_ConfigStruct.type = Enum_Flexcan_FrameTypeData;
FLEXCAN_SetRxMbConfig(FLEX_CAN1, 12, &FlexCAN_RxMB_ConfigStruct, true);
FLEXCAN_SetRxIndividualMask(FLEX_CAN1, 12, FLEXCAN_RX_MB_EXT_MASK(0xFFF, 0, 1));
FlexCAN_MB12_TransferStruct.mbIdx = 12;
FlexCAN_MB12_TransferStruct.frame = &FlexCAN_MB12_FrameStruct;
FLEXCAN_TransferReceiveNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB12_TransferStruct);
}
关于250kbs的波特率是参考灵动微官方库文件这里已经涵盖的,如果需要设置特殊的波特率,那我们首先需要查看关于CAN波特率配置库函数,然后配置预分频系数、相位段1、相位段2、传播段等相关参数,官方有关FlexCAN设置的波特率参数如下:
static void FLEXCAN_SetBaudRate(Flex_CAN_TypeDef* flex_can,u32 sourceClock_Hz,
u32 baudRate_Bps,flexcan_timing_config_t timingConfig)
{
u8 cnt;
u32 priDiv ;
// Loop through all possible time quanta configurations to find a match.
for (cnt = 0; cnt < sizeof(canTiming) / sizeof(canTiming[0]); cnt++) {
if ((sourceClock_Hz % (baudRate_Bps * canTiming[cnt].timeQuanta)) == 0U) {
// Compute the prescaler that goes with this TQ configuration.
priDiv = sourceClock_Hz / (baudRate_Bps * canTiming[cnt].timeQuanta);
timingConfig.preDivider = (u16)priDiv;
// Make sure the prescaler is valid.
if ((priDiv > 0U) && (priDiv <= 256U)) {
// Found a good bus timing configuration.
timingConfig.phaseSeg1 = canTiming[cnt].phaseSeg1;
timingConfig.phaseSeg2 = canTiming[cnt].phaseSeg2;
timingConfig.propSeg = canTiming[cnt].propSeg;
break;
}
}
}
// Update actual timing characteristic.
FLEXCAN_SetTimingConfig(flex_can, (const flexcan_timing_config_t*)(u32)&timingConfig);
}
在这个函数里我们查看到要配置CAN波特率和采样点的参数,timingConfig.preDivider、 timingConfig.phaseSeg1、timingConfig.phaseSeg2和 timingConfig.propSeg
比如我们需要设置一个30Kbs的波特率,假设此时CAN主频为36MHz,那么可以这么写
timingConfig.preDivider=100;
timingConfig.phaseSeg1 = 4;
timingConfig.phaseSeg2 = 3;
timingConfig.propSeg = 4;
CAN波特率计算公式:Budot=主频/预分频系数/(1+Tseg1+Tseg2)=36MHz/100/(1+(4+4)+3)=30kbs
采样点:sample=(1+CAN_BS1)/(1+CAN_BS1+CAN_BS2)=(1+4+4)/(1+4+4+3)=0.75
2、FlexCAN接收:
参考官方的demo,FlexCAN使用IRQ接收数据
void FLEX_CAN_IRQHandler(void)
{
FLEXCAN_TransferHandleIRQ(FLEX_CAN1, &FlexCAN_Handle);
__DSB();
}
数据处理是进入函数
void FLEXCAN_TransferHandleIRQ(Flex_CAN_TypeDef* flex_can, flexcan_handle_t* handle)
中,具体见官方库函数
由于一开始对CAN是不做滤波处理,接收的数据为CAN总线上所有数据,我们可以将数据赋值给一个数组,然后再对数组里数据进行处理:
void FlexCAN_Transfer_Callback(Flex_CAN_TypeDef *flex_can, flexcan_handle_t *handle, uint32_t status, uint32_t result, void *userData)
{
switch (status)
{
case Status_Flexcan_RxIdle:
if (10 == result)
{
FlexCAN_MB10_RxCompleteFlag = 1;
}
else if (11 == result)
{
FlexCAN_MB11_RxCompleteFlag = 1;
}
else if (12 == result)
{
FlexCAN_MB12_RxCompleteFlag = 1;
}
FlexCAN_RxMB_Handler();
break;
default:
break;
}
}
/*结构体CanMsg定义
typedef struct {
unsigned long len;
unsigned long ID;
Uint8 Data[8];
}flexcan_rx_msg_t;
*/
//CAN接收处理函数
void FlexCAN_RxMB_Handler(void)
{
flexcan_rx_msg_t flexcan_rx_msg;
if (FlexCAN_MB10_RxCompleteFlag == 1)
{
FlexCAN_MB10_RxCompleteFlag = 0;
flexcan_rx_msg.ID = FlexCAN_MB10_FrameStruct.id;
flexcan_rx_msg.len = FlexCAN_MB10_FrameStruct.length;
flexcan_rx_msg.Data[0] = FlexCAN_MB10_FrameStruct.dataByte0;
flexcan_rx_msg.Data[1] = FlexCAN_MB10_FrameStruct.dataByte1;
flexcan_rx_msg.Data[2] = FlexCAN_MB10_FrameStruct.dataByte2;
flexcan_rx_msg.Data[3] = FlexCAN_MB10_FrameStruct.dataByte3;
flexcan_rx_msg.Data[4] = FlexCAN_MB10_FrameStruct.dataByte4;
flexcan_rx_msg.Data[5] = FlexCAN_MB10_FrameStruct.dataByte5;
flexcan_rx_msg.Data[6] = FlexCAN_MB10_FrameStruct.dataByte6;
flexcan_rx_msg.Data[7] = FlexCAN_MB10_FrameStruct.dataByte7;
FLEXCAN_TransferReceiveNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB10_TransferStruct);
}
if (FlexCAN_MB11_RxCompleteFlag == 1)
{
FlexCAN_MB11_RxCompleteFlag = 0;
flexcan_rx_msg.ID = FlexCAN_MB11_FrameStruct.id;
flexcan_rx_msg.len = FlexCAN_MB11_FrameStruct.length;
flexcan_rx_msg.Data[0] = FlexCAN_MB11_FrameStruct.dataByte0;
flexcan_rx_msg.Data[1] = FlexCAN_MB11_FrameStruct.dataByte1;
flexcan_rx_msg.Data[2] = FlexCAN_MB11_FrameStruct.dataByte2;
flexcan_rx_msg.Data[3] = FlexCAN_MB11_FrameStruct.dataByte3;
flexcan_rx_msg.Data[4] = FlexCAN_MB11_FrameStruct.dataByte4;
flexcan_rx_msg.Data[5] = FlexCAN_MB11_FrameStruct.dataByte5;
flexcan_rx_msg.Data[6] = FlexCAN_MB11_FrameStruct.dataByte6;
flexcan_rx_msg.Data[7] = FlexCAN_MB11_FrameStruct.dataByte7;
FLEXCAN_TransferReceiveNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB11_TransferStruct);
}
if (FlexCAN_MB12_RxCompleteFlag == 1)
{
FlexCAN_MB12_RxCompleteFlag = 0;
felxcan_rx_msg.ID = FlexCAN_MB12_FrameStruct.id;
flexcan_rx_msg.len = FlexCAN_MB12_FrameStruct.length;
flexcan_rx_msg.Data[0] = FlexCAN_MB12_FrameStruct.dataByte0;
flexcan_rx_msg.Data[1] = FlexCAN_MB12_FrameStruct.dataByte1;
flexcan_rx_msg.Data[2] = FlexCAN_MB12_FrameStruct.dataByte2;
flexcan_rx_msg.Data[3] = FlexCAN_MB12_FrameStruct.dataByte3;
flexcan_rx_msg.Data[4] = FlexCAN_MB12_FrameStruct.dataByte4;
flexcan_rx_msg.Data[5] = FlexCAN_MB12_FrameStruct.dataByte5;
flexcan_rx_msg.Data[6] = FlexCAN_MB12_FrameStruct.dataByte6;
flexcan_rx_msg.Data[7] = FlexCAN_MB12_FrameStruct.dataByte7;
FLEXCAN_TransferReceiveNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB12_TransferStruct);
}
}
3、FlexCAN发送:
关于发送函数,在调用发送函数之前需判断一下帧ID。关于帧ID是标准帧还是扩展帧,我们只需要判断format也就是CAN的标识符是0还是1,根据官方给的demo我们可以知道0表示标准帧,1表示扩展帧。
参考官方给的帧ID判断方法:
//STD
if (FlexCAN_MB10_FrameStruct.format == (uint8_t)Enum_Flexcan_FrameFormatStandard)
{
if (FlexCAN_MB10_FrameStruct.type == (uint8_t)Enum_Flexcan_FrameTypeData)
{
flexcan_rx_msg.ID=FlexCAN_MB10_FrameStruct.id>>CAN_ID_STD_SHIFT;
}
else
{
}
}
//EXTEND
if (FlexCAN_MB10_FrameStruct.format == (uint8_t)Enum_Flexcan_FrameFormatExtend)
{
flexcan_rx_msg.ID=FlexCAN_MB10_FrameStruct.id;
}
然后就是选择FlexCAN的发送函数:
//STD
void FlexCAN_SendStandardFrameMessage(uint32_t ID, uint8_t *Buffer, uint8_t Length)
{
flexcan_frame_t FlexCAN_FrameStruct;
flexcan_mb_transfer_t FlexCAN_MB_TransferStruct;
FlexCAN_FrameStruct.length = (uint8_t)Length;
FlexCAN_FrameStruct.type = (uint8_t)Enum_Flexcan_FrameTypeData;
FlexCAN_FrameStruct.format = (uint8_t)Enum_Flexcan_FrameFormatStandard;
FlexCAN_FrameStruct.id = FLEXCAN_ID_STD(ID);
FlexCAN_FrameStruct.dataByte0 = Buffer[0];
FlexCAN_FrameStruct.dataByte1 = Buffer[1];
FlexCAN_FrameStruct.dataByte2 = Buffer[2];
FlexCAN_FrameStruct.dataByte3 = Buffer[3];
FlexCAN_FrameStruct.dataByte4 = Buffer[4];
FlexCAN_FrameStruct.dataByte5 = Buffer[5];
FlexCAN_FrameStruct.dataByte6 = Buffer[6];
FlexCAN_FrameStruct.dataByte7 = Buffer[7];
FlexCAN_MB_TransferStruct.mbIdx = 7;
FlexCAN_MB_TransferStruct.frame = &FlexCAN_FrameStruct;
FLEXCAN_TransferSendNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB_TransferStruct);
}
//EXTEND
void FlexCAN_SendExtendFrameMessage(uint32_t ID, uint8_t *Buffer, uint8_t Length)
{
flexcan_frame_t FlexCAN_FrameStruct;
flexcan_mb_transfer_t FlexCAN_MB_TransferStruct;
FlexCAN_FrameStruct.length = (uint8_t)Length;
FlexCAN_FrameStruct.type = (uint8_t)Enum_Flexcan_FrameTypeData;
FlexCAN_FrameStruct.format = (uint8_t)Enum_Flexcan_FrameFormatExtend;
FlexCAN_FrameStruct.id = FLEXCAN_ID_EXT(ID);
FlexCAN_FrameStruct.dataByte0 = Buffer[0];
FlexCAN_FrameStruct.dataByte1 = Buffer[1];
FlexCAN_FrameStruct.dataByte2 = Buffer[2];
FlexCAN_FrameStruct.dataByte3 = Buffer[3];
FlexCAN_FrameStruct.dataByte4 = Buffer[4];
FlexCAN_FrameStruct.dataByte5 = Buffer[5];
FlexCAN_FrameStruct.dataByte6 = Buffer[6];
FlexCAN_FrameStruct.dataByte7 = Buffer[7];
FlexCAN_MB_TransferStruct.mbIdx = 8;
FlexCAN_MB_TransferStruct.frame = &FlexCAN_FrameStruct;
FLEXCAN_TransferSendNonBlocking(FLEX_CAN1, &FlexCAN_Handle, &FlexCAN_MB_TransferStruct);
}
具体很多函数怎么用,可以参考灵动微官方给的例程。
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_58575597/article/details/139269065
|
|