近期想在TM4C129上UART3采用dma方式间断性发送数据,对官方例程进行修改后却只能连续发,望各位大佬指教一二
贴上代码
//***************************************************************************** // // udma_demo.c - uDMA example. // // Copyright (c) 2013-2017 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.1.4.178 of the EK-TM4C1294XL Firmware Package. // //***************************************************************************** #include <stdint.h> #include <stdbool.h> #include <string.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/rom_map.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 ICDI virtual COM port and running at 115,200, //! 8-N-1, is used to display messages from this application. // //***************************************************************************** //**************************************************************************** // // System clock rate in Hz. // //**************************************************************************** uint32_t g_ui32SysClock; //***************************************************************************** // // 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 10 #define UART_RXBUF_SIZE 10 //***************************************************************************** // // 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]; static uint8_t g_ui8RxBufA[UART_RXBUF_SIZE]; static uint8_t g_ui8RxBufB[UART_RXBUF_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 UART buffers filled, one for each ping-pong buffer. // //***************************************************************************** static uint32_t g_ui32RxBufACount = 0; static uint32_t g_ui32RxBufBCount = 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 pui8ControlTable[1024]; #elif defined(ccs) #pragma DATA_ALIGN(pui8ControlTable, 1024) uint8_t pui8ControlTable[1024]; #else uint8_t pui8ControlTable[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) { } #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,status; // // Check for the primary control structure to indicate complete. // status = ROM_uDMAIntStatus(); uDMAIntClear(status); ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SW); if(ui32Mode == UDMA_MODE_STOP) { // // Configure it for another transfer. // ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW, UDMA_MODE_AUTO, g_ui32SrcBuf, g_ui32DstBuf, MEM_BUFFER_SIZE); // // Initiate another transfer. // ROM_uDMAChannelEnable(UDMA_CHANNEL_SW); ROM_uDMAChannelRequest(UDMA_CHANNEL_SW); } } //***************************************************************************** // // The interrupt handler for UART1. This interrupt will occur when a DMA // transfer is complete using the UART1 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 UART3IntHandler(void) { uint32_t ui32Status; uint32_t ui32Mode; ui32Status = ROM_UARTIntStatus(UART3_BASE, 1); ROM_UARTIntClear(UART3_BASE, ui32Status); ui32Mode = ROM_uDMAChannelModeGet(UDMA_CH16_UART3RX | UDMA_PRI_SELECT); if(ui32Mode == UDMA_MODE_STOP) { ROM_uDMAChannelTransferSet(UDMA_CH16_UART3RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(UART3_BASE + UART_O_DR), g_ui8RxBufA, sizeof(g_ui8RxBufA)); } ui32Mode = ROM_uDMAChannelModeGet(UDMA_CH16_UART3RX | UDMA_ALT_SELECT); if(ui32Mode == UDMA_MODE_STOP) { // // Set up the next transfer for the "B" buffer, using the alternate // control structure. When the ongoing receive into the "A" buffer is // done, the uDMA controller will switch back to this one. This // example re-uses buffer B, but a more sophisticated application could // use a rotating set of buffers to increase the amount of time that // the main thread has to process the data in the buffer before it is // reused. // ROM_uDMAChannelTransferSet(UDMA_CH16_UART3RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(UART3_BASE + UART_O_DR), g_ui8RxBufA, sizeof(g_ui8RxBufB));////!!!!!!!!!!!!!!!!!!!!!!! } ui32Status = ROM_UARTIntStatus(UART3_BASE, 1); ROM_UARTIntClear(UART3_BASE, ui32Status); // ROM_UARTIntClear(UART3_BASE, UART_INT_DMATX ); if(!ROM_uDMAChannelIsEnabled(UDMA_CH17_UART3TX)) // if(ROM_UARTIntStatus(UART3_BASE, UART_INT_DMATX)) { ROM_uDMAChannelTransferSet(UDMA_CH17_UART3TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8TxBuf, (void *)(UART3_BASE + UART_O_DR), sizeof(g_ui8TxBuf)); ROM_uDMAChannelEnable(UDMA_CH17_UART3TX); // ui32Status = ROM_UARTIntStatus(UART3_BASE, 1); // ROM_UARTIntClear(UART3_BASE, ui32Status); //// ROM_UARTIntClear(UART3_BASE, UART_INT_DMATX ); } } void UART3Init(){ ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOJ); ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART3); ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART3); GPIOPinConfigure(GPIO_PJ0_U3RX); GPIOPinConfigure(GPIO_PJ1_U3TX); ROM_GPIOPinTypeUART(GPIO_PORTJ_BASE,GPIO_PIN_0|GPIO_PIN_1); ROM_UARTConfigSetExpClk(UART3_BASE, g_ui32SysClock, 115200, UART_CONFIG_WLEN_8 | UART_CONFIG_STOP_ONE | UART_CONFIG_PAR_NONE); ROM_UARTFIFOLevelSet(UART3_BASE, UART_FIFO_TX4_8, UART_FIFO_RX4_8); ROM_UARTEnable(UART3_BASE); ROM_UARTDMAEnable(UART3_BASE, UART_DMA_RX | UART_DMA_TX); // HWREG(UART3_BASE + UART_O_CTL) |= UART_CTL_LBE; ROM_uDMAChannelAssign(UDMA_CH16_UART3RX); ROM_uDMAChannelAssign(UDMA_CH17_UART3TX); // // Enable the UART DMA TX/RX interrupts. // ROM_UARTIntEnable(UART3_BASE, UART_INT_DMATX | UART_INT_DMARX); // // Enable the UART peripheral interrupts. // ROM_IntEnable(INT_UART3); } void uDMA_U3Rx(){ // // Put the attributes in a known state for the uDMA UART1RX channel. These // should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CH16_UART3RX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_USEBURST | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); // // Configure the control parameters for the primary control structure for // the UART RX channel. The primary contol structure is used for the "A" // part of the ping-pong receive. The transfer data size is 8 bits, the // source address does not increment since it will be reading from a // register. The destination address increment is byte 8-bit bytes. The // arbitration size is set to 4 to match the RX FIFO trigger threshold. // The uDMA controller will use a 4 byte burst transfer if possible. This // will be somewhat more effecient that single byte transfers. // ROM_uDMAChannelControlSet(UDMA_CH16_UART3RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // // Configure the control parameters for the alternate control structure for // the UART RX channel. The alternate contol structure is used for the "B" // part of the ping-pong receive. The configuration is identical to the // primary/A control structure. // ROM_uDMAChannelControlSet(UDMA_CH16_UART3RX | UDMA_ALT_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // // Set up the transfer parameters for the UART RX primary control // structure. The mode is set to ping-pong, the transfer source is the // UART data register, and the destination is the receive "A" buffer. The // transfer size is set to match the size of the buffer. // ROM_uDMAChannelTransferSet(UDMA_CH16_UART3RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG,//UDMA_MODE_PINGPONG,UDMA_MODE_BASIC (void *)(UART3_BASE + UART_O_DR), g_ui8RxBufA, sizeof(g_ui8RxBufA)); // // Set up the transfer parameters for the UART RX alternate control // structure. The mode is set to ping-pong, the transfer source is the // UART data register, and the destination is the receive "B" buffer. The // transfer size is set to match the size of the buffer. // ROM_uDMAChannelTransferSet(UDMA_CH16_UART3RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(UART3_BASE + UART_O_DR), g_ui8RxBufA, sizeof(g_ui8RxBufA));//!!!!!!!!!!!!!!!!!!! ROM_uDMAChannelEnable(UDMA_CH16_UART3RX); } void uDMA_U4Tx(uint32_t size, uint8_t *data){ // // Put the attributes in a known state for the uDMA UART1TX channel. These // should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CH17_UART3TX, 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_CH17_UART3TX, 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_CH17_UART3TX | 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. // ROM_uDMAChannelTransferSet(UDMA_CH17_UART3TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, data, (void *)(UART3_BASE + UART_O_DR), size); // // 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. // ROM_uDMAChannelEnable(UDMA_CH17_UART3TX); } //***************************************************************************** // // Initializes the UART1 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 InitUART4Transfer(void) { UART3Init(); uDMA_U3Rx(); uDMA_U4Tx(sizeof(g_ui8TxBuf),g_ui8TxBuf); } //***************************************************************************** // // Initializes the uDMA software channel to perform a memory to memory uDMA // transfer. // //***************************************************************************** void InitSWTransfer(void) { // uint_fast16_t ui16Idx; // // Enable interrupts from the uDMA software channel. // ROM_IntEnable(INT_UDMA); // // Put the attributes in a known state for the uDMA software channel. // These should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SW, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)); // // Configure the control parameters for the SW channel. The SW channel // will be used to transfer between two memory buffers, 32 bits at a time. // Therefore the data size is 32 bits, and the address increment is 32 bits // for both source and destination. The arbitration size will be set to 8, // which causes the uDMA controller to rearbitrate after 8 items are // transferred. This keeps this channel from hogging the uDMA controller // once the transfer is started, and allows other channels cycles if they // are higher priority. // ROM_uDMAChannelControlSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT, UDMA_SIZE_32 | UDMA_SRC_INC_32 | UDMA_DST_INC_32 | UDMA_ARB_8); // // Set up the transfer parameters for the software channel. This will // configure the transfer buffers and the transfer size. Auto mode must be // used for software transfers. // ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SW | UDMA_PRI_SELECT, UDMA_MODE_AUTO, g_ui32SrcBuf, g_ui32DstBuf, MEM_BUFFER_SIZE); // // Now the software channel is primed to start a transfer. The channel // must be enabled. For software based transfers, a request must be // issued. After this, the uDMA memory transfer begins. // ROM_uDMAChannelEnable(UDMA_CHANNEL_SW); ROM_uDMAChannelRequest(UDMA_CHANNEL_SW); } void uDMA_Init(){ // // 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(pui8ControlTable); } void delay_s(int s) { ROM_SysCtlDelay((g_ui32SysClock / (3 )) * s); // more accurate } //***************************************************************************** // // 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) { // // Set the clocking to run directly from the crystal at 120MHz. // g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_16MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000); uDMA_Init(); // // Initialize the uDMA memory to memory transfers. // InitSWTransfer(); // // Initialize the uDMA UART transfers. // // InitUART4Transfer(); UART3Init(); uDMA_U3Rx(); uDMA_U4Tx(sizeof(g_ui8TxBuf),g_ui8TxBuf); // // Loop until the button is pressed. The processor is put to sleep // in this loop so that CPU utilization can be measured. // while(1) { uint_fast16_t ui16Idx; // // Fill the TX buffer with a simple data pattern. // for(ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++) { g_ui8TxBuf[ui16Idx] = ui16Idx; } delay_s(10); for(ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++) { g_ui8TxBuf[ui16Idx] = 0x70; } delay_s(10); for(ui16Idx = 0; ui16Idx < UART_TXBUF_SIZE; ui16Idx++) { g_ui8TxBuf[ui16Idx] = 0x71; } delay_s(10); } }