我是靠谱客的博主 幸福缘分,最近开发中收集的这篇文章主要介绍全志V3S裸机串口驱动(中断方式接收,DMA接收有问题,小于32字节数据无法触发DMA传输),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

调试DMA接收遇到了个很奇怪的问题,就是DMA发送没问题,DMA接收的时候,如果数据小于32字节,数据被DMA从串口接收FIFO中取走了,但是并不会传输到指定的buff中,这个就没法用于接收未知长度的数据,问题还在研究中,估计应该是DMA中有FIFO导致的,这个在全志的资料中找不到任何信息。

 

串口基址

UART0

0x01C28000

UART1

0x01C28400

UART2

0x01C28800

 

串口寄存器

寄存器名称

偏移

解释

UART_RBR

0x00

UART接收缓冲寄存器

UART_THR

0x00

UART发送保持寄存器

UART_DLL

0x00

UART波特率除数锁存器低位寄存器

UART_DLH

0x04

UART波特率除数锁存器高位寄存器

UART_IER

0x04

UART中断使能寄存器

UART_IIR

0x08

UART中断身份寄存器

UART_FCR

0x08

UART FIFO控制寄存器

UART_LCR

0x0C

UART线控制寄存器

UART_MCR

0x10

UART调制解调器控制寄存器

UART_LSR

0x14

UART线状态寄存器

UART_MSR

0x18

UART调制解调器状态寄存器

UART_SCH

0x1C

UART暂存器

UART_USR

0x7C

UART状态寄存器

UART_TFL

0x80

UART发送FIFO级别

UART_RFL

0x84

UART接收FIFO级别

UART_HALT

0xA4

UART暂停TX寄存器

 

寄存器功能

UART_RBR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:0

R

0

UART接收缓冲寄存器

用于读取接收到的数据,只有当UART_LCR 的数据就绪DR=1时有效;

如果在FIFO模式下,且FIFO模式使能(UART_FCR[0]=1),则该寄存器访问接收FIFO的头部。 如果接收FIFO已满,并且在下一个数据字符到达之前未读取该寄存器,则将保留FIFO中已经存在的数据,但是所有输入数据都会丢失,并且会发生溢出错误。

 

 

 

 

UART_THR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:0

W

0

UART发送保持寄存器

用于发送数据,只有当UART_THRE的LSR[5]=1时,表示发送为空,才能将数据写入此寄存器。

如果在FIFO模式下启用了FIFO(FCR [0] = 1)并且设置了THRE,则在FIFO满之前可以将16个字符的数据写入THR。 当FIFO已满时,任何写数据的尝试都会导致写数据丢失。

 

 

 

 

UART_DLL

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:0

R/W

0

UART除数锁存器低位寄存器

16位读/写除数锁存寄存器的低8位,其中包含UART的波特率除数。 仅当DLAB位(LCR [7])置1并且UART不忙(USR [0]为零)时,才可以访问该寄存器。

输出波特率等于串行时钟(sclk)频率除以波特率除数值的16倍,如下所示:波特率=(串行时钟频率)/(16 *除数)。

注意,将除数锁存寄存器(DLL和DLH)设置为零时,波特率时钟被禁用,并且不发生串行通信。 同样,一旦设置了DLL,在发送或接收数据之前,至少应允许通过最慢的UART时钟的8个时钟周期。

 

 

 

 

UART_DLH

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:0

R/W

0

UART除数锁存器高位寄存器

16位读/写除数锁存寄存器的高8位,其中包含UART的波特率除数。 仅当DLAB位(LCR [7])置1并且UART不忙(USR [0]为零)时,才可以访问该寄存器。

输出波特率等于串行时钟(sclk)频率除以波特率除数值的16倍,如下所示:波特率=(串行时钟频率)/(16 *除数)。

注意,将除数锁存寄存器(DLL和DLH)设置为零时,波特率时钟被禁用,并且不发生串行通信。 同样,一旦设置了DLL,在发送或接收数据之前,至少应允许通过最慢的UART时钟的8个时钟周期。

 

 

 

 

UART_IER

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7

R/W

0

PTIME

可编程的中断模式使能

这用于启用/禁用三个中断的生成。

0:禁用

1:启用

6:4

-

-

-

3

R/W

0

EDSSI

启用调制解调器状态中断

这用于启用/禁用调制解调器状态中断的生成。 这是第四高优先级的中断。

0:禁用

1:启用

2

R/W

0

ELSI

启用接收器线路状态中断

这用于启用/禁用接收器线路状态中断的生成。 这是最高优先级的中断。

0:禁用

1:启用

1

R/W

0

ETBEI

使能发送保持寄存器空中断

这用于启用/禁用发送器保持寄存器空中断的生成。 这是第三高优先级的中断。

0:禁用

1:启用

0

R/W

0

ERBFI

启用接收到的数据可用中断

这用于启用/禁用接收数据可用中断和字符超时中断的生成(如果处于FIFO模式且启用了FIFO)。 这些是第二高优先级的中断。

0:禁用

1:启用

 

 

 

 

UART_IIR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:6

R

0

FEFLAG

FIFO使能标志

这用于指示启用还是禁用FIFO。

00:禁用

11:启用

5:4

-

-

-

3:0

R

0x1

IID

中断ID

这表示最高优先级的挂起中断,可以是以下类型之一:

0000:调制解调器状态

0001:没有待处理的中断

0010:THR为空

0100:接收到的数据可用

0110:接收器线路状态

0111:忙检测

1100:角色超时

位3指示仅当使能FIFO并将其用于区分字符超时条件中断时,才会发生中断。

 

中断id定义

中断id

优先级

中断类型

中断源

中断复位

0001

-

None

None

-

0110

接收线状态

溢出/奇偶校验/成帧错误或中断中断

读取线路状态寄存器

0100

第二

收到的数据可用

可用的接收器数据(禁用非FIFO模式或FIFO)或达到RCVR FIFO触发级别(启用FIFO模式和FIFO)

读取接收器缓冲寄存器(非FIFO模式或FIFO禁用)或FIFO降至触发电平以下(启用FIFO模式和FIFO)

1100

第二

字符超时指示

在最近的4个字符时间内,没有字符进出RCVR FIFO,并且在此期间至少有1个字符。

读取接收器缓冲寄存器

0010

第三

发送保持寄存器为空

发送器保持寄存器为空(禁止编程THRE模式)或XMIT FIFO等于或低于阈值(允许编程THRE模式)

读取IIR寄存器(如果有中断源); 或者,写入THR(未选择或禁用FIFO或三种模式)或超出阈值的XMIT FIFO(选择并启用了FIFO和THE模式)。

0000

第四

调制解调器状态

清除发送或数据集准备就绪或振铃指示器或数据载体检测。 请注意,如果启用了自动流控制模式,则CTS的更改(即设置了DCTS)不会引起中断。

读取调制解调器状态寄存器

0111

第五

忙检测指示

UART_16550_COMPATIBLE = NO,并且在UART忙时(USR [0]设置为1),主机尝试写入线路控制寄存器。

读取UART状态寄存

 

UART_FCR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:6

W

0

RT

RCVR触发

这用于选择接收器FIFO中的触发级别,在该触发级别生成接收到的数据可用中断。 在自动流控制模式下,它用于确定何时取消激活rts_n信号。 它还确定在某些操作模式下何时断言dma_rx_req_n信号。

FIFO中的

00:1个字符

01:FIFO¼已满

10:FIFO½已满

11:FIFO-2未满

5:4

W

0

TFT

TX空触发器

当THRE_MODE_USER =禁用时,写入无效。 该模式用于选择模式处于活动状态时在其上生成THRE中断的空阈值级别。 它还确定在某些操作模式下何时确定dma_tx_req_n信号。

00:FIFO为空

01:FIFO中2个字符

10:FIFO¼已满

11:FIFO½已满

3

W

0

DMAM

DMA模式

0:模式0

1:模式1

2

W

0

XFIFOR

XMIT FIFO复位

这将复位发送FIFO的控制部分,并将FIFO视为空。 这也会使DMA TX请求无效。这是“自我清除”,无需清除此位。

1

W

0

RFIFOR

RCVR FIFO复位

这将重置接收FIFO的控制部分,并将FIFO视为空。 这也会使DMA RX请求无效。这是“自我清除”,无需清除此位。

0

W

0

FIFOE

启用FIFO

这将启用/禁用发送(XMIT)和接收(RCVR)FIFO。 每当该位的值改变时,FIFO的XMIT和RCVR控制器部分都会复位。

 

 

 

 

 

UART_LCR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7

R/W

0

DLAB

除数锁存器访问位

仅当UART不忙(USR [0]为零)且始终可读时,它才可写。 该位用于使能除数锁存寄存器(DLL和DLH)的读写,以设置UART的波特率。 初始波特率设置后,必须清除该位以访问其他寄存器。

0:选择RX缓冲寄存器(RBR)/ TX保持寄存器(THR)和中断使能寄存器(IER)

1:选择除数锁存LS寄存器(DLL)和除数锁存MS寄存器(DLM)

 

6

R/W

0

BC

中断控制位

这用于使中断条件发送到接收设备。 如果设置为1,则串行输出被强制为间隔(逻辑0)状态。 当未处于由MCR [4]确定的环回模式时,将输出线强制为低电平,直到清除间隔位。 如果SIR_MODE =启用且处于活动状态(MCR [6]设置为1),则sir_out_n线会持续产生脉冲。 在环回模式下,中断条件在内部循环回到接收器,并且sir_out_n线被强制为低电平。

 

5:4

R/W

0

EPS

偶校验选择

仅当UART不忙(USR [0]为零)且始终可写时,它才可写。 启用奇偶校验(PEN设置为1)时,该选项用于在偶校验和奇校验之间进行选择。 设置LCR [5]将反转LCR [4]。

00:奇校验

01:偶校验

1X:反向LCR [4]

3

R/W

0

PEN

奇偶校验启用

仅当UART不忙(USR [0]为零)且始终可读时,它才可写。 该位用于分别启用和禁用发送和接收串行字符中的奇偶校验生成和检测。

0:禁用奇偶校验

1:启用奇偶校验

2

R/W

0

STOP

停止位数

仅当UART不忙(USR [0]为零)且始终可读时,它才可写。 这用于选择外围设备发送和接收的每个字符的停止位数。 如果设置为零,则在串行数据中发送一个停止位。 如果设置为1且数据位设置为5(LCR [1:0]设置为零),则发送一个半停止位。 否则,将发送两个停止位。 请注意,无论选择多少停止位,接收器仅检查第一个停止位。

0:1个停止位

1:当DLS(LCR [1:0])为零时,1.5个停止位,否则2个停止位

1:0

R/W

0

DLS

数据长度选择

仅当UART不忙(USR [0]为零)且始终可读时,它才可写。 这用于选择外围设备发送和接收的每个字符的数据位数。 可以选择的区域的位数如下:

00:5位

01:6位

10:7位

11:8位

 

 

 

 

UART_MCR

 

 

 

bit

R/W

默认值(HEX)

解释

31:7

-

-

-

6

R/W

0

SIRE

SIR模式启用

0:IrDA SIR模式禁用

1:启用IrDA SIR模式

5

R/W

0

AFCE

自动流控制启用

当启用FIFO并将自动流控制启用(AFCE)位置1时,将启用自动流控制功能。

0:禁用自动流控制模式

1:启用自动流控制模式

4

R/W

0

LOOP

回送模式

0:普通模式

1:回送模式

这用于使UART进入诊断模式以进行测试。 如果在UART模式下工作(SIR_MODE!=启用或未激活,MCR [6]设置为零),则输出线上的数据保持高电平,而串行数据输出在内部循环回到正弦线。 在这种模式下,所有中断都可以正常运行。 同样,在环回模式下,调制解调器控制输入(dsr_n,cts_n,ri_n,dcd_n)被断开,调制解调器控制输出(dtr_n,rts_n,out1_n,out2_n)在内部循环回到输入。 如果在红外模式下运行(SIR_MODE ==启用并激活,MCR [6]设置为1),则sir_out_n线上的数据保持低电平,而串行数据输出取反并循环回到sir_in线。

3:2

-

-

-

1

R/W

0

RTS

要求发送

这用于直接控制发送请求(rts_n)输出。 发送请求(rts_n)输出用于通知调制解调器或数据集UART已准备好交换数据。 当未启用自动RTS流控制(MCR [5]设置为零)时,通过将MCR [1](RTS)编程为高电平,可以将rts_n信号设置为低电平。在自动流控制中,AFCE_MODE ==启用并激活(MCR [5]设置为1)和FIFO使能(FCR [0]设置为1),rts_n输出的控制方式相同,但也通过接收器FIFO阈值触发器进行门控(当阈值以上时,rts_n为高电平无效) 。 当MCR [1]设置为低电平时,rts_n信号无效。

0:rts_n无效(逻辑1)

1:断言rts_n(逻辑0)

请注意,在环回模式(MCR [4]设置为1)下,rts_n输出保持为高电平无效,而此位置的值在内部环回至输入。

0

R/W

0

DTR

数据终端就绪

这用于直接控制数据终端就绪(dtr_n)输出。 写入此位置的值将被反转并在dtr_n上驱除。

0:dtr_n无效(逻辑1)

1:dtr_n置位(逻辑0)

数据终端就绪输出用于通知调制解调器或数据集UART准备建立通信。

请注意,在环回模式(MCR [4]设置为1)下,dtr_n输出保持为高电平无效,而此位置的值在内部环回至输入。

 

 

 

 

UART_LSR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7

R

0

FIFOERR

FIFO中的RX数据错误

禁用FIFO时,此位始终为0。启用FIFO时,如果RX FIFO中至少有一个PE,FE或BI,则该位设置为1。 只要FIFO中没有后续错误,就可以通过读取LSR寄存器来清除它。

6

R

0

TEMT

发送器空

如果禁用了FIFO,则每当TX保持寄存器和TX移位寄存器为空时,此位就设置为“ 1”。 如果使能了FIFO,则只要TX FIFO和TX移位寄存器为空,该位置1。 在这两种情况下,当一个字节被写入TX数据通道时,该位被清除。

5

R

0

THRE

TX保持寄存器为空

如果禁用了FIFO,则每当TX保持寄存器为空并准备接受新数据时,此位就设置为“ 1”,并且在CPU写入TX保持寄存器时将其清除。

如果启用了FIFO,则只要TX FIFO为空,该位就设置为“ 1”;写入至少一个字节后,该位将被清除。

到TX FIFO。

4

R

0

BI

数据中断中断

这用于指示检测到串行输入数据上的中断序列。

只要串行输入sin保持在逻辑“ 0”状态的时间长于开始时间+数据位+奇偶校验+停止位的总和,则该位置1。

在FIFO模式下,与中断条件相关的字符通过FIFO传送,并在字符位于FIFO顶部时显示。 读取LSR将清除BI位。 在非FIFO模式下,BI指示立即发生并一直持续到读取LSR。

 

3

R

0

FE

帧错误

这用于指示接收器中发生帧错误。 当接收器未在接收到的数据中检测到有效的STOP位时,就会发生成帧错误。

在FIFO模式下,由于成帧错误与接收到的字符相关联,因此当有成帧错误的字符位于FIFO的顶部时会显示出来。 当发生帧错误时,UART尝试重新同步。 它通过假设错误是由于下一个字符的起始位引起的,然后继续接收其他位(即数据)和/或奇偶校验和停止来完成此操作。 应该注意的是,如果中断中断发生,则帧错误(FE)位(LSR [3])将置1。

如中断中断(BI)位(LSR [4])所示。

0:无成帧错误

1:成帧错误

读取LSR会清除FE位。

 

2

R

0

PE

奇偶错误

如果奇偶校验使能(PEN)位(LCR [3])被置1,则用于指示接收器中发生奇偶校验错误。 在FIFO模式下,由于奇偶校验错误与接收到的字符相关联,因此当具有奇偶校验错误的字符到达FIFO的顶部时会显示出来。 应当注意,如果发生中断中断,则奇偶校验错误(PE)位(LSR [2])将置位,如中断中断(BI)位(LSR [4])所示。

0:无奇偶校验错误

1:奇偶校验错误

读取LSR会清除PE位。

1

R

0

OE

溢出错误

如果在读取之前的数据之前接收到新的数据字符,则会发生这种情况。 在非FIFO模式下,在从RBR读取前一个字符之前,当新字符到达接收器时,OE位置1。 发生这种情况时,RBR中的数据将被覆盖。 在FIFO模式下,当FIFO已满并且新字符到达接收器时,会发生溢出错误。 FIFO中的数据将保留,而接收移位寄存器中的数据将丢失。

0:无溢出错误

1:超限错误

读取LSR将清除OE位。

0

R

0

DR

数据就绪

这用于指示接收器在RBR或接收器FIFO中至少包含一个字符。

0:无数据准备

1:数据准备就绪

在非FIFO模式下读取RBR时,或在FIFO模式下接收方FIFO为空时,该位清零。

 

 

 

 

UART_MSR

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7

R

0

DCD

数据载体检测的线路状态

这用于指示调制解调器控制线dcd_n的当前状态。 该位是dcd_n的补码。 断言数据载波检测输入(dcd_n)时,表明调制解调器或数据集已检测到载波。

0:dcd_n输入无效(逻辑1)

1:断言dcd_n输入(逻辑0)

6

R

0

RI

振铃线状态

这用于指示调制解调器控制线ri_n的当前状态。 该位是ri_n的补码。 当振铃指示器输入(ri_n)被断言时,表明调制解调器或数据集已接收到电话振铃信号。

0:禁用ri_n输入(逻辑1)

1:ri_n输入有效(逻辑0)

5

R

0

DSR

数据集的线路状态就绪

这用于指示调制解调器控制线dsr_n的当前状态。 该位是dsr_n的补码。 断言数据集就绪输入(dsr_n)时,表明调制解调器或数据集已准备好与UART建立通信。

0:取消激活dsr_n输入(逻辑1)

1:断言dsr_n输入(逻辑0)

在环回模式(MCR [4]设置为1)下,DSR与MCR [0](DTR)相同。

4

R

0

CTS

清除发送的线路状态

这用于指示调制解调器控制线cts_n的当前状态。 该位是cts_n的补码。 确认清除发送输入(cts_n)时,表明调制解调器或数据集已准备好与UART交换数据。

0:cts_n输入无效(逻辑1)

1:断言cts_n输入(逻辑0)

在环回模式(MCR [4] = 1)下,CTS与MCR [1](RTS)相同。

3

R

0

DDCD

Delta数据载体检测

这用于指示自上次读取MSR以来,调制解调器控制线dcd_n已更改。

0:自上次读取MSR以来,dcd_n不变

1:自上次读取MSR以来在dcd_n上进行更改

读取MSR将清除DDCD位。

注:如果未设置DDCD位并且dcd_n信号被置为有效(低电平)并且发生了复位(软件或其他方式),则如果dcd_n信号仍然处于有效状态,则在除去复位后DDCD位置1。

2

R

0

TERI

后缘振铃指示器

这用于指示自上次读取MSR以来,输入ri_n发生了更改(从低电平有效到高电平无效)。

0:自上次读取MSR以来ri_n不变

1:自上次读取MSR以来在ri_n上进行更改

读取MSR将清除TERI位。

1

R

0

DDSR

Delta数据集就绪

这用于指示自上次读取MSR以来,调制解调器控制线dsr_n已更改。

0:自上次读取MSR以来,dsr_n不变

1:自上次读取MSR以来在dsr_n上进行更改

读取MSR将清除DDSR位。 在环回模式(MCR [4] = 1)中,DDSR反映了MCR [0](DTR)的变化。

注:如果未将DDSR位置1并将dsr_n信号置为有效(低电平)并且发生了复位(软件或其他方式),则如果dsr_n信号仍保持有效状态,则在除去复位后DDSR位置1。

0

R

0

DCTS

Delta清除发送

这用于指示自上次读取MSR以来,调制解调器控制线cts_n已更改。

0:自上次读取MSR以来,ctsdsr_n不变

1:自上次读取MSR以来在ctsdsr_n上进行更改

读取MSR将清除DCTS位。 在环回模式(MCR [4] = 1)中,DCTS反映了MCR [1](RTS)的变化。

注意:如果未设置DCTS位,并且cts_n信号被置为有效(低电平),并且发生了复位(软件或其他方式),则如果cts_n信号仍然处于有效状态,则在清除复位后将DCTS位置1。

 

 

 

 

UART_SCH

 

 

 

bit

R/W

默认值(HEX)

解释

31:8

-

-

-

7:0

R/W

0

SCRATCH_REG

暂存器

该寄存器供程序员用作临时存储空间。 它在UART中没有定义的目的。

 

 

 

 

UART_USR

 

 

 

bit

R/W

默认值(HEX)

解释

31:5

-

-

-

4

R

0

RFF

接收FIFO已满

这用于指示接收FIFO完全满。

0:接收FIFO未满

1:接收FIFO已满

当RX FIFO不再满时,该位被清除。

3

R

0

RFNE

接收FIFO不为空

这用于指示接收FIFO包含一个或多个条目。

0:接收FIFO为空

1:接收FIFO不为空

当RX FIFO为空时该位被清除。

2

R

0

TFE

发送FIFO为空

这用于指示发送FIFO完全为空。

0:发送FIFO不为空

1:发送FIFO为空

TX FIFO不再为空时,该位清零。

1

R

0

TFNF

发送FIFO未满

这用于指示发送FIFO未满。

0:发送FIFO已满

1:发送FIFO未满

TX FIFO已满时,该位被清除。

0

R

0

BUSY

UART忙位

0:空闲或无效

1:忙

 

 

 

 

UART_TFL

 

 

 

bit

R/W

默认值(HEX)

解释

31:7

-

-

-

6:0

R

0

TFL

发送FIFO级别

这表示发送FIFO中的数据条目数。

 

 

 

 

UART_RFL

 

 

 

bit

R/W

默认值(HEX)

解释

31:7

-

-

-

6:0

R

0

RFL

接收FIFO级别

这表示接收FIFO中的数据条目数。

 

 

 

 

UART_HALT

 

 

 

bit

R/W

默认值(HEX)

解释

31:6

-

-

-

5

R/W

 

SIR_RX_INVERT

SIR接收器脉冲极性反转

0:不反转接收器信号

1:反转接收器信号

4

R/W

 

SIR_TX_INVERT

SIR发射脉冲极性反转

0:不反转发送脉冲

1:反转发射脉冲

3

-

-

-

2

R/W

 

CHANGE_UPDATE

用户使用HALT [1]更改波特率或LCR配置后,写入1以更新配置,并等待该位自清除为0以完成更新过程。 向该位写入0无效。

1:更新触发器,更新完成后自清除为0。

1

R/W

 

CHCFG_AT_BUSY

当UART繁忙(USB [0]为1)时,这是一个使能位,供用户更改LCR寄存器配置(DLAB位除外)和波特率寄存器(DLH和DLL)。

1:忙时启用更改

0

R/W

 

HALT_TX

暂停TX

该寄存器用于暂停传输以进行测试,以便在实现和启用FIFO时,主机可以填充发送FIFO。

0:禁止暂停发送

1:停止发送

注意:如果未启用FIFO,则暂停TX寄存器的设置不会影响操作。

 

代码,只初始化了串口0的IO,也只测试过串口0,使用的FIFO+中断接收,尽量减少中断次数

UART.c

/*************************************************************************************************************
 * 文件名:			uart.c
 * 功能:			全志v3s UART通讯支持
 * 作者:			cp1300@139.com
 * 创建时间:		2020-08-11
 * 最后修改时间:	2020-08-17
 * 详细:			串口通信底层支持
*************************************************************************************************************/
#include "v3s_system.h"
#include "uart.h"
#include "typedef.h"
#if UART_DMA_EN	//使用DMA接收
#include "dma.h"
static DMA_CH_Type sg_UartRxDmaChannel[UART_ChMax] = {DMA_CH_NULL, DMA_CH_NULL, DMA_CH_NULL};					//初始化为无效
static const DMA_SOURCE_DRQ_TYPE scg_UartDmaRxDRQ[UART_ChMax] = {DMA_SOURCE_UART0_RX, DMA_SOURCE_UART1_RX, DMA_SOURCE_UART2_RX};	//串口 DMA 源类型
static const DMA_DEST_DRQ_TYPE scg_UartDmaTxDRQ[UART_ChMax] = {DMA_DEST_UART0_TX, DMA_DEST_UART1_TX, DMA_DEST_UART2_TX};			//串口 DMA 目标类型
static DMA_LLI_TYPE dma_tx_lln[UART_ChMax];                                                                                         //串口发送DMA链表
static DMA_LLI_TYPE dma_rx_lln[UART_ChMax];                                                                                         //串口接收DMA链表

#else
#include "irq_gic400.h"
static const V3S_IRQ_Typedef scg_UartIrqType[UART_ChMax] = {V3S_IRQ_UART0, V3S_IRQ_UART1, V3S_IRQ_UART2};	//中断编号
void UART1_IRQHandler(void);//串口1接收中断
void UART2_IRQHandler(void);//串口2接收中断
void UART3_IRQHandler(void);//串口3接收中断
static const void *scg_pUartIrqHandle[UART_ChMax] = {(const void *)UART1_IRQHandler, (const void *)UART2_IRQHandler, (const void *)UART3_IRQHandler};

#endif //UART_DMA_EN

static const u32 scg_UARTx_Base[UART_ChMax] = {UART0_BASE, UART1_BASE, UART2_BASE};		//基址

//相关UART状态结构
typedef struct
{
	bool		isNewDataFlag;	//接收到新数据
	bool		isBuffFull;		//接收Buff满
	bool		isIntRx;		//是否开启中断接收
	u8 			*RxBuff;		//接收Buff指针
	u16			RxBuffSize;		//接收缓冲区大小,一帧数据大小
	u16 		UartRxCnt;		//接收数据计数器
	u8			TempData;		//用于接收溢出后读取数据寄存器,清除读取数据标志
} UartRx_TypeDef;
static UartRx_TypeDef sg_UartRx[UART_ChMax];

/*************************************************************************************************************************
*函数        	:	bool UARTx_Config(UART_CH_Type ch,UART_Config_TypeDef * cfg)
*功能        	:	串口配置
*参数        	:	ch:串口号;cfg:配置结构体
*返回        	:	TRUE:配置成功; FALSE: 配置失败
*依赖			: 	底层宏定义
*作者       	:	cp1300@139.com
*时间     		:	2020-08-11
*最后修改时间	:	2020-08-11
*说明        	:	调用前请提前停止发送
*************************************************************************************************************************/
bool UARTx_Config(UART_CH_Type ch,UART_Config_TypeDef * cfg)
{
	u32 temp;
	bool isBusy;
	
	if(ch > UART_ChMax - 1)
		return FALSE;	//端口号超出范围
	
	isBusy = (r_UARTx_USR(scg_UARTx_Base[ch]) & BIT0) ? TRUE : FALSE;	//获取忙状态
	if(isBusy) 											//当前忙
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT1;		//使能忙时修改拨通了与LCR配置
	}
	else
	{
		r_UARTx_LCR(scg_UARTx_Base[ch]) &= ~BIT7;		//清除掉DLAB,此位必须清零才能访问其他寄存器;
	}
	
	//配置寄存器
	temp = 0;
	if(cfg->OddEvenVerify)								//开启了奇偶校验
	{
		temp |= BIT3;	
		if(cfg->OddEvenVerify == UART_EVEN)				//偶校验
		{
			temp |= BIT4;
		}
	}
	//停止位
	if(cfg->StopBitWidth == UART_STOP_2BIT)				//2个停止位
	{
		temp |= BIT2;	
	}

	//数据位数
	temp |= cfg->DataBitWidth & 0x3;
	//配置写入到LCR
	r_UARTx_LCR(scg_UARTx_Base[ch]) = temp;
	
	if(isBusy) 	
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT2;		//更新忙时修改
		while(r_UARTx_HALT(scg_UARTx_Base[ch]) & BIT2);	//等待更新成功
		r_UARTx_HALT(scg_UARTx_Base[ch]) &= ~BIT1;		//清除忙时修改拨通了与LCR配置
	}
	
	return TRUE;
}



/*************************************************************************************************************************
* 函数	:	void UARTx_SetBaudRate(UART_CH_Type ch,u32 baud)
* 功能	:	串口波特率设置
* 参数	:	ch:通道选择,baud:波特率,如9600,115200等等
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	2013316
* 最后修改时间 : 2013316
* 说明	: 	USART1~UART5,对应通道UART_CH1-UART_CH5
			设置前必须关闭串口
			会自动获取系统当前的时钟,并进行计算.
*************************************************************************************************************************/
bool UARTx_SetBaudRate(UART_CH_Type ch,u32 baud)
{
	u32 SysClk = 0;
	bool isBusy;
	
	SysClk = 24000000;										//获取系统时钟
	SysClk = SysClk / 16 / baud;							//计算波特率分频系数
	
	if(ch > UART_ChMax - 1)
		return FALSE;	//端口号超出范围
    
	isBusy = (r_UARTx_USR(scg_UARTx_Base[ch]) & BIT0) ? TRUE : FALSE;	//获取忙状态
	if(isBusy) 												//当前忙
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT1;			//使能忙时修改拨通了与LCR配置
	}
	else
	{
		r_UARTx_LCR(scg_UARTx_Base[ch]) |= BIT7;			//设置DLAB,才能设置波特率
	}
	
	
	r_UARTx_DLL(scg_UARTx_Base[ch]) = SysClk & 0xFF;		
	r_UARTx_DLH(scg_UARTx_Base[ch]) = (SysClk>>8) & 0xFF;
	
	if(isBusy) 												//当前忙
	{
		r_UARTx_HALT(scg_UARTx_Base[ch]) |= BIT2;			//更新忙时修改
		while(r_UARTx_HALT(scg_UARTx_Base[ch]) & BIT2);		//等待更新成功
		r_UARTx_HALT(scg_UARTx_Base[ch]) &= ~BIT1;			//清除忙时修改拨通了与LCR配置
	}
	else
	{
		r_UARTx_LCR(scg_UARTx_Base[ch]) &= ~BIT7;			//清除掉DLAB,此位必须清零才能访问其他寄存器;
	}
	
	

	return TRUE;
}




/*************************************************************************************************************************
* 函数	:	bool UARTx_Init(UART_CH_Type ch,u32 Speed,bool isEnableRx)
* 功能	:	串口初始化
* 参数	:	ch:通道选择,0->usart1,Speed:串口速度,isEnableRx:是否使能接收
* 返回	:	TRUE:成功,FALSE:失败
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 2020-08-17
* 说明	: 	
*************************************************************************************************************************/
bool UARTx_Init(UART_CH_Type ch,u32 Speed,bool isEnableRx)
{
	UART_Config_TypeDef cfg;
#if UART_DMA_EN	//使用DMA接收
#else	 		//中断接收
	V3S_IRQ_Typedef IrqType;
#endif //UART_DMA_EN
	
	//设置时钟与IO
	switch(ch)
	{
		case UART_CH1:
		{
			r_BUS_CLK_GATING2 |= BIT5;    //使能PIO总时钟-这个时钟貌似默认就是开启的
			GPIOB->CFG1 &= ~(0x7 << 0);   //清除PB8_SELECT
			GPIOB->CFG1 |= (0x3 << 0);    //PB8 -> UART0_TX
			GPIOB->CFG1 &= ~(0x7 << 4);   //清除PB9_SELECT
			GPIOB->CFG1 |= (0x3 << 4);    //PB9 -> UART0_RX
			
            r_BUS_CLK_GATING3 |= BIT16;		//使能UART0时钟
            
            r_BUS_SOFT_RST4 &= ~BIT16;		//复位UART0-一定要先使能时钟,才能复位寄存器
            Delay_US(1);
			r_BUS_SOFT_RST4 |= BIT16;		//停止复位UART0
		}break;
		case UART_CH2:
		{
			
		}break;
		case UART_CH3:
		{
			
		}break;
		default:return FALSE;
	}
	
	cfg.DataBitWidth = UART_DATA_8BIT;						//数据宽度8
	cfg.OddEvenVerify = UART_VERIFY_NULL;					//无奇偶校验
	cfg.StopBitWidth = UART_STOP_1BIT;						//1个停止位
	if(UARTx_SetBaudRate(ch, Speed) == FALSE) return FALSE;
	if(UARTx_Config(ch, &cfg) == FALSE) return FALSE;		//设置波特率
	r_UARTx_MCR(scg_UARTx_Base[ch]) = 0;					//关闭SIR模式,关闭流控
	r_UARTx_FCR(scg_UARTx_Base[ch]) = 0x07 | (2<<6) | (3<<4);	//开启FIFO,并将FIFO复位,接收FIFO为 1/2满触发,发送FIFO为1/2满触发
	r_UARTx_IER(scg_UARTx_Base[ch]) = 0;					//关闭所有中断
	sg_UartRx[ch].isIntRx = FALSE;							//没有开启中断接收
  
	if(isEnableRx)
	{
#if UART_DMA_EN	//使用DMA接收
		if(sg_UartRxDmaChannel[ch] == DMA_CH_NULL)			//没有申请过DMA通道-注意:串口的接收DMA通道会一直占用
		{
			sg_UartRxDmaChannel[ch] = DMA_RequestChannel("UART RX");		    //申请一个空闲的通道
		}
#else
		r_UARTx_IER(scg_UARTx_Base[ch]) |= BIT0 | BIT2;							//使能接收数据有效中断
		GIC_SetIrqPriority(scg_UartIrqType[ch], 2);	                    		//GIC设置一个中断的优先级
		GIC_SetIrqEdgeTriggered(scg_UartIrqType[ch], TRUE);              		//GIC设置一个中断为边沿触发
		GIC_RegisterIRQHandler(scg_UartIrqType[ch], (void (*)(void))scg_pUartIrqHandle[ch]);   	//注册中断服务程序
		GIC_IrqEnable(scg_UartIrqType[ch], TRUE);	                    		//GIC中断使能-串口中断使能
		sg_UartRx[ch].isIntRx = FALSE;						//开启了中断接收
#endif //UART_DMA_EN
	}

	
	return TRUE;
}




/*************************************************************************************************************************
* 函数	:	void UARTx_SendByte(UART_CH_Type ch,u8 data)
* 功能	:	UART单字节发送
* 参数	:	ch:通道号,dataL:要发送的数据
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 2020-08-12
* 说明	: 	单字节发送不要使用DMA,浪费
*************************************************************************************************************************/
void UARTx_SendByte(UART_CH_Type ch,u8 data)
{
	if(ch > UART_ChMax - 1)									//判断端口是否超出范围
		return;
	
	while((r_UARTx_TFL(scg_UARTx_Base[ch]) & 0x3F) > 62);	//FIFO大于62个字节就等一会,避免发送溢出
 	r_UARTx_THR(scg_UARTx_Base[ch]) = data;					//发送数据-写到FIFO中而已,并不会等待数据发送完成
}




/*************************************************************************************************************************
* 函数	:	void UARTx_SendData(UART_CH_Type ch,u8 *tx_buff,u16 byte_number)
* 功能	:	UART数据发送函数
* 参数	:	ch:通道号,tx_buff:发送缓冲区,byte_number:需要发送的字节
* 返回	:	无
* 依赖	:	void UART_SendByte(u8 ch,u8 data)
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	非DMA方式,非FIFO方式发送
*************************************************************************************************************************/
void UARTx_SendData(UART_CH_Type ch,u8 *pTxBuff,u16 DataLen)
{
	u16 i;
	if(ch > UART_ChMax - 1)						//判断端口是否超出范围
		return;
	
#if UART_DMA_EN
	{
		DMA_CH_Type dma_ch;
		
		dma_tx_lln[ch].cfg = DMA_GetConfig(scg_UartDmaTxDRQ[ch], //目标类型
								DMA_BURST_INCR1, 		//目标突发传输长度配置
								DMA_SIZE_8BIT, 			//目标数据宽度
								FALSE,					//目标地址自增模式
								isSdram_MemAddr(pTxBuff)? DMA_SOURCE_SDRAM : DMA_SOURCE_SRAM, 		//源类型
								DMA_BURST_INCR1, 		//源突发传输长度配置
								DMA_SIZE_8BIT, 			//源数据宽度
								TRUE);					//源地址自增模式
		dma_tx_lln[ch].src = (u32)pTxBuff;								//DMA源地址
		dma_tx_lln[ch].dst = (u32)&r_UARTx_THR(scg_UARTx_Base[ch]);	    //DMA目标地址
		dma_tx_lln[ch].len = DataLen;								    //传输长度
        dma_tx_lln[ch].reserved[0] = 0;
        dma_tx_lln[ch].reserved[1] = 0;

		//DMA参数寄存器值生成
		dma_tx_lln[ch].para = DMA_GetParameter(1, 					    //N=m*FIFO大小(字节),如果是非外设传输,设置为0
										1);				                //传输等待时钟周期数,猜测用于防止连续占用总线,就是传输以包后停几个周期
		dma_tx_lln[ch].next_lli = DMA_LINK_END;					        //指向下一个链表,最后一个指向0xFFFFF800
		//申请DMA通道
		dma_ch = DMA_RequestChannel("UARTx_SendData");		            //申请一个空闲的通道
		if(dma_ch != DMA_CH_NULL)							            //申请到空闲的通道了
		{
			DMA_ChannelStart(dma_ch, &dma_tx_lln[ch], 10);
			if(DMA_ChannelWaitComplete(dma_ch, DataLen*10) == TRUE)	    //等待DMA传输完成
			{
				
			}
			else
			{
				
			}
			DMA_FreedChannel(dma_ch);						            //释放DMA通道
		}
		else
		{
			/*for(i = 0;i < DataLen;i++)				//循环发送,直至发送完毕
			{
				UARTx_SendByte(ch, pTxBuff[i]);
			}*/
		}
	}
	
#else	
	for(i = 0;i < DataLen;i++)				//循环发送,直至发送完毕
	{
	 	UARTx_SendByte(ch, pTxBuff[i]);
	}
#endif //UART_DMA_EN
}



/*************************************************************************************************************************
* 函数	:	void UARTx_SendString(UART_CH_Type ch,char *pString)
* 功能	:	UART发送字符串
* 参数	:	ch:通道号
			pString:字符串指针
* 返回	:	无
* 依赖	:	void UART_SendByte(u8 ch,u8 data)
* 作者	:	cp1300@139.com
* 时间	:	2013-04-18
* 最后修改时间 : 2013-04-18
* 说明	: 	非DMA方式,非FIFO方式发送
*************************************************************************************************************************/
#include "string.h"
void UARTx_SendString(UART_CH_Type ch,char *pString)
{	
	if(ch > UART_ChMax - 1)						//判断端口是否超出范围
		return;
	
	UARTx_SendData(ch, (u8 *)pString, strlen(pString));
}






/*************************************************************************************************************************
* 函数	:	bool UARTx_GetNewDataFlag(UART_CH_Type ch)
* 功能	:	获取串口新数据标志
* 参数	:	ch:通道选择
* 返回	:	TRUE:成功,FALSE:失败
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	用于判断是否有新的数据,会清除掉新数据标志的
*************************************************************************************************************************/
bool UARTx_GetNewDataFlag(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)										//判断端口是否超出范围
		return FALSE;

	if(sg_UartRx[ch].isIntRx == TRUE)							//开启了中断接收
	{
		if(sg_UartRx[ch].isNewDataFlag == TRUE) 				//有新数据
		{
		 	sg_UartRx[ch].isNewDataFlag = FALSE;				//清除标志
			return TRUE;										//返回有新数据
		}
	}
	else														//没开启中断接收
	{
	 	if(r_UARTx_LSR(scg_UARTx_Base[ch]) & BIT0)				//接收数据就绪,但是需要读取RBR才能清楚
		{
			return TRUE;
		}
	}
	return FALSE;
}


/*************************************************************************************************************************
* 函数	:	bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch)
* 功能	:	获取串口接收缓冲区满标志
* 参数	:	ch:通道选择
* 返回	:	TRUE:成功,FALSE:失败
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	用于判断接收缓冲区是否满,会清除标志
*************************************************************************************************************************/
bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)					//判断端口是否超出范围
		return FALSE;
	
#if UART_DMA_EN

#else 
	if(sg_UartRx[ch].isBuffFull == TRUE)			//缓冲区已满
	{
	 	sg_UartRx[ch].isBuffFull = FALSE;			//清除满标志
		return TRUE;
	}
	return FALSE;
#endif //UART_DMA_EN
}




/*************************************************************************************************************************
* 函数	:	u8 UARTx_GetNewData(UART_CH_Type ch)
* 功能	:	获取串口新数据
* 参数	:	ch:通道选择
* 返回	:	收到的数据
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	用于接收一个字节数据
*************************************************************************************************************************/
u8 UARTx_GetNewData(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)								//判断端口是否超出范围
		return 0;

	return r_UARTx_RBR(scg_UARTx_Base[ch]);				//返回数据
}




#if UART_DMA_EN
/*************************************************************************************************************************
* 函数			:	void UARTx_SetRxDMA(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
* 功能			:	串口接收DMA配置
* 参数			:	ch:通道选择,RxBuffSize:缓冲区大小,RxBuff:缓冲区指针
* 返回			:	无
* 依赖			:	底层宏定义
* 作者			:	cp1300@139.com
* 时间			:	2020-08-18
* 最后修改时间 	: 	2020-08-18
* 说明			: 	
*************************************************************************************************************************/
void UARTx_SetRxDMA(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
{
	DMA_CH_Type dma_ch;
	
	dma_rx_lln[ch].cfg = DMA_GetConfig(isSdram_MemAddr(RxBuff)? DMA_DEST_SDRAM : DMA_DEST_SRAM, 	//目标类型
							DMA_BURST_INCR1, 		//目标突发传输长度配置
							DMA_SIZE_8BIT, 			//目标数据宽度
							TRUE,					//目标地址自增模式
							scg_UartDmaRxDRQ[ch], 	//源类型
							DMA_BURST_INCR1, 		//源突发传输长度配置
							DMA_SIZE_8BIT, 			//源数据宽度
							FALSE);					//源地址自增模式
    //uart_printf("cfg:0x%Xrn", dma_lli.cfg);
	dma_rx_lln[ch].src = (u32)&(r_UARTx_RBR(scg_UARTx_Base[ch]));//DMA源地址
    //uart_printf("src:0x%Xrn", dma_lli.src);
	dma_rx_lln[ch].dst = (u32)RxBuff;							//DMA目标地址
    //uart_printf("dst:0x%Xrn", dma_lli.dst);
	dma_rx_lln[ch].len = RxBuffSize;							//传输长度-buff大小
	//DMA参数寄存器值生成
	dma_rx_lln[ch].para = DMA_GetParameter(1, 					//N=m*FIFO大小(字节),如果是非外设传输,设置为0,如果一次传输小于32也设置为0
									1);				            //延时检查DMA触发信号周期
	dma_rx_lln[ch].next_lli = DMA_LINK_END;					    //指向下一个链表,最后一个指向0xFFFFF800
	
	//申请DMA通道
	dma_ch = sg_UartRxDmaChannel[ch];					//提前已经申请了一个空闲的通道,这个通道会一直给串口接收使用
	if(dma_ch != DMA_CH_NULL)							//申请到空闲的通道了
	{
		DMA_ChannelStart(dma_ch, &dma_rx_lln[ch], 0);
	}
	else
	{
		
	}
}

#endif //UART_DMA_EN



/*************************************************************************************************************************
* 函数	:	void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
* 功能	:	设置串口接收缓冲区
* 参数	:	ch:通道选择,RxBuffSize:缓冲区大小,RxBuff:缓冲区指针
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20120403
* 最后修改时间 : 20120403
* 说明	: 	一定要设置,否则开启中断接收时可能会异常
*************************************************************************************************************************/
void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize)
{
#ifdef _UCOS_II_
	OS_CPU_SR  cpu_sr;
#endif	//_UCOS_II_
	
	if(ch > UART_ChMax - 1)							//判断端口是否超出范围
		return;
	
#if UART_DMA_EN
	UARTx_SetRxDMA(ch, RxBuff, RxBuffSize);			//DMA配置
#endif //UART_DMA_EN
	
#ifdef _UCOS_II_
	OS_ENTER_CRITICAL();
#endif	//_UCOS_II_
	sg_UartRx[ch].RxBuffSize = RxBuffSize; 			//设置缓冲区大小
	sg_UartRx[ch].RxBuff = RxBuff;					//设置缓冲区指针
#if !UART_DMA_EN		
	sg_UartRx[ch].UartRxCnt = 0;					//计数器清零
#endif //!UART_DMA_EN
#ifdef _UCOS_II_
	OS_EXIT_CRITICAL();
#endif	//_UCOS_II_
}





/*************************************************************************************************************************
* 函数	:	u32 UARTx_GetRxCnt(UART_CH_Type ch)
* 功能	:	获取串口接收数据计数器
* 参数	:	ch:通道选择
* 返回	:	接收到的数据数量
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20130307
* 最后修改时间 : 20130307
* 说明	: 	无
*************************************************************************************************************************/
u32 UARTx_GetRxCnt(UART_CH_Type ch)
{	
	if(ch > UART_ChMax - 1)						//判断端口是否超出范围
		return 0;
	
#if UART_DMA_EN
	return  sg_UartRx[ch].RxBuffSize - DMA_ChannelGetCount(sg_UartRxDmaChannel[ch]);
#else
	return sg_UartRx[ch].UartRxCnt;			//返回计数值	
#endif //UART_DMA_EN	
}




/*************************************************************************************************************************
* 函数	:	void UARTx_ClearRxCnt(UART_CH_Type ch)
* 功能	:	清除串口接收数据计数器
* 参数	:	ch:通道选择
* 返回	:	无
* 依赖	:	底层宏定义
* 作者	:	cp1300@139.com
* 时间	:	20130307
* 最后修改时间 : 20130307
* 说明	: 	无
*************************************************************************************************************************/
void UARTx_ClearRxCnt(UART_CH_Type ch)
{
	if(ch > UART_ChMax - 1)					//判断端口是否超出范围
		return;
#if UART_DMA_EN
	UARTx_SetRxDMA(ch, sg_UartRx[ch].RxBuff, sg_UartRx[ch].RxBuffSize);			//DMA配置
#else
	sg_UartRx[ch].UartRxCnt = 0;				//计数器清零
#endif //UART_DMA_EN
}























#if !UART_DMA_EN	//使用的中断

//用于串口中断中循环读取数据
#if __ICCARM__
#pragma inline 
static void UARTx_ReadRxData(UART_CH_Type ch)
#else
__inline static void UARTx_ReadRxData(UART_CH_Type ch)
#endif //__ICCARM__
{
    while(r_UARTx_RFL(scg_UARTx_Base[ch]))   //接收FIFO中有数据,循环读取
    {
        if((sg_UartRx[ch].RxBuffSize) > 0 && (sg_UartRx[ch].UartRxCnt < sg_UartRx[ch].RxBuffSize))			//接收缓冲区大于0,并且没有满
        {
            (sg_UartRx[ch].RxBuff)[(sg_UartRx[ch].UartRxCnt) ++] = r_UARTx_RBR(scg_UARTx_Base[ch]); 		//将数据存放到缓冲区
            if(sg_UartRx[ch].UartRxCnt == sg_UartRx[ch].RxBuffSize) 										//缓冲区已满
            {
                 //sg_UartRx[ch].UartRxCnt = 0;																//接收计数器清零
                  sg_UartRx[ch].isBuffFull = TRUE;															//缓冲区已满标志
            }	
        }
        else //缓冲区满了,清除接收到的数据
        {
            sg_UartRx[ch].TempData = r_UARTx_RBR(scg_UARTx_Base[ch]);
        }
    }
}



//串口中断处理
#if __ICCARM__
#pragma inline 
static void UARTx_IRQHandler(UART_CH_Type ch)
#else
__inline static void UARTx_IRQHandler(UART_CH_Type ch)
#endif //__ICCARM__
{
	switch(r_UARTx_IIR(scg_UARTx_Base[ch]) & 0x0F)
	{
		case 0x06:	//接收线状态; 溢出/奇偶校验/成帧错误或中断中断,优先级1
		{
			while(r_UARTx_RFL(scg_UARTx_Base[ch]))                      //接收FIFO中有数据,循环读取
            {
                sg_UartRx[ch].TempData = r_UARTx_RBR(scg_UARTx_Base[ch]);
            }
		}break;
		case 0x04:	//收到可用的数据; 可用的接收器数据(禁用非FIFO模式或FIFO)或达到RCVR FIFO触发级别(启用FIFO模式和FIFO),优先级2
		{
			UARTx_ReadRxData(ch);
		}break;
		case 0x0C:	//接收字符超时;在FIFO模式下最近的4个字符时间内,没有字符进出RCVR FIFO,并且在此期间至少有1个字符,优先级2
		{
			//收到的数据没有满足FIFO阈值
            UARTx_ReadRxData(ch);
		}break;
		case 0x02:	//发送器为空,优先级3
		{
			//没有开启发送中断
		}break;
		case 0x00:	//调制解调器状态,优先级4
		{
			//没有使用到
		}break;
		case 0x07:	//忙检测,优先级5
		{
			//没用到
		}break;
		default:break;
	}
	r_UARTx_LSR(scg_UARTx_Base[ch]) |= r_UARTx_LSR(scg_UARTx_Base[ch]);	//清除中断
}


//串口1接收中断
void UART1_IRQHandler(void) {UARTx_IRQHandler(UART_CH1);}
//串口2接收中断
void UART2_IRQHandler(void) {UARTx_IRQHandler(UART_CH2);}
//串口3接收中断
void UART3_IRQHandler(void) {UARTx_IRQHandler(UART_CH3);}

#endif //UART_DMA_EN

UART.h

/*************************************************************************************************************
 * 文件名:			uart.h
 * 功能:			全志v3s UART通讯支持
 * 作者:			cp1300@139.com
 * 创建时间:		2020-08-11
 * 最后修改时间:	2020-08-11
 * 详细:			串口通信底层支持
*************************************************************************************************************/
#ifndef _UART_H_  
#define _UART_H_
#include "v3s_system.h"

/***********************配置相关************************/
#define UART_DMA_EN		0			//1:使能DAM收发模式;0:关闭DMA收发模式
#define UART_TX_TO_FIFI	0			//1:数据发送到发送FIFO则认为发送完成;0:数据从FIFO发送完成则认为发送完成
#define UART_ChMax		3			//串口通道数量


/*********************************************************/



//串口选择,串口1开始,到串口3
typedef enum
{
	UART_CH1	=		0,	//UART1
	UART_CH2	=		1,	//UART2
	UART_CH3	=		2,	//UART3
}UART_CH_Type;


//UART配置相关结构定义
typedef struct
{
	u8 OddEvenVerify;	//奇偶校验,奇,偶,无
	u8 StopBitWidth;	//停止位位宽1,2
	u8 DataBitWidth;	//数据位宽度
} UART_Config_TypeDef;


//奇偶校验
#define UART_VERIFY_NULL	0	//无校验
#define UART_ODD			1	//奇校验
#define UART_EVEN			2	//偶校验
//停止位
#define UART_STOP_1BIT		0	//一个停止位
#define UART_STOP_2BIT		1	//2个停止位
//数据位数
#define UART_DATA_5BIT		0	//5位数据长度
#define UART_DATA_6BIT		1	//6位数据长度
#define UART_DATA_7BIT		2	//7位数据长度
#define UART_DATA_8BIT		3	//8位数据长度

//相关API
bool UARTx_Init(UART_CH_Type ch,u32 Speed, bool isEnableRx);		//串口初始化
void UARTx_SendByte(UART_CH_Type ch,u8 data);						//UART单字节发送
void UARTx_SendData(UART_CH_Type ch,u8 *pTxBuff,u16 DataLen);		//UART数据发送函数
void UARTx_SendString(UART_CH_Type ch,char *pString);				//UART发送字符串
bool UARTx_GetNewDataFlag(UART_CH_Type ch);							//获取串口新数据标志
bool UARTx_GetRxBuffFullFlag(UART_CH_Type ch);						//获取串口接收缓冲区满标志
u8 	 UARTx_GetNewData(UART_CH_Type ch);								//获取串口新数据
void UARTx_SetRxBuff(UART_CH_Type ch,u8 *RxBuff,u16 RxBuffSize);	//设置串口接收缓冲区
void UARTx_ClearRxInt(UART_CH_Type ch);								//清除串口接收中断标志
u32  UARTx_GetRxCnt(UART_CH_Type ch);								//获取串口接收数据计数器
void UARTx_ClearRxCnt(UART_CH_Type ch);								//清除串口接收数据计数器


#endif //_UART_H_


//测试代码


//串口接收测试
static u8 buff[1024];
void UART1_RxTest(void)
{
	u16 cnt1,cnt2;
    
	UARTx_Init(UART_CH1, 115200, TRUE);
	UARTx_SetRxBuff(UART_CH1, (u8 *)buff, 1024-1);
	while(1)
	{
		cnt1 = UARTx_GetRxCnt(UART_CH1);
		SYS_DelayMS(20);
		cnt2 = UARTx_GetRxCnt(UART_CH1);
		if(cnt2 > 0 && cnt1 == cnt2)
		{
            //uart_printf("接收数据长度:%drn", cnt1);
			UARTx_SendData(UART_CH1, (u8 *)buff, cnt2);
			UARTx_ClearRxCnt(UART_CH1);
		}
		SYS_DelayMS(100);
	}
}

//在串口助手中发送数据,都会接收到一样的数据

最后

以上就是幸福缘分为你收集整理的全志V3S裸机串口驱动(中断方式接收,DMA接收有问题,小于32字节数据无法触发DMA传输)的全部内容,希望文章能够帮你解决全志V3S裸机串口驱动(中断方式接收,DMA接收有问题,小于32字节数据无法触发DMA传输)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(58)

评论列表共有 0 条评论

立即
投稿
返回
顶部