關于stm32h743的芯片兩路CAN的配置,以及一些心得。
FDCAN_HandleTypeDef FDCAN1_Handler;
FDCAN_RxHeaderTypeDef FDCAN1_RxHeader;
FDCAN_TxHeaderTypeDef FDCAN1_TxHeader;
FDCAN_HandleTypeDef FDCAN2_Handler;
FDCAN_RxHeaderTypeDef FDCAN2_RxHeader;
FDCAN_TxHeaderTypeDef FDCAN2_TxHeader;
FDCAN_RxHeaderTypeDef RxHeader;
//初始化FDCAN1,波特率為500Kbit/S
//配置FDCAN1的時鐘源為PLL1Q=200Mhz
//presc:分頻值,取值范圍1~512
//ntsjw:重新同步跳躍時間單元.范圍:1~128
//ntsg1: 取值范圍2~256
//ntsg2: 取值范圍2~128
//mode:FDCAN_MODE_NORMAL,普通模式;FDCAN_MODE_EXTERNAL_LOOPBACK,回環模式;
//返回值:0,初始化OK;
// 其他,初始化失敗;
u8 FDCAN1_Mode_Init(u16 presc,u8 ntsjw,u16 ntsg1,u8 ntsg2,u32 mode)
{
FDCAN_FilterTypeDef FDCAN1_RXFilter;
//初始化FDCAN1
HAL_FDCAN_DeInit(&FDCAN1_Handler); //先清除以前的設置
FDCAN1_Handler.Instance=FDCAN1;
FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC; //傳統模式
FDCAN1_Handler.Init.Mode=mode; //回環測試
FDCAN1_Handler.Init.AutoRetransmission=DISABLE; //關閉自動重傳!傳統模式下一定要關閉!!!
FDCAN1_Handler.Init.TransmitPause=DISABLE; //關閉傳輸暫停
FDCAN1_Handler.Init.ProtocolException=DISABLE; //關閉協議異常處理
FDCAN1_Handler.Init.NominalPrescaler=presc; //分頻系數
FDCAN1_Handler.Init.NominalSyncJumpWidth=ntsjw; //重新同步跳躍寬度
FDCAN1_Handler.Init.NominalTimeSeg1=ntsg1; //tsg1范圍:2~256
FDCAN1_Handler.Init.NominalTimeSeg2=ntsg2; //tsg2范圍:2~128
FDCAN1_Handler.Init.MessageRAMOffset=0; //信息RAM偏移
FDCAN1_Handler.Init.StdFiltersNbr=0; //標準信息ID濾波器編號
FDCAN1_Handler.Init.ExtFiltersNbr=0; //擴展信息ID濾波器編號
FDCAN1_Handler.Init.RxFifo0ElmtsNbr=1; //接收FIFO0元素編號
FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8; //接收FIFO0元素大小:8字節
FDCAN1_Handler.Init.RxBuffersNbr=0; //接收緩沖編號
FDCAN1_Handler.Init.TxEventsNbr=0; //發送事件編號
FDCAN1_Handler.Init.TxBuffersNbr=0; //發送緩沖編號
FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=1; //發送FIFO序列元素編號
FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION; //發送FIFO序列模式
FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8; //發送大小:8字節
if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1; //初始化FDCAN
//FDCAN1_Handler.Init.MessageRAMOffset = FDCAN1_Handler.msgRam.EndAddress-SRAMCAN_BASE;
//配置RX濾波器
FDCAN1_RXFilter.IdType=FDCAN_STANDARD_ID; //標準ID
FDCAN1_RXFilter.FilterIndex=14; //濾波器索引
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK; //濾波器類型
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //過濾器0關聯到FIFO0
FDCAN1_RXFilter.FilterID1=0x0000; //32位ID
FDCAN1_RXFilter.FilterID2=0x0000; //如果FDCAN配置為傳統模式的話,這里是32位掩碼
if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//濾波器初始化
HAL_FDCAN_Start(&FDCAN1_Handler); //開啟FDCAN
HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
return 0;
}
u8 FDCAN2_Mode_Init(u16 presc,u8 ntsjw,u16 ntsg1,u8 ntsg2,u32 mode)
{
FDCAN_FilterTypeDef FDCAN2_RXFilter;
//初始化FDCAN1
// HAL_FDCAN_DeInit(&FDCAN2_Handler); //先清除以前的設置
FDCAN2_Handler.Instance=FDCAN2;
FDCAN2_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC; //傳統模式
FDCAN2_Handler.Init.Mode=mode; //回環測試
FDCAN2_Handler.Init.AutoRetransmission=DISABLE; //關閉自動重傳!傳統模式下一定要關閉!!!
FDCAN2_Handler.Init.TransmitPause=DISABLE; //關閉傳輸暫停
FDCAN2_Handler.Init.ProtocolException=DISABLE; //關閉協議異常處理
FDCAN2_Handler.Init.NominalPrescaler=presc; //分頻系數
FDCAN2_Handler.Init.NominalSyncJumpWidth=ntsjw; //重新同步跳躍寬度
FDCAN2_Handler.Init.NominalTimeSeg1=ntsg1; //tsg1范圍:2~256
FDCAN2_Handler.Init.NominalTimeSeg2=ntsg2; //tsg2范圍:2~128
FDCAN2_Handler.Init.MessageRAMOffset=FDCAN1_Handler.msgRam.EndAddress-SRAMCAN_BASE; //信息RAM偏移
FDCAN2_Handler.Init.StdFiltersNbr=0; //標準信息ID濾波器編號
FDCAN2_Handler.Init.ExtFiltersNbr=0; //擴展信息ID濾波器編號
FDCAN2_Handler.Init.RxFifo0ElmtsNbr=1; //接收FIFO0元素編號
FDCAN2_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8; //接收FIFO0元素大小:8字節
FDCAN2_Handler.Init.RxBuffersNbr=0; //接收緩沖編號
FDCAN2_Handler.Init.TxEventsNbr=0; //發送事件編號
FDCAN2_Handler.Init.TxBuffersNbr=0; //發送緩沖編號
FDCAN2_Handler.Init.TxFifoQueueElmtsNbr=2; //發送FIFO序列元素編號
FDCAN2_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION; //發送FIFO序列模式
FDCAN2_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8; //發送大小:8字節
if(HAL_FDCAN_Init(&FDCAN2_Handler)!=HAL_OK) return 1; //初始化FDCAN
//FDCAN1_Handler.Init.MessageRAMOffset = FDCAN1_Handler.msgRam.EndAddress-SRAMCAN_BASE;
//配置RX濾波器
FDCAN2_RXFilter.IdType=FDCAN_STANDARD_ID; //標準ID
FDCAN2_RXFilter.FilterIndex=0; //濾波器索引
FDCAN2_RXFilter.FilterType=FDCAN_FILTER_MASK; //濾波器類型
FDCAN2_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //過濾器0關聯到FIFO0
FDCAN2_RXFilter.FilterID1=0x0000; //32位ID
FDCAN2_RXFilter.FilterID2=0x0000; //如果FDCAN配置為傳統模式的話,這里是32位掩碼
if(HAL_FDCAN_ConfigFilter(&FDCAN2_Handler,&FDCAN2_RXFilter)!=HAL_OK) return 2;//濾波器初始化
HAL_FDCAN_Start(&FDCAN2_Handler); //開啟FDCAN
HAL_FDCAN_ActivateNotification(&FDCAN2_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
return 0;
}
//FDCAN1底層驅動,引腳配置,時鐘使能
//HAL_FDCAN_Init()調用
//hsdram:FDCAN1句柄
void HAL_FDCAN_MspInit(FDCAN_HandleTypeDef* hfdcan)
{
/*
GPIO_InitTypeDef GPIO_Initure;
RCC_PeriphCLKInitTypeDef FDCAN_PeriphClk;
__HAL_RCC_FDCAN_CLK_ENABLE(); //使能FDCAN1時鐘
__HAL_RCC_GPIOA_CLK_ENABLE(); //開啟GPIOA時鐘
//FDCAN1時鐘源配置為PLL1Q
FDCAN_PeriphClk.PeriphClockSelection=RCC_PERIPHCLK_FDCAN;
FDCAN_PeriphClk.FdcanClockSelection=RCC_FDCANCLKSOURCE_PLL;
HAL_RCCEx_PeriphCLKConfig(&FDCAN_PeriphClk);
GPIO_Initure.Pin=GPIO_PIN_11|GPIO_PIN_12; //PA11,12
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽復用
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_MEDIUM; //超高速
GPIO_Initure.Alternate=GPIO_AF9_FDCAN1; //復用為CAN1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化
*/
GPIO_InitTypeDef GPIO_Initure;
RCC_PeriphCLKInitTypeDef FDCAN_PeriphClk;
__HAL_RCC_FDCAN_CLK_ENABLE(); //使能FDCAN1時鐘
__HAL_RCC_GPIOA_CLK_ENABLE(); //開啟GPIOA時鐘
__HAL_RCC_GPIOI_CLK_ENABLE(); //開啟GPIOI時鐘
__HAL_RCC_GPIOB_CLK_ENABLE(); //開啟GPIOB時鐘
//FDCAN1時鐘源配置為PLL1Q
FDCAN_PeriphClk.PeriphClockSelection=RCC_PERIPHCLK_FDCAN;
FDCAN_PeriphClk.FdcanClockSelection=RCC_FDCANCLKSOURCE_PLL;
HAL_RCCEx_PeriphCLKConfig(&FDCAN_PeriphClk);
GPIO_Initure.Pin=GPIO_PIN_12; //PA12
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽復用
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_MEDIUM; //超高速
GPIO_Initure.Alternate=GPIO_AF9_FDCAN1; //復用為CAN1
HAL_GPIO_Init(GPIOA,&GPIO_Initure); //初始化
GPIO_Initure.Pin=GPIO_PIN_9; //PI9
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽復用
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_MEDIUM; //超高速
GPIO_Initure.Alternate=GPIO_AF9_FDCAN1; //復用為CAN1
HAL_GPIO_Init(GPIOI,&GPIO_Initure); //初始化
GPIO_Initure.Pin=GPIO_PIN_5|GPIO_PIN_13; //PB5
GPIO_Initure.Mode=GPIO_MODE_AF_PP; //推挽復用
GPIO_Initure.Pull=GPIO_PULLUP; //上拉
GPIO_Initure.Speed=GPIO_SPEED_FREQ_MEDIUM; //超高速
GPIO_Initure.Alternate=GPIO_AF9_FDCAN2; //復用為CAN2
HAL_GPIO_Init(GPIOB,&GPIO_Initure); //初始化
#if FDCAN1_RX0_INT_ENABLE
HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn,1,2);
HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn);
#endif
#if FDCAN2_RX1_INT_ENABLE
HAL_NVIC_SetPriority(FDCAN2_IT0_IRQn,1,3);
HAL_NVIC_EnableIRQ(FDCAN2_IT0_IRQn);
#endif
}
//此函數會被HAL_FDCAN_DeInit調用
//hfdcan:fdcan句柄
void HAL_FDCAN_MspDeInit(FDCAN_HandleTypeDef* hfdcan)
{
__HAL_RCC_FDCAN_FORCE_RESET(); //復位FDCAN1
__HAL_RCC_FDCAN_RELEASE_RESET(); //停止復位
#if FDCAN1_RX0_INT_ENABLE
HAL_NVIC_DisableIRQ(FDCAN1_IT0_IRQn);
#endif
#if FDCAN2_RX1_INT_ENABLE
HAL_NVIC_DisableIRQ(FDCAN2_IT0_IRQn);
#endif
}
//can發送一組數據(固定格式:ID為0X12,標準幀,數據幀)
//len:數據長度(最大為8),可設置為FDCAN_DLC_BYTES_2~FDCAN_DLC_BYTES_8
//msg:數據指針,最大為8個字節.
//返回值:0,成功;
// 其他,失敗;
u8 FDCAN1_Send_Msg(u8* msg,u32 len)
{
FDCAN1_TxHeader.Identifier=0x13; //32位ID
FDCAN1_TxHeader.IdType=FDCAN_STANDARD_ID; //標準ID
FDCAN1_TxHeader.TxFrameType=FDCAN_DATA_FRAME; //數據幀
FDCAN1_TxHeader.DataLength=len; //數據長度
FDCAN1_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;
FDCAN1_TxHeader.BitRateSwitch=FDCAN_BRS_OFF; //關閉速率切換
FDCAN1_TxHeader.FDFormat=FDCAN_CLASSIC_CAN; //傳統的CAN模式
FDCAN1_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS; //無發送事件
FDCAN1_TxHeader.MessageMarker=0;
if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN1_Handler,&FDCAN1_TxHeader,msg)!=HAL_OK) return 1;//發送
return 0;
}
u8 FDCAN2_Send_Msg(u8* msg,u32 len)
{
FDCAN2_TxHeader.Identifier=0x12; //32位ID
FDCAN2_TxHeader.IdType=FDCAN_STANDARD_ID; //標準ID
FDCAN2_TxHeader.TxFrameType=FDCAN_DATA_FRAME; //數據幀
FDCAN2_TxHeader.DataLength=len; //數據長度
FDCAN2_TxHeader.ErrorStateIndicator=FDCAN_ESI_ACTIVE;
FDCAN2_TxHeader.BitRateSwitch=FDCAN_BRS_OFF; //關閉速率切換
FDCAN2_TxHeader.FDFormat=FDCAN_CLASSIC_CAN; //傳統的CAN模式
FDCAN2_TxHeader.TxEventFifoControl=FDCAN_NO_TX_EVENTS; //無發送事件
FDCAN2_TxHeader.MessageMarker=0;
if(HAL_FDCAN_AddMessageToTxFifoQ(&FDCAN2_Handler,&FDCAN2_TxHeader,msg)!=HAL_OK) return 1;//發送
return 0;
}
//can口接收數據查詢
//buf:數據緩存區;
//返回值:0,無數據被收到;
// 其他,接收的數據長度;
u8 FDCAN1_Receive_Msg(u8 *buf)
{
if(HAL_FDCAN_GetRxMessage(&FDCAN1_Handler,FDCAN_RX_FIFO0,&FDCAN1_RxHeader,buf)!=HAL_OK)return 0;//接收數據
return FDCAN1_RxHeader.DataLength>>16;
}
u8 FDCAN2_Receive_Msg(u8 *buf)
{
if(HAL_FDCAN_GetRxMessage(&FDCAN2_Handler,FDCAN_RX_FIFO0,&FDCAN2_RxHeader,buf)!=HAL_OK)return 0;//接收數據
return FDCAN2_RxHeader.DataLength>>16;
}
#if FDCAN1_RX0_INT_ENABLE
//FDCAN1中斷服務函數
void FDCAN1_IT0_IRQHandler(void)
{
HAL_FDCAN_IRQHandler(&FDCAN1_Handler);
}
#endif
#if FDCAN2_RX1_INT_ENABLE
//FDCAN1中斷服務函數
void FDCAN2_IT0_IRQHandler(void)
{
HAL_FDCAN_IRQHandler(&FDCAN2_Handler);
}
#endif
//FIFO0回調函數
void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs)
{
u8 i=0;
u8 rxdata[8];
u8 rxdata_can1[8];
u8 rxdata_can2[8];
if((RxFifo0ITs&FDCAN_IT_RX_FIFO0_NEW_MESSAGE)!=RESET) //FIFO1新數據中斷
{
//提取FIFO0中接收到的數據
HAL_FDCAN_GetRxMessage(hfdcan,FDCAN_RX_FIFO0,&RxHeader,rxdata);
//printf("id:%#x\r\n",FDCAN1_RxHeader.Identifier);
// printf("len:%d\r\n",FDCAN1_RxHeader.DataLength>>16);
// for(i=0;i<8;i++)
//printf("rxdata[%d]:%d\r\n",i,rxdata[ i]);
HAL_FDCAN_ActivateNotification(hfdcan,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
}
}
can.h文件
//FDCAN1接收RX0中斷使能
#define FDCAN1_RX0_INT_ENABLE 0 //0,不使能;1,使能.
#define FDCAN2_RX1_INT_ENABLE 1
u8 FDCAN1_Mode_Init(u16 presc,u8 ntsjw,u16 ntsg1,u8 ntsg2,u32 mode);
u8 FDCAN1_Send_Msg(u8* msg,u32 len);
u8 FDCAN1_Receive_Msg(u8 *buf);
u8 FDCAN2_Mode_Init(u16 presc,u8 ntsjw,u16 ntsg1,u8 ntsg2,u32 mode);
u8 FDCAN2_Send_Msg(u8* msg,u32 len);
u8 FDCAN2_Receive_Msg(u8 *buf);
main函數
FDCAN1_Mode_Init(10,8,31,8,FDCAN_MODE_INTERNAL_LOOPBACK); //回環測試
FDCAN2_Mode_Init(10,8,31,8,FDCAN_MODE_INTERNAL_LOOPBACK); //回環測試
canbuf_can1_tx[0]=0;//填充發送緩沖區
canbuf_can1_tx[1]=1;
canbuf_can1_tx[2]=2;
canbuf_can1_tx[3]=3;
canbuf_can1_tx[4]=4;
canbuf_can1_tx[5]=5;
canbuf_can1_tx[6]=6;
canbuf_can1_tx[7]=7+t;
canbuf_can2_tx[0]=10;//填充發送緩沖區
canbuf_can2_tx[1]=11;
canbuf_can2_tx[2]=12;
canbuf_can2_tx[3]=13;
canbuf_can2_tx[4]=14;
canbuf_can2_tx[5]=15;
canbuf_can2_tx[6]=0x10;
canbuf_can2_tx[7]=0x11+t;
res=FDCAN1_Send_Msg(canbuf_can1_tx,FDCAN_DLC_BYTES_8);//發送8個字節
res=FDCAN2_Send_Msg(canbuf_can2_tx,FDCAN_DLC_BYTES_8);//發送8個字節
/*如果要用輪詢方式打開下列兩個函數,將中斷關掉
//key=FDCAN1_Receive_Msg(canbuf_can1_rx);
// key=FDCAN2_Receive_Msg(canbuf_can2_rx);
在調試的時候遇到不進中斷的問題,當時以為can1 fifo0對應的中斷是中斷0那么can2 的中斷則對應的是中斷1所以調試半天也不進中斷。
個人理解不知道對不對如果想要can2對應中斷1那么應該設置對應fifo1 ,在配置can2的時候偏移地址應該設置fifo1的地址才可以,這個沒有研究以后有時間在研究。
而我的設置是圍繞fifo0的配置來的所以應該遵循fifo0的配置,(fifo0對應中斷0)還有在設置fifo0的中斷時can1和can2共用回掉fifo0的函數而且他們也共用一條中斷線0,在回調函數中可以設置想要的id和數據。
本人也第一次用stm32h743的芯片在can配置的時候會有理解不對的地方還請大家指出不勝感激。
|