本来采用这一款芯片就是看中了其有双通道的CANFD,这个大大解决了CAN2.0B的传输效率问题,以往产品升级和批量传输数据的时候,总是容易出现总线堵塞,这次就简单测试一下其性能,还会比较一下STM新出的STM32H503CBT6,进行比较;STM32H503CBT6采用M33内核,主频250M,同样带有FPU和DSP指令,带有1路CANFD。

1.FR3068X-C can测试

按照SDK的外设例程,打开对应例程,修改部分时钟,因为本次测试的CANFD是总裁段是1M波特率,数据段是4M波特率,所以需要重新配置一下时钟。

/*********************************************************************
  • * @fn      system_clock_config
  • *
  • * @brief   System Misc Init.
  • */
  • void system_clock_config(void)
  • {
  •     System_ClkConfig_t ClkConfig;

  •     /* CORE HSCLK Config */
  •     ClkConfig.CORE_HSCLK_CFG.CORE_HSCLK_Source = CORE_HSCLK_SEL_HES;
  •     /* PLL clock = HSE_VALUE*N + (HSE_VALUE/65535)*M */
  •     /* SPLL CLK Config */
  •     ClkConfig.SPLL_CFG.PowerEn = PLL_POWER_ENABLE;
  •     ClkConfig.SPLL_CFG.PLL_N = 8;
  •     ClkConfig.SPLL_CFG.PLL_M = 0;
  •     /* PLL clock = HSE_VALUE*N + (HSE_VALUE/65535)*M */
  •     /* AUPLL CLK Config */
  •     ClkConfig.AUPLL_CFG.PowerEn = PLL_POWER_ENABLE;
  •     ClkConfig.AUPLL_CFG.PLL_N = 8;
  •     ClkConfig.AUPLL_CFG.PLL_K = 0;
  •     ClkConfig.AUPLL_CFG.PLL_D = 0;

  •     System_CORE_HSCLK_config(&ClkConfig.CORE_HSCLK_CFG);
  •     if (System_SPLL_config(&ClkConfig.SPLL_CFG,200) == -1)
  •         while(1);   
  •     if (System_AUPLL_config(&ClkConfig.AUPLL_CFG,200) == -1)
  •         while(1);

  •     ClkConfig.MCU_Clock_Source = MCU_CLK_SEL_SPLL_CLK;
  •     ClkConfig.SOC_DIV  = 1;    /* This parameter is valid when MCU_Clock_Source == MCU_CLK_SEL_SPLL_CLK */
  •     ClkConfig.MCU_DIV  = 1;
  •     ClkConfig.APB0_DIV = 1;
  •     ClkConfig.APB1_DIV = 1;
  •     ClkConfig.APB2_DIV = 1;

  •     System_MCU_clock_Config(&ClkConfig);
  • }
  • 复制代码

    上述代码,将主时钟设置为192Mhz,然后继续初始化CAN时钟,

    /************************************************************************************
  • * @fn      can_demo
  • *
  • * @brief   can demo
  • */
  • void can_demo(void)
  • {
  •     uint32_t ram_size;

  •     GPIO_InitTypeDef GPIO_Handle;
  •     __SYSTEM_MCAN_CLK_SELECT_SPLL();        //192/2=96M
  •     __SYSTEM_GPIOA_CLK_ENABLE();
  •     __SYSTEM_MCAN3_CLK_ENABLE();
  •     printf("can clock:%d\r\n", system_get_peripheral_clock(PER_CLK_CANx));

  •     /* CAN3 IO init */
  •     /* A10: CAN3_Rx */
  •     /* A11: CAN3_Tx */
  •     GPIO_Handle.Pin       = GPIO_PIN_10|GPIO_PIN_11;
  •     GPIO_Handle.Mode      = GPIO_MODE_AF_PP;
  •     GPIO_Handle.Pull      = GPIO_PULLUP;
  •     GPIO_Handle.Alternate = GPIO_FUNCTION_5;
  •     gpio_init(GPIOA, &GPIO_Handle);

  •     /* CAN init */
  •     CAN3_Handle.CANx = CAN3;
  •     CAN3_Handle.Init.Prescaler     = 4;    // 96M/4=24M, bit rate = 24M/16+5+1+1+1 = 1M
  •     CAN3_Handle.Init.SyncJumpWidth = 3;
  •     CAN3_Handle.Init.TimeSeg1      = 16;
  •     CAN3_Handle.Init.TimeSeg2      = 5;
  •     CAN3_Handle.Init.DataBit_RateSwitch = CAN_FUNC_ENABLE;
  •     CAN3_Handle.Init.DataBit_Prescaler = 1;    // 96M/1=96M, data bit rate = 96M/16+5+1+1+1 = 4M
  •     CAN3_Handle.Init.DataBit_SyncJumpWidth = 3;
  •     CAN3_Handle.Init.DataBit_TimeSeg1 = 16;
  •     CAN3_Handle.Init.DataBit_TimeSeg2 = 5;
  •     can_init(&CAN3_Handle);

  •     // can_enter_test_mode(&CAN3_Handle,CAN_EXTERNAL_LOOP_BACK_TEST_MODE);
  •     /* CAN Message RAM config */
  •     CAN3_Handle.RAMConfig.StartAddress = (uint32_t)Can0Buffer;
  •     CAN3_Handle.RAMConfig.StandardIDFilterNums = 128;
  •     CAN3_Handle.RAMConfig.ExtendedIDFilterNums = 64;
  •     CAN3_Handle.RAMConfig.TxFIFOQueueNums       = 32;
  •     CAN3_Handle.RAMConfig.TxDedicatedBufferNums = 0;
  •     CAN3_Handle.RAMConfig.RxFIFO0Nums           = 64;
  •     CAN3_Handle.RAMConfig.RxFIFO1Nums           = 64;
  •     CAN3_Handle.RAMConfig.DataBufferSize = CAN_DATA_BUFFER_SIZE_64_BYTE;
  •     ram_size = can_message_ram_init(&CAN3_Handle);
  •     printf("can3 use ram size %d \r\n", ram_size);
  •    
  •     struct_FilterCfg_t FilterCfg;
  •    
  •     /* ---------------------- standard ID filter ---------------------- */
  •     /* Range filter from SFID1 to SFID2 (SFID2 �� SFID1) */
  •     FilterCfg.FilterType  = CAN_FILTER_RANGE_FILTER;
  •     FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
  •     FilterCfg.FilterID_1 = 0x400;
  •     FilterCfg.FilterID_2 = 0x500;
  •     can_add_standard_filter(&CAN3_Handle, FilterCfg, 0);
  •    
  •     /* Single ID filter */
  •     FilterCfg.FilterType  = CAN_FILTER_SINGLE_ID_FILTER;
  •     FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
  •     FilterCfg.FilterID_1 = 0x750;
  •     FilterCfg.FilterID_2 = 0x750;
  •     can_add_standard_filter(&CAN3_Handle, FilterCfg, 1);

  •     /* Dual ID filter   */
  •     FilterCfg.FilterType  = CAN_FILTER_DUAL_ID_FILTER;
  •     FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
  •     FilterCfg.FilterID_1 = 0x600;
  •     FilterCfg.FilterID_2 = 0x601;
  •     can_add_standard_filter(&CAN3_Handle, FilterCfg, 2);

  •     /* filter and mask */
  •     FilterCfg.FilterType  = CAN_FILTER_CLASSIC_FILTER;
  •     FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO0;
  •     FilterCfg.FilterID_1 = 0xF0;    // filter
  •     FilterCfg.FilterID_2 = 0xFC;    // mask
  •     can_add_standard_filter(&CAN3_Handle, FilterCfg, 3);
  •    
  •     /* ---------------------- extended ID filter ---------------------- */
  •     /* Range filter from SFID1 to SFID2 (SFID2 �� SFID1) */
  •     FilterCfg.FilterType  = CAN_FILTER_RANGE_FILTER;
  •     FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO1;
  •     FilterCfg.FilterID_1 = 0x10000;
  •     FilterCfg.FilterID_2 = 0x20000;
  •     can_add_extended_filter(&CAN3_Handle, FilterCfg, 0);

  •     /* Dual ID filter   */
  •     FilterCfg.FilterType  = CAN_FILTER_DUAL_ID_FILTER;
  •     FilterCfg.ProcessMode = FILTER_PROCESS_SET_PRIORITY_AND_STORE_IN_RxFIFO1;
  •     FilterCfg.FilterID_1 = 0x333333;
  •     FilterCfg.FilterID_2 = 0x444444;
  •     can_add_extended_filter(&CAN3_Handle, FilterCfg, 1);
  •    
  •     CAN3_Handle.RxFIFO0_New_Message_Callback = RxFIFO0_New_Message_handle;
  •     CAN3_Handle.RxFIFO1_New_Message_Callback = RxFIFO1_New_Message_handle;
  •     CAN3_Handle.Transmission_Completed_Callback = Transmission_Completed_handle;
  •    
  •     can_int_select_line(&CAN3_Handle, INT_RxFIFO0_NEW_MESSAGE, CAN_INT_LINE0);
  •     can_int_select_line(&CAN3_Handle, INT_RxFIFO1_NEW_MESSAGE, CAN_INT_LINE0);
  •     can_int_select_line(&CAN3_Handle, INT_TRANSMISSION_COMPLETED, CAN_INT_LINE0);
  •     can_int_enable(&CAN3_Handle, INT_RxFIFO0_NEW_MESSAGE);
  •     can_int_enable(&CAN3_Handle, INT_RxFIFO1_NEW_MESSAGE);
  •     can_int_enable(&CAN3_Handle, INT_TRANSMISSION_COMPLETED);

  •     NVIC_EnableIRQ(CAN3_Line0_IRQn);
  •    
  •     /* init timer CLOCK */

  •     __SYSTEM_TIMER0_CLK_ENABLE();
  •     __SYSTEM_TIMER1_CLK_ENABLE();
  •     __SYSTEM_TIMER2_CLK_ENABLE();
  •     __SYSTEM_TIMER3_CLK_ENABLE();
  •     NVIC_EnableIRQ(TIMER0_IRQn);
  •     NVIC_EnableIRQ(TIMER1_IRQn);
  •     NVIC_EnableIRQ(TIMER2_IRQn);
  •     NVIC_EnableIRQ(TIMER3_IRQn);
  •    
  •     timer_int_enable(Timer0);
  •     timer_int_enable(Timer1);
  •     timer_int_enable(Timer2);
  •     timer_int_enable(Timer3);
  •     /* timer0 */
  •     timer_init(Timer0, 24000*10);
  •     /* timer1 */
  •     timer_init(Timer1, 24000*20);
  •     /* timer2 */
  •     timer_init(Timer2, 24000*30);
  •     /* timer3 */
  •     timer_init(Timer3, 24000*40);

  •     // timer_start(Timer0);
  •     // timer_start(Timer1);
  •     // timer_start(Timer2);
  •     // timer_start(Timer3);
  •     for (int i = 0; i < 64; i++)
  •         TxBuffer[i] = i + 0x30;

  •     CANTxHeader.DLC           = CAN_FD_DLC15_DATA_LENGTH_64BYTE;
  •     CANTxHeader.IdType        = CAN_ID_EXTENDED;
  •     CANTxHeader.FrameType     = CAN_DATA_FRAME;
  •     CANTxHeader.FormatMode    = CAN_FD_FRAME;
  •     CANTxHeader.BitRateSwitch = CAN_FUNC_ENABLE;
  •     CANTxHeader.Identifier    = 0x444444;
  •     while(1)
  •     {
  •         can_add_tx_message(&CAN3_Handle, CANTxHeader, TxBuffer);

  •         // can_add_tx_message(&CAN3_Handle, CANTxHeader, TxBuffer);

  •     }
  • }
  • 复制代码

    上述代码重新配置了CAN的时钟为2分频的SPLL,然后管脚配置为A10 A11,使用CAN3,

    void can3_line0_irq(void)
  • {
  •     can_IRQHandler(&CAN3_Handle);
  • }
  • 复制代码

    注意,别忘了修改CAN中断函数名称,改为CAN3,

    上述程序的目的是为了测试一下是否能够按照大约4M波特率进行测试,测试结果是大约每秒钟能发送5100帧左右的数据。

    1.png


    若调整为2M的数据波特率,则大约能发送3100帧,并且稳定性比较好

    5.png


    2.测试STM32H503CBT6,设置主频为240M,开启缓存,CANFD的速度为仲裁段1M,数据段2-4M,while循环发送,看看处理能力。

    先看一下,经典CAN模式下,500K波特率下的速度,大概3400帧

    2.png


    经典CAN模式下,1M波特率下是6700帧的水平

    3.png

    CANFD模式下,因为使用的是TJA1042T,标称是5M的转换器,不知道为什么不能跑到4M数据波特率,所以仲裁帧是1M,数据帧是2M,可以看到发送速度是3100帧左右,但是数据略微有点波动2900-3100之间浮动,

    4.png



    以上的测试内容不是想说明什么强弱,只是看一下在空任务状态,各个SDK采用的发送方式能否跑满带宽。

    双通道中FR3068在通道1,STM32在通道2,看一下经过一段时间以后,出现了一点点的性能累计差异。

    视频可以看到,在经过一段时间以后,FR3068X发送帧率稳定在3050-3100左右,STM32稍微低一些,在2900-3100左右。

    上述的测试方法存在部分问题,也许更加严谨的测试方法能测试出部分开销,但是2M波特率下都能稳定在3100左右就挺好了。