Hi,
I wanted to post a modified version of the udma_demo.c for the whoever might need it. I'm new to DMA and thought modifying this example was a good start.
I do have one question. Why am I unable to utilize the internal loopback for the SSI0 interface ?
//***************************************************************************** // // udma_demo.c - uDMA example. // // Copyright (c) 2013-2014 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.0.12573 of the EK-TM4C1294XL Firmware Package. // //***************************************************************************** #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 "inc/hw_ssi.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 "driverlib/ssi.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 SSI_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 #define UART_RXBUF_SIZE 256 //***************************************************************************** // // The SSI0 Buffers // //***************************************************************************** static uint8_t g_ui8SSITxBuf[SSI_BUFFER_SIZE]; static uint8_t g_ui8SSIRxBuf[SSI_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 UART buffers filled, one for each ping-pong buffer. // //***************************************************************************** static uint32_t g_ui32RxBufACount = 0; static uint32_t g_ui32RxBufBCount = 0; //***************************************************************************** // // The count of SSI0 buffers filled // //***************************************************************************** static uint32_t g_ui32SSIRxCount = 0; static uint32_t g_ui32SSITxCount = 0; //***************************************************************************** // // The CPU usage in percent, in 16.16 fixed point format. // //***************************************************************************** static uint32_t g_ui32CPUUsage; //***************************************************************************** // // 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++; } // // Call the CPU usage tick function. This function will compute the amount // of cycles used by the CPU since the last call and return the result in // percent in fixed point 16.16 format. // g_ui32CPUUsage = CPUUsageTick(); } //***************************************************************************** // // 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++; } } //***************************************************************************** // // SSI0 Interrupt Handler // //***************************************************************************** void SSI0IntHandler(void) { uint32_t ui32Status; uint32_t ui32Mode; ui32Status = ROM_SSIIntStatus(SSI0_BASE, 1); ROM_SSIIntClear(SSI0_BASE, ui32Status); ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT); if(ui32Mode == UDMA_MODE_STOP) { g_ui32SSIRxCount++; ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(SSI0_BASE + SSI_O_DR), g_ui8SSIRxBuf, sizeof(g_ui8SSIRxBuf)); ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0RX); } if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_SSI0TX)) { g_ui32SSITxCount++; ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8SSITxBuf, (void *)(SSI0_BASE + SSI_O_DR), sizeof(g_ui8SSITxBuf)); ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX); } } void InitSPITransfer(void) { uint_fast16_t ui16Idx; // // Fill the TX buffer with a simple data pattern. // for(ui16Idx = 0; ui16Idx < SSI_BUFFER_SIZE; ui16Idx++) { g_ui8SSITxBuf[ui16Idx] = ui16Idx; } // // Enable the uDMA interface for both TX and RX channels. // ROM_SSIDMAEnable(SSI0_BASE, SSI_DMA_RX | SSI_DMA_TX); // // This register write will set the SSI0 to operate in loopback mode. Any // data sent on the TX output will be received on the RX input. // //HWREG(SSI1_BASE + SSI_O_CR1) |= SSI_CR1_LBM; //**************************************************************************** //uDMA SSI0 RX //**************************************************************************** // // Put the attributes in a known state for the uDMA SSI0RX channel. These // should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0RX, UDMA_ATTR_USEBURST | UDMA_ATTR_ALTSELECT | (UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK)); // // Configure the control parameters for the primary control structure for // the SSIORX channel. // ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_SIZE_8 | UDMA_SRC_INC_NONE | UDMA_DST_INC_8 | UDMA_ARB_4); // // Set up the transfer parameters for the SSI0RX Channel // ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0RX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, (void *)(SSI0_BASE + SSI_O_DR), g_ui8SSIRxBuf, sizeof(g_ui8SSIRxBuf)); //**************************************************************************** //uDMA SSI0 TX //**************************************************************************** // // Put the attributes in a known state for the uDMA SSI0TX channel. These // should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_ALTSELECT | UDMA_ATTR_HIGH_PRIORITY | UDMA_ATTR_REQMASK); // // Set the USEBURST attribute for the uDMA SSI0TX channel. This will // force the controller to always use a burst when transferring data from // the TX buffer to the SSI0. This is somewhat more effecient bus usage // than the default which allows single or burst transfers. // ROM_uDMAChannelAttributeEnable(UDMA_CHANNEL_SSI0TX, UDMA_ATTR_USEBURST); // // Configure the control parameters for the SSI0 TX. // ROM_uDMAChannelControlSet(UDMA_CHANNEL_SSI0TX | 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 SSI0 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 theUART0 // data register. // ROM_uDMAChannelTransferSet(UDMA_CHANNEL_SSI0TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8SSITxBuf, (void *)(SSI0_BASE + SSI_O_DR), sizeof(g_ui8SSITxBuf)); // // Now both the uDMA SSI0 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_CHANNEL_SSI0RX); ROM_uDMAChannelEnable(UDMA_CHANNEL_SSI0TX); // // Enable the SSI0 DMA TX/RX interrupts. // ROM_SSIIntEnable(SSI0_BASE, SSI_DMATX | SSI_DMARX); // // Enable the SSI0 peripheral interrupts. // ROM_IntEnable(INT_SSI0); } void ConfigureSSI0(void) { uint32_t trashBin[1] = {0}; // // Enable the SSI0 Peripheral. // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0); ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_SSI0); // // Configure GPIOA_3 as the SSI Chip Select // ROM_GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3); ROM_GPIOPinWrite(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_PIN_3); // // Configure GPIO Pins for SSI0 mode. // ROM_GPIOPinConfigure(GPIO_PA2_SSI0CLK); ROM_GPIOPinConfigure(GPIO_PA4_SSI0XDAT0); ROM_GPIOPinConfigure(GPIO_PA5_SSI0XDAT1); ROM_GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | GPIO_PIN_2); SSIConfigSetExpClk(SSI0_BASE, g_ui32SysClock, SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, 1000000, 8); SSIEnable(SSI0_BASE); /* Clear SSI0 RX Buffer */ while (ROM_SSIDataGetNonBlocking(SSI0_BASE, &trashBin[0])) {} } //***************************************************************************** // // 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 UART1IntHandler(void) { uint32_t ui32Status; uint32_t ui32Mode; // // Read the interrupt status of the UART. // ui32Status = ROM_UARTIntStatus(UART1_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(UART1_BASE, ui32Status); // // Check the DMA control table to see if the ping-pong "A" transfer is // complete. The "A" transfer uses receive buffer "A", and the primary // control structure. // ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_PRI_SELECT); // // If the primary control structure indicates stop, that means the "A" // receive buffer is done. The uDMA controller should still be receiving // data into the "B" buffer. // if(ui32Mode == UDMA_MODE_STOP) { // // Increment a counter to indicate data was received into buffer A. In // a real application this would be used to signal the main thread that // data was received so the main thread can process the data. // g_ui32RxBufACount++; // // Set up the next transfer for the "A" buffer, using the primary // control structure. When the ongoing receive into the "B" buffer is // done, the uDMA controller will switch back to this one. This // example re-uses buffer A, 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_CHANNEL_UART1RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(UART1_BASE + UART_O_DR), g_ui8RxBufA, sizeof(g_ui8RxBufA)); } // // Check the DMA control table to see if the ping-pong "B" transfer is // complete. The "B" transfer uses receive buffer "B", and the alternate // control structure. // ui32Mode = ROM_uDMAChannelModeGet(UDMA_CHANNEL_UART1RX | UDMA_ALT_SELECT); // // If the alternate control structure indicates stop, that means the "B" // receive buffer is done. The uDMA controller should still be receiving // data into the "A" buffer. // if(ui32Mode == UDMA_MODE_STOP) { // // Increment a counter to indicate data was received into buffer A. In // a real application this would be used to signal the main thread that // data was received so the main thread can process the data. // g_ui32RxBufBCount++; // // 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_CHANNEL_UART1RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(UART1_BASE + UART_O_DR), g_ui8RxBufB, sizeof(g_ui8RxBufB)); } // // If the UART1 DMA TX channel is disabled, that means the TX DMA transfer // is done. // if(!ROM_uDMAChannelIsEnabled(UDMA_CHANNEL_UART1TX)) { // // Start another DMA transfer to UART1 TX. // ROM_uDMAChannelTransferSet(UDMA_CHANNEL_UART1TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8TxBuf, (void *)(UART1_BASE + UART_O_DR), sizeof(g_ui8TxBuf)); // // The uDMA TX channel must be re-enabled. // ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1TX); } } //***************************************************************************** // // 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 InitUART1Transfer(void) { 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; } // // Enable the UART peripheral, and configure it to operate even if the CPU // is in sleep. // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART1); ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART1); // // Configure the UART communication parameters. // ROM_UARTConfigSetExpClk(UART1_BASE, g_ui32SysClock, 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(UART1_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(UART1_BASE); ROM_UARTDMAEnable(UART1_BASE, UART_DMA_RX | UART_DMA_TX); // // This register write will set the UART to operate in loopback mode. Any // data sent on the TX output will be received on the RX input. // HWREG(UART1_BASE + UART_O_CTL) |= UART_CTL_LBE; // // Put the attributes in a known state for the uDMA UART1RX channel. These // should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART1RX, 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_CHANNEL_UART1RX | 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_CHANNEL_UART1RX | 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_CHANNEL_UART1RX | UDMA_PRI_SELECT, UDMA_MODE_PINGPONG, (void *)(UART1_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_CHANNEL_UART1RX | UDMA_ALT_SELECT, UDMA_MODE_PINGPONG, (void *)(UART1_BASE + UART_O_DR), g_ui8RxBufB, sizeof(g_ui8RxBufB)); // // Put the attributes in a known state for the uDMA UART1TX channel. These // should already be disabled by default. // ROM_uDMAChannelAttributeDisable(UDMA_CHANNEL_UART1TX, 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_UART1TX, 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_UART1TX | 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_CHANNEL_UART1TX | UDMA_PRI_SELECT, UDMA_MODE_BASIC, g_ui8TxBuf, (void *)(UART1_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. // ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1RX); ROM_uDMAChannelEnable(UDMA_CHANNEL_UART1TX); // // Enable the UART DMA TX/RX interrupts. // ROM_UARTIntEnable(UART1_BASE, UART_INT_DMATX | UART_INT_DMARX); // // Enable the UART peripheral interrupts. // ROM_IntEnable(INT_UART1); } //***************************************************************************** // // Configure the UART and its pins. This must be called before UARTprintf(). // //***************************************************************************** void ConfigureUART(void) { // // Enable the GPIO Peripheral used by the UART. // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // // Enable UART0 // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_UART0); ROM_SysCtlPeripheralSleepEnable(SYSCTL_PERIPH_UART0); // // Configure GPIO Pins for UART mode. // ROM_GPIOPinConfigure(GPIO_PA0_U0RX); ROM_GPIOPinConfigure(GPIO_PA1_U0TX); ROM_GPIOPinTypeUART(GPIO_PORTA_BASE, GPIO_PIN_0 | GPIO_PIN_1); // // Initialize the UART for console I/O. // UARTStdioConfig(0, 115200, g_ui32SysClock); } //***************************************************************************** // // 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) { static uint32_t ui32PrevSeconds; static uint32_t ui32PrevXferCount; static uint32_t ui32PrevUARTCount = 0; uint32_t ui32XfersCompleted; uint32_t ui32BytesTransferred; // // Set the clocking to run directly from the crystal at 120MHz. // g_ui32SysClock = MAP_SysCtlClockFreqSet((SYSCTL_XTAL_25MHZ | SYSCTL_OSC_MAIN | SYSCTL_USE_PLL | SYSCTL_CFG_VCO_480), 120000000); // // 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_GPION); // // Enable the GPIO port that is used for the SSI chip select // ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // // Enable the GPIO pins for the LED (PN0). // ROM_GPIOPinTypeGPIOOutput(GPIO_PORTN_BASE, GPIO_PIN_0); // // Initialize the UART. // ConfigureUART(); UARTprintf("\033[2J\033[H"); UARTprintf("uDMA Example\n"); // // Initialize SSI0. // ConfigureSSI0(); // // Show the clock frequency on the display. // UARTprintf("Tiva C Series @ %u MHz\n\n", g_ui32SysClock / 1000000); // // Show statistics headings. // UARTprintf("CPU\tRemaining\tSSI TX\t\t\t UART\n"); UARTprintf("Usage\tTime\t\tTransfers\t\t Transfers\n"); // // Configure SysTick to occur 100 times per second, to use as a time // reference. Enable SysTick to generate interrupts. // ROM_SysTickPeriodSet(g_ui32SysClock / SYSTICKS_PER_SECOND); ROM_SysTickIntEnable(); ROM_SysTickEnable(); // // Initialize the CPU usage measurement routine. // CPUUsageInit(g_ui32SysClock, SYSTICKS_PER_SECOND, 2); // // 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); // // Initialize the uDMA SPI transfers. // InitSPITransfer(); // // Initialize the uDMA UART transfers. // InitUART1Transfer(); // // Remember the current SysTick seconds count. // ui32PrevSeconds = g_ui32Seconds; // // Remember the current count of memory buffer transfers. // ui32PrevXferCount = g_ui32SSITxCount; // // Loop until the button is pressed. The processor is put to sleep // in this loop so that CPU utilization can be measured. // while(1) { // // Check to see if one second has elapsed. If so, the make some // updates. // if(g_ui32Seconds != ui32PrevSeconds) { // // Turn on the LED as a heartbeat // GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0); // // Print a message showing the CPU usage percent. // The fractional part of the percent value is ignored. // UARTprintf("%2u%%", g_ui32CPUUsage >> 16); // // Tell the user how many seconds we have to go before ending. // UARTprintf("\t%d seconds", 10 - g_ui32Seconds); // // Remember the new seconds count. // ui32PrevSeconds = g_ui32Seconds; // // Calculate how many memory transfers have occurred since the last // second. // ui32XfersCompleted = g_ui32SSITxCount - ui32PrevXferCount; // // Remember the new transfer count. // ui32PrevXferCount = g_ui32SSITxCount++;; // // Compute how many bytes were transferred in the memory transfer // since the last second. // ui32BytesTransferred = ui32XfersCompleted * SSI_BUFFER_SIZE * 4; // // Print a message showing the transfer rate. // UARTprintf("\t%8u Bytes/Sec", ui32BytesTransferred); // // Calculate how many UART transfers have occurred since the last // second. This expression is split to prevent a compiler warning // about undefined order of volatile accesses. // ui32XfersCompleted = g_ui32RxBufACount; ui32XfersCompleted += g_ui32RxBufBCount - ui32PrevUARTCount; // // Remember the new UART transfer count. This expression is split // to prevent a compiler warning about undefined order of volatile // accesses. // ui32PrevUARTCount = g_ui32RxBufACount; ui32PrevUARTCount += g_ui32RxBufBCount; // // Compute how many bytes were transferred by the UART. The number // of bytes received is multiplied by 2 so that the TX bytes // transferred are also accounted for. // ui32BytesTransferred = ui32XfersCompleted * UART_RXBUF_SIZE * 2; // // Print a message showing the transfer rate. // UARTprintf("\t%8u Bytes/Sec\n", ui32BytesTransferred); // // Turn off the LED. // GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, ~GPIO_PIN_0); } // // Put the processor to sleep if there is nothing to do. This allows // the CPU usage routine to measure the number of free CPU cycles. // If the processor is sleeping a lot, it can be hard to connect to // the target with the debugger. // ROM_SysCtlSleep(); // // See if we have run long enough and exit the loop if so. // if(g_ui32Seconds >= 10) { break; } } // // Indicate on the display that the example is stopped. // UARTprintf("\nStopped\n"); ROM_IntDisable(INT_UART1); ROM_IntDisable(INT_SSI0); // // Loop forever with the CPU not sleeping, so the debugger can connect. // while(1) { // // Turn on the LED. // GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, GPIO_PIN_0); // // Delay for a bit. // SysCtlDelay(g_ui32SysClock / 20 / 3); // // Turn off the LED. // GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_0, 0); // // Delay for a bit. // SysCtlDelay(g_ui32SysClock / 20 / 3); } }
//***************************************************************************** // // startup_ccs.c - Startup code for use with TI's Code Composer Studio. // // Copyright (c) 2013-2014 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.0.12573 of the EK-TM4C1294XL Firmware Package. // //***************************************************************************** #include <stdint.h> #include "inc/hw_nvic.h" #include "inc/hw_types.h" //***************************************************************************** // // Forward declaration of the default fault handlers. // //***************************************************************************** void ResetISR(void); static void NmiSR(void); static void FaultISR(void); static void IntDefaultHandler(void); //***************************************************************************** // // External declaration for the reset handler that is to be called when the // processor is started // //***************************************************************************** extern void _c_int00(void); //***************************************************************************** // // Linker variable that marks the top of the stack. // //***************************************************************************** extern uint32_t __STACK_TOP; //***************************************************************************** // // External declarations for the interrupt handlers used by the application. // //***************************************************************************** extern void SysTickHandler(void); extern void UART1IntHandler(void); extern void SSI0IntHandler(void); extern void uDMAErrorHandler(void); //***************************************************************************** // // The vector table. Note that the proper constructs must be placed on this to // ensure that it ends up at physical address 0x0000.0000 or at the start of // the program if located at a start address other than 0. // //***************************************************************************** #pragma DATA_SECTION(g_pfnVectors, ".intvecs") void (* const g_pfnVectors[])(void) = { (void (*)(void))((uint32_t)&__STACK_TOP), // The initial stack pointer ResetISR, // The reset handler NmiSR, // The NMI handler FaultISR, // The hard fault handler IntDefaultHandler, // The MPU fault handler IntDefaultHandler, // The bus fault handler IntDefaultHandler, // The usage fault handler 0, // Reserved 0, // Reserved 0, // Reserved 0, // Reserved IntDefaultHandler, // SVCall handler IntDefaultHandler, // Debug monitor handler 0, // Reserved IntDefaultHandler, // The PendSV handler SysTickHandler, // The SysTick handler IntDefaultHandler, // GPIO Port A IntDefaultHandler, // GPIO Port B IntDefaultHandler, // GPIO Port C IntDefaultHandler, // GPIO Port D IntDefaultHandler, // GPIO Port E IntDefaultHandler, // UART0 Rx and Tx UART1IntHandler, // UART1 Rx and Tx SSI0IntHandler, // SSI0 Rx and Tx IntDefaultHandler, // I2C0 Master and Slave IntDefaultHandler, // PWM Fault IntDefaultHandler, // PWM Generator 0 IntDefaultHandler, // PWM Generator 1 IntDefaultHandler, // PWM Generator 2 IntDefaultHandler, // Quadrature Encoder 0 IntDefaultHandler, // ADC Sequence 0 IntDefaultHandler, // ADC Sequence 1 IntDefaultHandler, // ADC Sequence 2 IntDefaultHandler, // ADC Sequence 3 IntDefaultHandler, // Watchdog timer IntDefaultHandler, // Timer 0 subtimer A IntDefaultHandler, // Timer 0 subtimer B IntDefaultHandler, // Timer 1 subtimer A IntDefaultHandler, // Timer 1 subtimer B IntDefaultHandler, // Timer 2 subtimer A IntDefaultHandler, // Timer 2 subtimer B IntDefaultHandler, // Analog Comparator 0 IntDefaultHandler, // Analog Comparator 1 IntDefaultHandler, // Analog Comparator 2 IntDefaultHandler, // System Control (PLL, OSC, BO) IntDefaultHandler, // FLASH Control IntDefaultHandler, // GPIO Port F IntDefaultHandler, // GPIO Port G IntDefaultHandler, // GPIO Port H IntDefaultHandler, // UART2 Rx and Tx IntDefaultHandler, // SSI1 Rx and Tx IntDefaultHandler, // Timer 3 subtimer A IntDefaultHandler, // Timer 3 subtimer B IntDefaultHandler, // I2C1 Master and Slave IntDefaultHandler, // CAN0 IntDefaultHandler, // CAN1 IntDefaultHandler, // Ethernet IntDefaultHandler, // Hibernate IntDefaultHandler, // USB0 IntDefaultHandler, // PWM Generator 3 IntDefaultHandler, // uDMA Software Transfer uDMAErrorHandler, // uDMA Error IntDefaultHandler, // ADC1 Sequence 0 IntDefaultHandler, // ADC1 Sequence 1 IntDefaultHandler, // ADC1 Sequence 2 IntDefaultHandler, // ADC1 Sequence 3 IntDefaultHandler, // External Bus Interface 0 IntDefaultHandler, // GPIO Port J IntDefaultHandler, // GPIO Port K IntDefaultHandler, // GPIO Port L IntDefaultHandler, // SSI2 Rx and Tx IntDefaultHandler, // SSI3 Rx and Tx IntDefaultHandler, // UART3 Rx and Tx IntDefaultHandler, // UART4 Rx and Tx IntDefaultHandler, // UART5 Rx and Tx IntDefaultHandler, // UART6 Rx and Tx IntDefaultHandler, // UART7 Rx and Tx IntDefaultHandler, // I2C2 Master and Slave IntDefaultHandler, // I2C3 Master and Slave IntDefaultHandler, // Timer 4 subtimer A IntDefaultHandler, // Timer 4 subtimer B IntDefaultHandler, // Timer 5 subtimer A IntDefaultHandler, // Timer 5 subtimer B IntDefaultHandler, // FPU 0, // Reserved 0, // Reserved IntDefaultHandler, // I2C4 Master and Slave IntDefaultHandler, // I2C5 Master and Slave IntDefaultHandler, // GPIO Port M IntDefaultHandler, // GPIO Port N 0, // Reserved IntDefaultHandler, // Tamper IntDefaultHandler, // GPIO Port P (Summary or P0) IntDefaultHandler, // GPIO Port P1 IntDefaultHandler, // GPIO Port P2 IntDefaultHandler, // GPIO Port P3 IntDefaultHandler, // GPIO Port P4 IntDefaultHandler, // GPIO Port P5 IntDefaultHandler, // GPIO Port P6 IntDefaultHandler, // GPIO Port P7 IntDefaultHandler, // GPIO Port Q (Summary or Q0) IntDefaultHandler, // GPIO Port Q1 IntDefaultHandler, // GPIO Port Q2 IntDefaultHandler, // GPIO Port Q3 IntDefaultHandler, // GPIO Port Q4 IntDefaultHandler, // GPIO Port Q5 IntDefaultHandler, // GPIO Port Q6 IntDefaultHandler, // GPIO Port Q7 IntDefaultHandler, // GPIO Port R IntDefaultHandler, // GPIO Port S IntDefaultHandler, // SHA/MD5 0 IntDefaultHandler, // AES 0 IntDefaultHandler, // DES3DES 0 IntDefaultHandler, // LCD Controller 0 IntDefaultHandler, // Timer 6 subtimer A IntDefaultHandler, // Timer 6 subtimer B IntDefaultHandler, // Timer 7 subtimer A IntDefaultHandler, // Timer 7 subtimer B IntDefaultHandler, // I2C6 Master and Slave IntDefaultHandler, // I2C7 Master and Slave IntDefaultHandler, // HIM Scan Matrix Keyboard 0 IntDefaultHandler, // One Wire 0 IntDefaultHandler, // HIM PS/2 0 IntDefaultHandler, // HIM LED Sequencer 0 IntDefaultHandler, // HIM Consumer IR 0 IntDefaultHandler, // I2C8 Master and Slave IntDefaultHandler, // I2C9 Master and Slave IntDefaultHandler // GPIO Port T }; //***************************************************************************** // // This is the code that gets called when the processor first starts execution // following a reset event. Only the absolutely necessary set is performed, // after which the application supplied entry() routine is called. Any fancy // actions (such as making decisions based on the reset cause register, and // resetting the bits in that register) are left solely in the hands of the // application. // //***************************************************************************** void ResetISR(void) { // // Jump to the CCS C initialization routine. This will enable the // floating-point unit as well, so that does not need to be done here. // __asm(" .global _c_int00\n" " b.w _c_int00"); } //***************************************************************************** // // This is the code that gets called when the processor receives a NMI. This // simply enters an infinite loop, preserving the system state for examination // by a debugger. // //***************************************************************************** static void NmiSR(void) { // // Enter an infinite loop. // while(1) { } } //***************************************************************************** // // This is the code that gets called when the processor receives a fault // interrupt. This simply enters an infinite loop, preserving the system state // for examination by a debugger. // //***************************************************************************** static void FaultISR(void) { // // Enter an infinite loop. // while(1) { } } //***************************************************************************** // // This is the code that gets called when the processor receives an unexpected // interrupt. This simply enters an infinite loop, preserving the system state // for examination by a debugger. // //***************************************************************************** static void IntDefaultHandler(void) { // // Go into an infinite loop. // while(1) { } }
Regards,
Daniel