This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] TMS320F28379D:带有 DMA 的 SPI 问题:DMA 读取第一个字错误

Guru**** 2526070 points


请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/952234/tms320f28379d-spi-with-dma-problem-dma-reads-first-word-wrong

器件型号:TMS320F28379D

尊敬的同事、您好!

在这一问题上已有一段时间了、我们高度赞赏任何评论和想法。

我有一个程序、用于通过 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);
} 

当然、这是一个小的延迟、在这种情况下并不重要、因此我可以离开它、但我想找出原因。 也许我应该检查一些寄存器、并等待一些标志被设置等 这样它就更可靠了。  

如果您有任何想法、请告诉我。

此致、

伊凡。

 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Ivan、

    您可能需要重新发送您的图像、但它们没有出现。 一些问题/说明:

    [引用 USER="Ivan Minakov1]*这是从 SPI 函数读取的。 除地址外、写入 SPI 函数基本上是相同的。  [/报价]

    我看到 CH5写入 SPI、而 CH6从 SPI 读取。 这是您的意思吗?  

    Ch5从同一个 dummy_var 读取并写入 SPI TX 寄存器。  

    Ch6读取 SPI RX 寄存器并写入 RX_Buf。

    [引述 USER="Ivan Minakov1]\n 请注意底部的第5行和第6行。 当 delay >=9或 调用 dma_isBaseValid()函数时,程序按预期工作。 基本上、即使没有延迟、来自 SEND 函数的相同代码也能正常工作。 发送和接收缓冲区都位于同一代码段中。

    这里您提到了一个"发送缓冲区"、但我只看到您从 dummy_var 读取、我认为它实际上不是缓冲区。

    [引用 USER="Ivan Minakov1]]我认为它可能是 SPI 移位 smth 的第一个字错误。 我使用逻辑分析仪检查了数据、输入的数据是正确的、没有额外的字。 此外、逻辑分析仪的两个图(正确和错误操作)看起来相同、包括传输之间的时间等 因此、我假设这实际上不是 DMA 的问题、而是 SPI 的问题。

    您的图片没有通过、因此我看不到您的期望与您的接收。 假设 SPI 设置为主器件并禁用环回、我假设 SPI 从某些外部源接收数据。 是这样吗? 或者是否有外部回送连接?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    此外,您是否可以尝试配置和启动 CH6 (SPI RX)*Before * CH5 (SPI TX)?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    大家好、Gus!  

    感谢您的回复!

    [引用 user="Gus Martinez"]您的图片未通过、因此我看不到您对您所收到的图片的期望。 假设 SPI 设置为主器件并禁用环回、我假设 SPI 从某些外部源接收数据。 是这样吗? 或者是否有外部回送连接?[/quot]

    很抱歉、 我修复了图像。

    [引用用户="Gus Martinez"]

    我看到 CH5写入 SPI、而 CH6从 SPI 读取。 这是您的意思吗?  

    Ch5从同一个 dummy_var 读取并写入 SPI TX 寄存器。  

    Ch6读取 SPI RX 寄存器并写入 RX_Buf。

    [/报价]

    基本上、我有一个外部 SPI 器件(KSZ8851SNL)、我从该器件发送和接收数据。 我有两个缓冲器、TX_Buf 和 RX_Buf。  

    发送函数使用 DMA CH5将数据从 TX_Buf 写入 SPI、并使用 DMA CH6从 SPI 读取虚拟数据至 dummy_var。  

    接收函数使用 DMA CH5将0x00数据从 dummy_var 写入 SPI、并使用 DMA CH6从 SPI 读取数据到 rx_Buf。

    在这两种情况下、DMA 的配置是相同的、但地址除外。 发送功能正常工作、接收功能仅在增加延迟的情况下工作。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    如果我首先配置 CH6、则无论延迟如何、数据始终像以前一样移位(尝试9、90、500、5000):

    EALLOW;
    //配置 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 (5000); // TODO:在较小的延迟下不能工作?!????
    // DMA_isBaseValid (DMA_CH6_BASE);
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    //配置 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;
    
    
    //开始传输
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC;
    EDIS; 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Ivan、

    感谢您澄清这些问题。 我现在更好地理解了您的问题。  

    我一直在思考您的观察结果。 我不确定这里发生了什么、但它可能与您触发 DMA 的方式有关。

    在接收代码中、我看到您正在强制执行第一个 CH5传输。 在强制执行第一个 CH5传输之前、您是否能够检查 x[0]的内容? 如果 x[0]的内容已经改变、那么这将告诉我们 CH6已经启动了第一个传输、然后我们将需要弄清这是为什么。

    您可能希望在触发器和断点之前放置一个 while (1)、只是为了确保停止程序执行不会对问题的实际行为产生影响。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Gus、

    感谢您的回复! 正如您说过的、我尝试将 while (1)放入、并且 x[0]的内容在 我触发传输之前实际上会更改为0x0101! 您有什么想法吗?

    此致、

    伊凡。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我还尝试逐个激活两个通道、首先是 CH6、其次是 CH5、但问题仍然存在。  

    //启动 DMA 通道
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_RUN; 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Ivan、

    看起来 DMA 已从 SPI 接收到 RX 事件。 在配置 SPI 之后以及在启用 DMA 通道之前、您能否检查 SPIFFRx 寄存器的内容? 最好知道 RXFFST 和 RXFFINT 位的状态。 如果这些位不为零、则出于某种原因、SPI 已接收到一个或多个字符。 您可能需要尝试通过调用 SPI_resetRxFIFO()来重置 RX FIFO。 我想您可以在调用 SPI_setFIFOInterruptLevel()后执行该操作。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Gus、

    我已检查 SPIFFRx 寄存器。  RXFFST 为0x00、 RXFFINT 为1。

    下面是我尝试的方法:

    1.按建议添加 SPI_resetRxFIFO()-无效

    2. 在 DMA 初始化之前添加 SPI_resetRxFIFO()-无效

    3. 在强制触发之前添加 SPI_resetRxFIFO()(在这里我使用了 HWREG 版本的它,而不是函数)-无效

    4.  在强制触发前清除 RXFFINT -无效

    5.同时执行3和4 -没有效果

    我注意到的是、在我启用 DMA CH6之后

    //启动 DMA 通道
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN; 

    SPIRXBUF 和 x[0]的内容都是0x0101 -总是同一个错误的数字(至少在第一次传输时、它会改变)。 我用 while (1)技术检查了它。 此外、正如我之前提到的、逻辑分析仪上不存在该数据。

    在启用 CH6之前、我还尝试复位 FIFO 并清除中断标志。 在这种情况下、行为仍然相同(错误的第一次传输)、但数字不同(0x8000)。 如果我只 清除中断标志、那么该数字仍然是相同的0x0101。

    下面是我的测试代码的一个片段:

    //设置传输寄存器。
    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;
    
    // SYSCTL_DELAY (9); // TODO:在较小的延迟下不能工作?!????
    // while (1);
    
    EDIS;
    
    //重置 RX FIFO。
    //
    HWREGH (SPIB_BASE + SPI_O_FFRX)&=~SPI_FFRX_RXFIFORESET;
    HWREGH (SPIB_BASE + SPI_O_FFRX)|= SPI_FFRX_FIFORESET;
    
    //清除中断标志
    HWREGH (SPIB_BASE + SPI_O_FFRX)|= SPI_FFRX_RXFFINTCLR;
    
    
    // while (1);
    
    EALLOW;
    //启动 DMA 通道
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    while (1);
    
    //开始传输
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC;
    EDIS; 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    伊万

    [引用 USER="Ivan Minakov1]I 检查 了 SPIFFRx 寄存器。  RXFFST 为0x00、 RXFFINT 为1。[/QUINT]

    RXFFINT 位被置位是奇数。 您能否发布 SPIFFRx 寄存器的全部内容? 或者、发布所有 SPI 寄存器内容可能更好。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    GUS、这里是所有 SPI 寄存器的内容:

    1.起动通道5之前

    2.起动通道6之前

    3.强制触发 CH5之前

     4.强制触发后触发 CH5

    测试代码:

    //配置 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;
    
    // while (1);
    
    //启动 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;
    
    // while (1);
    
    //启动 DMA 通道
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    // while (1);
    
    //开始传输
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC;
    EDIS;
    
    while (1); 

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    基本上、在1-3种情况下寄存器的内容是相同的、在第4种情况下、差异是 SPIRXEMU、SPIRXBUF、SPIDAT 和 SPIFFRX。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Ivan、  

    您是否删除了复位 RX FIFO 和中断标志的指令? 很抱歉、我应该更清楚一点、这里的目标是查看这两条指令是否对 RXFFINT 标志产生影响。 我猜是因为在启用 DMA 时设置了此标志、所以您在开始时会得到额外的 DMA 传输。

    您能否添加说明来清除 RX FIFO 和中断标志并捕获 SPI 寄存器的状态?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我在 INIT 函数中仍然有一条复位 FIFO 指令:

    (笑声)
    针对 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);
    
    //复位 FIFO
    SPI_resetRxFIFO (SPIB_BASE);
    (笑声) 

    以下是在启动 CH6之前插入复位的结果:

    代码:

    (笑声)
    //设置传输寄存器。
    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;
    
    EDIS;
    
    //重置 RX FIFO。
    //
    HWREGH (SPIB_BASE + SPI_O_FFRX)&=~SPI_FFRX_RXFIFORESET;
    HWREGH (SPIB_BASE + SPI_O_FFRX)|= SPI_FFRX_FIFORESET;
    
    //清除中断标志
    HWREGH (SPIB_BASE + SPI_O_FFRX)|= SPI_FFRX_RXFFINTCLR;
    
    // while (1);
    
    EALLOW;
    //启动 DMA 通道
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    // while (1);
    
    //开始传输
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC;
    EDIS;
    
    while (1);
    (笑声) 

     1.起动通道6之前

     2.强制触发 CH5之前

    3.强制触发后触发 CH5

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    案例3后的结果:

    数据 x[0]仍然错误、但编号现在是0x0000、而不是0x0101。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    好的、这里是我对您发布的原始代码在这个线程的开头发生了什么的理论。

    1. 您对 DMA CH5进行了编程并启用了它(设置运行位)。 由于 SPI TXFFINT 被置位(TXFFST < TXFFIL)、DMA 将立即被触发并开始将数据移动到 SPI TX FIFO。 注意:稍后强制触发 CH5可能不会产生任何实际影响。  
    2. 然后、您对 DMA CH6进行编程并启用它(设置运行位)。 由于设置了 SPI RXFFINT (基于上面未显式清零 RXFFINT 标志位的实验)、DMA 将立即被触发并开始从 SPI RX FIFO 移动数据。 注意:CPU 比 SPI 快得多。 到目前为止、SPI 仍然很可能尚未完成第一个字符的传输。 因此、DMA CH6将仅拾取 SPI RX FIFO 中的任何内容。 此时、DMA CH6已将 CH5的头跳过一个字符、导致数据缓冲区中的偏移。

    为什么延迟很重要? 因为您为 SPI 提供了完成第一次传输的时间。 因此、在启用 CH6时、SPI RX FIFO 中有一个有效值。

    如何解决问题:

    • 确保在启用 CH6之前清除 RXFFINT 标志*。  
    • 请勿强制触发 CH5。 我敢打赌、TXFFINT 置1会导致在您"运行"CH5后立即触发 Ch5。
    • 使 CH5和 CH6更接近(设置运行)。 或者至少确保先启用 CH6。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好、Gus、

    感谢您的解释、这对我来说是完美的、但问题仍然存在。 我听从了您的建议、下面是代码现在的样子:

    //配置 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 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;
    
    EDIS;
    
    //清除中断标志
    HWREGH (SPIB_BASE + SPI_O_FFRX)|= SPI_FFRX_RXFFINTCLR;
    
    EALLOW;
    //启动 DMA CH6
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    //启动 DMA CH5
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    //开始传输
    // HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC;
    EDIS; 

    如果我不强制触发 CH5、则仅传输第一个假字(x[0]= 0x0101)、如果我强制触发、则会发生完全传输、数据看起来像以前一样移位、x[0]和以前一样是0x0101。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    此外、如果我在启用 CH6之后和启用 CH5之前立即停止、则第一个传输已经发生并且 x[0]= 0x0101。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好 Ivan、

    因此、看起来 CH6是以某种方式触发的。 在启用通道6之前、您能否检查通道6上的 PERINTFLG 状态? 如果设置了该值、那么可能就是原因所在。 在启用 CH6之前、您可以使用 PERINTCLR 位将该位清零。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    Gus、  

    我再次浏览我的代码、发现在我停止 DMA CH5和 CH6之前、我已经通过 SPI 发送了几个控制字。 设置 SPI 和 DMA 中的标志并填充 RX FIFO 的寄存器。 这是其中一个问题、但第二个问题、为什么 x[0]错误与 PERINTCLR 有关。 与原始代码相比、这基本上是最大的变化。  

    非常感谢您付出的时间和努力! 我真的很感谢。

    最终代码:

    //设置 DMA
    EALLOW;
    //配置 DMA CH5
    //设置源地址。
    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 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;
    
    //清除外设中断 CH6
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_PERINTCLR;
    //启动 DMA CH6
    HWREGH (DMA_CH6_BASE + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    //启动 DMA CH5
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_RUN;
    
    //开始传输
    HWREGH (DMA_CH5_base + DMA_O_CONTROL)|= DMA_CONTROL_PERINTFRC;
    EDIS; 

    此致、

    伊凡。