打印
[MM32软件]

灵动微MM32芯片FlexCAN配置

[复制链接]
1508|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
tpgf|  楼主 | 2024-6-7 08:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
记录一下自己学习关于灵动微芯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

使用特权

评论回复
沙发
yangxiaor520| | 2024-6-10 09:27 | 只看该作者
FLEXCAN有什么特殊之处?

使用特权

评论回复
板凳
daichaodai| | 2024-6-12 22:47 | 只看该作者
FLEXCAN和标准CAN有什么区别?只是命名不同而已?

使用特权

评论回复
地板
huquanz711| | 2024-6-13 07:45 | 只看该作者
同问楼主,FLEXCAN和标准CAN有什么不同啊?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1931

主题

15650

帖子

12

粉丝