精华内容
下载资源
问答
  • STM32F407+WM8978+LAN8720A时遇到关于I2S DMA中断无法触发的问题一、关于问题描述二、造成问题原因三、解决问题 在使用STM32F407实现音频处理时遇到一些关于DMA问题。其中音频芯片使用时WM8978,通信...

    STM32F407+WM8978+LAN8720A时遇到的关于I2S DMA中断无法触发的问题


    在使用STM32F407实现音频的处理时遇到一些关于DMA的问题。其中音频芯片使用的时WM8978,通信方式是以太网通信,其芯片是LAN8720A。

    一、关于问题的描述

    关于问题的描述:在基本实现音频的录音和播放时,将以太网功能加入工程中,在I2S DMA 处理数据时,DMA处理中断请求时总是进入传输错误中断管理中,没有办法进行I2S DMA 的传输完成中断和半传输完成中断的触发如下:
    在这里插入图片描述

    二、造成问题的原因

    此时,其对应的寄存器值如下:
    在这里插入图片描述
    在这里插入图片描述
    其中ISR为DMA中断状态寄存器,去上图ISR值为0x00000008,
    查STM32F407的基本手册中关于中断状态寄存器的资料:
    在这里插入图片描述
    在这里插入图片描述
    在《STM32F4xx中文参考手册》的 9.3.18 错误管理,中有DMA错误管理的相关描述:
    在这里插入图片描述其中,尤其值得注意的是,在我的程序中没有使用双缓冲,而是使用的是循环缓冲,所以传输错误的原因是第一条,即DMA 读或写访问期间发生总线错误。

    三、解决问题

    在我的这个工程中,一共有以下几个地方使用到了DMA :
    在这里插入图片描述
    即ETH、I2S2、SDIO、USB_OTG_FS这几个地方,所以先要 弄清楚这几个功能使用的DMA总线的问题。
    我们看看STM32F407的存储器和总线架构:
    在这里插入图片描述
    在这里插入图片描述
    内部SRAM 的映射地址:
    在这里插入图片描述
    从这就可以看出是要增加SRAM的空间大小,在原来的工程中SRAM的空间大小如下:
    在这里插入图片描述
    增加IRAM1的大小:从0x20000增加到0x30000,即
    在这里插入图片描述
    所以,当再运行到这个位置时
    在这里插入图片描述
    在这里插入图片描述

    DMA中断状态寄存器ISR的值是0x00000030,即代表数据流 x 上发生传输完成事件和数据流 x 上发生半传输事件,如下
    在这里插入图片描述
    就这样,解决了I2S DMA 的传输完成中断和半传输完成中断的触发问题。

    展开全文
  • 两种DMA触发方式的传输过程

    千次阅读 2013-09-04 11:19:16
    DMA数据传输可由 2 种方法触发:或者软件请求数据(通过一个函数例如 read)或者硬件异步推数据到系统. 在第一种情况, 包含步骤总结如下: 1. 当一个进程调用 read, 驱动方法分配一个 DMA 缓冲并引导硬件来...

    DMA数据传输可由 2 种方法触发:或者软件请求数据(通过一个函数例如 read)或者硬件异步推数据到系统.

    在第一种情况, 包含的步骤总结如下:

    • 1. 当一个进程调用 read, 驱动方法分配一个 DMA 缓冲并引导硬件来传输它的数据到那个缓冲. 这个进程被置为睡眠.

    • 2. 硬件写数据到这个 DMA 缓冲并且在它完成时引发一个中断.

    • 3. 中断处理获得输入数据, 确认中断, 并且唤醒进程, 它现在可以读数据了.

    第 二 种情况,当 DMA 被异步使用. 例如, 这发生在数据获取设备, 它在没有人读它们的时候也持续推入数据. 在这个情况下, 驱动应当维护一个缓冲以至于后续的读调用能返回所有的累积的数据给用户空间. 这类传输包含的步骤有点不同:

    • 1. 硬件引发一个中断来宣告新数据已经到达.

    • 2. 中断处理分配一个缓冲并且告知硬件在哪里传输数据.

    • 3. 外设写数据到缓冲并且引发另一个中断当完成时.

    • 处理者分派新数据, 唤醒任何相关的进程, 并且负责杂务.


      第二种传输方式常常在网卡驱动中见到,不管哪种方式,DMA都依赖于中断的通知。

    展开全文
  • 最进项目需求用到了一款SPI通讯方式的磁编码器,每次在定时器触发比较中断后开始读取3个SPI数据,触发的周期40us,如果在中断中开始读取磁编数据大概需要十几个us,再加上处理其它事情差不多整个中断要停留二十几...

    最进项目需求用到了一款SPI通讯方式的传感器,每次在定时器触发比较中断后开始读取3个SPI数据,定时器触发的周期40us,如果在中断中开始读取传感器数据大概需要十几个us,再加上处理其它的事情差不多整个中断要停留二十几个us占用了大量时间,所以想有个办法可以让定时器自动触发3个SPI数据的读取,数据读取完毕后再进入中断开始处理数据。

    要实现自动触发首先想到的是要开启SPI的发送和接收DMA,当接收DMA使能后,需要再使能发送DMA才能触发SPI通讯,现在的关键问题就是如何使定时器能够自动触发SPI发送DMA的使能,这时就可以使用定时器的DMA写SPI发送DMA控制寄存器,无论是定时器更新DMA还是比匹配DMA都可以,如将定时器更新DMA的目标外设地址设置为SPI发送DMA的控制寄存器,当定时器更新DMA触发时会写SPI发送DMA控制器,使其使能开启。经实际程序验证此方案可行。

    展开全文
  • 调试DMA接收遇到了个很奇怪问题,就是DMA发送没问题,DMA接收时候,如果数据小于32字节,数据被DMA从串口接收FIFO中取走了,但是并不会传输到指定buff中,这个就没法用于接收未知长度数据,问题还在研究中,...

    调试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%X\r\n", dma_lli.cfg);
    	dma_rx_lln[ch].src = (u32)&(r_UARTx_RBR(scg_UARTx_Base[ch]));//DMA源地址
        //uart_printf("src:0x%X\r\n", dma_lli.src);
    	dma_rx_lln[ch].dst = (u32)RxBuff;							//DMA目标地址
        //uart_printf("dst:0x%X\r\n", 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("接收数据长度:%d\r\n", cnt1);
    			UARTx_SendData(UART_CH1, (u8 *)buff, cnt2);
    			UARTx_ClearRxCnt(UART_CH1);
    		}
    		SYS_DelayMS(100);
    	}
    }

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

    展开全文
  • 但是DMA有一个不好点就是中断触发机制,要么是half,要么是接收完毕, 那么就有一个很难受问题,一帧数据,基本上会被切断,所以对于那些对帧完整性有较高要求场景,DMA的这种中断就很难使用。 常用解决.....
  • 串口接收/发送有三种模式:中断、轮询、DMA,轮询方式并不推荐,也不经常使用,这里主要看中断DMA方式中断: 串口触发中断两种方式:RXNE、IDLE,一种是接收到一个数据接中断一次,一种是等待数据发送...
  • 两路ADC个采集64个(2路总共128个)数据,然后使用DMA传输完成,触发中断。停止采集,等待数据处理完后再启动下一次采集。 实际效果: 采集完这128个数据,且DMA传输完成后,进入了中断。等我...
  • 项目一开始使用的串口都是以DMA加空闲中断的方式使用的,但是再和485的芯片使用的时候,遇到了一点问题。 串口需要将使能引脚先置低,然后接受才有效。这个时候,发送数据,需要把使能引脚拉高,才能发送。但是由于...
  • 紧接着上一篇文章,如何合理处理多个串口接收大量数据。此种方法,很厉害,很NB,首先,利用DMA 可节省大量CUP资源。...2、触发接收数据中断。 3、假如数据有进来,将上面环形数据偏移量与长度 入队。 4、出...
  • STC89C52的中断

    2021-01-31 16:40:57
    中断分为四个步骤:中断请求->中断响应->中断处理->中断返回 ...这两个外部中断源标识和它们的触发方式控制位由特殊功能寄存器TCON的低4位控制。 内部中断源(3个) T0-定时器/计数器0中断
  • 在STM32F103中使用空闲中断的时候,经常会出现丢数据的情况,我猜测是因为连接环境中有延时,造成标志位误触发的情况。 解决思路,直接使用LL库代替HAL库,不用DMA也不用空闲中断,用最原始的办法就是直接接收中断...
  • 紧接着上一篇文章,如何合理处理多个串口接收大量数据。此种方法,很厉害,很NB可节省大量CUP资源。...2、触发接收数据中断。 3、把数据长度、地址 入队。 4、再开辟一个函数专门处理数据出队函数。
  • 单片机—中断

    2020-12-28 10:55:03
    目录前言中断 前言 定时器理论简单整理。 中断 1、CPU与外设之间传送数据方式可以有以下几种: (1)无条件传送方式 (2)查询方式 ...(2)外部中断有两种信号方式,即电平触发方式和下降沿触发方式
  • ADC时钟1.3 STM32F0-ADC通道选择1.4 STM32F0-ADC转化模式1.5 STM32F0-ADC转化时间1.5 STM32F0-ADC触发方式2、DMA2.1 STM32F0-DMA通道优先级2.2 STM32F0-DMA传输2.3 STM32F0-DMA传输2.4 STM32F0-DMA中断 ...
  • DMA+USART+stm32

    2017-08-09 17:15:00
    众所周知,串口是按照字节传输,每一次传输一个字节。要传一帧数据,需要按照协议,帧头,帧尾,长度等信息,从...收包:采用DMA+串口空闲中断方式DMA空闲中断在,收到串口数据,串口空闲1个字节,自动触发。 ...
  •     串口接收方式可以有很多种,之前也提到过使用延时判断串口...也介绍过使用DMA的空闲中断触发以判断串口接收完成。以上两种方式,在一定情况下可以使用效果也还可以。延时判断的方式,对于不跑操作系...
  • LPC51U68能够支持ADC直接多通道转换,但是一般要中断提醒转换结束,如果需要多路ADC连续采样多个点,就需要...例子采用DMA的方式,定时触发ADC多通道转换,并用DMA搬走数据,所以可以连续触发转换,直到预先设定次数
  • DMA(Direct Memory Access)直接存储器访问,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程,通过硬件为RAM和IO设备开辟一条直接传输数据通道,使得CPU效率大大提高。...
  • 在结构上改进主要包括可变宽度存储器接口、更快速指令周期时间、可设置优先级双通道DMA处理器、灵活引导程序装入方式、可重新定位的中断向量表以及可选边缘/电平触发中断方式等。对TMS320C32开发可以...
  • 文章目录接口接口解决的问题接口的功能端口与内存的统一编制与独立编制...DMA工作方式中断技术中断向量表中断控制器Intel 8259A8259工作过程8259A的功能结束中断的处理方式屏蔽中断源方式中断触发方式8259初始化编程...
  • DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场过程。 STM32的DMA有以下一些特征: 1、每一个通道都直接连接专用硬件DMA请求,每一个通道都同样支持软件触发。这些功能通过软件来...
  • "分散-聚集DMA"以及"scatterlist

    千次阅读 2017-06-07 15:34:51
    块设备驱动程序只要向磁盘控制器发送一些适当命令(如前面我们所讲scsi命令)就可以触发一次数据传送;一旦完成数据传送,控制器就会发出一个中断通知块设备驱动程序。大多数情况,磁盘控制器直接采用DMA方式...
  • 【STM32】USART IDLE + DMA 异常解决方案

    千次阅读 2018-09-28 20:28:43
    UART 部分是用来与上位机进行交互,接收数据采用 IDLE 中断 + DMA 的方式,发送数据采用阻塞的方式。上位机可以通过指令触发中转板定时采集 Slave 数据,也会通过指令对 Slave 进行配置。 问题描述 先来说下问题...
  • 嵌入式(二十三):中断

    千次阅读 2020-05-29 15:41:11
    a、中断的概念: 在执行程序的过程中,由于某种外界的原因,必须尽快终止当前的程序执行,而去执行相应的处理程序,待处理结束后,在回来继续执行被终止的程序。这种机制——称计算机中断系统 b、计算机系统中传送...
  • 中断方式操作。每个包含2个64字节FIFO,一个接,一个发。   非FIFO模式相当于FIFO模式一个寄存器缓冲模式。   每一个UART有7种状态,overrun错误,校验错误,帧错误,断点,接收缓冲区准备好,发送缓冲区...
  • 对数据采集板卡进行编程使用方式主要有以下3种:软仵触发方式中断传输方式,DMA数据传输方式。 (1)软件触发方式。实际上就是采用系统提供时钟在毫秒级精确等级上,通过对寄存器查询来实现数据采集,...

空空如也

空空如也

1 2 3
收藏数 56
精华内容 22
关键字:

dma中断的触发方式