Thread 中讨论的其他器件: EK-TM4C1294XL
您好!
我需要配置 TM4C129ENCPDT 微控制器、以便通过 UDMA 将16位字从 RAM 缓冲器传输到 EPI。 每个字传输都必须在通用定时器(GPTM)以周期模式运行的情况下触发(定时器 DMA 超时事件)。 使用的通用定时器将持续产生超时事件、并且 uDMA 通道还必须将字连续移动到 EPI、当字传输计数达到最大值时、源地址必须自动回绕到 RAM 缓冲区、并持续重复缓冲区。 我知道 C2000系列微控制器 DMA 具有这种操作模式、但我不知道是否可以使用 Tiva C UDMA 实现它。
我已经通过设置 DMA 控制表任务列表、使用散聚模式实施并测试了持续的 uDMA 传输、其中第二个任务是重新加载用于缓冲区传输的 uDMA 通道配置:
#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);
}
这种配置似乎可以正常工作、但问题在于、在散聚模式下、配置重新加载事件会增加一个额外的暂停来继续向 EPI 传输数据流、尤其是当我需要尽快将数据流式传输到 EPI 而不暂停时。 同时、字传输周期必须由通用定时器控制。 那么、我需要知道是否有任何其他 UDMA 配置可启用持续数据传输、其中原子源地址自动换行和传输计数复位发生在 DMA 硬件中?