欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

stm32 HAL库分析之CAN

程序员文章站 2024-02-26 19:15:34
...

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和发送的帧的数据类型,数据帧还是遥控帧.
stm32 HAL库分析之CAN
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寄存器,检查三个寄存器中是否有发送完成的邮箱.
stm32 HAL库分析之CAN
stm32 HAL库分析之CAN
具体的判断逻辑如上所示,也就是去检查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库里面没有发送时中断是关掉了,根本就不会在中断里面清掉标志位,根本就不存在这个问题。当我们使用中断的方式发送时, 又不会进行超时判断。因此只有在使用不规范的时候才会出现这个问题,因此这句注释就是无稽之谈。