Other Parts Discussed in Thread: EK-TM4C1294XL
Hi,
I need to configure TM4C129ENCPDT microcontroller to transfer 16-bit words from RAM buffer to EPI via uDMA. Each word transfer must be triggered (timer DMA timeout event) with General-Purpose Timer (GPTM) running in periodic mode. The used General-Purpose Timer timer will generate the timeout events continuously and the uDMA channel must also move the words continuously to EPI and when the words transfer count reach maximum then the source address must wrap back to RAM buffer beginning automatically and continue repeating the buffer continuously. I know that C2000 series microcontrollers DMA has this operating mode but I do not know if it is possible to implement it with Tiva C uDMA.
I have implemented and tested the continues uDMA transfer using the Scatter-Gather Mem/per by setting up the DMA control table task list where the second task is to reload uDMA channel configuration for buffer transfer:
#define EPI_PORTA_PINS (GPIO_PIN_7 | GPIO_PIN_6) #define EPI_PORTB_PINS (GPIO_PIN_3) #define EPI_PORTC_PINS (GPIO_PIN_7 | GPIO_PIN_6 | GPIO_PIN_5 | GPIO_PIN_4) #define EPI_PORTG_PINS (GPIO_PIN_1 | GPIO_PIN_0) #define EPI_PORTK_PINS (GPIO_PIN_5 | GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0) #define EPI_PORTL_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0) #define EPI_PORTM_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0) #define EPI_PORTQ_PINS (GPIO_PIN_3 | GPIO_PIN_2 | GPIO_PIN_1 | GPIO_PIN_0) #define EPI_PORTP_PINS (GPIO_PIN_3 | GPIO_PIN_2) uint32_t sys_clk; static uint16_t src_buf[1024]; #pragma DATA_ALIGN(udma_control_table, 1024) tDMAControlTable udma_control_table[1024]; tDMAControlTable dma_task_list_preload; tDMAControlTable dma_mem_tasks[] = { { (((void*)&src_buf) + 0x0000007F), // src end addr (void*)0xA000007F, // dst end addr UDMA_CHCTL_SRCSIZE_16 | UDMA_CHCTL_SRCINC_16 | UDMA_CHCTL_DSTSIZE_16 | UDMA_CHCTL_DSTINC_16 | UDMA_CHCTL_ARBSIZE_1 | ((64 - 1) << UDMA_CHCTL_XFERSIZE_S) | UDMA_CHCTL_XFERMODE_PER_SGA }, { &(dma_task_list_preload.ui32Control), // src end addr &(udma_control_table[UDMA_CHANNEL_TMR0B].ui32Control), // dst end addr UDMA_CHCTL_SRCSIZE_32 | UDMA_CHCTL_SRCINC_NONE | UDMA_CHCTL_DSTSIZE_32 | UDMA_CHCTL_DSTINC_NONE | UDMA_CHCTL_ARBSIZE_1 | ((1 - 1) << UDMA_CHCTL_XFERSIZE_S) | UDMA_CHCTL_XFERMODE_MEM_SG } }; tDMAControlTable dma_task_list_preload = { &(dma_mem_tasks[1].ui32Spare), // src end addr &(udma_control_table[UDMA_CHANNEL_TMR0B | UDMA_ALT_SELECT].ui32Spare), // dst end addr UDMA_CHCTL_SRCSIZE_32 | UDMA_CHCTL_SRCINC_32 | UDMA_CHCTL_DSTSIZE_32 | UDMA_CHCTL_DSTINC_32 | UDMA_CHCTL_ARBSIZE_4 | ((8 - 1) << UDMA_CHCTL_XFERSIZE_S) | UDMA_CHCTL_XFERMODE_MEM_SG }; void uDMAErrorHandler(void) { uint32_t err; err = uDMAErrorStatusGet(); uDMAErrorStatusClear(); } void uDMAIntHandler(void) { uint32_t int_status; int_status = uDMAIntStatus(); uDMAIntClear(int_status); } int main(void) { uint32_t i; init_sys(&sys_clk); IntRegister(INT_UDMA, uDMAIntHandler); IntRegister(INT_UDMAERR, uDMAErrorHandler); SysCtlPeripheralEnable(SYSCTL_PERIPH_EPI0); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOC); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOG); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOK); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOM); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOQ); SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOP); GPIOPinConfigure(GPIO_PK0_EPI0S0); // D0 GPIOPinConfigure(GPIO_PK1_EPI0S1); // D1 GPIOPinConfigure(GPIO_PK2_EPI0S2); // D2 GPIOPinConfigure(GPIO_PK3_EPI0S3); // D3 GPIOPinConfigure(GPIO_PC7_EPI0S4); // D4 GPIOPinConfigure(GPIO_PC6_EPI0S5); // D5 GPIOPinConfigure(GPIO_PC5_EPI0S6); // D6 GPIOPinConfigure(GPIO_PC4_EPI0S7); // D7 GPIOPinConfigure(GPIO_PA6_EPI0S8); // D8 GPIOPinConfigure(GPIO_PA7_EPI0S9); // D9 GPIOPinConfigure(GPIO_PG1_EPI0S10); // D10 GPIOPinConfigure(GPIO_PG0_EPI0S11); // D11 GPIOPinConfigure(GPIO_PM3_EPI0S12); // D12 GPIOPinConfigure(GPIO_PM2_EPI0S13); // D13 GPIOPinConfigure(GPIO_PM1_EPI0S14); // D14 GPIOPinConfigure(GPIO_PM0_EPI0S15); // D15 GPIOPinConfigure(GPIO_PL0_EPI0S16); // A0 GPIOPinConfigure(GPIO_PL1_EPI0S17); // A1 GPIOPinConfigure(GPIO_PL2_EPI0S18); // A2 GPIOPinConfigure(GPIO_PL3_EPI0S19); // A3 GPIOPinConfigure(GPIO_PQ0_EPI0S20); // A4 GPIOPinConfigure(GPIO_PQ1_EPI0S21); // A5 GPIOPinConfigure(GPIO_PQ2_EPI0S22); // A6 GPIOPinConfigure(GPIO_PQ3_EPI0S23); // A7 GPIOPinConfigure(GPIO_PB3_EPI0S28); // /RD GPIOPinConfigure(GPIO_PP2_EPI0S29); // /WR GPIOPinConfigure(GPIO_PP3_EPI0S30); // /CS GPIOPinConfigure(GPIO_PK5_EPI0S31); // CLK GPIOPinTypeEPI(GPIO_PORTA_BASE, EPI_PORTA_PINS); GPIOPinTypeEPI(GPIO_PORTB_BASE, EPI_PORTB_PINS); GPIOPinTypeEPI(GPIO_PORTC_BASE, EPI_PORTC_PINS); GPIOPinTypeEPI(GPIO_PORTG_BASE, EPI_PORTG_PINS); GPIOPinTypeEPI(GPIO_PORTK_BASE, EPI_PORTK_PINS); GPIOPinTypeEPI(GPIO_PORTL_BASE, EPI_PORTL_PINS); GPIOPinTypeEPI(GPIO_PORTM_BASE, EPI_PORTM_PINS); GPIOPinTypeEPI(GPIO_PORTQ_BASE, EPI_PORTQ_PINS); GPIOPinTypeEPI(GPIO_PORTP_BASE, EPI_PORTP_PINS); EPIDividerSet(EPI0_BASE, 1); EPIModeSet(EPI0_BASE, EPI_MODE_HB16); EPIDividerCSSet(EPI0_BASE, 0, 1); EPIDMATxCount(EPI0_BASE, 128); EPIConfigHB16Set(EPI0_BASE, (EPI_HB16_MODE_ADDEMUX | EPI_HB16_WRWAIT_0 | EPI_HB16_RDWAIT_0 | EPI_HB16_CSCFG_CS), 0); EPIAddressMapSet(EPI0_BASE, EPI_ADDR_PER_SIZE_256B | EPI_ADDR_PER_BASE_A); // Start address 0xA000.0000 // Fill read buffer for(i = 0; i < 128; i++) { src_buf[i] = (i + 1) * 0x0200; } // uDMA SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); IntEnable(INT_UDMAERR); IntEnable(INT_UDMA); uDMAEnable(); uDMAControlBaseSet(udma_control_table); uDMAChannelAttributeDisable(UDMA_CHANNEL_TMR0B, UDMA_ATTR_ALL); udma_control_table[UDMA_CHANNEL_TMR0B].pvDstEndAddr = dma_task_list_preload.pvDstEndAddr; udma_control_table[UDMA_CHANNEL_TMR0B].pvSrcEndAddr = dma_task_list_preload.pvSrcEndAddr; udma_control_table[UDMA_CHANNEL_TMR0B].ui32Control = dma_task_list_preload.ui32Control; uDMAChannelEnable(UDMA_CHANNEL_TMR0B); // GPTimer0A/B - PL4/PL5 SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOL); SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER0); GPIOPinConfigure(GPIO_PL5_T0CCP1); GPIOPinTypeTimer(GPIO_PORTL_BASE, GPIO_PIN_5); GPIOPadConfigSet(GPIO_PORTL_BASE, GPIO_PIN_5, GPIO_STRENGTH_12MA, GPIO_PIN_TYPE_STD); TimerConfigure(TIMER0_BASE, (TIMER_CFG_SPLIT_PAIR | TIMER_CFG_B_PERIODIC)); TimerControlStall(TIMER0_BASE, TIMER_BOTH, true); TimerPrescaleSet(TIMER0_BASE, TIMER_B, 0x00000000); TimerLoadSet(TIMER0_BASE, TIMER_B, 0x000007FF); TimerUpdateMode(TIMER0_BASE, TIMER_A, TIMER_UP_LOAD_IMMEDIATE); TimerDMAEventSet(TIMER0_BASE, TIMER_DMA_TIMEOUT_B); // TIMER_DMA_TIMEOUT_B assumes TIMER_CFG_B_PERIODIC mode TimerEnable(TIMER0_BASE, TIMER_BOTH); while(1); }
This configuration seems to work ok but the problem is that in Scatter-Gather mode the configuration reload event will add an extra pause to continues data stream to EPI, especially if I need to stream the data to EPI fast as possible and without pauses. Same time the word transfer period must be controllable via General-Purpose Timer. So I need to know if there is any other uDMA configuration that enables continues data transfer where the atomic source address wrap and transfer count reset happens in DMA hardware automatically?