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
theId */ 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[2
U] <<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
returnHAL_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
theId */ 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[2
U] <<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) /*!< Errorwarning 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) /*!< Lasterror 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 (RQCPxand 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库里面没有发送时中断是关掉了,根本就不会在中断里面清掉标志位,根本就不存在这个问题。当我们使用中断的方式发送时,
又不会进行超时判断。因此只有在使用不规范的时候才会出现这个问题,因此这句注释就是无稽之谈。

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信