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.
工具/软件:Code Composer Studio
大家好、
我正在研究一个项目、该项目需要在2个 TM4C123G、套件 A 处理电源处理(ADC、PWM 等)、套件 B 通过 RS-485处理 MODBUS 到 PC 之间开发一种通信方法。 目标是经常进行通信、而不中断 A 的电源过程和 B 的 MODBUS 通信、我已经进行了 I2C、SPI 通信。 这两种方法既快速又准确、但仍然存在缺陷、因为 I2C 没有任何 FIFO、SPI 通信很难在不中断的情况下同步。 我发现 uDMA 可以独立处理而不中断主程序、因此我尝试使用 uDMA UART 来使通信数据始终可访问。 我是 UDMA 领域的新手、但我做了一些研究。 目前、我了解 uDMA 的工作方式、遗憾的是、我不知道如何正确设置它。 我尝试修改了我在网上找到的一些代码、但到目前为止没有任何反应(代码附在下面)。
我的想法是、当数据进入任何套件的 Rx 引脚时、它将触发 UDMA、以便所有数据直接进入 UDMA 寄存器并触发一个标志。 在 while (1)循环中、如果该标志处于开启状态、则会处理数据并响应另一个套件(这也是我选择 UART 而不是 I2C 和 SPI 的原因)。 更多详细信息、套件 B 向套件 A 发送一个包含8字节无符号字符的请求包、套件 A 在完成电源处理后将检查该标志。 如果标志打开、套件 A 将收集数据并将16 (或32字节)的 ADC 信息包发送到套件 B。为了满足这些要求、我应该设置哪种模式和数据类型?
使用 UART FIFO 联机以触发 UDMA 的代码。 是否有任何方法可以在不使用 UART FIFO 的情况下将数据直接传输到 UDMA?
谢谢你。
#include #include #include "inc/hw_memmap.h" #include "inc/hw_ints.h" #include "inc/hw_uart.h" #include "driverlib/gpio.h" #include "driverlib/pin_map.h" #include "driverlib/ssi.h" #include "driverlib/sectl.h" #include "driverlib/static trabme.h" 、#include "driverlib.0"、darm.1u.h、#include "driverlib.0";include "driverlib.0uart.1uart.0";include "driver1.dartal.h、dtrabtore.h、d4、d4、0u.0u.h、tore.h、tore.h、d4、0u.inc //启用 GPIO 端口 A SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); //启用 DMA SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); IntEnable (INT_UDMAERR); uDMAEnable(); uDMAControlBaseSet (uDMAControlTable); //启用 UART 0外设 SysCtlPeripheralEnable (SYSCTL_Periph_UART0); //将 A0和 A1设置为 UART 0的 RX 和 TX 引脚 GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0); GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_1); //配置 UART (来自 PIOSC 的时钟、115.2k 8-N-1) UARTConfigSetExpClk (UART0_BASE、SysCtlClockGet ()、115200、(UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_LEON)); 当 FIFO 处于1/8容量时、//触发中断 UARTFIFOLevelSet (UART0_BASE、UART_FIFO_TX1_8、UART_FIFO_RX1_8); //确保中断是清除的 UARTIntClear (UART0_BASE、(UART_INT_RX | UART_INT_RT | UART_INT_TX | UART_INT_OE | UART_INT_be | UART_INT_PE | UART_INT_FE)); //启用 UART 0 UARTEnable (UART0_BASE); //在 UART RX 上启用 DMA UARTDMAEnable (UART0_BASE、UART_DMA_RX); // //将 UDMA UART TX 通道的属性置于已知状态。 这些 默认情况下、//应已禁用。 // uDMAChannelAttributeDisable (UDMA_CHANGE_UART0TX、UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); // //将 UDMA UART RX 通道的属性置于已知状态。 这些 默认情况下、//应已禁用。 // uDMAChannelAttributeDisable (UDMA_CHANGE_UART0RX、UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); uDMAChannelAttributeEnable (UDMA_CHANGE_UART0TX、UDMA_ATTR_USEBURST); uDMAChannelControlSet (UDMA_CHANNEL_UART0TX | UDMA_PRI_SELECT、UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_8); uDMAChannelControlSet (UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT、UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8); //在此 UART 上启用 DMA 中断 UARTIntEnable (UART0_BASE、UART_INT_DMARX | UART_INT_DMATX); //在此 UART 上启用中断 IntEnable (INT_UART0); } void uartInterruptHandler (void) { //如果是 RX 中断 IF (UARTIntStatus (UART0_BASE、TRUE)& UART_INT_DMARX) { //在 UART RX 上禁用 DMA,并清除中断 UARTDMADisable (UART0_BASE、UART_DMA_RX); UARTIntClear (UART0_BASE,UART_INT_DMARX); } //如果是 TX 中断 IF (UARTIntStatus (UART0_BASE、TRUE)和 UART_INT_DMATX) { //在 UART TX 上禁用 DMA,并清除中断 UARTDMADisable (UART0_BASE、UART_DMA_TX); UARTIntClear (UART0_BASE,UART_INT_DMATX); } } int main() { SysCtlClockSet (SYSCTL_SYSDIV_2_5 | SYSCTL_USE_OSC | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz); //初始化 UART initUART0(); for (;;) { /********* *接收 * //设置为接收缓冲区 uDMAChannelTransferSet (uDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、UDMA_MODE_BASIC、(void *)(UART0_BASE + UART_O_DR)、&buffer、sizeof (buffer); //启用 DMA 通道以开始接收 uDMAChannelEnable (UDMA_CHANGE_UART0RX); //在 UART RX 上启用 DMA UARTDMAEnable (UART0_BASE、UART_DMA_RX); /********* *发送 * //设置为发送缓冲区 uDMAChannelTransferSet (uDMA_CHANGE_UART0TX | UDMA_PRI_SELECT、UDMA_MODE_BASIC、&buffer、(void *)(UART0_BASE + UART_O_DR)、sizeof (buffer); //必须首先启用 DMA 通道,否则将立即发生中断 uDMAChannelEnable (UDMA_CHANGE_UART0TX); //在 UART TX 上启用 DMA UARTDMAEnable (UART0_BASE、UART_DMA_TX); while (uDMAChannelIsEnabled (UDMA_CHANGE_UART0RX)) { //等待响应,然后再发送更多 } }
您好、Charles、
我错了 UARTFIFODisable()函数(我不知道怎么看不到它),所以我对 FIFO 过多的问题感到很抱歉。
总之、关于 UDMA、我尝试了演示并查看了数据的变化。 但正如我说过的、我不知道如何正确设置自动请求模式、因为我不熟悉指令中的术语。 我认为、在不了解简单示例的情况下使用更复杂的示例并不是开始学习的好方法。 因此、为了更深入地了解(我的知识非常浅)、我要求提供一些解释或说明。 因此、如果您能对我温和一点、我将不胜感激。
您能解释一下数据流、我看到有 dst 和 SRC、这是 UDMA 的寄存器。 但我无法确定数据将进入何处、通过哪一个函数、我们将知道数据已在 uDMA 中完成接收或传输。
非常感谢。
此致、
尊敬的 Charles:
非常感谢您的详细解释和建议。 我要花一点时间来弄清楚这个问题,所以我会反复阅读你的答复和所有文件,以便了解这里的情况。 之后、我将尝试根据该知识进行编程。 在此之前 、您能否检查我的新代码和结果以了解我是否处于正确的方向?
此致、
不结盟运动
您好、Charles、
为了实现我的主要目标、我已经完成了一些代码。 但我不知道代码为什么不起作用、请帮我解决。 主要思路是 UDMA 将 Rx 数据引导到 Rx 缓冲器而不使用 Rx FIFO、LED 每1秒亮起和熄灭一次。 仅当 LED 熄灭时才会处理和响应请求。 因此、我尝试将数据从 UART0_BASE 定向到 g_ui8RxBuf[]、如果接收到数据、则模式从自动切换到停止(我不知道是否正确理解、请告诉我是否错误)。 只有这样、数据才会被处理和响应。
这是我的代码。
/********* * 图书馆包括 「民政事务局」 /#include #include #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/driverlib"#driver.h" #include "driverlib/driverlib"#driverlib.driver.h"#include "driverlib"#driverlib/driverlib.driverlib.driver.h"#include"#driverlib#driverlib.driverlib.driverlib.driver.h * 常量定义 了********* / #define MEM_BUFFER_SIZE 1024 #define UART_BUF_SIZE 16/********* * 变量 /uint8_t ui8ControlTable[MEM_BUFF_SIZE]; 静态无符号字符 g_ui8TxBuf[UART_BUF_SIZE]; 静态无符号字符 g_ui8RxBuf[UART_BUF_SIZE]; 静态 UINT32_t g_u32uDMAErrCount = 0; 静态 UINT8_ui32_uT = 0 ;静态 uint8 = uuuuuui_uint8 uuuuuui_deta. * 函数调用 /void uDMAErrorHandler(); void InitudDMAnUARTTransfer(); void ConfigureUART(); void TIMERISR(); void ConfigureTIMER (); void SendUART (unsigned char X); /********* * 主要计划 / int main (void) { uint32_t ui32模式; uint8_t ui8Index; SysCtlClockSet (SYSCTL_SYSDIV_2_5 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz); G_ui32Timer = SysCtlClockGet (); G_ui8模式= 1; SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF); GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_3); GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3、GPIO_PIN_3); SysCtlDelay (g_ui32Timer/10); GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3、0); SysCtlDelay (g_ui32Timer/10); ConfigureUART(); InitDDMAnUARTTransfer(); ConfigureTIME(); while (1) { if (g_ui8模式) { GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3、GPIO_PIN_3); SysCtlDelay (g_ui32Timer); GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_3、0); TimerIntRegister (TIMER0_BASE、TIMER_A、TIMERISR); IntEnable (INT_TIMER0A); TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerEnable (TIMER0_BASE、TIMER_A); TimerLoadSet (TIMER0_BASE、TIMER_A、g_ui32Timer); G_ui8Mode = 0; } 其他 { ui32Mode = uDMAChannelModeGet (UDMA_CHANGE_UART0RX | UDMA_PRI_SELECT); if (ui32Mode = uDMA_MODE_STOP) { for (ui8Index = 0;ui8Index < UART_BUF_SIZE;ui8Index++) { g_ui8TxBuf[ui8Index]= g_ui8RxBuf[ui8Index]+ 1; } for (ui8Index = 0;ui8Index < UART_BUF_SIZE;ui8Index++) { SendUART (g_ui8TxBuf[ui8Index]); } uDMAChannelTransferSet (uDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、UDMA_MODE_AUTO、(void *)(UART0_BASE + UART_O_DR)、g_ui8RxBuf、sizeof (g_ui8RxBuf)); uDMAChannelEnable (UDMA_CHANGE_UART0RX); } } } /********* * 功能定义 / void uDMAErrorHandler (void) { uint32_t ui32Status; ui32Status = uDMAErrorStatusGet (); if (ui32状态) { uDMAErrorStatusClear (); G_ui32uDMAErrCount++; } } void TIMERISR (void) { TimerIntClear (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerDisable (TIMER0_BASE、TIMER_A); TimerIntDisable (TIMER0_BASE、TIMER_TINA_TIMEOUT); G_ui8Mode = 1; } void InitudDMAnUARTTransfer (void) { SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); IntEnable (INT_UDMAERR); uDMAEnable(); uDMAControlBaseSet (ui8ControlTable); SysCtlPeripheralEnable (SYSCTL_Periph_UART0); IntEnable (INT_UART0); UARTConfigSetExpClk (UART0_BASE、SysCtlClockGet ()、9600、UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_LEON); UARTFIFODisable (UART0_BASE); UARTEnable (UART0_BASE); uDMAChannelAttributeDisable (UDMA_CHANGE_UART0RX、UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); uDMAChannelAttributeEnable (uDMA_CHANNEL UART0RX、UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); uDMAChannelControlSet (UDMA_CHANNEL_UART0RX | UDMA_PRI_SELECT、UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_8); uDMAChannelTransferSet (uDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、UDMA_MODE_AUTO、(void *)(UART0_BASE + UART_O_DR)、g_ui8RxBuf、sizeof (g_ui8RxBuf)); uDMAChannelEnable (UDMA_CHANGE_UART0RX); UARTDMAEnable (UART0_BASE、UART_DMA_RX); } void ConfigureUART (void) { SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); SysCtlPeripheralEnable (SYSCTL_Periph_UART0); SysCtlPeripheralSlepEnable (SYSCTL_Periph_UART0); GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); GPIOPinTypeUART (GPIO_PORta_base、GPIO_PIN_0 | GPIO_PIN_1); } void ConfigureTIMER (void) { SysCtlPeripheralEnable (SYSCTL_Periph_TIMER0); TimerConfigure (TIMER0_BASE、TIMER_CFG_A_ONE_SHOT); TimerLoadSet (TIMER0_BASE、TIMER_A、g_ui32Timer); TimerIntRegister (TIMER0_BASE、TIMER_A、TIMERISR); IntEnable (INT_TIMER0A); TimerIntEnable (TIMER0_BASE、TIMER_TINA_TIMEOUT); TimerEnable (TIMER0_BASE、TIMER_A); G_ui8Mode = 1; } void SendUART (unsigned char X) { UARTCharPut (UART0_BASE、X); if (UARTCharsAvail (UART0_BASE)) { UARTCharPut (UART0_BASE、UARTCharGet (UART0_BASE)); } }
您好!
我修改了 exising TivaWare UDMA 示例、并使其成为使用基本模式的简单 DMA 传输。 运行后、您可以查看 g_ui32RxBufA、您应该会看到 Rx 缓冲区的值与 g_ui8TxBuf 相同。 我建议您先让 UDMA 工作、然后再将计时器等其他代码合并到应用中、从而使调试更轻松。
#include #include 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/utilidex"#driverlib/driver.h"#include "driverlib.driverlib"#driverlib/driver.h"#include "driverlib#driverlib.driverlib#driver.h"#include "driverlib.us.md.us.us.driverlib"#include "driverlib_utils/drivers.md.md.us.md.ide"#include "#include "driverlib // //! \addtogroup example_list //!UDMA (UDMA_DEMO)
//! //! 此示例应用演示了如何使用 uDMA 控制器 来实现//! 在存储器缓冲区之间传输数据、以及与 A // !之间传输数据 UART。 测试在退出前运行10秒钟。 //! //! UART0、连接到 ICDI 虚拟 COM 端口并以115、200运行、 //! 8-N-1用于显示来自此应用程序的消息。 //// ***************** // // ////系统时钟速率,单位为 Hz。 //// ************* uint32_t g_ui32SysClock; //********* // // SysTick 中断使用的每秒 SysTick 数。 //// ***************** #define SYSTICKS_PER_second 100 //************* // //内存传输源和目的缓冲区的大小(以字为单位)。 //// ***************** #define MEM_buffer_size 1024 //********* // // UART 发送和接收缓冲区的大小。 它们 不需要是//大小相同。 //// ***************** #define UART_TXBUF_SIZE 256 #define UART_RXBUF_SIZE 256 //********* // //用于 UART 传输的发送和接收缓冲区。 //// ***************** 静态 uint8_t g_ui8TxBuf[UART_TXBUF_SIZE]; 静态 uint8_t g_ui8RxBufA[UART_RXBUF_SIZE]; //********* // // uDMA 错误的计数。 此值由 UDMA 错误 //处理程序递增。 //// ***************** 静态 uint32_t g_ui32uDMAErrCount = 0; //********* // 填充的 UART 缓冲器计数 // //********* 静态 uint32_t g_ui32RxBufACount = 0; //********* // // uDMA 控制器使用的控制表。 此表必须与 1024字节边界对齐//。 //// ***************** #if defined (ewarm) #pragma DATA_alignment=1024 uint8_t pui8ControlTable[1024]; #Elif Defined (CCS) #pragma DATA_ALIGN (pui8ControlTable、1024) uint8_t pui8ControlTable[1024]; #else uint8_t pu8ControlTable[1024]____(dio_attend_)(_1024) *(_1024)(_diforitudi8ControlTable_)*(_1024) // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *dpcFilename、uint32_t ui32Line) { #endif //********* // // uDMA 错误的中断处理程序。 如果 // uDMA 在尝试执行传输时遇到总线错误,则会发生此中断。 此 //处理程序仅在发生错误时递增计数器。 //// ***************** void uDMAErrorHandler (void) { uint32_t ui32Status; // //检查 uDMA 错误位 // ui32Status = ROM_uDMAErrorStatusGet (); // //如果存在 uDMA 错误,则清除该错误并递增 //错误计数器。 // if (ui32状态) { ROM_uDMAErrorStatusClear (); G_ui32uDMAErrCount++; } } //********* // // UART1的中断处理程序。 当使用 UART1 UDMA 通道完成 DMA //传输时、将发生此中断。 如果外设发出错误信号、它也将被//触发。 //// ***************** 空 UART1 IntHandler (空) { uint32_t ui32Status; uint32_t ui32模式; // //读取 UART 的中断状态。 // ui32Status = ROM_UARTIntStatus (UART1_BASE、1); // //清除任何挂起状态,即使由于没有 UART,应该没有任何挂起状态 //中断已启用。 如果启用了 UART 错误中断 //这些中断可能在这里发生,应该被处理。 UDMA 的影响 //用于 RX 和 TX、那么这两个中断都不应该 //已启用。 // ROM_UARTIntClear (UART1_BASE、ui32Status); G_ui32RxBufACount = 1; ROM_IntDisable (INT_UART1); ROM_IntDisable (INT_UDMA); } //********* // //初始化 UART1外设并设置 TX 和 RX UDMA 通道。 //将 UART 配置为环回模式,以便在 TX 上发送的任何数据都将 在 RX 上接收//。 UDMA 通道的配置使 TX 通道 //将数据从缓冲区复制到 UART TX 输出。 UDMA RX 通道 //将接收任何传入到缓冲区中的数据。 //// ***************** void InitUART1传输(void) { uint_fast16_t ui16Idx; // //用简单的数据模式填充 TX 缓冲区。 // 对于(ui16Idx = 0;ui16Idx < UART_TXBUF_SIZE;ui16Idx++) { g_ui8TxBuf[ui16Idx]= ui16Idx; } // //启用 UART 外设,并将其配置为即使 CPU 也能正常工作 //处于睡眠状态。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UART1); ROM_SysCtlPeripheralSlepEnable (SYSCTL_Periph_UART1); // //配置 UART 通信参数。 // ROM_UARTConfigSetExpClk (UART1_base、g_ui32SysClock、115200、 UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE); // //将 TX 和 RX 触发阈值设置为4。 这将由使用 // uDMA 控制器发出信号,指示何时应传输更多数据。 。 //将配置 uDMA TX 和 RX 通道,以便可以传输4个通道 当 UART 准备传输更多数据时、//以突发方式传输字节。 // ROM_UARTFIFOLevelSet (UART1_base、UART_FIFO_TX4_8、UART_FIFO_RX4_8); // //启用 UART 以进行操作,并为两个 TX 启用 UDMA 接口 //和 RX 通道。 // ROM_UARTEnable (UART1_BASE); ROM_UARTDMAEnable (UART1_base、UART_DMA_RX | UART_DMA_TX); // //该寄存器写入将 UART 设置为在环回模式下运行。 任何 //在 TX 输出上发送的数据将在 RX 输入上接收。 // HWREG (UART1_BASE + UART_O_CTL)|= UART_CTL_LBE; // //将 UDMA UART1RX 通道的属性置于已知状态。 这些 默认情况下、//应已禁用。 // ROM_uDMAChannelAttributeDisable (UDMA_CHANGE_UART1RX、 UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); // //为配置主控制结构体的控制参数 // UART RX 通道。 传输数据大小为8位 //源地址不会递增,因为它将从读取 //寄存器。 目的地址增量是字节8位字节。 。 //仲裁大小设置为4以匹配 RX FIFO 触发阈值。 //如果可能,UDMA 控制器将使用4字节突发传输。 这种情况 //比单字节传输的效率要高一些。 // ROM_uDMAChannelControlSet (UDMA_CHANGE_UART1RX | UDMA_PRI_SELECT、 UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // //设置 UART RX 主控件的传输参数 //结构。 。 //传输大小设置为与缓冲区大小匹配。 // ROM_uDMAChannelTransferSet (UDMA_CHANGE_UART1RX | UDMA_PRI_SELECT、 UDMA_MODE_BASIC、 (void *)(UART1_base + UART_O_DR)、 g_ui8RxBufA、sizeof (g_ui8RxBufA); // //将 UDMA UART1TX 通道的属性置于已知状态。 这些 默认情况下、//应已禁用。 // ROM_uDMAChannelAttributeDisable (UDMA_CHANGE_UART1TX、 UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); // //设置 UDMA UART TX 通道的 USEBURST 属性。 这将会 //强制控制器在传输数据时始终使用突发 //将 TX 缓冲器连接到 UART。 这是比较高效的总线使用 //不是允许单次或突发传输的默认值。 // ROM_uDMAChannelAttributeEnable (UDMA_CHANGE_UART1TX、UDMA_ATTR_USEBURST); // //配置 UART TX 的控制参数。 UDMA UART TX //通道用于将数据块从缓冲区传输到 UART。 //数据大小为8位。 源地址增量为8位字节 //因为数据来自缓冲区。 目的增量为 //由于数据将被写入 UART 数据寄存器,因此不存在。 。 //仲裁大小设置为4,与 UART TX FIFO 触发器匹配 //阈值。 // ROM_uDMAChannelControlSet (UDMA_CHANGE_UART1TX | UDMA_PRI_SELECT、 UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4); // //设置 uDMA UART TX 通道的传输参数。 这将会 //配置传输源和目的以及传输大小。 //使用基本模式是因为外设正在进行 UDMA 传输 //请求。 源是 TX 缓冲区、目的是 UART //数据寄存器。 // ROM_uDMAChannelTransferSet (UDMA_CHANGE_UART1TX | UDMA_PRI_SELECT、 UDMA_MODE_BASIC、g_ui8TxBuf、 (void *)(UART1_base + UART_O_DR)、 sizeof (g_ui8TxBuf)); // //现在,UDMA UART TX 和 RX 通道都被引脚以启动 A //传输。 一旦启用通道、外设将会启动 //发出传输请求,数据传输将开始。 // ROM_uDMAChannelEnable (UDMA_CHANGE_UART1RX); ROM_uDMAChannelEnable (UDMA_CHANGE_UART1TX); // //启用 UART DMA TX/RX 中断。 // ROM_UARTIntEnable (UART1_BASE、UART_INT_DMATX | UART_INT_DMATX); // //启用 UART 外设中断。 // ROM_IntEnable (INT_UART1); } //********* // //配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 //// ***************** void ConfigureUART (void) { // //启用 UART 使用的 GPIO 外设。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //启用 UART0 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UART0); ROM_SysCtlPeripheralSlepEnable (SYSCTL_Periph_UART0); // //为 UART 模式配置 GPIO 引脚。 // ROM_GPIOPinConfigure (GPIO_PA0_U0RX); ROM_GPIOPinConfigure (GPIO_PA1_U0TX); ROM_GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //初始化控制台 I/O 的 UART // UARTStdioConfig (0、115200、g_ui32SysClock); } //************* // //此示例演示了如何使用 uDMA 控制 器在内存缓冲区之间以及与外设之间传输数据//,在本例中为 UART。 // UDMA 控制 器被配置为重复传输一个数据块//从一个内存缓冲区到另一个内存缓冲区。 它还被设置为将一 个//数据块从一个缓冲区重复复制到 UART 输出。 UART 数据循环 //返回,以便接收相同的数据。 //// ***************** int main (void) { // //将时钟设置为直接从频率为120MHz 的晶体运行。 // G_ui32SysClock = MAP_SysCtlClockFreqSet ((SYSCTL_XTAL_25MHz | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480)、120000000); // //使外设在 CPU 处于睡眠状态时运行。 // ROM_SysCtlPeripheralClockGating (真); // //启用用于板载 LED 的 GPIO 端口。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_GPION); // //为 LED (PN0)启用 GPIO 引脚。 // ROM_GPIOPinTypeGPIOOutput (GPIO_PORTN_BASE、GPIO_PIN_0); // //初始化 UART。 // ConfigureUART (); UARTprintf ("\033[2J\033[H"); UARTprintf ("UDMA 示例\n"); // //在显示屏上显示时钟频率。 // UARTprintf ("Tiva C 系列@%u MHz\n\n"、g_ui32SysClock / 1000000); // //在系统级别启用 uDMA 控制器。 使其继续 //在处理器处于睡眠状态时运行。 // ROM_SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); ROM_SysCtlPeripheralSlepEnable (SYSCTL_Periph_UDMA); // //启用 uDMA 控制器错误中断。 将发生该中断 //如果在传输过程中出现总线错误。 // ROM_IntEnable (INT_UDMAERR); // //启用 UDMA 控制器。 // ROM_uDMAEnable(); // //指向控制表以用于通道控制结构体。 // ROM_uDMAControlBaseSet (pui8ControlTable); // //初始化 UDMA UART 传输。 // InitUART1传输(); // //等待,直到 DMA 传输完成 // while (g_ui32RxBufACount == 0x0){ } UARTprintf ("UDMA 示例完成\n"); // //在测试完成后禁用 uDMA 和 UART 中断。 // ROM_IntDisable (INT_UART1); ROM_IntDisable (INT_UDMA); // //在 CPU 未休眠的情况下永久循环,因此调试器可以进行连接。 // while (1) { // //打开 LED。 // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_0、GPIO_PIN_0); // //延迟一位。 // SysCtlDelay (g_ui32SysClock / 20/3); // //关闭 LED。 // GPIOPinWrite (GPIO_PORTN_BASE、GPIO_PIN_0、0); // //延迟一位。 // SysCtlDelay (g_ui32SysClock / 20/3); } }
您好、Charles、
我非常感谢您的代码、它真的很有帮助。 我现在可以更深入地了解 uDMA、非常感谢。
但是、我仍然对 UART0_BASE 中的数据有疑问。 目前、我分配了要从 UART0_BASE 读取的数据、其发生方式与我预期的完全相同。 我现在能够控制数据处理时间。 但是、当我向 MCU 发送数据时、g_ui8RxBuf 的指针会不断增加。 因此、如果要将指针重置到数组的开头、 我该怎么办? 我是否应该通过将 g_ui8RxBuf 数组的所有元素设置为0x00来清除它? 这种情况是否有最佳解决方案?
此致、
不结盟运动
尊敬的 Charles:
我尝试了一些方法来重置 Rx 缓冲器的指针。 目前、我提出了一个解决方案、我可以调用3个函数
uDMAChannelAttributeDisable (UDMA_CHANGE_UART0RX、 UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); uDMAChannelControlSet (UDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、 UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); uDMAChannelTransferSet (UDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、 UDMA_MODE_BASIC、 (void *)(UART0_BASE + 0)、 g_ui8RxBuf、sizeof (g_ui8RxBuf));
这是复位缓冲器的有效方法吗?
此致、
不结盟运动
尊敬的 Charles:
我发现、我设置 Rx 缓冲器阵列的大小足以容纳1个包含8个无符号字符的帧。 因此、当我发送超过8个字符时、将发生溢出(我不能识别这一点、所以我认为问题是指针)。 为了解决这个问题、我增加了缓冲区的大小、并使用一个标志来控制数据流。 每当处理并响应接收到的数据时、所有缓冲区都将被清除;因此、该过程将检查缓冲区以查看其是否与帧匹配。 只有当帧匹配时、标志才会打开以发送下一个数据包。 这种方法可防止器件在没有接收任何响应的情况下发送1个以上的数据包。 我还将 Rx 缓冲器的大小增加到64、作为第二次防御、我尝试将其增加到256、但不知道为什么程序不再工作。 我使用的代码根据您的示例进行了修改、我想我对 UDMA 有了更深入的了解、但我不确定您能否检查代码以确保我不会使其混乱? 非常感谢!
#include #include #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/interrupt.h" #include "driverlib/driverlib"#driverh/us.mdexe" #include "driverlib/driverlib#driver.h"#driverlib#driverlib.us.us.use.m#include "drivers/driverlib"#drivers.us.ude/driverlib#include "drivers.utils/driverlib"#include "drivers.md.md.ide"#include "driver.h // //! \addtogroup example_list //!UDMA (UDMA_DEMO)
//! //! 此示例应用演示了如何使用 uDMA 控制器 来实现//! 在存储器缓冲区之间传输数据、以及与 A // !之间传输数据 UART。 测试在退出前运行10秒钟。 //! //! UART0、连接到 ICDI 虚拟 COM 端口并以115、200运行、 //! 8-N-1用于显示来自此应用程序的消息。 //// ***************** // // ////系统时钟速率,单位为 Hz。 //// ************* uint32_t g_ui32SysClock; //********* // // SysTick 中断使用的每秒 SysTick 数。 //// ***************** #define SYSTICKS_PER_second 100 //************* // //内存传输源和目的缓冲区的大小(以字为单位)。 //// ***************** #define MEM_buffer_size 1024 //********* // // UART 发送和接收缓冲区的大小。 它们 不需要是//大小相同。 //// ***************** #define UART_BUF_SIZE 64 /************* // //用于 UART 传输的发送和接收缓冲区。 //// ***************** 静态 uint8_t g_ui8TxBuf[UART_BUF_SIZE]; 静态 uint8_t g_ui8RxBuf[UART_BUF_SIZE]; //********* // // uDMA 错误的计数。 此值由 UDMA 错误 //处理程序递增。 //// ***************** 静态 uint32_t g_ui32uDMAErrCount = 0; //********* // 填充的 UART 缓冲器计数 // //********* 静态 uint32_t g_ui32RxBufCount = 0; //********* // // uDMA 控制器使用的控制表。 此表必须与 1024字节边界对齐//。 //// ***************** #if defined (ewarm) #pragma DATA_alignment=1024 uint8_t pui8ControlTable[1024]; #Elif Defined (CCS) #pragma DATA_ALIGN (pui8ControlTable、1024) uint8_t pui8ControlTable[1024]; #else uint8_t pu8ControlTable[1024]____(dio_attend_)(_1024) *(_1024)(_diforitudi8ControlTable_)*(_1024) // //如果驱动程序库遇到错误,则调用的错误例程。 //// ***************** #ifdef debug void __error__(char *dpcFilename、uint32_t ui32Line) { #endif //********* // // uDMA 错误的中断处理程序。 如果 // uDMA 在尝试执行传输时遇到总线错误,则会发生此中断。 此 //处理程序仅在发生错误时递增计数器。 //// ***************** void uDMAErrorHandler (void) { uint32_t ui32Status; // //检查 uDMA 错误位 // ui32Status = uDMAErrorStatusGet (); // //如果存在 uDMA 错误,则清除该错误并递增 //错误计数器。 // if (ui32状态) { uDMAErrorStatusClear (); G_ui32uDMAErrCount++; } } //********* // // UART0的中断处理程序。 当使用 UART0 UDMA 通道完成 DMA //传输时、将发生此中断。 如果外设发出错误信号、它也将被//触发。 //// ***************** 空 UART0IntHandler (空) { uint32_t ui32Status; uint32_t ui32模式; // //读取 UART 的中断状态。 // ui32Status = UARTIntStatus (UART0_BASE、1); // //清除任何挂起状态,即使由于没有 UART,应该没有任何挂起状态 //中断已启用。 如果启用了 UART 错误中断 //这些中断可能在这里发生,应该被处理。 UDMA 的影响 //用于 RX 和 TX、那么这两个中断都不应该 //已启用。 // UARTIntClear (UART0_BASE、ui32Status); G_ui32RxBufCount++; // IntDisable (INT_UART0); IntDisable (INT_UDMA); } //********* // //初始化 UART0外设并设置 TX 和 RX UDMA 通道。 //将 UART 配置为环回模式,以便在 TX 上发送的任何数据都将 在 RX 上接收//。 UDMA 通道的配置使 TX 通道 //将数据从缓冲区复制到 UART TX 输出。 UDMA RX 通道 //将接收任何传入到缓冲区中的数据。 //// ***************** void InitUART0Transfer (void) { // //启用 UART 外设,并将其配置为即使 CPU 也能正常工作 //处于睡眠状态。 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); SysCtlPeripheralSlepEnable (SYSCTL_Periph_UART0); //将 TX 和 RX 触发阈值设置为4。 这将由使用 // uDMA 控制器发出信号,指示何时应传输更多数据。 。 //将配置 uDMA TX 和 RX 通道,以便可以传输4个通道 当 UART 准备传输更多数据时、//以突发方式传输字节。 // UARTFIFOLevelSet (UART0_BASE、UART_FIFO_TX4_8、UART_FIFO_RX4_8); // //启用 UART 以进行操作,并为两个 TX 启用 UDMA 接口 //和 RX 通道。 // UARTEnable (UART0_BASE); UARTDMAEnable (UART0_BASE、UART_DMA_RX | UART_DMA_TX); // //将 UDMA UART0RX 通道的属性置于已知状态。 这些 默认情况下、//应已禁用。 // uDMAChannelAttributeDisable (UDMA_CHANGE_UART0RX、 UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); // //为配置主控制结构体的控制参数 // UART RX 通道。 传输数据大小为8位 //源地址不会递增,因为它将从读取 //寄存器。 目的地址增量是字节8位字节。 。 //仲裁大小设置为4以匹配 RX FIFO 触发阈值。 //如果可能,UDMA 控制器将使用4字节突发传输。 这种情况 //比单字节传输的效率要高一些。 // uDMAChannelControlSet (UDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、 UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // //设置 UART RX 主控件的传输参数 //结构。 。 //传输大小设置为与缓冲区大小匹配。 // uDMAChannelTransferSet (UDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、 UDMA_MODE_BASIC、 (void *)(UART0_BASE + UART_O_DR)、 g_ui8RxBuf、sizeof (g_ui8RxBuf)); // //将 UDMA UART0TX 通道的属性置于已知状态。 这些 默认情况下、//应已禁用。 // uDMAChannelAttributeDisable (UDMA_CHANGE_UART0TX、 UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIOR| UDMA_ATTR_REQMASK); // //设置 UDMA UART TX 通道的 USEBURST 属性。 这将会 //强制控制器在传输数据时始终使用突发 //将 TX 缓冲器连接到 UART。 这是比较高效的总线使用 //不是允许单次或突发传输的默认值。 // uDMAChannelAttributeEnable (UDMA_CHANGE_UART0TX、UDMA_ATTR_USEBURST); // //配置 UART TX 的控制参数。 UDMA UART TX //通道用于将数据块从缓冲区传输到 UART。 //数据大小为8位。 源地址增量为8位字节 //因为数据来自缓冲区。 目的增量为 //由于数据将被写入 UART 数据寄存器,因此不存在。 。 //仲裁大小设置为4,与 UART TX FIFO 触发器匹配 //阈值。 // uDMAChannelControlSet (UDMA_CHANGE_UART0TX | UDMA_PRI_SELECT、 UDMA_SIZE_8 | UDMA_SRC_INC_8 | UDMA_DST_INC_NONE | UDMA_ARB_4); // //设置 uDMA UART TX 通道的传输参数。 这将会 //配置传输源和目的以及传输大小。 //使用基本模式是因为外设正在进行 UDMA 传输 //请求。 源是 TX 缓冲区、目的是 UART //数据寄存器。 // uDMAChannelTransferSet (UDMA_CHANGE_UART0TX | UDMA_PRI_SELECT、 UDMA_MODE_BASIC、g_ui8TxBuf、 (void *)(UART0_BASE + UART_O_DR)、 sizeof (g_ui8TxBuf)); // //现在,UDMA UART TX 和 RX 通道都被引脚以启动 A //传输。 一旦启用通道、外设将会启动 //发出传输请求,数据传输将开始。 // uDMAChannelEnable (UDMA_CHANGE_UART0RX); uDMAChannelEnable (UDMA_CHANGE_UART0TX); // //启用 UART DMA TX/RX 中断。 // UARTIntEnable (UART0_BASE、UART_INT_DMATX | UART_INT_DMATX); // //启用 UART 外设中断。 // IntEnable (INT_UART0); } //********* // //配置 UART 及其引脚。 这必须在 UARTprintf()之前调用。 //// ***************** void ConfigureUART (void) { // //启用 UART 使用的 GPIO 外设。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOA); // //启用 UART0 // SysCtlPeripheralEnable (SYSCTL_Periph_UART0); SysCtlPeripheralSlepEnable (SYSCTL_Periph_UART0); // //为 UART 模式配置 GPIO 引脚。 // GPIOPinConfigure (GPIO_PA0_U0RX); GPIOPinConfigure (GPIO_PA1_U0TX); GPIOPinTypeUART (GPIO_Porta_base、GPIO_PIN_0 | GPIO_PIN_1); // //初始化控制台 I/O 的 UART // UARTStdioConfig (0、115200、g_ui32SysClock); } //* 检查数据和响应 */ uint8_t Check (void) { if (g_ui8RxBuf[0]!='R') { 返回0; } 返回1; } void TxAssign (void) { uint8_t ui8Index; for (ui8Index = 0;ui8Index < 8;ui8Index++) { g_ui8TxBuf[ui8Index]= g_ui8RxBuf[ui8Index]+ 1; } } void ClearBuf (void) { uint8_t ui8Index; for (ui8Index = 0;ui8Index < UART_BUF_SIZE;ui8Index++) { G_ui8RxBuf[ui8Index]= g_ui8TxBuf[ui8Index]= 0; } } void SendTxBuf (void) { uint8_t ui8Index; for (ui8Index = 0;ui8Index < 8;ui8Index++) { UARTCharPut (UART0_BASE、g_ui8TxBuf[ui8Index]); if (UARTCharsAvail (UART0_BASE)) { UARTCharPut (UART0_BASE、UARTCharGet (UART0_BASE)); } } UARTIntEnable (UART0_BASE、UART_INT_DMATX | UART_INT_DMATX); // //启用 UART 外设中断。 // IntEnable (INT_UART0); } //********* // //此示例演示了如何使用 uDMA 控制 器在内存缓冲区之间以及与外设之间传输数据//,在本例中为 UART。 // UDMA 控制 器被配置为重复传输一个数据块//从一个内存缓冲区到另一个内存缓冲区。 它还被设置为将一 个//数据块从一个缓冲区重复复制到 UART 输出。 UART 数据循环 //返回,以便接收相同的数据。 //// ***************** int main (void) { // //将时钟设置为直接从频率为120MHz 的晶体运行。 // SysCtlClockSet (SYSCTL_SYSDIV_4 | SYSCTL_USE_PLL | SYSCTL_OSC_MAIN | SYSCTL_XTAL_16MHz); G_ui32SysClock = SysCtlClockGet (); // //使外设在 CPU 处于睡眠状态时运行。 // SysCtlPeripheralClockGating (真); // //启用用于板载 LED 的 GPIO 端口。 // SysCtlPeripheralEnable (SYSCTL_Periph_GPIOF); // //为 LED (PN0)启用 GPIO 引脚。 // GPIOPinTypeGPIOOutput (GPIO_PORTF_BASE、GPIO_PIN_1); // //初始化 UART。 // ConfigureUART(); UARTprintf ("\033[2J\033[H"); UARTprintf ("UDMA 示例\n"); // //在显示屏上显示时钟频率。 // UARTprintf ("Tiva C 系列@%u MHz\n\n"、g_ui32SysClock / 1000000); // //在系统级别启用 uDMA 控制器。 使其继续 //在处理器处于睡眠状态时运行。 // SysCtlPeripheralEnable (SYSCTL_Periph_UDMA); SysCtlPeripheralSlepEnable (SYSCTL_Periph_UDMA); // //启用 uDMA 控制器错误中断。 将发生该中断 //如果在传输过程中出现总线错误。 // IntEnable (INT_UDMAERR); // //启用 UDMA 控制器。 // uDMAEnable(); // //指向控制表以用于通道控制结构体。 // uDMAControlBaseSet (pui8ControlTable); // //初始化 UDMA UART 传输。 // InitUART0Transfer(); // //等待,直到 DMA 传输完成 // while (g_ui32RxBufCount = 0x0){ } UARTprintf ("UDMA 示例完成\n"); // ////////////在测试完成后禁用 UDMA 和 UART 中断。 //// IntDisable (INT_UART0); IntDisable (INT_UDMA); // //在 CPU 未休眠的情况下永久循环,因此调试器可以进行连接。 // while (1) { // //打开 LED。 // GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_1、GPIO_PIN_1); // //延迟一位。 // SysCtlDelay (g_ui32SysClock/100); // //关闭 LED。 // GPIOPinWrite (GPIO_PORTF_BASE、GPIO_PIN_1、0); // //延迟一位。 // SysCtlDelay (g_ui32SysClock/100); if (Check ()) { TxAssign(); SendTxBuf(); } ClearBuf(); uDMAChannelTransferSet (UDMA_CHANGE_UART0RX | UDMA_PRI_SELECT、 UDMA_MODE_BASIC、 (void *)(UART0_BASE + UART_O_DR)、 g_ui8RxBuf、sizeof (g_ui8RxBuf)); } }
此致、
不结盟运动