我试图使用恩智浦LPC1788微控制器上的定时器触发SPI通信。在DMA用户手册的功能中,它写道控制器可以使用定时器来触发DMA突发。但我无法找到在DMA控制器中配置触发源的提示。
我计划发送一个高频率的SPI命令,并使用DMA控制器以相同的频率读取结果SPI。转移应由计时器触发。这可能吗?
原因我可以在计时器ISR中实现传输。但控制器已经忙于做其他更重要的事情。
修改:
今天我有时间再次重试。我使用定时器3匹配0来计数1 kHz。然后我将DMA流3配置为源外设类型TIM3M0和目标连接类型SSP0 TX。定时器触发DMA传输一次,但随后禁用通道。
因此,当数据按预期传输一次时,配置接缝是正确的。所以我尝试为DMA配置循环模式。我发现DMA控制器中的链表配置是什么接缝完美的。我为自己添加了一个元素链接来关闭循环。现在如果我运行这个例子,定时器再次触发DMA通道,并且通信以尽可能快的无限循环开始。这也不是我想要存档的内容。为什么不等待源外设的触发条件。目前我认为这个微控制器是不可能的。
我在这里添加了当前的注册配置:
计时器配置
DMA源外设选择
DMA流3配置
编辑2:
我也认为这是可能的。你必须使用3个频道。
我现在添加了我正在测试的代码。该链条按预期运行一次。但重新启用链条还没有成功。我在链中添加了三个测试元素,以查看是否执行了get。你看到任何明显的错误吗? 问题是您必须在通道传输终止后用所有寄存器重新配置整个DMA通道。
GPDMA_LLI_Type linkedListEntry[15];
uint32_t specialControlSPI = 0x0;
uint32_t specialControlEnable = 0x0;
uint32_t specialConfigSPI = 0x0;
uint32_t specialConfigEnable = 0x0;
uint32_t specialConfigReenab = 0x0;
uint32_t specialCotrolReenab = 0x0;
uint32_t linkedListEnab = 0x0;
uint32_t linkedListReenab = 0x0;
uint32_t myTest = 0x0;
uint32_t myTest2 = 0x0;
uint32_t srcDataRegisterSPI = 0x0;
uint32_t srcDataRegisterEnab= 0x0;
uint32_t srcDataRegisterReenab = 0x0;
uint32_t destDataRegisterEnab= 0x0;
uint32_t destDataRegisterReenab = 0x0;
const uint32_t pattern1 = 0xAABBCCDD;
const uint32_t pattern2 = 0xEEFF0088;
#define MEMORY_TRANSFER_BURST (GPDMA_BSIZE_1)
#define MEMORY_TRANSFER_WIDTH (GPDMA_WIDTH_WORD)
void configureDMA_ForSPI_ADC_Tx(DMA dmaTx, void* data, uint32_t size)
{
//Disable all required channels
GPDMA_ChannelCmd(3, DISABLE);
GPDMA_ChannelCmd(4, DISABLE);
GPDMA_ChannelCmd(5, DISABLE);
//Form spcecial control for "enable" channel
uint32_t specialControl = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
uint32_t j = 0;
//Configure "enable" channel to be triggered by timer 3 match 0 resulting in a memory transfer
GPDMA_Channel_CFG_Type conf;
conf.ChannelNum = 4;
conf.DstConn = 0;
conf.SrcConn = GPDMA_CONN_MAT3_0;
conf.TransferType = GPDMA_TRANSFER_M2M_CTRL_DMA;
conf.SrcMemAddr = (uint32_t)&specialControlSPI;
conf.TransferSize = 4;
conf.DstMemAddr = (uint32_t)&LPC_GPDMACH3->CControl;
conf.DMALLI = (uint32_t)&linkedListEntry[j],
GPDMA_Setup(&conf, &specialControl);
//Prepare linked list to enable "enable" channel again
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH3->CSrcAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterSPI;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH3->CConfig; ///Enable SPI channel
linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigSPI;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CControl;
linkedListEntry[j].SrcAddr = (uint32_t)&specialCotrolReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CLLI;
linkedListEntry[j].SrcAddr = (uint32_t)&linkedListReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CDestAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&destDataRegisterReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CSrcAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH5->CConfig; ///Enable "Reenable" channel
linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigReenab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4) \
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH7->CControl;
linkedListEntry[j].SrcAddr = (uint32_t)&pattern1;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&myTest;
linkedListEntry[j].SrcAddr = (uint32_t)&pattern1;
linkedListEntry[j].NextLLI = 0;
j++;
//------------------------------------------------------------------------------------------------------------------
//Form special control for "SPI" channel
specialControl = GPDMA_DMACCxControl_TransferSize(size) \
| GPDMA_DMACCxControl_SBSize((uint32_t)GPDMA_BSIZE_1)
| GPDMA_DMACCxControl_DBSize((uint32_t)GPDMA_BSIZE_1)
| GPDMA_DMACCxControl_SWidth((uint32_t)GPDMA_WIDTH_HALFWORD)
| GPDMA_DMACCxControl_DWidth((uint32_t)GPDMA_WIDTH_HALFWORD)
| GPDMA_DMACCxControl_SI;
//Configure "SPI" channel to be triggered by software resulting in a peripheral transfer and a memory transfer in linked list
conf.ChannelNum = 3;
conf.DMALLI = 0,
conf.DstConn = GPDMA_CONN_SSP0_Tx;
conf.SrcConn = 0;
conf.TransferType = GPDMA_TRANSFER_M2P_CTRL_DMA;
conf.SrcMemAddr = (uint32_t)data;
conf.TransferSize = size;
conf.DstMemAddr = 0;
GPDMA_Setup(&conf, &specialControl);
//------------------------------------------------------------------------------------------------------------------
//Form special control for "reenab" channel
specialControl = GPDMA_DMACCxControl_TransferSize(size)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
//Configure "SPI" channel to be triggered by software resulting in a peripheral transfer and a memory transfer in linked list
conf.ChannelNum = 5;
conf.DstConn = 0;
conf.SrcConn = 0;
conf.TransferType = GPDMA_TRANSFER_M2M_CTRL_DMA;
conf.TransferSize = 4;
conf.SrcMemAddr = (uint32_t)&specialControlEnable;
conf.DstMemAddr = (uint32_t)&LPC_GPDMACH4->CControl;
conf.DMALLI = (uint32_t)&linkedListEntry[j],
GPDMA_Setup(&conf, &specialControl);
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CLLI;
linkedListEntry[j].SrcAddr = (uint32_t)&linkedListEnab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CDestAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&destDataRegisterEnab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CSrcAddr;
linkedListEntry[j].SrcAddr = (uint32_t)&srcDataRegisterEnab;
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
//Prepare linked list to enable "enable" channel again
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&LPC_GPDMACH4->CConfig;
linkedListEntry[j].SrcAddr = (uint32_t)&specialConfigEnable; ///Enable trigger channel again
linkedListEntry[j].NextLLI = (uint32_t)&linkedListEntry[j+1];
j++;
linkedListEntry[j].Control = GPDMA_DMACCxControl_TransferSize(4)
| GPDMA_DMACCxControl_SBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_DBSize((uint32_t)MEMORY_TRANSFER_BURST)
| GPDMA_DMACCxControl_SWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_DWidth((uint32_t)MEMORY_TRANSFER_WIDTH)
| GPDMA_DMACCxControl_SI
| GPDMA_DMACCxControl_DI;
linkedListEntry[j].DstAddr = (uint32_t)&myTest2;
linkedListEntry[j].SrcAddr = (uint32_t)&pattern2;
linkedListEntry[j].NextLLI = 0;
j++;
//Store the configuration registers for DMA operation
specialControlSPI = LPC_GPDMACH3->CControl | GPDMA_DMACCxControl_TransferSize(size);
specialControlEnable = LPC_GPDMACH4->CControl | GPDMA_DMACCxControl_TransferSize(4);
specialCotrolReenab = LPC_GPDMACH5->CControl | GPDMA_DMACCxControl_TransferSize(4);
srcDataRegisterSPI = LPC_GPDMACH3->CSrcAddr;
srcDataRegisterEnab = LPC_GPDMACH4->CSrcAddr;
srcDataRegisterReenab = LPC_GPDMACH5->CSrcAddr;
destDataRegisterEnab = LPC_GPDMACH4->CDestAddr;
destDataRegisterReenab = LPC_GPDMACH5->CDestAddr;
specialConfigSPI = (0x1) | LPC_GPDMACH3->CConfig;
specialConfigEnable = (0x1) | LPC_GPDMACH4->CConfig;
specialConfigReenab = (0x1) | LPC_GPDMACH5->CConfig;
linkedListReenab = LPC_GPDMACH5->CLLI;
linkedListEnab = LPC_GPDMACH4->CLLI;
//Enable the channel "enable" channel. Hopfully will be triggered by timer match soon. This should enable SPI transfer
GPDMA_ChannelCmd(4, ENABLE);
}