背景:今天在一個項目調試的時候發現了一些問題,由此貼記錄一下問題解決的過程。
使用的芯片是GD32F305VE。使用到了CAN1和TIMER0。在使用這連個外設的時候發送了一些問題。
單獨使用CAN1。功能正常。
單獨使用TIMER0。配置為輸出模式。功能正常。
但是當兩個功能同時使用,初始化的時候,就出問題了。
1、引腳配置
//TIMER0 引腳定義
#define TIMER0_CH2_GPIO_PIN GPIO_PIN_10
#define TIMER0_CH1_GPIO_PIN GPIO_PIN_9
#define TIMER0_CH2N_GPIO_PIN GPIO_PIN_15
#define TIMER0_CH1N_GPIO_PIN GPIO_PIN_14
//CAN1引腳定義
#define CAN1_CLOCK RCU_GPIOB
#define CAN1_GPIO GPIOB
#define CAN1_TX_GPIO_PIN GPIO_PIN_13
#define CAN1_RX_GPIO_PIN GPIO_PIN_12
?從引腳上看,每個是沒有用到重復的引腳的。都是單獨分開。
2、發現問題
但是這時候,會導致一個問題。
CAN1的初始化失敗了。
//這是底層的庫函數,CAN初始化
ErrStatus can_init(uint32_t can_periph, can_parameter_struct* can_parameter_init)
{uint32_t timeout = CAN_TIMEOUT;ErrStatus flag = ERROR;/* disable sleep mode */CAN_CTL(can_periph) &= ~CAN_CTL_SLPWMOD;/* enable initialize mode */CAN_CTL(can_periph) |= CAN_CTL_IWMOD;/* wait ACK */while((CAN_STAT_IWS != (CAN_STAT(can_periph) & CAN_STAT_IWS)) && (0U != timeout)){timeout--;}/* check initialize working success */if(CAN_STAT_IWS != (CAN_STAT(can_periph) & CAN_STAT_IWS)){flag = ERROR;}else{/* set the bit timing register */CAN_BT(can_periph) = (BT_MODE((uint32_t)can_parameter_init->working_mode) | \BT_SJW((uint32_t)can_parameter_init->resync_jump_width) | \BT_BS1((uint32_t)can_parameter_init->time_segment_1) | \BT_BS2((uint32_t)can_parameter_init->time_segment_2) | \BT_BAUDPSC(((uint32_t)(can_parameter_init->prescaler) - 1U)));/* time trigger communication mode */if(ENABLE == can_parameter_init->time_triggered){CAN_CTL(can_periph) |= CAN_CTL_TTC;}else{CAN_CTL(can_periph) &= ~CAN_CTL_TTC;}/* automatic bus-off managment */if(ENABLE == can_parameter_init->auto_bus_off_recovery){CAN_CTL(can_periph) |= CAN_CTL_ABOR;}else{CAN_CTL(can_periph) &= ~CAN_CTL_ABOR;}/* automatic wakeup mode */if(ENABLE == can_parameter_init->auto_wake_up){CAN_CTL(can_periph) |= CAN_CTL_AWU;}else{CAN_CTL(can_periph) &= ~CAN_CTL_AWU;}/* automatic retransmission mode disable */if(ENABLE == can_parameter_init->no_auto_retrans){CAN_CTL(can_periph) |= CAN_CTL_ARD;}else{CAN_CTL(can_periph) &= ~CAN_CTL_ARD;}/* receive fifo overwrite mode */ if(ENABLE == can_parameter_init->rec_fifo_overwrite){CAN_CTL(can_periph) |= CAN_CTL_RFOD;}else{CAN_CTL(can_periph) &= ~CAN_CTL_RFOD;} /* transmit fifo order */if(ENABLE == can_parameter_init->trans_fifo_order){CAN_CTL(can_periph) |= CAN_CTL_TFO;}else{CAN_CTL(can_periph) &= ~CAN_CTL_TFO;} /* disable initialize mode */CAN_CTL(can_periph) &= ~CAN_CTL_IWMOD;timeout = CAN_TIMEOUT;/* wait the ACK */while((CAN_STAT_IWS == (CAN_STAT(can_periph) & CAN_STAT_IWS)) && (0U != timeout)){timeout--;}/* check exit initialize mode */if(0U != timeout){flag = SUCCESS;}} return flag;
}
進入這個函數后,會進入使能初始化工作工作模式。這個查看用戶手冊可以查到。
下圖是進入函數運行中的寄存器狀態。這是是出于初始化工作狀態的
但退出函數之前,發現并沒有退出初始化工作模式。導致初始化失敗了。
3、定位問題
在定位問題的過程中,試了一下把TIMER0的初始化先屏蔽掉。結果就又正常了。
因此定位問題發生在TIMER0的初始化。
但是很奇怪,TIMER0的初始化,只初始化了通道1,和通道2,沒有初始化通道0,按理說是不應該有影響的。
查看了寄存器
這個地方導致,這個腳被初始化為輸出。再看下一個寄存器。
這里導致輸出為高電平,和示波器抓到的波形一樣。
所以這就是導致CAN1初始化失敗的原因。
4、原理
5、解決方法
把通道0配置初始化為輸入模式。就能解決問題了。