1、STM32CubeMX配置
2、生成代码查看
3、编写代码
程序下载:http://download.csdn.net/download/white_loong/10137468
4、使用CAN分析仪测试(波特率125K)
问题:
程序CAN收发同时打开例如:
1、main() {
HAL_CAN_Receive_IT();
HAL_CAN_Transmit_IT();
}
HAL_CAN_RxCpltCallback() {
HAL_CAN_Receive_IT(); // Rearm receive
}
HAL_CAN_TxCpltCallback() {
HAL_CAN_Transmit_IT(); // Rearm transmit
}
例2:main() {
HAL_CAN_Receive_IT();
while(1){
HAL_CAN_Transmit();
}
}
HAL_CAN_RxCpltCallback() {
HAL_CAN_Receive_IT(); // Rearm receive
}
现象:调用HAL_CAN_Receive_IT
/HAL_CAN_Transmit_IT
函数失败,返回值为HAL_BUSY,之后无法再次接收/发送。
原因分析:
分析HAL库程序会发现:
HAL库在操作CAN总线时会进行上锁 __HAL_LOCK(hcan)/解锁 __HAL_LOCK(hcan)的操作,类似于进程线程操作中的互斥锁。
对例2进行分析:
主程序中HAL_CAN_Transmit()进行发送时CAN总线在上锁后解锁前,接收中断触发,进入中断回调函数。但是在再次开接收中断时CAN总线上锁导致,开中断失败。
具体程序如下:
HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)
{
uint32_t transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
uint32_t tickstart = 0;
/* Check the parameters */
assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));
assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));
assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));
/* Process locked */
__HAL_LOCK(hcan);
if(hcan->State == HAL_CAN_STATE_BUSY_RX)
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_BUSY_TX_RX;
}
else
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_BUSY_TX;
}
/* Select one empty transmit mailbox */
if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME0))
{
transmitmailbox = 0;
}
else if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME1))
{
transmitmailbox = 1;
}
else if (HAL_IS_BIT_SET(hcan->Instance->TSR, CAN_TSR_TME2))
{
transmitmailbox = 2;
}
else
{
transmitmailbox = CAN_TXSTATUS_NOMAILBOX;
}
if (transmitmailbox != CAN_TXSTATUS_NOMAILBOX)
{
/* Set up the Id */
hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;
if (hcan->pTxMsg->IDE == CAN_ID_STD)
{
assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));
hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << CAN_TI0R_STID_BIT_POSITION) |
hcan->pTxMsg->RTR);
}
else
{
assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));
hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << CAN_TI0R_EXID_BIT_POSITION) |
hcan->pTxMsg->IDE |
hcan->pTxMsg->RTR);
}
/* Set up the DLC */
hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;
hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0;
hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;
/* Set up the data field */
WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDLR, ((uint32_t)hcan->pTxMsg->Data[3] << CAN_TDL0R_DATA3_BIT_POSITION) |
((uint32_t)hcan->pTxMsg->Data[2] << CAN_TDL0R_DATA2_BIT_POSITION) |
((uint32_t)hcan->pTxMsg->Data[1] << CAN_TDL0R_DATA1_BIT_POSITION) |
((uint32_t)hcan->pTxMsg->Data[0] << CAN_TDL0R_DATA0_BIT_POSITION) );
WRITE_REG(hcan->Instance->sTxMailBox[transmitmailbox].TDHR, ((uint32_t)hcan->pTxMsg->Data[7] << CAN_TDL0R_DATA3_BIT_POSITION) |
((uint32_t)hcan->pTxMsg->Data[6] << CAN_TDL0R_DATA2_BIT_POSITION) |
((uint32_t)hcan->pTxMsg->Data[5] << CAN_TDL0R_DATA1_BIT_POSITION) |
((uint32_t)hcan->pTxMsg->Data[4] << CAN_TDL0R_DATA0_BIT_POSITION) );
/* Request transmission */
SET_BIT(hcan->Instance->sTxMailBox[transmitmailbox].TIR, CAN_TI0R_TXRQ);
/* Get timeout */
tickstart = HAL_GetTick();
/* Check End of transmission flag */
while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))
{
/* Check for the Timeout */
if(Timeout != HAL_MAX_DELAY)
{
if((Timeout == 0) || ((HAL_GetTick()-tickstart) > Timeout))
{
hcan->State = HAL_CAN_STATE_TIMEOUT;
/* Process unlocked */
__HAL_UNLOCK(hcan);
return HAL_TIMEOUT;
}
}
}
if(hcan->State == HAL_CAN_STATE_BUSY_TX_RX)
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_BUSY_RX;
/* Process unlocked */
__HAL_UNLOCK(hcan);
}
else
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_READY;
}
/* Process unlocked */
__HAL_UNLOCK(hcan);
/* Return function status */
return HAL_OK;
}
else
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_ERROR;
/* Process unlocked */
__HAL_UNLOCK(hcan);
/* Return function status */
return HAL_ERROR;
}
}
HAL_StatusTypeDef HAL_CAN_Receive_IT(CAN_HandleTypeDef* hcan, uint8_t FIFONumber)
{
/* Check the parameters */
assert_param(IS_CAN_FIFO(FIFONumber));
if((hcan->State == HAL_CAN_STATE_READY) || (hcan->State == HAL_CAN_STATE_BUSY_TX))
{
/* Process locked */
__HAL_LOCK(hcan);
if(hcan->State == HAL_CAN_STATE_BUSY_TX)
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_BUSY_TX_RX;
}
else
{
/* Change CAN state */
hcan->State = HAL_CAN_STATE_BUSY_RX;
}
/* Set CAN error code to none */
hcan->ErrorCode = HAL_CAN_ERROR_NONE;
/* Enable interrupts: */
/* - Enable Error warning Interrupt */
/* - Enable Error passive Interrupt */
/* - Enable Bus-off Interrupt */
/* - Enable Last error code Interrupt */
/* - Enable Error Interrupt */
/* - Enable Transmit mailbox empty Interrupt */
__HAL_CAN_ENABLE_IT(hcan, CAN_IT_EWG |
CAN_IT_EPV |
CAN_IT_BOF |
CAN_IT_LEC |
CAN_IT_ERR |
CAN_IT_TME );
/* Process unlocked */
__HAL_UNLOCK(hcan);
if(FIFONumber == CAN_FIFO0)
{
/* Enable FIFO 0 message pending Interrupt */
__HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP0);
}
else
{
/* Enable FIFO 1 message pending Interrupt */
__HAL_CAN_ENABLE_IT(hcan, CAN_IT_FMP1);
}
}
else
{
return HAL_BUSY;
}
/* Return function status */
return HAL_OK;
}
相关定义:
typedef struct
{
CAN_TypeDef *Instance; /*!< Register base address */
CAN_InitTypeDef Init; /*!< CAN required parameters */
CanTxMsgTypeDef* pTxMsg; /*!< Pointer to transmit structure */
CanRxMsgTypeDef* pRxMsg; /*!< Pointer to reception structure */
HAL_LockTypeDef Lock; /*!< CAN locking object */
__IO HAL_CAN_StateTypeDef State; /*!< CAN communication state */
__IO uint32_t ErrorCode; /*!< CAN Error code */
}CAN_HandleTypeDef;
#define __HAL_LOCK(__HANDLE__) \
do{ \
if((__HANDLE__)->Lock == HAL_LOCKED) \
{ \
return HAL_BUSY; \
} \
else \
{ \
(__HANDLE__)->Lock = HAL_LOCKED; \
} \
}while (0)
#define __HAL_UNLOCK(__HANDLE__) \
do{ \
(__HANDLE__)->Lock = HAL_UNLOCKED; \
}while (0)
对例2解决(例1可参照):
1、对CAN状态进行判断(推荐使用)
若已经加锁,先解锁,操作,再加锁
if((CanHandle)->Lock == HAL_LOCKED){
__HAL_UNLOCK(CanHandle);
HAL_CAN_Receive_IT(); // Rearm receive
(CanHandle )->Lock = HAL_LOCKED
}
else{
HAL_CAN_Receive_IT(); // Rearm receive
}
}
2、直接对寄存器进行操作
HAL_CAN_RxCpltCallback() {
__HAL_CAN_ENABLE_IT();
}