stm32 HAL库分析之CAN
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 } 751752 /* 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; 792793 /* 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库里面没有发送时中断是关掉了,根本就不会在中断里面清掉标志位,根本就不存在这个问题。当我们使用中断的方式发送时, 又不会进行超时判断。因此只有在使用不规范的时候才会出现这个问题,因此这句注释就是无稽之谈。
stm32 HAL库分析之CAN相关推荐
- stm32 hal库分析之uart
hal库 uart 基本概念: 同步是指:发送方发出数据后,等接收方发回响应以后才发下一个数据包的通讯方式. 异步是指:发送方发出数据后,不等接收方发回响应,接着发送下个数据包的通讯方式. 同步是阻塞 ...
- STM32的HAL库分析及使用
STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直接配 ...
- STM32 HAL库 串口DMA(收发)和STM32串口中断接收(接收时间管理机制)+ESP8266 wifi模组通信问题
一.HAL库 串口 DMA+ESP8266模组通信问题 用STM32 HAL库串口的DMA发送和空闲中断接收处理数据,单片机发送AT指令给ESP8266 wifi模组问题:单片机连续几次给wifi模组 ...
- STM32 HAL库学习笔记4-SPI
STM32 HAL库学习笔记4-SPI 前言 一.SPI协议简介 SPI物理层 SPI协议层 1.基本通讯过程 2. 通讯的起始和停止信号 3. 数据有效性 4. CPOL/CPHA 及通讯模式 二. ...
- stm32+HAL库制作转速仪
stm32+HAL库制作转速仪 前言 电机在运行过程中,需要实时检测其转速的稳定性,有效反映电机的运行情况. 本文介绍了基于stm32的转速仪的设计,可以用光电门传感器和红外对管传感器测量,可以设置选 ...
- STM32 HAL库 CubeMX教程(五)串口通信基础
STM32 HAL库 CubeMX教程(五)串口通信基础 串口通信简介 CubeMX配置 初始化程序分析 程序编写 参考文献 STM32 HAL库 CubeMX系列教程 目录 串口通信简介 UART: ...
- STM32 HAL库详解 及 手动移植
源: STM32 HAL库详解 及 手动移植
- STM32 HAL库、标准外设库、LL库(STM32 Embedded Software)
STM32 Embedded Software 工作以来一直使用ST的STM32系列芯片,ST为开发者提供了非常方便的开发库.到目前为止,有标准外设库(STD库).HAL库.LL库 三种.前两者都是常 ...
- STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机
STM32 HAL库PID控制电机 第二章 TB6612FNG芯片驱动GB37-520电机(HAL库) 1 电路图 2 TB6612简介 TB6612是双驱动,可同时驱动两个电机 STBY:接单片机的 ...
最新文章
- requireJS 从概念到实战
- 金融贷款逾期的模型构建7——模型融合
- Ubuntu-C++环境设置
- BZOJ 3884 上帝与集合的正确用法
- Scala-列表操作
- 字符串类习题、面试题详解(第二篇)
- Oracle 11g xe版本---总结1
- 表格序号_让Excel表格中的序号自动更新,再也不怕删除、插入行了
- [NLP]OpenNLP Maven工程的依赖
- 禁止绿盟扫描oracle,Oracle Enterprise Manager Grid Control JSP代码执行漏洞(CVE-2010-3600)
- 联想笔记本电源管理-设置充电上下限
- 百度UEditor编辑器压缩(缩放)图片只压缩jpg格式的解决方法
- 短视频直播美颜sdk可以接入其它视频社交平台吗?
- NFT 生成物及素材展示(小熊、性别形象、道具)
- java下载m3u8转ts合成mp4
- css所有属性大合集,包含中文标题
- 智能电网与配网自动化工程建设
- Spark删除redis千万级别set集合数据
- 电脑pc页面在手机缩放显示
- 数据库系统概论(第五版)王珊 自用复习笔记