STM32HAL——USART系列

UART

硬件控制(RTS/CTS)

RTS (Require ToSend,发送请求)为输出信号,用于指示本设备准备好可接收数据,低电平有效,低电平说明本设备可以接收数据。

CTS (Clear ToSend,发送允许)为输入信号,用于判断是否可以向对方发送数据,低电平有效,低电平说明本设备可以向对方发送数据。

两者可在 HAL 中选择是否启用。(由硬件接口判断,并且注意在串口监视软件中设置相应的 Hardware Control )由于是硬件接口,无需修改软件层面。

中断控制

涉及 USART 的中断事件表

Interrupt Event Event Flag Enable Control Bit
TransmitData Register Empty TXE TXEIE
Clear To Send (CTS) flag CTS CTSIE
Transmission Complete TC TCIE
Received Data Ready to be Read RXNE RXNEIE
Overrun Error Detected ORE RXNEIE
Idle LineDetected IDLE IDLEIE
Parity Error PE PEIE
BreakFlag LBD LBDIE
Noise Flag, Overrun error and Framing Error in multi buffer communication NF or ORE or FE EIE

以上任意一个中断事件发生,都会进入 USARTX_IRQHandler 函数。这里需要用户自己判断标志位(具体可以参考 HAL 库做法)并处理相应中断,然后清除标志位

HAL

HAL 库实现 UART_HandleTypeDef 作为一个 UART 实例。

总的传诵方式分为三种:DMA、IT、阻塞传输。

阻塞传输:

HAL_UART_TransmitHAL_UART_Receive是阻塞传输。两个函数都会传入一个Size,为接受/发送数据的长度。待传送字符串传递完后执行下一行代码。

阻塞传输注意超时设置,这个会由于硬件关系而有不同,数量级在千级别。

中断传输:

HAL_UART_Transmit_ITHAL_UART_Receive_IT是非阻塞传输。 HAL 开启中断传送,并将 UART 设置位忙碌状态(供其余函数查询是否传输完毕)。

中断传输会调用回调函数。HAL_UART_TxCpltCallbackHAL_UART_TxHalfCpltCallbackHAL_UART_RxCpltCallbackHAL_UART_RxHalfCpltCallback 会在相应的中断处理函数执行到一定状态后调用。可以重新定义这些函数实现不同的功能。HAL_UART_IRQHandler 是 HAL 中断处理函数。在相应的中断处理函数中调用。修改一般在回调函数中进行。一般通过这个函数了解 UART 执行过程。

中断传输问题在于一定要收满字长才会停止,否则会一直等待。

DMA 传输 (见下一节)

总结:UART 一般通过这些函数调用:HAL_UART_TransmitHAL_UART_ReceiveHAL_UART_Transmit_ITHAL_UART_Receive_IT。如果需要添加特定功能,则在回调函数中修改。必要时才修改中断处理函数。

DMA

The DMA Controller

DMA 单元有如下接口:

  1. 两个主端口(peripheral & memory port)连接到 AHB 总线上。一个和外设(slave peripheral)交互,另一个和内存控制器交互。
  2. 一个从端口(slave port),实现 CPU 对 DMA 单元控制。
  3. 拥有一系列独立和可编程通道(request sources),每个与一个外设的请求线连接。
  4. 每一个通道拥有优先级供调度使用。
  5. 数据可以双向流动。( memory-to-peripheral & peripheral-to-memory)。
  • STM32F1
    DMA 结构示意

从上图可以看出:

  1. DAM 中的一条 REQ LINE (Channel) 可以与多个外设相连。DMA 通道与芯片的外设在硬件上相连,通过手册确定需要的通道。同一时间内,同一通道上只有一个设备活动。
  2. 每个通道拥有优先级,决定对总线的使用权。
  • STM32F4
    在这里插入图片描述

每个 DMA 拥有8个独立的流(Stream);每个流拥有至多8个通道(Channel)。同一时间内,流中最多有一个通道活动。

这一系列 DMA 中,只有 DMA2 可以配置为内存之间传输。

DMA 工作阶段

  • sample and arbitration phase.
  • address computation phase.
  • bus access phase.(More than one clock cycle, but there is a maximum duraion)
  • final acknowledgement phase.

Handle Type

typedef struct {
    
     
    DMA_Channel_TypeDef *Instance;/* Register base address*/ 
    DMA_InitTypeDef Init;/* DMA communication parameters */ 
    HAL_LockTypeDef Lock;/* DMA locking object*/ 
    __IO HAL_DMA_StateTypeDef State;/* DMA transfer state*/ 
    void* Parent;/* Parent object state*/ 
    void (* XferCpltCallback)( struct __DMA_HandleTypeDef * hdma); 
    void (* XferHalfCpltCallback)( struct __DMA_HandleTypeDef * hdma); 
    void (* XferErrorCallback)( struct __DMA_HandleTypeDef * hdma); 
    __IO uint32_tErrorCode;/* DMA Error code*/ 
} DMA_HandleTypeDef;
  • instance :与 DMA 通道相关。
  • Init: DMA 配置参数设置。
  • Parent : 指向外设的 Handler
  • XferCpltCallbackXferHalfCpltCallbackXferErrorCallback : DMA 回调函数。在中断处理函数中调用。

使用

  1. Polling 方式:HAL_DMA_Start 开始 DMA 传输; HAL_DMA_PollForTransfer 查询 DMA 传输状态,传输完成(或者出错后)返回。
  2. 中断方式:HAL_DMA_Start_IT 开始中断。HAL_DMA_RegisterCallback 设置回调函数。在回调函数中改变传输完成的标志位,供主函数判断是否完成。

注意在 NIVC 中配置生成 HAL 中断处理函数。

下面以 UART 开启方式说明:

    HAL_DMA_Start_IT(huart->hdmarx, (uint32_t)&huart->Instance->DR, *(uint32_t *)tmp, Size);

	// 省略
	
    /* Enable the DMA transfer for the receiver request by setting the DMAR bit
    in the UART CR3 register */
    SET_BIT(huart->Instance->CR3, USART_CR3_DMAR);

先是用 HAL_DMA_Start_IT 设置 DMA 传输,包括双方的地址,传输数据的长度。然后设置 UART 相应位,开启 DMA 中断请求。每当数据接收完成后,就会发出一次 DMA 请求,传送一次数据。直到输送完指定长度为止。这样在每次传输时,都不用经过 CPU,减轻了 CPU 负担。

内存到内存的传输不需要设置请求,开始后直接传送。

CubeMX 配置

在这里插入图片描述
图中,Priority 表示该请求的优先级。下面 Increment Address 表示每次传送是否自增地址。(对于串口,其数据寄存器固定,无需自增;而内存需要自增地址,传送下一个数据。)Data Width 每次传送的数据长度。(串口是一个字节的数据寄存器 TDR。)

F4 中内存传输函数 HAL_DMAEx_ChangeMemory , 可以独立于 CPU 传输数据。

DMA 传输数据时,数据应该声明为全局变量或者 static 变量。对于函数中的局部变量,在函数返回时会释放掉,之后用作另外数据的存储地址。此时再用 DMA 传输反而会污染数据。

Data Width 根据具体的应用场景而定,会对传输速度有较大影响。例如在内存中传输整数数组时,采用字(Word)比字节(Byte) 快。

实验记录

  • minicom

minicom 是在端口上敲入字符就传送,而不是敲下回车才一起传送。所以用 HAL_UART_Transmit 只会收到第一个字符。

修改方法

  1. 修改阻塞传输只需要修改对应函数即可。HAL_UART_TransmitHAL_UART_Receive
  2. 修改中断传输需要将修改 HAL_UART_IRQHandlerUART_Receive_ITUART_Transmit_ITUART_EndTransmit_IT。(最终依据要求确定需要修改的函数。)参考这些函数中读取数据和使能/失能中断标志位的方法HAL_UART_IRQHandler 如下所示:

在这里插入图片描述

中断标志位判断,再依据此调用相应的处理函数UART_Receive_ITUART_Transmit_ITUART_EndTransmit_IT

猜你喜欢

转载自blog.csdn.net/lib0000/article/details/112406696