【STM32G0B1 FDCAN调试深度解析与技巧分享】

STM32G0B1 FDCAN调试深度详解

  • 目录
  • 1.FDCAN模块featurelist
  • 2.初始化配置
  • 1.CAN波特率配置
  • 2.采样点配置
  • 3.其他配置
  • 3.过滤配置
  • 1.不需要ID过滤,即全部接受
  • 2.只接受某些ID
  • 4.中断配置
  • 5.数据发送
  • 目录

    1.FDCAN模块featurelist

    STM32G0B1集成2路独立(相对STM32F10系列2路是非完全独立的)的CANFD模块
    1.2个接收FIFO,每个FIFO有3级深度
    2.1个发送FIFO,3级深度,可配置发送优先级
    3.1个Tx Event FIFO(暂未研究应用场景)
    4.2个中断线,可配置中断关联哪个中断线
    5.强大且灵活的过滤器,标准帧有28个过滤器,扩展帧有8个过滤器

    2.初始化配置

    初始化可以基于cubmx进行配置

    各个参数如下

      uint32_t ClockDivider;                 /*!< Specifies the FDCAN kernel clock divider.
                                                  The clock is common to all FDCAN instances.
                                                  This parameter is applied only at initialisation of
                                                  first FDCAN instance.
                                                  This parameter can be a value of @ref FDCAN_clock_divider.   */
    
      uint32_t FrameFormat;                  /*!< Specifies the FDCAN frame format.
                                                  This parameter can be a value of @ref FDCAN_frame_format     */
    
      uint32_t Mode;                         /*!< Specifies the FDCAN mode.
                                                  This parameter can be a value of @ref FDCAN_operating_mode   */
    
      FunctionalState AutoRetransmission;    /*!< Enable or disable the automatic retransmission mode.
                                                  This parameter can be set to ENABLE or DISABLE               */
    
      FunctionalState TransmitPause;         /*!< Enable or disable the Transmit Pause feature.
                                                  This parameter can be set to ENABLE or DISABLE               */
    
      FunctionalState ProtocolException;      /*!< Enable or disable the Protocol Exception Handling.
                                                  This parameter can be set to ENABLE or DISABLE               */
    
      uint32_t NominalPrescaler;             /*!< Specifies the value by which the oscillator frequency is
                                                  divided for generating the nominal bit time quanta.
                                                  This parameter must be a number between 1 and 512            */
    
      uint32_t NominalSyncJumpWidth;         /*!< Specifies the maximum number of time quanta the FDCAN
                                                  hardware is allowed to lengthen or shorten a bit to perform
                                                  resynchronization.
                                                  This parameter must be a number between 1 and 128            */
    
      uint32_t NominalTimeSeg1;              /*!< Specifies the number of time quanta in Bit Segment 1.
                                                  This parameter must be a number between 2 and 256            */
    
      uint32_t NominalTimeSeg2;              /*!< Specifies the number of time quanta in Bit Segment 2.
                                                  This parameter must be a number between 2 and 128            */
    
      uint32_t DataPrescaler;                /*!< Specifies the value by which the oscillator frequency is
                                                  divided for generating the data bit time quanta.
                                                  This parameter must be a number between 1 and 32             */
    
      uint32_t DataSyncJumpWidth;            /*!< Specifies the maximum number of time quanta the FDCAN
                                                  hardware is allowed to lengthen or shorten a data bit to
                                                  perform resynchronization.
                                                  This parameter must be a number between 1 and 16             */
    
      uint32_t DataTimeSeg1;                 /*!< Specifies the number of time quanta in Data Bit Segment 1.
                                                  This parameter must be a number between 1 and 32             */
    
      uint32_t DataTimeSeg2;                 /*!< Specifies the number of time quanta in Data Bit Segment 2.
                                                  This parameter must be a number between 1 and 16             */
    
      uint32_t StdFiltersNbr;                /*!< Specifies the number of standard Message ID filters.
                                                  This parameter must be a number between 0 and 28             */
    
      uint32_t ExtFiltersNbr;                /*!< Specifies the number of extended Message ID filters.
                                                  This parameter must be a number between 0 and 8             */
    
      uint32_t TxFifoQueueMode;              /*!< Tx FIFO/Queue Mode selection.
                                                  This parameter can be a value of @ref FDCAN_txFifoQueue_Mode */
    

    这里重点讲以下几点:

    1.CAN波特率配置

    CAN的时钟源有三个,分别是PCLK,PLLQ,HSE,根据需要选择,假定选的是PCLK=64M,那么
    仲裁域baud=64M/ClockDivider(only CAN1,CAN2固定为1) / NominalPrescaler / (1+NominalTimeSeg1+NominalTimeSeg2) = 64M/1/4/(1+27+4)=500K
    数据域boud=64M/ClockDivider(only CAN1,CAN2固定为1)/DataPrescaler/(1+DataTimeSeg1+DataTimeSeg2) = 64M/1/2/(1+25+5)=1M其中以上几个参数有一下注意事项:
    1)仲裁域波特率/数据域波特率 >= 1/8,比如仲裁域500K,数据域最多不超过4M
    2)仲裁域和数据域的跳跃段SyncJumpWidth分别<=各自的TimeSeg2

    2.采样点配置

    仲裁域和数据域的采样点 = (1+Seg1)/(1+Seg1+Seg2),仲裁域和数据域的采样点可以不相同,但要遵循以下范围:
    baud > 800K: 75%
    baud > 500K:80%
    baud <= 500K: 87.5%

    3.其他配置

    FrameFormat:配置传统can模式还是canfd模式,建议canfd,因为canfd兼容can模式(可以收发传统can报文)
    AutoRetransmission:配置can发送时,未收到ack是否重复,一般配置重发
    TransmitPause:配置是否允许发送暂停,一般不需要
    ProtocolException:一般不需要
    StdFiltersNbr:配置标准帧过滤器个数,最多28个,如果不用id过滤功能,不用关心。
    ExtFiltersNbr:配置扩展帧过滤器个数,最多8个,如果不用id过滤功能,不用关心。
    TxFifoQueueMode:配置发送模式,一般配置fifo就行了,即根据写入txfifo先后顺序发送报文。但有些应用场景需要后塞入发送fifo的报文,根据id或其他特性需要优先发送的场景,结合这个参数的配置可以满足

    3.过滤配置

    STM32G0的过滤器是我目前用过最好用的filter,主要有以下特点
    1.标准帧和扩展帧的分别可以配置,包括使用过滤器的个数和每个过滤器的模式
    2.支持[ID1,ID2]这种范围过滤
    3.支持双过滤ID1,ID2满足任意即可(范围已经包含这种模式)
    4.传统的filter,mask模式,即mask某位为1,则需要匹配对应的filter为;mask某位为0,则不用关心
    5.通过过滤器的报文可以指定到进入那个FIFO,同时还支持相关优先级的配置,可以参考手册SFEC/EFEC位。

    应用举例,

    1.不需要ID过滤,即全部接受

    不用配置过滤器,直接调用

    HAL_StatusTypeDef HAL_FDCAN_ConfigGlobalFilter(FDCAN_HandleTypeDef *hfdcan, FDCAN_ACCEPT_IN_RX_FIFO0 ,FDCAN_ACCEPT_IN_RX_FIFO0 , FDCAN_FILTER_REMOTE,
                                                   FDCAN_FILTER_REMOTE )
    

    允许接受所有的标准帧和扩展帧以及各自的远程帧即可

    2.只接受某些ID

    使用下面接口配置标准帧过滤,使用那个过滤器(如果StdFiltersNbr配置为3,那么可使用的过滤器分别是0,1,2)

    HAL_StatusTypeDef HAL_FDCAN_ConfigFilter(FDCAN_HandleTypeDef *hfdcan, const FDCAN_FilterTypeDef *sFilterConfig)
    
    typedef struct
    {
      uint32_t IdType;           //配置标准帧或扩展帧
    
      uint32_t FilterIndex;      //0~StdFiltersNbr-1或0~ExtFiltersNbr-1
    
      uint32_t FilterType;       //范围、双id、传统屏蔽方式
    
      uint32_t FilterConfig;     //通过过滤器不进或进入rxfifo0或rxfifo1及是否设置优先级
    
      uint32_t FilterID1;        /*!< Specifies the filter identification 1.
                                      This parameter must be a number between:
                                       - 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID
                                       - 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID       */
    
      uint32_t FilterID2;        /*!< Specifies the filter identification 2.
                                      This parameter must be a number between:
                                       - 0 and 0x7FF, if IdType is FDCAN_STANDARD_ID
                                       - 0 and 0x1FFFFFFF, if IdType is FDCAN_EXTENDED_ID       */
    
    } FDCAN_FilterTypeDef;
    

    如果需要设置多个规则,多次调用该接口,保证每次设置的FilterIndex不同(标准帧和扩展帧有各自的FilterIndex 0-27或0-7)

    进行全局滤波器设置,设置标准和扩展的远程帧,设置标准和扩展的未通过滤波器的报文如何处理

    HAL_StatusTypeDef HAL_FDCAN_ConfigGlobalFilter(FDCAN_HandleTypeDef *hfdcan, FDCAN_ACCEPT_IN_RX_FIFO0 ,FDCAN_ACCEPT_IN_RX_FIFO0 , FDCAN_FILTER_REMOTE,
                                                   FDCAN_FILTER_REMOTE )
    

    比如设置某些id通过滤波器进入FIFO0,按照一般的设计,不通过滤波器的默认就被丢弃了,而STM32G0B1的FDCAN可以设置不通过滤波器的报文如何处理:拒绝或者进入FIFO0或FIFO1,这个机制对于某些应用设置ID白名单或黑名单或进行高级分组非常有效。

    附RxFIFO及过滤器等位域定义

    typedef struct{
    	union {
    		uint32_t Raw;
    		struct {
    			union {
    				uint32_t S0;
    				struct {
    					uint32_t SFID2:11;
    					uint32_t      :5;
    					uint32_t SFID1:11;
    					uint32_t SFEC :3;
    					uint32_t SFT  :2;
    				} S0Bit;
    			} S0;
    		} Head;
    	} StdFilter[28];//Standard Filter element
    	union {
    		uint32_t Raw[2];
    		struct {
    			union {
    				uint32_t F0;
    				struct {
    					uint32_t EFID1:29;
    					uint32_t EFEC :3;
    				} F0Bit;
    			} F0;
    			union {
    				uint32_t F1;
    				struct {
    					uint32_t EFID2:29;
    					uint32_t      :1;
    					uint32_t EFT  :2;
    				} F1Bit;
    			} F1;
    		} Head;
    	} ExtFilter[8];//Extended Filter element
    	union {
    		uint32_t Raw[18];//占位
    		struct {
    			union {
    				uint32_t R0;//占位
    				struct {
    					uint32_t    :18;
    					uint32_t ID :11;//Identifier
    					uint32_t RTR:1;//Received frame is a remote frame
    					uint32_t XTD:1;//Extended identifier
    					uint32_t ESI:1;//Error state indicator
    				} R0BitS;
    				struct {
    					uint32_t ID :29;//Identifier
    					uint32_t RTR:1;//Received frame is a remote frame
    					uint32_t XTD:1;//Extended identifier
    					uint32_t ESI:1;//Error state indicator
    				} R0BitE;
    			} R0;
    			union {
    				uint32_t R1;//占位
    				struct {
    					uint32_t RXTS:16;//Rx timestamp
    					uint32_t DLC :4;
    					uint32_t BRS :1;//Frame received with bit rate switching
    					uint32_t FDF :1;//FDCAN frame format (new DLC-coding and CRC)
    					uint32_t     :2;
    					uint32_t FIDX:7;//Filter index
    					uint32_t ANMF:1;//Received frame did not match any Rx filter element
    				} R1Bit;
    			} R1;
    			uint8_t Data[64];
    		} Head;
    	} RxFifo[2][3];//RxFIFO0和1
    	union {
    		uint32_t Raw[2];
    		struct {
    			union {
    				uint32_t E0;
    				struct {
    					uint32_t ID:29;//Identifier
    					uint32_t RTR:1;//Received frame is a remote frame
    					uint32_t XTD:1;//Extended identifier
    					uint32_t ESI:1;//Error state indicator
    				} E0Bit;
    			} E0;
    			union {
    				uint32_t E1;
    				struct {
    					uint32_t TXTS:16;
    					uint32_t DLC :4;
    					uint32_t BRS :1;
    					uint32_t EDF :1;
    					uint32_t ET  :2;
    					uint32_t MM  :8;
    				} E1Bit;
    			} E1;
    		} Head;
    	} TxEventFifo[3];//Tx Event FIFO
    	union {
    		uint32_t Raw[18];//占位
    		struct {
    			union {
    				uint32_t T0;
    				struct {
    					uint32_t ID:29;//Identifier
    					uint32_t RTR:1;//Received frame is a remote frame
    					uint32_t XTD:1;//Extended identifier
    					uint32_t ESI:1;//Error state indicator
    				} T0Bit;
    			} T0;
    			union {
    				uint32_t T1;
    				struct {
    					uint32_t    :16;
    					uint32_t DLC:4;
    					uint32_t BRS:1;//CAN FD frames transmitted with bit rate switching
    					uint32_t FDF:1;//Frame transmitted in CAN FD format
    					uint32_t    :1;
    					uint32_t EFC:1;//Store Tx events
    					uint32_t MM:8;//Message marker
    				} T1Bit;
    			} T1;
    			uint8_t  Data[64];
    		} Head;
    	} TxQueueFifo[3];//Tx FIFO/Queue
    } Stm32g_FdcanMbType;
    

    如果想读rxfifo中的数据,使用该类型指针强行指向下面这个地址
    #define SRAMCAN_BASE (APBPERIPH_BASE + 0x0000B400UL)
    对于CAN2,加上sizeof(Stm32g_FdcanMbType)偏移即可,特别注意,m0不支持非对其访问,不可使用位域进行写操作!!!

    4.中断配置

    由于STM32G0B1是M0+内核,基于成本考虑,CAN1和CAN2的中断线0,CAN1和CAN2的的中断线1是同一个中断源

      .word TIM16_FDCAN_IT0_IRQHandler        /* TIM16 & FDCAN1_IT0 & FDCAN2_IT0 */
      .word TIM17_FDCAN_IT1_IRQHandler        /* TIM17 & FDCAN1_IT1 & FDCAN2_IT1 */
    

    如果同时使用CAN1和CAN2,建议CAN1使用中断线0,CAN2使中断线1,这样的好处是中断里不用判断到底是CAN1还是CAN2了,可以提升性能。注意,FIFO0&FIF01和IL0&IL1是无关的,不是FIFO0对应IL0的

    HAL_StatusTypeDef HAL_FDCAN_ConfigInterruptLines(FDCAN_HandleTypeDef *hfdcan, uint32_t ITList, uint32_t InterruptLine)
    

    使能接收中断接口

    HAL_StatusTypeDef HAL_FDCAN_ActivateNotification(FDCAN_HandleTypeDef *hfdcan, uint32_t ActiveITs,
                                                     uint32_t BufferIndexes)
    

    读取中断里接受的报文

    HAL_StatusTypeDef HAL_FDCAN_GetRxMessage(FDCAN_HandleTypeDef *hfdcan, uint32_t RxLocation,
                                             FDCAN_RxHeaderTypeDef *pRxHeader, uint8_t *pRxData)
    

    5.数据发送

    HAL_StatusTypeDef HAL_FDCAN_AddMessageToTxFifoQ(FDCAN_HandleTypeDef *hfdcan, const FDCAN_TxHeaderTypeDef *pTxHeader,
                                                    const uint8_t *pTxData)
    

    当指定为传统can帧,可以发送标准帧、扩展帧及对应的远程帧,数据长度最多为8;
    指定为canfd帧,可以设置标准帧、扩展帧,不可以发送远程帧,同时可以设置数据域波特率是否加速,数据长度分别为0~8,12,16,20,24,32,48,64(对应dlc为0-F)

    作者:w13427858168

    物联沃分享整理
    物联沃-IOTWORD物联网 » 【STM32G0B1 FDCAN调试深度解析与技巧分享】

    发表回复