This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TM4C123GH6PGE:如何为 UART 执行全双工通信进行最高效的设置、从而产生未知的消息大小?

Guru**** 2391245 points
Other Parts Discussed in Thread: EK-TM4C123GXL

请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes

器件型号:TM4C123GH6PGE
Thread 中讨论的其他器件:EK-TM4C123GXL

嗨、噢
这更是一个一般性问题。 我喜欢改进我的简单通用 UART Zephir 驱动程序。 该驱动程序侦听 UART Rx 中断,然后将 Rx 数据复制到环回缓冲区,并设置信号量以激活处理线程。 TX 也是通过拉出字节来完成的。

由于我使用的是 RTOS、因此我想减轻 MCU 的数据复制负担、并在后台执行其他操作。

因此、我正在寻找最小的 MCU 负载生成方式。

DMA 是一个不错的选择、但我以前没有使用过它。 特别是对于 Rx、我想知道如何执行"消息末尾突发"检测。 例如、我将 DMA 设置为 Rx 1000字节。 现在发送666Bytes 的消息。 由于 DMA 没有达到1000字节、它仍在等待334字节。 无 intr 等 如何进行这种中断+缓冲区翻转、以便我们不会丢失任何数据、以防在执行缓冲区翻转时出现某些数据。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Stefan、

    我完全理解您在这里的目标、但如果 在传输开始前也知道要接收的字符数、那么使用 uDMA 接收字符只会很好。 如果不是、例如任意长度字符串以终止字符结束时、则最好使用中断、因为您可以识别终止字符。

    UDMA 实际上没有您所描述的消息突发结束功能、您会根据遇到的大小限制获得中断。

    我想知道、由于您确实拥有 RTOS 架构、是否会有中间的接地。 是否可以像今天一样处理初始数据传输并在其中包含一个大小为数据包字节、然后您可以配置 DMA 以接收数据包的其余部分? 这将使您能够解决 uDMA 问题并利用它来减轻 CPU 负载。 但是、它肯定依赖于一定程度的闭环系统、在该系统中、您知道每次新传输都会得到初始的"字符数"标记。

    此致、

    Ralph Jacobi  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗨、噢
    Thx 表示快速答案。 让我们尝试向前推进一点。

    对于 Zephyr UART 驱动程序的 STM32端口、我使用了 DMA 和 UART 中断的组合。

    对于 Rx、它的工作方式如下:
    1) 设置 DMA 缓冲器并在 ringbuffer 模式中启动 DMA
    2) 使用 DMA 半完成和全完成中断进行数据处理
    3) 进入空闲状态时使用 UART 中断(进行数据处理)

    这是我的 STM32代码(https://github.com/StefJar/zephyr_stm32_uart3_dma_driver/blob/master/uart3_dma.c)。 它是 Zephir 异步 UART API 的基础。 因此、您可以更好地了解我所说的内容。

    UART+DMA RX 所需的是:

    1) 为我们提供 DMA 传输当前状态的函数。 我正在寻找 DMA Rx 数据指针的偏移量。
    2) 已经有了 UART_TXINT_MODE_EOT 模式、应该为我们提供传输结束中断。 因此、检测"突发"的一切都很好

    我喜欢尝试一个实验、也许您可以通过 TI 的人员来帮助:
    1) 在 ringbuffer 模式中为 UART0 Rx 设置 DMA、缓冲区大小为1024字节
    2) 使用传输结束 intr enabeled 设置 UART0

    如果您可以复制或指向正确的代码段,那就很好了;)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Stefan、

    感谢您分享有关如何成功实施此操作的更多详细信息和想法。 听起来好像这里有一些选项可以让您按照所需的方向前进。

    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3838392 #3838392">我想尝试一个实验、也许您可以借助 TI 的人员:
    1) 在 ringbuffer 模式中为 UART0 Rx 设置 DMA、缓冲区大小为1024字节
    2) 使用传输结束 intr enabeled 设置 UART0
    [/报价]

    我查看了我们的 TivaWare 示例之一、我认为这一点很好。 此示例为 uDMA_demo、可在[Install Path]\TivaWare_C_Series-2.2.0.295\examples\boards\ek-tm4c123gxl\uDMA_demo 中找到。 此示例包括使用两个 RX 缓冲器。 它们默认为256、但 如果需要、可以将 UART_RXBUF_SIZE 更改为1024字节! 也就是说、DMA 缓冲区已经为1024、这可能更多是您想要调整的内容。 缓冲区大小应该易于使用。

    该项目没有 UART 传输结束中断设置、因为这是一个循环回送应用、因此 UDMA 在同一外设上发送和接收。

    要配置 UART0 TX 中断(UART 配置的其余部分位于 UDMA_DEMO 中)、您将使用以下 API:

        //
        // Enable the UART interrupt.
        //
        MAP_IntEnable(INT_UART0);
        MAP_UARTIntEnable(UART0_BASE, UART_INT_TX);

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    已获取最新的 TI HAL (2.2.0.295)、x 对其进行了编译。 是的

    DMA 方面的快速问题。 如何获取当前的 DMA 写入指针/偏移量?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Stefan、

    uDMAChannelSizeGet 可以获取当前传输大小信息:

    //! This function is used to get the uDMA transfer size for a channel.  The
    //! transfer size is the number of items to transfer, where the size of an item
    //! might be 8, 16, or 32 bits.  If a partial transfer has already occurred,
    //! then the number of remaining items is returned.  If the transfer is
    //! complete, then 0 is returned.

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    为了我的理解、让我们假设一个示例。

    DMA 缓冲器 addr=1000 size=1024B
    uDMA init RX、addr=1000、size=1024

    UART0 RX -> 100字节

    UART Rx 线路保持平静

    UART0 INTR -> UART_TXINT_MODE_EOT
    UART0 ISR ->偏移= uDMAChannelSizeGet ()

    因为多路复用的100字节的输出现在是100?

    现在假设我们收到下一个突发消息

    UART0 RX -> 300Bytes in One burst

    UART Rx 线路保持平静

    UART0 INTR -> UART_TXINT_MODE_EOT
    UART0 ISR ->偏移= uDMAChannelSizeGet ()

    现在、是否为100 + 300 = 400?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Stefan、

    很遗憾通知我,但我现在已不在办公室,直至星期三。 我的同事查尔斯在星期一返回。 我将请他在星期一回顾并答复你。

    此致、

    Ralph Jacobi

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ralph

    希望您能玩得开心。 目前、我首先尝试通过 DMA 在 TX 上进行处理。 稍后、我想通过 DMA 添加 RX。 因此我设置了一个"空"项目。 只有 PLL 将初始化至80MHz。

    目前、该代码仅通过轮询输出在 UART0上打印某些内容。 DMA 不启动。 也许您可以查看并判断出出现了什么问题。

    struct k_sem uartTxDone;
    struct k_mutex uartTxGuard;
    uint8_t ui8ControlTable[1024] __attribute__ ((aligned(1024)));
    
    static void udma_tiva_isr_error(const struct device *dev) {
    
    }
    
    static void udma_tiva_isr_software(const struct device *dev) {
    
    }
    
    static void UART0IntHandler(const struct device *dev) {
        uint32_t ui32Status;
        uint32_t ui32Mode;
    
        ui32Status = UARTIntStatus(UART0_BASE, 1);
    
        UARTIntClear(UART0_BASE, ui32Status);
    
        if(false == uDMAChannelIsEnabled(UDMA_CHANNEL_UART0TX)) {
        	k_sem_give(&uartTxDone);
        }
    }
    
    void initUART(void) {
        k_sem_init(&uartTxDone, 0, 1);
        k_mutex_init(&uartTxGuard);
    
    	IRQ_CONNECT(5,0, UART0IntHandler, NULL, 0);
    	irq_enable(5);
    
    	IRQ_CONNECT(46,0, udma_tiva_isr_software, NULL, 0);
    	irq_enable(46);
    
    	IRQ_CONNECT(47,0, udma_tiva_isr_error, NULL, 0);
    	irq_enable(47);
    
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	uDMAEnable();
    	uDMAControlBaseSet(ui8ControlTable);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_SYSTEM);
    
        UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
        		UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                UART_CONFIG_PAR_NONE);
    
        UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
    
        UARTEnable(UART0_BASE);
    
        UARTDMAEnable(UART0_BASE, UART_DMA_TX);
    
        uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX,
    		UDMA_ATTR_ALTSELECT |
    		UDMA_ATTR_HIGH_PRIORITY |
    		UDMA_ATTR_REQMASK
    	);
    
        uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_USEBURST);
    
        uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
        		UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                UDMA_ARB_4);
    }
    
    void send(char * txt, const uint32_t len) {
        k_mutex_lock(&uartTxGuard, K_FOREVER);
    	uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
        		UDMA_MODE_BASIC,
    			txt, // source
                (void *)(UART0_BASE + UART_O_DR), // dest
                len);
    
        uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
        k_sem_take(&uartTxDone, K_FOREVER);
        k_mutex_unlock(&uartTxGuard);
    }
    
    void sendTxt(char * txt) {
    	send(txt, strlen(txt));
    }
    
    void sendPoll(char * txt) {
    	uint32_t c;
    	c = strlen(txt);
        while(c) {
            UARTCharPutNonBlocking(UART0_BASE, *txt);
            txt++;
            c--;
        }
    }
    
    
    void main(void) {
        initUART();
    
        sendPoll("start done!\n\r");
        for (;;) {
        	sendTxt("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ hello!\n\r");
        	k_sleep(K_SECONDS(1));
        }
    }

    我的蓝图是"/TivaWare_C_Series-2.2.0.295/examples/boards/ek-tm4c123gxl/uDMA_demo"

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     您在下面编写了几行代码。

    RQ_CONNECT (5、0、UART0IntHandler、NULL、0);
    IRQ_ENABLE (5);

    IRQ_connect 是您自己的 API。 您是否应该使用21而不是5作为 UART0的向量编号? 在 TI-RTOS 中、您将指定21、而不是5。 您应该检查 RTOS 要执行的操作。  

    如果在  UART0IntHandler()处放置一个断点,您是否看到处理器在那里停止?

    可能还有一个问题需要问、您使用的是什么 RTOS。 如果您使用的是 TI-RTOS, 则一定不能使用 TivaWare IntRegister() API 来插入中断矢量。 这会使由 TI-RTOS 管理的矢量表混乱。 我不知道您使用什么 RTOS、我不知道是否建议使用 IRQ_CONNECT 为您的 RTOS 手动插入中断矢量。 如果您的 RTOS 正常、则可以忽略此问题。 请参阅此帖子。  https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/849627/faq-can-i-update-the-vector-table-with-intregister-when-using-ti-rtos?tisearch=e2e-sitesearch&keymatch=faq%3Atrue

    在我将您的代码与 /TivaWare_C_Series-2.2.0.295/examples/boards/ek-tm4c123gxl/uDMA_demo 进行比较后、还有一件事是您没有下面的行。  

    //
    //启用 UART DMA TX 中断。
    //
    ROM_UARTIntEnable (UART0_BASE、UART_INT_DMATX);

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Thx
    intr 的优点、但正如前面所说的-我使用的是 Zephir 框架/工具链。 它们使用实际 intr 编号(请参阅数据表第105页的表2.9)而不是向量编号。 TI HAL 增加了16以获得数字;)
    在 Zephir 中、intr 矢量生成由工具链完成。 IRQ_CONNECT 是连接 ISR 和矢量表的正确宏。
    我之前完成了 UART 驱动程序(捕获 Rx 和 TX 内部)。 intr 初始化程序的工作效果非常好。

    我更改了代码一位

    #include <stddef.h>
    #include <string.h>
    #include <errno.h>
    
    #include <zephyr.h>
    #include <logging/log.h>
    #include <logging/log_ctrl.h>
    #include <power/reboot.h>
    
    #include "../drv/tiva/cfg_tiva.h"
    #include "../drv/tiva/sysctl_tiva.h"
    
    struct k_sem uartTxDone;
    struct k_mutex uartTxGuard;
    uint8_t __aligned(1024) ui8ControlTable[1024];
    
    static void udma_tiva_isr_error(const struct device *dev) {
        uint32_t ui32Status;
    
        //
        // Check for uDMA error bit
        //
        ui32Status = uDMAErrorStatusGet();
    
        //
        // If there is a uDMA error, then clear the error and increment
        // the error counter.
        //
        if(ui32Status) {
            uDMAErrorStatusClear();
        }
    }
    
    static void udma_tiva_isr_software(const struct device *dev) {
    
    }
    
    static void uart0IntHandler(const struct device *dev) {
        uint32_t ui32Status;
        uint32_t ui32Mode;
    
        ui32Status = UARTIntStatus(UART0_BASE, 1);
    
        UARTIntClear(UART0_BASE, ui32Status);
    
        if(false == uDMAChannelIsEnabled(UDMA_CHANNEL_UART0TX)) {
        	k_sem_give(&uartTxDone);
        }
    }
    
    void initUART(void) {
        k_sem_init(&uartTxDone, 0, 1);
        k_mutex_init(&uartTxGuard);
    
    	IRQ_CONNECT(5,0, uart0IntHandler, NULL, 0);
    	irq_enable(5);
    
    	IRQ_CONNECT(46,0, udma_tiva_isr_software, NULL, 0);
    	irq_enable(46);
    
    	IRQ_CONNECT(47,0, udma_tiva_isr_error, NULL, 0);
    	irq_enable(47);
    
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
    	while (false == SysCtlPeripheralReady(SYSCTL_PERIPH_UDMA)){
    
    	}
    	uDMAEnable();
    	uDMAControlBaseSet(ui8ControlTable);
    
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    	SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
    	while (false == SysCtlPeripheralReady(SYSCTL_PERIPH_UART0)){
    
    	}
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1);
    
        //UARTClockSourceSet(UART0_BASE, UART_CLOCK_SYSTEM);
        UARTClockSourceSet(UART0_BASE, UART_CLOCK_PIOSC);
    
        UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
        		UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                UART_CONFIG_PAR_NONE);
    
        UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
    
        UARTIntEnable(UART0_BASE, UART_INT_DMATX);
        UARTIntClear(UART0_BASE, 0xFFFFFFFF);
    
        UARTEnable(UART0_BASE);
    
        uDMAErrorStatusClear();
        UARTDMAEnable(UART0_BASE, UART_DMA_TX);
    
        uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX,
    		UDMA_ATTR_ALTSELECT |
    		UDMA_ATTR_HIGH_PRIORITY |
    		UDMA_ATTR_REQMASK
    	);
    
        uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_USEBURST);
    
        uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
        		UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                UDMA_ARB_4);
    }
    
    void send(char * txt, const uint32_t len) {
        k_mutex_lock(&uartTxGuard, K_FOREVER);
    	uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
        		UDMA_MODE_BASIC,
    			txt, // source
                (void *)(UART0_BASE + UART_O_DR), // dest
                len);
    
        uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
        k_sem_take(&uartTxDone, K_FOREVER);
        k_mutex_unlock(&uartTxGuard);
    }
    
    void sendTxt(char * txt) {
    	send(txt, strlen(txt));
    }
    
    void sendPoll(char * txt) {
    	uint32_t c;
    	c = strlen(txt);
        while(c) {
            UARTCharPutNonBlocking(UART0_BASE, *txt);
            txt++;
            c--;
        }
    }
    
    
    void main(void) {
        initUART();
    
        sendPoll("start done!\n\r");
        for (;;) {
        	sendTxt("1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ hello!\n\r");
        	k_sleep(K_SECONDS(1));
        }
    }

    我检查了 ui8ControlTable 变量的对齐情况。 其放置偏移为8K。 因此、它认为这是可以的。

    调用"uDMAChannelEnable (UDMA_CHANGE_UART0TX);"后不久
    我收到 DMA 错误 intr。 状态为1。
    因此、我想有些设置错误。

    也许您可以针对您的工具链运行代码(请替换 intr 处理程序)并检查它是否起作用?

    DMA UART 示例仅执行内部回送。 让我们来看一个示例、其中使用它来延长 UART 的使用寿命! ;)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3853267 #3853267">调用"uDMAChannelEnable (UDMA_CHANGE_UART0TX)"后不久;"
    我收到 DMA 错误 intr。 状态为1。

    如果您收到 DMA 错误中断、则表示存在总线错误。 总线错误最有可能意味着 DMA 正在读取或写入非法或未实现的地址。 我建议您执行 以下任一调试建议:

     -按原样运行 UDMA_DEMO。 UDMA_DEMO 使用 UART1而不是 UART0。 捕捉 UART1寄存器和 UDMA 寄存器设置以及 ui8ControlTable。 修改您自己的 UART1代码、并对所有寄存器执行相同的捕捉操作并进行比较。  

    或:

     -修改 UART0的 UDMA_DEMO。 首先确保它首先工作正常。 捕获 UART0、UDMA 寄存器设置和 ui8ControlTable、并与您自己的代码进行比较。  

    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3853267 #3853267"> DMA UART 示例仅执行内部回送。 让我们来看一个示例、其中使用它来延长 UART 的使用寿命! [/报价]

    您只需注释掉以下行即可禁用环回。  

    //  HWREG (UART1_BASE + UART_O_CTL)|= UART_CTL_LBE;

    并替换为以下行以配置 UART1引脚。  

    //
    //为 UART 模式配置 GPIO 引脚。
    //
    ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOB);

    ROM_GPIOPinConfigure (GPIO_PB0_U1RX);
    ROM_GPIOPinConfigure (GPIO_PB1_U1TX);
    ROM_GPIOPinTypeUART (GPIO_PORTB_BASE、GPIO_PIN_0 | GPIO_PIN_1);

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如您所见、我的代码是 UDMA 的简化版本。 所做的更改是:
    -使用 UART0而不是 UART1

    -无 RX 设置

    -不需要回送,我们需要一些真正的 IO

    它必须处理该设置

    uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_USEBURST);
    
    uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
        UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
        UDMA_ARB_4);

    可能 UDMA_ARB_4/UDMA_ATTR_USEBURST 错误。 我的想法是使用一个未对齐(UINT32)指针、该指针传递给 SEND 函数。

    也许您更了解如何配置 UDMA 控制器及其通道。

    我正在寻找最小的 TX 示例;)

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好!

     为什么不尝试以下示例? 我修改了 UART0的 TivaWare UDMA_DEMO 示例、它适用于我。  

    #include <stdint.h>
    #include <stdbool.h>
    #include "inc/hw_ints.h"
    #include "inc/hw_memmap.h"
    #include "inc/hw_types.h"
    #include "inc/hw_uart.h"
    #include "driverlib/fpu.h"
    #include "driverlib/gpio.h"
    #include "driverlib/interrupt.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/rom.h"
    #include "driverlib/sysctl.h"
    #include "driverlib/systick.h"
    #include "driverlib/uart.h"
    #include "driverlib/udma.h"
    #include "utils/cpu_usage.h"
    #include "utils/uartstdio.h"
    #include "utils/ustdlib.h"
    
    //*****************************************************************************
    //
    //! \addtogroup example_list
    //! <h1>uDMA (udma_demo)</h1>
    //!
    //! This example application demonstrates the use of the uDMA controller to
    //! transfer data between memory buffers, and to transfer data to and from a
    //! UART.  The test runs for 10 seconds before exiting.
    //!
    //! UART0, connected to the FTDI virtual COM port and running at 115,200,
    //! 8-N-1, is used to display messages from this application.
    //
    //*****************************************************************************
    
    //*****************************************************************************
    //
    // The number of SysTick ticks per second used for the SysTick interrupt.
    //
    //*****************************************************************************
    #define SYSTICKS_PER_SECOND     100
    
    //*****************************************************************************
    //
    // The size of the memory transfer source and destination buffers (in words).
    //
    //*****************************************************************************
    #define MEM_BUFFER_SIZE         1024
    
    //*****************************************************************************
    //
    // The size of the UART transmit and receive buffers.  They do not need to be
    // the same size.
    //
    //*****************************************************************************
    #define UART_TXBUF_SIZE         256 //256
    #define UART_RXBUF_SIZE         256
    
    //*****************************************************************************
    //
    // The source and destination buffers used for memory transfers.
    //
    //*****************************************************************************
    static uint32_t g_ui32SrcBuf[MEM_BUFFER_SIZE];
    static uint32_t g_ui32DstBuf[MEM_BUFFER_SIZE];
    
    //*****************************************************************************
    //
    // The transmit and receive buffers used for the UART transfers.  There is one
    // transmit buffer and a pair of recieve ping-pong buffers.
    //
    //*****************************************************************************
    static uint8_t g_ui8TxBuf[UART_TXBUF_SIZE];
    
    //*****************************************************************************
    //
    // The count of uDMA errors.  This value is incremented by the uDMA error
    // handler.
    //
    //*****************************************************************************
    static uint32_t g_ui32uDMAErrCount = 0;
    
    //*****************************************************************************
    //
    // The count of times the uDMA interrupt occurred but the uDMA transfer was not
    // complete.  This should remain 0.
    //
    //*****************************************************************************
    static uint32_t g_ui32BadISR = 0;
    
    //*****************************************************************************
    //
    // The count of memory uDMA transfer blocks.  This value is incremented by the
    // uDMA interrupt handler whenever a memory block transfer is completed.
    //
    //*****************************************************************************
    static uint32_t g_ui32MemXferCount = 0;
    
    
    //*****************************************************************************
    //
    // The number of seconds elapsed since the start of the program.  This value is
    // maintained by the SysTick interrupt handler.
    //
    //*****************************************************************************
    static uint32_t g_ui32Seconds = 0;
    
    //*****************************************************************************
    //
    // The control table used by the uDMA controller.  This table must be aligned
    // to a 1024 byte boundary.
    //
    //*****************************************************************************
    #if defined(ewarm)
    #pragma data_alignment=1024
    uint8_t ui8ControlTable[1024];
    #elif defined(ccs)
    #pragma DATA_ALIGN(ui8ControlTable, 1024)
    uint8_t ui8ControlTable[1024];
    #else
    uint8_t ui8ControlTable[1024] __attribute__ ((aligned(1024)));
    #endif
    
    //*****************************************************************************
    //
    // The error routine that is called if the driver library encounters an error.
    //
    //*****************************************************************************
    #ifdef DEBUG
    void
    __error__(char *pcFilename, uint32_t ui32Line)
    {
        while(1)
        {
            //
            // Hang on runtime error.
            //
        }
    }
    #endif
    
    //*****************************************************************************
    //
    // The interrupt handler for the SysTick timer.  This handler will increment a
    // seconds counter whenever the appropriate number of ticks has occurred.  It
    // will also call the CPU usage tick function to find the CPU usage percent.
    //
    //*****************************************************************************
    void SysTickHandler(void)
    {
        static uint32_t ui32TickCount = 0;
    
        //
        // Increment the tick counter.
        //
        ui32TickCount++;
    
        //
        // If the number of ticks per second has occurred, then increment the
        // seconds counter.
        //
        if(!(ui32TickCount % SYSTICKS_PER_SECOND))
        {
            g_ui32Seconds++;
        }
    }
    
    //*****************************************************************************
    //
    // The interrupt handler for uDMA errors.  This interrupt will occur if the
    // uDMA encounters a bus error while trying to perform a transfer.  This
    // handler just increments a counter if an error occurs.
    //
    //*****************************************************************************
    void
    uDMAErrorHandler(void)
    {
        uint32_t ui32Status;
    
        //
        // Check for uDMA error bit
        //
        ui32Status = ROM_uDMAErrorStatusGet();
    
        //
        // If there is a uDMA error, then clear the error and increment
        // the error counter.
        //
        if(ui32Status)
        {
            ROM_uDMAErrorStatusClear();
            g_ui32uDMAErrCount++;
        }
    }
    
    //*****************************************************************************
    //
    // The interrupt handler for uDMA interrupts from the memory channel.  This
    // interrupt will increment a counter, and then restart another memory
    // transfer.
    //
    //*****************************************************************************
    void
    uDMAIntHandler(void)
    {
        uint32_t ui32Mode;
    
        //
        // Check for the primary control structure to indicate complete.
        //
        ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART0TX);
        if(ui32Mode == UDMA_MODE_STOP)
        {
            //
            // Increment the count of completed transfers.
            //
            g_ui32MemXferCount++;
    
            //
            // Configure it for another transfer.
            //
            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX, UDMA_MODE_AUTO,
                                         g_ui32SrcBuf, g_ui32DstBuf,
                                         MEM_BUFFER_SIZE);
    
            //
            // Initiate another transfer.
            //
            ROM_uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
            ROM_uDMAChannelRequest(UDMA_CHANNEL_UART0TX);
        }
    
        //
        // If the channel is not stopped, then something is wrong.
        //
        else
        {
            g_ui32BadISR++;
        }
    }
    
    //*****************************************************************************
    //
    // The interrupt handler for UART0.  This interrupt will occur when a DMA
    // transfer is complete using the UART0 uDMA channel.  It will also be
    // triggered if the peripheral signals an error.  This interrupt handler will
    // switch between receive ping-pong buffers A and B.  It will also restart a TX
    // uDMA transfer if the prior transfer is complete.  This will keep the UART
    // running continuously (looping TX data back to RX).
    //
    //*****************************************************************************
    void UART0IntHandler(void)
    {
        uint32_t ui32Status;
    
        //
        // Read the interrupt status of the UART.
    
        //
        ui32Status = ROM_UARTIntStatus(UART0_BASE, 1);
    
        //
        // Clear any pending status, even though there should be none since no UART
        // interrupts were enabled.  If UART error interrupts were enabled, then
        // those interrupts could occur here and should be handled.  Since uDMA is
        // used for both the RX and TX, then neither of those interrupts should be
        // enabled.
        //
        ROM_UARTIntClear(UART0_BASE, ui32Status);
    
        //
        // If the UART0 DMA TX channel is disabled, that means the TX DMA transfer
        // is done.
        //
        if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_UART0TX))
        {
            //
            // Start another DMA transfer to UART0 TX.
            //
            ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                                       UDMA_MODE_BASIC, g_ui8TxBuf,
                                       (void *)(UART0_BASE + UART_O_DR),
                                       sizeof(g_ui8TxBuf));
    
            //
            // The uDMA TX channel must be re-enabled.
            //
            ROM_uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
        }
    }
    
    //*****************************************************************************
    //
    // Initializes the UART0 peripheral and sets up the TX and RX uDMA channels.
    // The UART is configured for loopback mode so that any data sent on TX will be
    // received on RX.  The uDMA channels are configured so that the TX channel
    // will copy data from a buffer to the UART TX output.  And the uDMA RX channel
    // will receive any incoming data into a pair of buffers in ping-pong mode.
    //
    //*****************************************************************************
    void InitUART0Transfer(void)
    {
        unsigned int uIdx;
    
        //
        // Fill the TX buffer with a simple data pattern.
        //
        for(uIdx = 0; uIdx < UART_TXBUF_SIZE; uIdx++)
        {
            g_ui8TxBuf[uIdx] = uIdx;
        }
    
        //
        // Enable the peripherals used by this example.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Set GPIO A0 and A1 as UART pins.
        //
        GPIOPinConfigure(GPIO_PA1_U0TX);
        ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1);
    
        //
        // Enable the UART peripheral, and configure it to operate even if the CPU
        // is in sleep.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0);
    
        //
        // Configure the UART communication parameters.
        //
        ROM_UARTConfigSetExpClk(UART0_BASE, ROM_SysCtlClockGet(), 115200,
                                UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                UART_CONFIG_PAR_NONE);
    
        //
        // Set both the TX and RX trigger thresholds to 4.  This will be used by
        // the uDMA controller to signal when more data should be transferred.  The
        // uDMA TX and RX channels will be configured so that it can transfer 4
        // bytes in a burst when the UART is ready to transfer more data.
        //
        ROM_UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
    
        //
        // Enable the UART for operation, and enable the uDMA interface for both TX
        // and RX channels.
        //
        ROM_UARTEnable(UART0_BASE);
        ROM_UARTDMAEnable(UART0_BASE, UART_DMA_TX);
    
        //
        // Enable the UART peripheral interrupts.  Note that no UART interrupts
        // were enabled, but the uDMA controller will cause an interrupt on the
        // UART interrupt signal when a uDMA transfer is complete.
        //
        ROM_IntEnable(INT_UART0);
    
        //
        // Put the attributes in a known state for the uDMA UART0TX channel.  These
        // should already be disabled by default.
        //
    
        ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART0TX,
                                        UDMA_ATTR_ALTSELECT |
                                        UDMA_ATTR_HIGH_PRIORITY |
                                        UDMA_ATTR_REQMASK);
    
        //
        // Set the USEBURST attribute for the uDMA UART TX channel.  This will
        // force the controller to always use a burst when transferring data from
        // the TX buffer to the UART.  This is somewhat more effecient bus usage
        // than the default which allows single or burst transfers.
        //
        ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_UART0TX, UDMA_ATTR_USEBURST);
    
        //
        // Configure the control parameters for the UART TX.  The uDMA UART TX
        // channel is used to transfer a block of data from a buffer to the UART.
        // The data size is 8 bits.  The source address increment is 8-bit bytes
        // since the data is coming from a buffer.  The destination increment is
        // none since the data is to be written to the UART data register.  The
        // arbitration size is set to 4, which matches the UART TX FIFO trigger
        // threshold.
        //
        ROM_uDMAChannelControlSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                                  UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE |
                                  UDMA_ARB_4);
    
        //
        // Set up the transfer parameters for the uDMA UART TX channel.  This will
        // configure the transfer source and destination and the transfer size.
        // Basic mode is used because the peripheral is making the uDMA transfer
        // request.  The source is the TX buffer and the destination is the UART
        // data register.
        //UART_O_DR is (UARTDR) register at offset 0x000
        ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT,
                                   UDMA_MODE_BASIC, g_ui8TxBuf,
                                   (void *)(UART0_BASE + UART_O_DR),
                                   sizeof(g_ui8TxBuf));
    
        //
        // Now both the uDMA UART TX and RX channels are primed to start a
        // transfer.  As soon as the channels are enabled, the peripheral will
        // issue a transfer request and the data transfers will begin.
        //
        uDMAChannelEnable(UDMA_CHANNEL_UART0TX);
    
    }
    
    //*****************************************************************************
    //
    // This example demonstrates how to use the uDMA controller to transfer data
    // between memory buffers and to and from a peripheral, in this case a UART.
    // The uDMA controller is configured to repeatedly transfer a block of data
    // from one memory buffer to another.  It is also set up to repeatedly copy a
    // block of data from a buffer to the UART output.  The UART data is looped
    // back so the same data is received, and the uDMA controlled is configured to
    // continuously receive the UART data using ping-pong buffers.
    //
    // The processor is put to sleep when it is not doing anything, and this allows
    // collection of CPU usage data to see how much CPU is being used while the
    // data transfers are ongoing.
    //
    //*****************************************************************************
    int main(void)
    {
    
        //
        // Enable lazy stacking for interrupt handlers.  This allows floating-point
        // instructions to be used within interrupt handlers, but at the expense of
        // extra stack usage.
        //
        ROM_FPULazyStackingEnable();
    
        //
        // Set the clocking to run from the PLL at 50 MHz.
        //
        ROM_SysCtlClockSet(SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN |
                           SYSCTL_XTAL_16MHZ);
    
        //
        // Enable peripherals to operate when CPU is in sleep.
        //
        ROM_SysCtlPeripheralClockGating(true);
    
        //
        // Enable the GPIO port that is used for the on-board LED.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);
    
        //
        // Enable the GPIO pins for the LED (PF2).
        //
        ROM_GPIOPinTypeGPIOOutput(GPIO_PORTF_BASE, GPIO_PIN_2);
    
    
        //
        // Configure SysTick to occur 100 times per second, to use as a time
        // reference.  Enable SysTick to generate interrupts.
        //
        ROM_SysTickPeriodSet(ROM_SysCtlClockGet() / SYSTICKS_PER_SECOND);
    
        //
        // Enable the uDMA controller at the system level.  Enable it to continue
        // to run while the processor is in sleep.
        //
        ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA);
        ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UDMA);
    
        //
        // Enable the uDMA controller error interrupt.  This interrupt will occur
        // if there is a bus error during a transfer.
        //
        ROM_IntEnable(INT_UDMAERR);
    
        //
        // Enable the uDMA controller.
        //
        ROM_uDMAEnable();
    
        //
        // Point at the control table to use for channel control structures.
        //
        ROM_uDMAControlBaseSet(ui8ControlTable);
    
        //
        // Initialize the uDMA UART transfers.
        //
        InitUART0Transfer();
    
    
        // Loop forever with the CPU not sleeping, so the debugger can connect.
        //
        while(1)
        {
            //
            // Turn on the GREEN LED.
            //
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, GPIO_PIN_2);
    
            //
            // Delay for a bit.
            //
            SysCtlDelay(SysCtlClockGet() / 20 / 3);
    
            //
            // Turn off the GREEN LED.
            //
            GPIOPinWrite(GPIO_PORTF_BASE, GPIO_PIN_2, 0);
    
            //
            // Delay for a bit.
            //
            SysCtlDelay(SysCtlClockGet() / 20 / 3);
    
        }
    }
    

    我可以清楚地看到数据来自 TX 引脚。

    数据也会输出到终端。 由于我输出非 ASCII 数据、某些字符是不可读的。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Thx

    我终于明白了。 DMA 控制器无法从闪存传输数据。

    我的测试字符串被放置在闪存中。 如果我将其放入 RAM 中、就像这样

    char testTxt []="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ hello!\n\n";

    它工作正常。

    那么、后续问题:如何配置 DMA 控制器从闪存中传输数据?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Stefan、

     这很不可能。 请参阅数据表。  

    μ μDMA 控制器可以与片上 SRAM 之间传输数据。 但是、因为闪存
    存储器和 ROM 位于单独的内部总线上、无法从传输数据
    Flash 存储器或带有 μ μDMA 控制器的 ROM

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的澄清

    下一个问题
    UART4的 UDMA 时、它将是一个很好的选择。 由于 UDMA_CHANGE_UART0TX 与 UART0TX 不同、但 UDMA_CH19_UART4TX 看起来对我来说是合适的通道。 我是否可以将 UDMA_CHANGE_UART0TX 替换为 UDMA_CH19_UART4TX、或者还有其他需要考虑的事项。

    我现在开始通过 DMA 实现 RX

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、还请确保按照以下步骤调用、将 UART4RX 和 UART4TX 分配到通道18和19、因为 GPTTimer0A 和 GPTTimer0B 是这两个通道上的默认外设。  

    uDMAChannelAssign (UDMA_CH18_UART4RX);

    uDMAChannelAssign (UDMA_CH19_UART4TX);

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我现在正在运行通过 DMA 的 RX。 过孔

    uint32_t getRXamount(const uint32_t channel) {
    	return sizeof(rxBuffer) - uDMAChannelSizeGet(UART0_RX_CHANNEL  | UDMA_PRI_SELECT);
    }
    


    我可以通过 DMA 控制器检查多少字节为 Rx。

    现在、我需要了解 UART 外设何时进行数据复用以及 Rx 数据流何时完成。

    因此、我调整了 UART 初始化以捕获 RX 和 RT 中断

    void initUART(void){
    	IRQ_CONNECT(5,0, uart0IntHandler, NULL, 0);
    	irq_enable(5);
    
        //
        // Enable the peripherals used by this example.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);
    
        //
        // Set GPIO A0 and A1 as UART pins.
        //
        GPIOPinConfigure(GPIO_PA1_U0TX);
        GPIOPinConfigure(GPIO_PA0_U0RX);
        GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_1 | GPIO_PIN_0);
    
        //
        // Enable the UART peripheral, and configure it to operate even if the CPU
        // is in sleep.
        //
        SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0);
        //
        // Configure the UART communication parameters.
        //
        UARTConfigSetExpClk(UART0_BASE, SysCtlClockGet(), 115200,
                                UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE |
                                UART_CONFIG_PAR_NONE);
    
        //
        // Set both the TX and RX trigger thresholds to 4.  This will be used by
        // the uDMA controller to signal when more data should be transferred.  The
        // uDMA TX and RX channels will be configured so that it can transfer 4
        // bytes in a burst when the UART is ready to transfer more data.
        //
        UARTFIFOLevelSet(UART0_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8);
    
        //
        // Enable the UART for operation, and enable the uDMA interface for both TX
        // and RX channels.
        //
        UARTEnable(UART0_BASE);
        UARTDMAEnable(UART0_BASE, UART_DMA_TX | UART_DMA_RX);
        UARTIntEnable(UART0_BASE, UART_INT_RX | UART_INT_RT);
    }

    目前我只获得 RX DMA 停止中断、但没有获得 RX 或 RT 中断。 有什么想法、我需要更改什么才能获得这些中断?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3860056 #3860056">我只获得 RX DMA 停止中断、但不会获得 RX 或 RT 中断。 有什么想法、我需要更改什么才能获得这些中断?[/quot]

    数据表中对此进行了说明。  

    当某个外设使能 μ μDMA 后、μ μDMA 控制器将停止正常的传输中断
    外设到达中断控制器的时间(中断仍会在外设中报告
    中断寄存器)。 因此、当使用 μ μDMA 传输大量数据而不是接收数据时
    来自外设的多个中断随着数据的流动、中断控制器只接收一个中断
    传输完成后。 未屏蔽的外设错误中断继续发送到
    中断控制器。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的澄清
    我知道 UDMA 控制器捕获并处理 UART intr。
    是否可以捕获 RT intr? 我能否获取 unmask intr? 是否有其他方法可以检测 UART 是否处于活动/停用状态(syscontrol/power 等)?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3860878 #3860878"]是否可以捕获 RT intr?

    这是一个好问题。 我读取了 UART 的数据表、下面是我找到的数据。 我想您需要做的是在 UART 中断 ISR 中、检查 DMACHIS 寄存器以查看是否设置了相应 UART 的标志。 如果该位置位、则读取 UART 中断状态寄存器。

    UART 还可配置为停止使用 DMA 进行接收
    接收错误时的通道。 如果 UARTDMACR 寄存器的 DMAERR 位被置位且接收信号
    错误发生、DMA 接收请求被自动禁用。 这种错误情况是可以的
    通过清除相应的 UART 错误中断来清除。

    当使用 μ μDMA 从 UART 的 FIFO 执行传输时、任何中断都是如此
    由 UART 生成、DMA 通道中断状态中 UART 模块的状态位
    (DMACHIS)寄存器必须在中断处理例程结束时被检查。 如果状态位为
    置位、通过向中断写入1来清除中断。

    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3860878 #3860878"]是否有其他方法可以检测 UART 是否处于活动/停用状态(syscontrol/power 等)?

    我认为我不理解这个问题。 您可以通过软件激活 UART、因此您应该知道 UART 处于活动状态。 如果由于错误而停用、那么通过读取 DMACHIS 寄存器来参考上述答案。 您对 syscontrol 和 power 有何看法? 通过 syscontrol 启用 UART 的时钟是一个软件步骤。 如果 UART 断电、则整个器件断电。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    嗨、噢
    我玩了一点点。 到目前为止、我还没有成功捕获任何指示 UART 复用一个突发字节(通过 DMA)的 intr。 我可以通过 uDMAChannelSizeGet 随时完美地检查 DMA 状态。

    问题的核心意图是设置 UART Rx、使其在后台(通过 DMA)传输 Rx 字节、直到缓冲区运行或 UART Rx 静默。

    它归结为对长度未知的 UART 消息的突发检测。

    想法是启动 DMA Rx 并像 RT 那样监听 UART INTR。 如果 RT intr 命中、我们可以通过 uDMAChannelSizeGet 检查我们已复用的字节数。  如果我们超过 DMA 缓冲区、我们会认为出现了问题。

    根据我的当前理解、我们可以通过 DMA 完美地设置 RX。 但我们无法检测 UART 何时处于静默状态(如果我错了、请更正我)。 这是因为 DMA 控制器接管了 UART 内部。 意味着 NVIC 不会触发任何 UART intr。 这就是我们无法读回 RX 或 RT intr 的原因。

    我们还发现、我可以将 DMA 用于 TX。 这里的限制条件是存储器需要位于 RAM 内部。 因此、直接闪存传输失败。

    对我来说、当前解决我的问题的最佳解决方案是:
    TX -> UART + UDMA + UART DMA INTR
    RX -> UART + FIFO + UART RX 和 RT INTR

    也许您可以指向一个示例、该示例描述了通过 FIFO 和 intr 进行 RX 的最有效方式(=最低 MCU 负载)。

    请添加一条评论、我很高兴结束此问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    [引用 userid="495727" URL"~/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1037828/tm4c123gh6pge-how-to-do-the-most-efficient-setup-for-the-uart-to-do-full-duplex-comms-with-unknown-message-sizes/3862631 #3862631"]Idea 是启动 DMA Rx 并侦听 UART INTR、如 RT。 如果 RT intr 命中、我们可以通过 uDMAChannelSizeGet 检查我们已复用的字节数。  如果我们超过 DMA 缓冲区、我们会认为出现了问题。
    [/报价]

    让我们首先尝试了解 RT (接收超时)在非 UDMA 环境中的含义。 请从 d/s 中阅读下面的说明 这通常意味着处理器可能太忙、无法及时读取 RXFIFO 中剩余的数据。 UDMA 是否会发生这种情况? 是的、如果 uDMA 正忙于为其他通道提供服务、并且没有及时从 RXFIFO 传输数据。 假设您要将1024字节从 UART RXFIFO 传输到缓冲区、则会发生仅传输1020字节的情况。 RXFIFO 中还有4个。 如果您调用  uDMAChannelSizeGet 、它将报告待传输的剩余字节数、在本例中为4。 我不明白为什么您要检查您是否超出了 DMA 缓冲区。 缓冲区将为1024、如果您处于 RT 状态、则不会超过该缓冲区。 我在前面建议您阅读  DMACHIS。  你试过吗? 您为什么不做实验? 设置 UDMA 以从 UART 传输256字节。 但是、让外部 UART 器件实际传输257个字节。 这意味着 UDMA 不会在 RXFIFO 中保留1个字节。 如果启用 RT 中断、您是否会获得任何中断?

    接收 FIFO 不为空且不再有数据时、接收超时中断有效
    HSE 位清零时在32位周期内接收、HSE 位清零时在64位周期内接收
    已设置。 当 FIFO 通过读取变为空时、接收超时中断被清除
    所有数据(或通过读取保存寄存器)、或当1写入中的相应位时
    UARTICR 寄存器。

    31.2.3.14 uDMAChannelSizeGet
    获取 uDMA 通道控制结构体的当前传输大小。
    原型:
    uint32_t
    uDMAChannelSizeGet (uint32_t ui32ChannelStructIndex)
    参数:
    ui32ChannelStructIndex 是带有任一通道的 UDMA 通道编号的逻辑 OR
    UDMA_PRI_SELECT 或 UDMA_ALT_SELECT。

    描述:
    此函数用于获取通道的 uDMA 传输大小。 传输大小为
    要传输的数据单元数、其中数据单元的大小可能为8、16或32位。 如果是局部的
    传输已发生、然后返回剩余的项目数。 如果是传输
    完成、然后返回0。
    返回:
    返回待传输的剩余项目数

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    在 RT intr 上:我之前在非 FIFO 模式下使用过它来检测突发结束。 我可能误解了它。

    到目前为止我的测试:我为 RX 和 TX 激活了 DMA、并在 UART0 ISR 中放入了一个断点。 对于 TX、当 DMA 完成传输时、我看到了。
    对于 RX、我没有看到任何 intr、除非 Rx 缓冲区已被 DMA 控制器完全填满。 正如您在 DMA 控制器接管 intr 之前所说的那样。 这是有道理的。

    现在、我通过 DMA 回到了 TX、通过 intr 和 FIFO 回到了 RX。 工作得相当好。 如前所述、我确信使用该 MCU 无法进行 RX DMA + RX 突发检测(就像我之前使用的 STM32F412那样)。

    感谢您努力向我解释。