尊敬的同事、您好!
在这一问题上已有一段时间了、我们高度赞赏任何评论和想法。
我有一个程序、用于通过 DMA 向 SPI 写入数据或从 SPI 读取数据。
从 main 调用 DMA 初始化:
/**@简短配置通道5和6的 DMA */
void initdma()
{
dma_initController();
//配置 DMA CH5
DMA_CONFIGMode (DMA_CH5_base、DMA_TRIGGER_SPIBTX、DMA_CFG_OneShot_disable | DMA_CFG_SIZE 16BIT | DMA_CFG_CONSTICE_DISABLE);
DMA_enableTrigger (DMA_CH5_base);
//配置 DMA CH6
DMA_CONFIGMode (DMA_CH6_BASE、DMA_TRIGGER_SPIBRX、DMA_CFG_OneShot_disable | DMA_CFG_SIZE 16BIT | DMA_CFG_CONSTICE_DISABLE);
DMA_enableTrigger (DMA_CH6_BASE);
}
然后、从计时器中断调用另一个函数、该函数配置 DMA 通道并开始传输:
处理 DMA 的函数的一部分:
这是从 SPI 函数读取的。 除地址外、写入 SPI 函数基本上是相同的。
//配置 DMA CH5 EALLOW; //设置源地址。 HWREG (DMA_CH5_base + DMA_O_SRC_BGE_ADDR_SHADDADDR)=(uint32_t)虚拟 var; HWREG (DMA_CH5_base + DMA_O_SRC_ADDR_SHADDow) =(uint32_t) dummy_var; //设置目标地址。 HWREG (DMA_CH5_base + DMA_O_dst_beg_ADDR_shadow)=(SPIB_BASE + SPI_O_TXBUF); HWREG (DMA_CH5_base + DMA_O_DST_ADDR_SHADDow) =(SPIB_BASE + SPI_O_TXBUF); //设置突发寄存器。 HWREGH (DMA_CH5_base + DMA_O_BURST_SIZE) = 0; HWREGH (DMA_CH5_base + DMA_O_SRC_BURST_STEP)= 0; HWREGH (DMA_CH5_base + DMA_O_DST_BURST_STEP)= 0; //设置传输寄存器。 HWREGH (DMA_CH5_base + DMA_O_TRANSION_SIZE) = len_w + len_dummy_w - 1U; HWREGH (DMA_CH5_base + DMA_O_SRC_TRANSFER_STEP)= 0; HWREGH (DMA_CH5_base + DMA_O_dst_transfer_step)= 0; //启动 DMA 通道 HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_RUN; //配置 DMA CH6 //设置源地址。 HWREG (DMA_CH6_BASE + DMA_O_SRC_BGE_ADDR_SHADDR)=(SPIB_BASE + SPI_O_RXBUF); HWREG (DMA_CH6_BASE + DMA_O_SRC_ADDR_SHADOW) =(SPIB_BASE + SPI_O_RXBUF); //设置目标地址。 HWREG (DMA_CH6_BASE + DMA_O_dst_beg_ADDR_SHADDR)=(uint32_t) rx_buf.p_rx_pckt; HWREG (DMA_CH6_BASE + DMA_O_DST_ADDR_SHADOW) =(uint32_t) rx_buf.p_rx_pckt; //设置突发寄存器。 HWREGH (DMA_CH6_BASE + DMA_O_BURST_SIZE) = 0; HWREGH (DMA_CH6_BASE + DMA_O_SRC_BURST_STEP)= 0; HWREGH (DMA_CH6_BASE + DMA_O_DST_BURST_STEP)= 1; //设置传输寄存器。 HWREGH (DMA_CH6_BASE + DMA_O_TRANSION_SIZE) = len_w + len_dummy_w - 1U; HWREGH (DMA_CH6_BASE + DMA_O_SRC_TRANSFER_STEP)= 0; HWREGH (DMA_CH6_BASE + DMA_O_DST_TRANSFER_STEP)= 1; //启动 DMA 通道 // SYSCTL_DELAY (9); // TODO:在较小的延迟下不能工作?!???? DMA_isBaseValid (DMA_CH6_BASE); HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN; //开始传输 HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC; EDIS;
请注意底部的第5行和第6行。 当 delay >=9或 调用 dma_isBaseValid()函数时,程序按预期工作。 基本上、即使没有延迟、来自 SEND 函数的相同代码也能正常工作。 发送和接收缓冲区都位于同一代码段中。
DMA 从另一个函数停止:
(摘录)
//停止 DMA CH5和 CH6 EALLOW; HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_HALT; HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_HALT; EDIS;
我每次都必须重新初始化 DMA、因为我对写入和读取使用相同的通道。
预期行为:
所有数据都正确、从 x[0]开始。 这是具有附加延迟的程序的结果。
无延迟工作方式:
红线下的数据是正确的、但应从 x[0]开始、因此它基本上会移入存储器中。 数据 x[0]是一些随机数据、有时会更改。
这种行为是稳定的、DMA 始终开始写入比应有高1个地址的数据。
当我添加延迟时、第一次传输是错误的(它也从相同的+1地址开始)、但之后所有传输都是正确的。 如前所述、向 SPI 发送数据时不会发生这种情况、尽管它基本上是相同的代码。
我认为这可能是 SPI 将 smth 的第一个字移入错误。 我使用逻辑分析仪检查了数据、输入的数据是正确的、没有额外的字。 此外、逻辑分析仪的两个图(正确和错误操作)看起来相同、包括传输之间的时间等 我想这实际上不是 DMA 的问题、而是 SPI 的问题。
在 DMA 传输之前、我也不重新配置 SPI、并且在数据表中也没有找到关于配置 DMA 后所需延迟的任何内容。
我的 SPI 配置:
void init_spib_master (void) { //在配置 SPI 之前将其复位 SPI_disableModule (SPIB_BASE); // SPI 配置。 使用40MHz SPICLK 和16位字大小。 SPI_setConfig (SPIB_BASE、DEVICE_LSPCLK_FREQ、SPI_PROT_POL0PHA1、 SPI_MODE_MASTER、40000000、16); SPI_enableHighSpeedMode (SPIB_BASE); SPI_disableLoopback (SPIB_BASE); SPI_setEmulationMode (SPIB_BASE、SPI_emulation_free_run); 针对 DMA 的// FIFO 配置 SPI_enableFIFO (SPIB_BASE); SPI_clearInterruptStatus (SPIB_BASE、SPI_INT_RXFF | SPI_INT_TXFF); SPI_setFIFOInterruptLevel (SPIB_BASE、SPI_FIFO_TX1、SPI_FIFO_RX1); //启用 SPI 模块。 SPI_enableModule (SPIB_BASE); }
当然、这是一个小的延迟、在这种情况下并不重要、因此我可以离开它、但我想找出原因。 也许我应该检查一些寄存器、并等待一些标志被设置等 这样它就更可靠了。
如果您有任何想法、请告诉我。
此致、
伊凡。









