本章描述了使用集成外设API的功能对uart (Universal Asynchronous Receiver transmitter)的控制。
JN516x微控制器有两个uart,表示为UART0和UART1,它们可以独立启用。这些uart是16550兼容的,可用于串行数据的输入/输出,可编程波特率高达4Mbps。
6.1 串口信号和引脚
UART采用以下信号接口与外部设备连接:
- 传输数据(TxD)输出-连接到外部设备上RxD
- 接收数据(RxD)输入-连接到外部设备上TxD
- 请求发送(RTS)输出- CTS连接到外部设备
- 清除发送(CTS)输入-连接到外部设备上RTS
在JN516x设备上,有两个串口:
- UART0可以在四线操作模式(默认)或2线模式
- UART1可以在2线操作模式(默认)或在1线(仅传输)
默认情况下,复用的引脚为 DIO模式
UART0使用的引脚可以替代用于连接JTAG模拟器调试。
UART0信号可以使用vAHI_UartSetLocation()函数从DIO4-7移动到DIO12-15。使用相同的功能,UART1信号可以分别从DIO14和DIO15移动到DIO11和DIO9。如果需要此函数,则必须在启用UART之前调用它。
6.2 UART操作
UART的发送和接收路径每一个都有一个FIFO缓冲区,它允许与外部设备执行多字节串行传输:
- TxD与发送FIFO连接
- RxD与接收FIFO连接
fifo包含在RAM中,由应用程序定义。每个FIFO的大小从16字节到2047字节不等。
在本地设备上,CPU可以一次写/读数据到/从FIFO一个字节或一个数据块。这两条路径是独立的,所以传输和接收是独立发生的。在fifo和TxD/RxD行之间的数据移动由DMA(直接内存访问)引擎处理,不涉及CPU。
6.2.1 两线制模式
在双线模式下,UART只使用TxD和RxD两根信号线。为了方便发送设备(例如,当发送FIFO包含一些数据时),数据是未经通知的传输。数据也可以在未通知的情况下接收,并方便发送设备。这可能会导致问题和数据的丢失——例如,如果接收设备在其接收FIFO中没有足够的空间来接收发送的数据。
6.2.2 四线模式(带流量控制)仅限UART0
四线制时,UART0的信号线为TxD、RxD、RTS和CTS。这允许实现流控制,从而确保发送的数据总是可以被接受。流量控制的一般原理如下所述。
RTS和CTS行是用来指示设备之间传输数据何时是安全的标志。其中一台设备的RTS线与另一台设备的CTS线相连。
目的设备指示源设备何时应该向它发送数据,如下所示:
- 目的地设备准备接收数据时,它断言RTS请求源设备发送数据。这可能是当目的地设备上的接收FIFO填充级别低于预先定义的级别并且FIFO能够接收更多的数据。
- 断言RTS线的目标设备被源设备视为CTS的断言。然后源设备能够从它的发送FIFO发送数据。
集成外设API提供控制和监控RTS/CTS线路的功能,允许应用程序手动实现流量控制算法。在实践中,对于繁忙的CPU来说,手动流控制可能是一个负担,特别是当UART以高波特率运行时。由于这个原因,API提供了一个自动流量控制选项,其中RTS线的状态直接由目的地设备上的接收FIFO填充级别控制。
6.2.3 单线模式(仅限UART1)
在单线模式下,UART1使用TxD线在不通知的情况下传输数据,方便发送设备。在这种模式下,数据不被接收,并且RxD线是未使用的(因此相关的DIO引脚可用作其他用途)。
6.3 配置UART
本节描述在使用UART传输串行数据之前配置UART的各个方面。
6.3.1 启用UART
UART是通过函数bAHI_UartEnable()来启用的,默认情况下,该函数在4线模式下启用UART0,在2线模式下启用UART1。这必须是第一个UART函数调用,除非你想在非默认模式下使用UART:
- 如果你想在2线使用UART0模式(没有流控制),您将首先需要调用vAHI_UartSetRTSCTS()来释放的控制量用于流量控制RTS和CTS线;
- 如果您希望使用UART1机模式(仅传输),您将首先需要调用vAHI_UartTxOnly()来释放销用于RxD的控制权。
函数bAHI_UartEnable()还允许配置用于UART发送和接收路径的FIFO缓冲区。应用程序将每个缓冲区定义为RAM的一部分,并且必须指定每个缓冲区的起始地址和大小(以字节为单位)。最大可能的缓冲区大小是2047字节,最小可能的缓冲区大小是16字节。
6.3.2 设置波特率
提供以下功能设置波特率的UART:
-
vAHI_UartSetBaudRate ()
此功能允许设置以下标准波特率之一:4800、9600、19200、38400、76800或115200bps。 -
vAHI_UartSetBaudDivisor
此函数允许指定一个16位整数除数(除数),用于从1MHz频率导出波特率,给定如下,
-
vAHI_UartSetClocksPerBit
使用这个函数可以获得比单独使用vAHI_UartSetBaudDivisor()更精确的波特率。后一个函数的除数与vAHI_UartSetClocksPerBit()的8位整数参数(Cpb)一起使用,从16MHz的外围时钟导出波特率,给出如下::
由上式可知,所能达到的最高推荐波特率为4Mbps(除数=1,Cpb=3)。
6.3.3 设置其他UART属性
除了设置UART的波特率(如6.3.2节所述)之外,还需要配置UART的许多其他属性。这些属性是使用函数vAHI_UartSetControl()设置的,包括以下内容:
- 奇偶校验位
- 字的长度(5,6,7,8),通常为8,一个字节
- 停止位(1或者1.5/2)
- RTS的初始状态
6.3.4 启用中断
可以在各种条件下生成UART中断。可以使用vAHI_UartSetInterrupt()函数启用和配置中断。可能的中断条件如下:
- 传输FIFO空:传输FIFO已成为空(因此需要更多的数据)
- 接收数据:接收FIFO填充数据到一个预定义的水平,也可以设置为1、4、8、14个字节。当FIFO填充级别再次低于预定义级别时,此中断被清除。
- 超时:启用中断时启用中断接收数据。
- 接收线状态:RxD行上发生了一个错误条件
- 调制状态:CTS线已经检测到的变化(例如,它已经被断言表明远程设备可以接受数据)的UART0操作四线模式
UART中断是由一个回调函数处理的,它必须使用函数vAHI_Uart0RegisterCallback()或vAHI_Uart1RegisterCallback()来注册。
6.4 两线模式传输串行数据
在两线模式下,UART只使用信号RxD和TxD,而不实现流量控制。
注意1:对于UART1, 2线模式为默认模式。
注意2:为了在2线模式下操作UART0,必须首先调用函数vAHI_UartSetRTSCTS()来释放用于流控制的DIOs控制。这个函数必须在vAHI_UartEnable()之前调用。
6.4.1 传输数据(两线模式)
数据通过调用以下函数之一通过UART传输:
- vAHI_UartWriteData():这个函数可以用来写一个字节的数据传输FIFO。如果使用该函数,可以多次调用该函数来对数据字节进行排队传输。
- u16AHI_UartBlockWriteData():这个函数是用来写一块数据字节传输FIFO。该函数将返回已成功写入FIFO的字节数。
一旦在FIFO中,数据字节一旦到达FIFO的头就开始被传输(并且假定TxD线是空闲的)。数据从FIFO传输到TxD行由DMA自动处理。
可以使用以下方法提示应用程序调用vAHI_UartWriteData()或u16AHI_UartBlockWriteData()函数:
- 函数u16AHI_UartReadTxFifoLevel()可以检查当前在传输FIFO中等待的字符数(如果有足够的空闲空间,那么可以将更多的数据写入FIFO)。
- 函数u8AHI_UartReadLineStatus()可以用来检查是否传输FIFO是空的。
- 可以生成一个中断当传输FIFO空(即,当最后一个数据字节的FIFO开始传播)——这启用中断使用函数vAHI_UartSetInterrupt()。
- 计时器可以用来安排周期性传输(提供数据传输)。
6.4.2 接收数据(两线模式)
当源设备发送数据时,在RxD线上接收数据。数据从RxD线到接收FIFO的本地传输由DMA引擎自动处理。目标应用程序可以使用以下函数之一从FIFO读取数据:
- u8AHI_UartReadData():这个函数可以用来读取一个字节的数据接收FIFO。
- u8AHI_UartReadLineStatus函数()可以用来检查接收FIFO包含数据是否可读(或者为空)。
以下方法可以用来提示应用程序调用u8AHI_UartReadData()或u16AHI_UartBlockReadData()函数:
- 函数u16AHI_UartReadRxFifoLevel()可以检查当前接收FIFO的字符数。
- u8AHI_UartReadLineStatus函数()可以用来检查接收FIFO包含数据是否可读(或者为空)。
- 可以生成一个中断时,接收FIFO包含一定数量的数据字节——这启用中断使用函数vAHI_UartSetInterrupt(),在中断的触发电平必须指定为1、4、8、14个字节。
- 计时器可以用来安排定期读取接收FIFO。在每次定时读取之前,可以使用u8AHI_UartReadLineStatus()或u16ahi_uartreadrxfifollevel()检查FIFO中是否存在数据。