STM32H7是一款相对来说比较新的MCU,很多例程上面都是只给了一个can口的例子,对于两个can口同时使用没有明确的说明。本文主要针对同时使用CAN1 CAN2 做一个教学。
1.对于CAN口配置分为以下几点:
1.波特率配置,不细说,按照官方例程配置。
2.CANRAM配置
消息RAM的宽度为32位,总共大小10k,一个宽度为1个字,总共32个字。
其中主要分为4部分,
1。滤波器配置
2.输入数据缓冲区配置
3.输出数据缓冲区配置
4.can配置的起始地址的配置。
针对于234做一个主要的讲解。
2.3都类似,配置一个缓冲区 每个元素的长度len和所有元素的个数num,则该缓冲区的长度为 len * num
4.非常重要,CANRAM的起始地址配置。举个例子,比如上述的参数占用的RAM字节数为800字节,这块配置为CAN1的配置,RAM的起始地址为0x0400AC00,
那么结束地址就要加800字节。那么如果要配置CAN2,CAN2参数MessageRAMOffset就必须至少从800开始计算起。CAN1的MessageRAMOffset为0。这样的话CAN1和CAN2才可以同时使用。记住:CAN1和CAN2的RAM配置并不是并行配置的,是串行配置的,每个CAN的配置都占用独立的一块RAM。
贴上代码供大家参考:
CAN_PARA_CFG can_cfg[ODO_CAN_END] =
{
{
.Instance = FDCAN1,
.Mode=FDCAN_MODE_NORMAL,
.NominalPrescaler=10,
.NominalSyncJumpWidth=8,
.NominalTimeSeg1=31,
.NominalTimeSeg2=8,
.TxBuffersNbr = 0,
.TxFifoQueueElmtsNbr = 32,
.MessageRAMOffset = 0,
.filtertype = 1,
.filterID1 = 0,
.filterID2 = 0xFFFF
},
{
.Instance = FDCAN2,
.Mode=FDCAN_MODE_NORMAL,
.NominalPrescaler=10,
.NominalSyncJumpWidth=8,
.NominalTimeSeg1=31,
.NominalTimeSeg2=8,
.TxBuffersNbr=0,
.TxFifoQueueElmtsNbr = 32,
.MessageRAMOffset = 500,
.filtertype = 1,
.filterID1 = 0,
.filterID2 = 0xFFFF
}
};
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* hfdcan)
{
if (hfdcan->Instance == FDCAN1)
{
HAL_FDCAN1_MspInit(hfdcan);
}
else if(hfdcan->Instance == FDCAN2)
{
HAL_FDCAN2_MspInit(hfdcan);
}
}
void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* hfdcan)
{
if (hfdcan->Instance == FDCAN1)
{
HAL_FDCAN1_MspDeInit(hfdcan);
}
else if (hfdcan->Instance == FDCAN2)
{
HAL_FDCAN2_MspDeInit(hfdcan);
}
}
u4 board_can_init(CAN_NAME canname)
{
FDCAN_FilterTypeDef FDCANRxFilterType;
HAL_FDCAN_DeInit(&can_cfg[canname].FDCANHalHandler);
can_cfg[canname].FDCANHalHandler.Instance=can_cfg[canname].Instance;
can_cfg[canname].FDCANHalHandler.Init.FrameFormat=FDCAN_FRAME_CLASSIC; //传统模式
can_cfg[canname].FDCANHalHandler.Init.Mode=can_cfg[canname].Mode;
can_cfg[canname].FDCANHalHandler.Init.AutoRetransmission=DISABLE; //关闭自动重传
can_cfg[canname].FDCANHalHandler.Init.TransmitPause=DISABLE; //关闭传输暂停
can_cfg[canname].FDCANHalHandler.Init.ProtocolException=DISABLE; //关闭协议异常处理
can_cfg[canname].FDCANHalHandler.Init.NominalPrescaler=can_cfg[canname].NominalPrescaler; //分频系数
can_cfg[canname].FDCANHalHandler.Init.NominalSyncJumpWidth=can_cfg[canname].NominalSyncJumpWidth; //重新同步跳跃宽度
can_cfg[canname].FDCANHalHandler.Init.NominalTimeSeg1=can_cfg[canname].NominalTimeSeg1; //tsg1范围:2~256
can_cfg[canname].FDCANHalHandler.Init.NominalTimeSeg2=can_cfg[canname].NominalTimeSeg2; //tsg2范围:2~128
can_cfg[canname].FDCANHalHandler.Init.MessageRAMOffset=can_cfg[canname].MessageRAMOffset;
can_cfg[canname].FDCANHalHandler.Init.StdFiltersNbr=1; //标准信息滤波器个数
can_cfg[canname].FDCANHalHandler.Init.ExtFiltersNbr=0; //扩展信息滤波器个数
can_cfg[canname].FDCANHalHandler.Init.RxFifo0ElmtsNbr=32; //接收FIFO0元素编号
can_cfg[canname].FDCANHalHandler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8; //接收FIFO0元素大小:8字节
can_cfg[canname].FDCANHalHandler.Init.RxFifo1ElmtsNbr=0; //接收FIFO1元素编号
can_cfg[canname].FDCANHalHandler.Init.RxBuffersNbr=0; //接收缓冲编号
can_cfg[canname].FDCANHalHandler.Init.TxEventsNbr=0; //发送事件编号
can_cfg[canname].FDCANHalHandler.Init.TxBuffersNbr=can_cfg[canname].TxBuffersNbr; //发送缓冲编号
can_cfg[canname].FDCANHalHandler.Init.TxFifoQueueElmtsNbr=can_cfg[canname].TxFifoQueueElmtsNbr; //发送FIFO序列元素编号
can_cfg[canname].FDCANHalHandler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION; //发送FIFO序列模式
can_cfg[canname].FDCANHalHandler.Init.TxElmtSize=FDCAN_DATA_BYTES_8; //发送大小:8字节
if(HAL_FDCAN_Init(&can_cfg[canname].FDCANHalHandler)!=HAL_OK) return 1; //初始化FDCAN
/*fifo 0 设置为覆盖写*/
HAL_FDCAN_ConfigRxFifoOverwrite(&can_cfg[canname].FDCANHalHandler,FDCAN_RX_FIFO0,FDCAN_RX_FIFO_OVERWRITE);
FDCANRxFilterType.IdType=FDCAN_STANDARD_ID; //标准ID
FDCANRxFilterType.FilterIndex=can_cfg[canname].filtertype; //滤波器索引
FDCANRxFilterType.FilterType=FDCAN_FILTER_MASK; //滤波器类型
FDCANRxFilterType.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
FDCANRxFilterType.FilterID1=can_cfg[canname].filterID1; //>ID1
FDCANRxFilterType.FilterID2=can_cfg[canname].filterID2; //<ID2
if(HAL_FDCAN_ConfigFilter(&can_cfg[canname].FDCANHalHandler,&FDCANRxFilterType)!=HAL_OK)
{
return 2;//滤波器初始化
}
if (HAL_FDCAN_ConfigGlobalFilter(&can_cfg[canname].FDCANHalHandler, FDCAN_ACCEPT_IN_RX_FIFO0, FDCAN_ACCEPT_IN_RX_FIFO0, ENABLE, ENABLE) != HAL_OK)
{
return 2;
}
HAL_FDCAN_ActivateNotification(&can_cfg[canname].FDCANHalHandler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
HAL_FDCAN_ActivateNotification(&can_cfg[canname].FDCANHalHandler,FDCAN_IT_TX_FIFO_EMPTY,0);
can_cfg[canname].FDCAN_TxHeader.IdType = FDCAN_STANDARD_ID;
can_cfg[canname].FDCAN_TxHeader.TxFrameType = FDCAN_DATA_FRAME;
can_cfg[canname].FDCAN_TxHeader.DataLength = FDCAN_DLC_BYTES_8;
can_cfg[canname].FDCAN_TxHeader.ErrorStateIndicator = FDCAN_ESI_ACTIVE;
can_cfg[canname].FDCAN_TxHeader.BitRateSwitch = FDCAN_BRS_OFF;
can_cfg[canname].FDCAN_TxHeader.FDFormat = FDCAN_CLASSIC_CAN;
can_cfg[canname].FDCAN_TxHeader.TxEventFifoControl = FDCAN_NO_TX_EVENTS;
can_cfg[canname].FDCAN_TxHeader.MessageMarker = 0;
HAL_FDCAN_Start(&can_cfg[canname].FDCANHalHandler); //开启FDCAN
return success;
}
/*can1 初始化*/
void can1_init(void)
{
board_can_init(ODO_CAN1);
}
/*can 初始化*/
void can2_init(void)
{
board_can_init(ODO_CAN2);
}
复制代码
下面给大家奉上一个排查硬件连接的一个小技巧:
进入调试模式:
1.查看can协议状态寄存器,刚初始化完毕并且没有接上CAN总线,则LEC位是状态7,表示未检测到任何CAN总线事件。当你把设置连接上CAN总线,如果程序和硬件没什么问题,那么,LEC状态变为0.表示未发生任何错误。 如果没有连接上CAN总线,而你发送了数据给外面,则LEC会变为状态5,bit0ERR,表示在消息发送过程中,器件希望发送显性电平,但受监控的宗闲置为隐形。
可以参考我的博客:https://my.oschina.net/u/2252538/blog/3155525 |