stm32 HAL库分析之CAN

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_27087571/article/details/81271951

stm32 HAL库分析之CAN

阻塞发送

 HAL_StatusTypeDef HAL_CAN_Transmit(CAN_HandleTypeDef* hcan, uint32_t Timeout)                       
 565 {                                                                                                   
 566   uint32_t transmitmailbox = CAN_TXSTATUS_NOMAILBOX;                                                
 567   uint32_t tickstart = 0U;                                                                          
 568                                                                                                     
 569   /* Check the parameters */                                                                        
 570   assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));                                                   
 571   assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));                                                      
 572   assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));                                                      
 573                                                                                                     
 574   if(((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) || \                                                                                                                           
 575      ((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) || \                                      
 576      ((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2))                                          
 577   {                                                                                                 
 578     /* Process locked */                                                                            
 579     __HAL_LOCK(hcan);                                                                               
 580                                                                                                     
 581     /* Change CAN state */                                                                          
 582     switch(hcan->State)                                                                             
 583     {                                                                                               
 584       case(HAL_CAN_STATE_BUSY_RX0):                                                                 
 585           hcan->State = HAL_CAN_STATE_BUSY_TX_RX0;                                                  
 586           break;                                                                                    
 587       case(HAL_CAN_STATE_BUSY_RX1):                                                                 
 588           hcan->State = HAL_CAN_STATE_BUSY_TX_RX1;                                                  
 589           break;                                                                                    
 590       case(HAL_CAN_STATE_BUSY_RX0_RX1):                                                             
 591           hcan->State = HAL_CAN_STATE_BUSY_TX_RX0_RX1;                                              
 592           break;                                                                                    
 593       default: /* HAL_CAN_STATE_READY */                                                            
 594           hcan->State = HAL_CAN_STATE_BUSY_TX;                                                      
 595           break;                                                                                    
 596     }                                                                                               
 597                                                                                                     
 598     /* Select one empty transmit mailbox */                                                         
 599     if ((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)                                         
 600     {                                                                                               
 601       transmitmailbox = CAN_TXMAILBOX_0;                                                            
 602     }                                                                                               
 603     else if ((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)                                    
 604     {                                                                                               
 605       transmitmailbox = CAN_TXMAILBOX_1;                                                            
 606     }                                                                                               
 607     else                                                                                            
 608     {                                                                                               
 609       transmitmailbox = CAN_TXMAILBOX_2;                                                            
 610     }                                                                                               
 611  
 612     /* Set up the Id */                                                                             
 613     hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;                               
 614     if (hcan->pTxMsg->IDE == CAN_ID_STD)                                                            
 615     {                                                                                               
 616       assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));                                                                                                                                   
 617       hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << 21U) | \          
 618                                                   hcan->pTxMsg->RTR);                               
 619     }                                                                                               
 620     else                                                                                            
 621     {                                                                                               
 622       assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));                                              
 623       hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << 3U) | \           
 624                                                   hcan->pTxMsg->IDE | \                             
 625                                                   hcan->pTxMsg->RTR);                               
 626     }                                                                                               
 627                                                                                                     
 628     /* Set up the DLC */                                                                            
 629     hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;                                                       
 630     hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0U;                      
 631     hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;                          
 632                                                                                                     
 633     /* Set up the data field */                                                                     
 634     hcan->Instance->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)hcan->pTxMsg->Data[3U] << 24U) | 
 635                                              ((uint32_t)hcan->pTxMsg->Data[2U] << 16U) |            
 636                                              ((uint32_t)hcan->pTxMsg->Data[1U] << 8U) |             
 637                                              ((uint32_t)hcan->pTxMsg->Data[0U]));                   
 638     hcan->Instance->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)hcan->pTxMsg->Data[7U] << 24U) | 
 639                                              ((uint32_t)hcan->pTxMsg->Data[6U] << 16U) |            
 640                                              ((uint32_t)hcan->pTxMsg->Data[5U] << 8U) |             
 641                                              ((uint32_t)hcan->pTxMsg->Data[4U]));                   
 642     /* Request transmission */                                                                      
 643     hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;                               
 644                                                                                                     
 645     /* Get tick */                                                                                  
 646     tickstart = HAL_GetTick();                                                                      
 647                                                                                                     
 648     /* Check End of transmission flag */                                                            
 649     while(!(__HAL_CAN_TRANSMIT_STATUS(hcan, transmitmailbox)))                                      
 650     {                                                                                               
 651       /* Check for the Timeout */                                                                   
 652       if(Timeout != HAL_MAX_DELAY)                                                                  
 653       {                                                                                             
 654        if((Timeout == 0U)||((HAL_GetTick() - tickstart ) > Timeout))
  655        {                                                                                            
 656          hcan->State = HAL_CAN_STATE_TIMEOUT;                                                       
 657                                                                                                     
 658          __HAL_CAN_CANCEL_TRANSMIT(hcan, transmitmailbox);                                          
 659                                                                                                     
 660          /* Process unlocked */                                                                     
 661          __HAL_UNLOCK(hcan);                                                                        
 662          return HAL_TIMEOUT;                                                                        
 663         }                                                                                           
 664       }                                                                                             
 665     }                                                                                               
 666                                                                                                     
 667     /* Change CAN state */                                                                          
 668     switch(hcan->State)                                                                             
 669     {                                                                                               
 670       case(HAL_CAN_STATE_BUSY_TX_RX0):                                                              
 671           hcan->State = HAL_CAN_STATE_BUSY_RX0;                                                     
 672           break;                                                                                    
 673       case(HAL_CAN_STATE_BUSY_TX_RX1):                                                              
 674           hcan->State = HAL_CAN_STATE_BUSY_RX1;                                                     
 675           break;                                                                                    
 676       case(HAL_CAN_STATE_BUSY_TX_RX0_RX1):                                                          
 677           hcan->State = HAL_CAN_STATE_BUSY_RX0_RX1;                                                 
 678           break;                                                                                    
 679       default: /* HAL_CAN_STATE_BUSY_TX */                                                          
 680           hcan->State = HAL_CAN_STATE_READY;                                                        
 681           break;                                                                                    
 682     }                                                                                               
 683                                                                                                     
 684     /* Process unlocked */                                                                          
 685     __HAL_UNLOCK(hcan);                                                                             
 686                                                                                                     
 687     /* Return function status */                                                                    
 688     return HAL_OK;                                                                                                                                                                       
 689   }                                                                                                 
 690   else                                                                                              
 691   {                                                                                                 
 692     /* Change CAN state */                                                                          
 693     hcan->State = HAL_CAN_STATE_ERROR;                                                              
 694                                                                                                     
 695     /* Return function status */                                                                    
 696     return HAL_ERROR;                                                                               
 697   }                                                                                                 
 698 }                            

代码分析:
1. 检查参数,根据TSR发送状态寄存器,判断可用的发送邮箱的个数,如果有可用邮箱的话就继续往下走,没有的话就报错.
2. 由小往大选定一个可用的邮箱.
3. 对邮箱的TIR寄存,标识寄存器器进行配置,主要是ID和发送的帧的数据类型,数据帧还是遥控帧.
这里写图片描述
4. 将数据的长度放到长度控制和时间戳控制寄存器TDTR
5. 将8个字节的数据放到邮箱的数据寄存器,分别是TDLR,TDHR,每个寄存器各放4个字节的数据.
6. 将TIR寄存器的TXRQ置位,请求发送邮箱里面的数据.
7. 循环等待,CAN_TSR_RQCP(上一次发送成功置位),CAN_TSR_TXOK(邮箱请求完成置位),CAN_TSR_TME(邮箱为空置位)这3个寄存器是否被置位.并且判断整个发送过程中是否超时.
8. 根据状态返回值.

无阻塞发送

706 HAL_StatusTypeDef HAL_CAN_Transmit_IT(CAN_HandleTypeDef* hcan)                                      
 707 {                                                                                                   
 708   uint32_t  transmitmailbox = CAN_TXSTATUS_NOMAILBOX;                                               
 709                                                                                                     
 710   /* Check the parameters */                                                                        
 711   assert_param(IS_CAN_IDTYPE(hcan->pTxMsg->IDE));                                                   
 712   assert_param(IS_CAN_RTR(hcan->pTxMsg->RTR));                                                      
 713   assert_param(IS_CAN_DLC(hcan->pTxMsg->DLC));                                                      
 714                                                                                                     
 715   if(((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0) || \                                                                                                                           
 716      ((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1) || \                                      
 717      ((hcan->Instance->TSR&CAN_TSR_TME2) == CAN_TSR_TME2))                                          
 718   {                                                                                                 
 719     /* Process Locked */                                                                            
 720     __HAL_LOCK(hcan);                                                                               
 721                                                                                                     
 722     /* Select one empty transmit mailbox */                                                         
 723     if((hcan->Instance->TSR&CAN_TSR_TME0) == CAN_TSR_TME0)                                          
 724     {                                                                                               
 725       transmitmailbox = CAN_TXMAILBOX_0;                                                            
 726     }                                                                                               
 727     else if((hcan->Instance->TSR&CAN_TSR_TME1) == CAN_TSR_TME1)                                     
 728     {                                                                                               
 729       transmitmailbox = CAN_TXMAILBOX_1;                                                            
 730     }                                                                                               
 731     else                                                                                            
 732     {                                                                                               
 733       transmitmailbox = CAN_TXMAILBOX_2;                                                            
 734     }                                                                                               
 735                                                                                                     
 736     /* Set up the Id */                                                                             
 737     hcan->Instance->sTxMailBox[transmitmailbox].TIR &= CAN_TI0R_TXRQ;                               
 738     if(hcan->pTxMsg->IDE == CAN_ID_STD)                                                             
 739     {                                                                                               
 740       assert_param(IS_CAN_STDID(hcan->pTxMsg->StdId));                                              
 741       hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->StdId << 21U) | \          
 742                                                 hcan->pTxMsg->RTR);                                 
 743     }                                                                                               
 744     else                                                                                            
 745     {                                                                                               
 746       assert_param(IS_CAN_EXTID(hcan->pTxMsg->ExtId));                                              
 747       hcan->Instance->sTxMailBox[transmitmailbox].TIR |= ((hcan->pTxMsg->ExtId << 3U) | \           
 748                                                 hcan->pTxMsg->IDE | \                               
 749                                                 hcan->pTxMsg->RTR);                                 
 750     }                                                                                               
 751
  752     /* Set up the DLC */                                                                            
 753     hcan->pTxMsg->DLC &= (uint8_t)0x0000000F;                                                       
 754     hcan->Instance->sTxMailBox[transmitmailbox].TDTR &= (uint32_t)0xFFFFFFF0U;                      
 755     hcan->Instance->sTxMailBox[transmitmailbox].TDTR |= hcan->pTxMsg->DLC;                          
 756                                                                                                     
 757     /* Set up the data field */                                                                                                                                                          
 758     hcan->Instance->sTxMailBox[transmitmailbox].TDLR = (((uint32_t)hcan->pTxMsg->Data[3U] << 24U) | 
 759                                            ((uint32_t)hcan->pTxMsg->Data[2U] << 16U) |              
 760                                            ((uint32_t)hcan->pTxMsg->Data[1U] << 8U) |               
 761                                            ((uint32_t)hcan->pTxMsg->Data[0U]));                     
 762     hcan->Instance->sTxMailBox[transmitmailbox].TDHR = (((uint32_t)hcan->pTxMsg->Data[7U] << 24U) | 
 763                                            ((uint32_t)hcan->pTxMsg->Data[6U] << 16U) |              
 764                                            ((uint32_t)hcan->pTxMsg->Data[5U] << 8U) |               
 765                                            ((uint32_t)hcan->pTxMsg->Data[4U]));                     
 766                                                                                                     
 767     /* Change CAN state */                                                                          
 768     switch(hcan->State)                                                                             
 769     {                                                                                               
 770       case(HAL_CAN_STATE_BUSY_RX0):                                                                 
 771           hcan->State = HAL_CAN_STATE_BUSY_TX_RX0;                                                  
 772           break;                                                                                    
 773       case(HAL_CAN_STATE_BUSY_RX1):                                                                 
 774           hcan->State = HAL_CAN_STATE_BUSY_TX_RX1;                                                  
 775           break;                                                                                    
 776       case(HAL_CAN_STATE_BUSY_RX0_RX1):                                                             
 777           hcan->State = HAL_CAN_STATE_BUSY_TX_RX0_RX1;                                              
 778           break;                                                                                    
 779       default: /* HAL_CAN_STATE_READY */                                                            
 780           hcan->State = HAL_CAN_STATE_BUSY_TX;                                                      
 781           break;                                                                                    
 782     }                                                                                               
 783                                                                                                     
 784     /* Set CAN error code to none */                                                                
 785     hcan->ErrorCode = HAL_CAN_ERROR_NONE;                                                           
 786                                                                                                     
 787     /* Process Unlocked */                                                                          
 788     __HAL_UNLOCK(hcan);                                                                             
 789                                                                                                     
 790     /* Request transmission */                                                                      
 791     hcan->Instance->sTxMailBox[transmitmailbox].TIR |= CAN_TI0R_TXRQ;                               
 792
  793     /* Enable Error warning, Error passive, Bus-off,                                                
 794        Last error and Error Interrupts */                                                           
 795     __HAL_CAN_ENABLE_IT(hcan, CAN_IT_EWG |                                                          
 796                               CAN_IT_EPV |                                                          
 797                               CAN_IT_BOF |                                                          
 798                               CAN_IT_LEC |                                                          
 799                               CAN_IT_ERR |                                                          
 800                               CAN_IT_TME);                                                          
 801   }                                                                                                 
 802   else                                                                                              
 803   {                                                                                                 
 804     /* Change CAN state */                                                                          
 805     hcan->State = HAL_CAN_STATE_ERROR;                                                              
 806                                                                                                     
 807     /* Return function status */                                                                    
 808     return HAL_ERROR;                                                                               
 809   }                                                                                                 
 810                                                                                                     
 811   return HAL_OK;                                                                                                                                                                         
 812 }                                                                                       

代码分析:
前面1-6的步骤和阻塞是发送都是一样的.
7. 开启中断
一帧数据发送完成之后,进入can的中断.
注意开启的中断:

449 #define CAN_IT_TME                  ((uint32_t)CAN_IER_TMEIE)   /*!< Transmit mailbox empty interrupt */

463 /* Error Interrupts */                                                                                                            
464 #define CAN_IT_EWG                  ((uint32_t)CAN_IER_EWGIE) /*!< Error warning interrupt   */     
465 #define CAN_IT_EPV                  ((uint32_t)CAN_IER_EPVIE) /*!< Error passive interrupt   */     
466 #define CAN_IT_BOF                  ((uint32_t)CAN_IER_BOFIE) /*!< Bus-off interrupt         */     
467 #define CAN_IT_LEC                  ((uint32_t)CAN_IER_LECIE) /*!< Last error code interrupt */     
468 #define CAN_IT_ERR                  ((uint32_t)CAN_IER_ERRIE) /*!< Error Interrupt           */ 

一个发送邮箱空中断,还有5种错误情况引起的中断

1251   if(__HAL_CAN_GET_IT_SOURCE(hcan, CAN_IT_TME))                                                     
1252   {                                                                                                 
1253     tmp1 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_0);                                        
1254     tmp2 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_1);                                        
1255     tmp3 = __HAL_CAN_TRANSMIT_STATUS(hcan, CAN_TXMAILBOX_2);                                                                     
1256     if(tmp1 || tmp2 || tmp3)                                                                                                     
1257     {                                                                                                                            
1258       tmp1 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK0);                                                            
1259       tmp2 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK1);                                              
1260       tmp3 = __HAL_CAN_GET_FLAG(hcan, CAN_FLAG_TXOK2);                                              
1261       /* Check Transmit success */                                                                  
1262       if(tmp1 || tmp2 || tmp3)                                                                      
1263       {                                                                                             
1264         /* Call transmit function */                                                                                             
1265         CAN_Transmit_IT(hcan);                                                                                                   
1266       }                                                                                                                          
1267       else /* Transmit failure */                                                                                                
1268       {                                                                                                                          
1269         /* Set CAN error code to TXFAIL error */                                                                                 
1270         errorcode |= HAL_CAN_ERROR_TXFAIL;                                                                                       
1271       }                                                                                                                          
1272                                                                                                                                  
1273       /* Clear transmission status flags (RQCPx and TXOKx) */                                       
1274       SET_BIT(hcan->Instance->TSR, CAN_TSR_RQCP0  | CAN_TSR_RQCP1  | CAN_TSR_RQCP2 | \              
1275                                    CAN_FLAG_TXOK0 | CAN_FLAG_TXOK1 | CAN_FLAG_TXOK2);               
1276     }                                                                                               
1277   }  

其中判断,发送是否完成的代码.
1. 第一句话还是和之前的一样,读取到三个邮箱的状态,也就是RQCP, TXOK,TME,三个寄存器的状态.
2. 第二句话就是进一步去判断,TXOK寄存器,检查三个寄存器中是否有发送完成的邮箱.
这里写图片描述
这里写图片描述
具体的判断逻辑如上所示,也就是去检查TSR这个寄存器的第1,9,11位来判断是否发送完成.如果发送完成就可去调用CAN_Transmit_IT,在这个里面主要是关中断,再调用用户的回调函数.
3. 清掉RQCP, TXOK寄存器的标志位

题外话:
公司的代码,移植的是can的驱动代码,里面有一句话让我觉得很奇怪:

    if(HAL_CAN_Transmit(&g_sCAN_Handler[dwDevice], 10) != HAL_OK)
    {//注:如果发送中断使能,因在发送中断里会清相关标志,这样会导致此函数会超时,而发送实际是成功的
        return FALSE; 
    }

为什么会有这样一句奇怪的注释,这里使用的阻塞的方式发送数据,那么计算超时的时候就会检查RQCP, TXOK,这两个位用来判断是否发送完成。但是在hal库里面没有发送时中断是关掉了,根本就不会在中断里面清掉标志位,根本就不存在这个问题。当我们使用中断的方式发送时, 又不会进行超时判断。因此只有在使用不规范的时候才会出现这个问题,因此这句注释就是无稽之谈。

猜你喜欢

转载自blog.csdn.net/qq_27087571/article/details/81271951