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.

[参考译文] TMS320F28069:不完整的 McBSP DMA 传输

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

https://e2e.ti.com/support/microcontrollers/c2000-microcontrollers-group/c2000/f/c2000-microcontrollers-forum/930758/tms320f28069-incomplete-mcbsp-dma-transfers

器件型号:TMS320F28069

您好!

我指的是有关 McBSP DMA 的链接主题的最后一个问题。

在我们的系统中、一个 SPI 从器件被连接至用作 SPI 主器件的 C2000 McBSP 模块(通过 McBSP)。 从器件定期(每1ms)请求 SPI 主器件使用 GPIO (外部中断)启动 SPI 传输。 传输的字节数为12字节。 SPI 传输由 DMA 处理并在 EXTI 中断(来自从器件)中启动。 由于 C2000也在控制电机、EXTI ISR 所花费的时间必须尽可能短(= McBSP + DMA 传输初始化且 START 必须是最佳)。

问题是:如果我在启动时只初始化一次 DMA 通道、那么第一次传输是正确的(发送了12个字节)、但下一次传输不完整:缺少前4个字节(仅发送了8个字节)。

您是否有什么想法不是为了重新启用 DMA 通道(运行= 1)来重新启动完整的传输?

下面是 DMA 配置:

DMA->DMACTRL |=(1 <<0);
ASM (" NOP");

//通道1:McBSPA 发送
//------

dma->ch1.burse_size = 1u; //每个突发
DMA 2个16位字->CH1.SRC_BURST_STEP = 1;//递增1个16位地址。 在 dma->ch1.dst_burst_step =
1之间;//递增1个16位 addr。 在 dma->ch1.transfer_size
= 2U 之间;//每隔(2 + 1)个突发(= 12字节)中断一次。

DMA->CH1.SRC_TRANSFER_STEP = 1;//在突发中的每个字之后移至缓冲器中的下一个字。
DMA->CH1.dst_transfer_step = 0xFFFF;//减量返回 McBSP DXR2寄存器。

dma->ch1.SRC_ADDR_SHADDADDR =(UINT32_t)&p_txBuf[0];
dma->ch1.SRC_beg_ADDR_SHADDR =(UINT32_t)&p_txBuf[0];// TODO (S):不需要-要检查。
dma->ch1.dst_ADDR_SHADDADDR =(uint32_t)&obj->mcbspAHandle->DXR2;
dma->ch1.dst_beg_ADDR_shadow =(uint32_t)&obj->mcbspAHandle->DXR2;// TODO (S):不需要检查。

//清除同步错误标志
dma->ch1.control |=(1U <<7);

//设置为最大值以避免任何源/目标绕回。
DMA->CH1.SRC_WOP_SIZE = 0xFFFFFFU;
DMA->CH1.DST_WOP_SIZE = 0xFFFFFFU;

// DMA->CH1.MODE |=(1U << 15);//启用通道中断。
DMA->CH1.MODE |=(1U <<9);//在传输结束时生成中断。
DMA->CH1.MODE |=(1U <<8);//启用外设中断事件。

DMA->CH1.MODE |=(14U <<0);// DMA 中断源:MXEVTA (McBSP 传输)。

dma->ch1.control |=(1U <<4);//清除所有杂散中断标志。

//通道2:McBSPA 接收
//---------------

dma->ch2.burse_size = 1u; //每个突发
DMA 2个16位字->CH2.SRC_BURST_STEP = 1;//递增1个16位地址。 在 dma->ch2.dst_burst_step =
1之间;//递增1个16位 addr。 在 dma->ch2.transfer_size
= 2U 之间;//每隔(2 + 1)个突发(= 12字节)中断一次。

DMA->CH2.SRC_TRANSFER_STEP = 0xFFFF;//再回到 McBSP DRR2寄存器。
dma->ch2.dst_transfer_step = 1;//在突发中的每个字之后移动到缓冲器中的下一个字。

dma->ch2.SRC_ADDR_SHADDR_SHADDR =(UINT32_t)&obj->mcbspAHandle->DRR2;
dma->ch2.SRC_beg_ADDR_SHADDR_SHADDR =(UINT32_t)&obj->mcbspAHandle->DRR2;// TODO (S):不需要检查。
dma->ch2.dst_ADDR_SHADDADDR =(UINT32_t)&p_rxBuf[0];
dma->ch2.dst_beg_ADDR_SHADDR =(UINT32_t)&p_rxBuf[0];// TODO (S):不需要-要检查。

//清除同步错误标志
dma->ch2.control |=(1U <<7);

//设置为最大值以避免任何源/目标绕回。
DMA->CH2.SRC_WOP_SIZE = 0xFFFFFFU;
DMA->CH2.DST_WOP_SIZE = 0xFFFFFFU;

DMA->CH2.MODE |=(1U << 15);//启用通道中断。
DMA->CH2.MODE |=(1U <<9);//在传输结束时生成中断。
DMA->CH2.MODE |=(1U <<8);//启用外设中断事件。

DMA->CH2.MODE |=(15U << 0);// DMA 中断源:MREVTA (McBSP 接收)。

dma->ch2.control |=(1U <<4);//清除任何伪中断标志。 

以下是在每个从器件请求时重新启动传输的代码:

enable_protected_register_write_mode;
dma->ch1.control |=(1U <<0);
dma->ch2.control |=(1U <<0);
disable_protected_register_write_mode; 

以下是第一个传输(完成):

下面是下一次传输(缺少字节):

此致

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

    Johann、

    您能否跨配置为 McBSP 寄存器发送数据。  我认为这里最重要的是 XCR1/XCR2和 SPCR2寄存器。  我正在寻找您在每次传输中指定的位数、就像 McBSP 将生成其中断一样。  我假设它是16、但我想确定。

    此外、您是否设置了 DMA 模式寄存器(位11)中的 Continuous 位、或者是否要在传输完成并为 X 发送 ISR 提供服务后暂停?

    最棒的

    Matthew

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

    Matthew、您好!

    [引用用户="MatthewPaate"]

    我假设它是16、但我想确定。

    [/报价]

    正如您将在以下配置中看到的、我们已将 XWDLEN1和 RWDLEN1的传输设置为32位、以便尽可能快。 即使它应该是16位、我仍然不明白它为什么能够在第一次传输时正常工作。

    以下是 McBSP 寄存器配置:

    HAL_Obj * obj =(HAL_Obj *) handle;
    McBSP_obj * McBSP =(McBSP_obj *) obj->mcbspaHandle;
    
    //步骤1:将发送器和接收器置于复位状态。
    //----------------------------
    McBSP->SPCR2 &=~McBSP_SPCR2_XRST;
    McBSP->SPCR1 &=~McBSP_SPCR1_RRST;
    //步骤2:将采样率发生器置于复位状态。
    //----------------------------
    McBSP->SPCR2 &=~McBSP_SPCR2_GRST;
    //步骤3:对影响 SPI 操作的寄存器进行编程。
    //----------------------------
    McBSP->SPCR1 ||(2 << McBSP_SPCR1_CLKSTP_POS);//时钟停止模式,无时钟延迟。
    
    // SPI 模式0选择(低非活动状态、McBSP 在
    SCLK 的上升沿发送数据、在下降沿接收数据。
    McBSP->PCR 和=~McBSP_PCR_CLKXP;
    McBSP->PCR 和=~McBSP_PCR_CLKRP;
    
    McBSP->PCR ||(1U << McBSP_PCR_CLKXM_POS);//时钟在 MCLKX 引脚上传输。
    
    //设置单相发送/接收帧。
    McBSP->XCR2 &&~McBSP_XCR2_XPhase;
    McBSP->RCR2 &&~McBSP_RCR2_RPHASE;
    
    //设置1个串行字的发送和接收帧长度。
    McBSP->XCR1 &&~McBSP_XCR1_XFRLEN1;
    McBSP->RCR1 &&~McBSP_RCR1_RFRLEN1;
    
    //将发送和接收数据包长度设置为32位。
    McBSP->XCR1 |=(0x05 <<McBSP_XCR1_XWDLEN1_POS);
    McBSP->RCR1 |=(0x05 <<McBSP_RCR1_RWDLEN1_POS);
    
    //选择 LSPCLK 作为采样率发生器的输入时钟。
    McBSP->PCR &=~McBSP_PCR_SCLKME;
    McBSP->SRGR2 |= McBSP_SRGR2_CLKSM;
    
    //将 LSPCLK 分频30以获得3MHz 的 CLKG 频率。
    McBSP->SRGR1 ||(McBSP_CLKDV << McBSP_SRGR1_CLKGDV_POS);
    
    // FSX 引脚是输出引脚,用于芯片选择。
    McBSP->PCR |=(1U <<McBSP_PCR_FSXM_POS);
    
    McBSP->SRGR2 &=~(1U <<12);//帧同步。 FSX 引脚上的脉冲。
    
    // FSX 引脚为低电平有效。
    McBSP->PCR |= McBSP_PCR_FSXP;
    
    // SPI 主站操作要求字段 XDATDLY 和 RDATDLY 设置为1。
    McBSP->XCR2 |=(1U <<McBSP_XCR2_XDATDLY_POS);
    McBSP->RCR2 |=(1U <<McBSP_RCR2_RDATDLY_POS); 

    以下是在配置并再次启动 DMA 之前禁用 McBSP 的代码:

    McBSP->SPCR2 &=~(1U <<7);
    McBSP->SPCR2 &=~McBSP_SPCR2_XRST;
    McBSP->SPCR1 &=~McBSP_SPCR1_RST;
    McBSP->SPCR2 &=~McBSP_SPCR2_GRST; 

    下面是在 DMA 被配置和启动后启用 McBSP 的代码:

    McBSP->SPCR2 &=~(1U <<7);
    McBSP->SPCR2 &=~McBSP_SPCR2_XRST;
    McBSP->SPCR1 &=~McBSP_SPCR1_RST;
    McBSP->SPCR2 &=~McBSP_SPCR2_GRST; 

    关于用例、我们需要在传输完成后暂停、并为 RX ISR 提供服务、如下图所示:

    在 RX ISR 中、我们读取并处理 SPI 从器件发送的数据。

    此致、
    Johann

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

    Johann、

    在 LA 图中、我们缺少0xB0/A0/B1/A1、我认为这是应该发生的第一个32位传输。  此外、我们还知道我们没有关闭 SRC 地址、因为我们只获得2次传输、而不是3次传输的非预期数据(来自附近未初始化地址的垃圾)。

    我想通过查看通道1的 DMA 地址寄存器(源和目的)的状态来进行调试、此时您禁用了 McBSP TX、但在您重新启用 DMA 之前和之后、都需要设置相应的 RUNSTS 位= 1。   

    我怀疑、在第一次迭代的最后一次传输之后、来自 McBSP 到 DMA 的 EVT 信号仍然被锁存在本地 DMA 逻辑中、因此一旦您重新启用 DMA 通道、它就会尝试将该初始字写入 McBSP DXR2/1、 但 McBSP 尚未重新启用、因此我们错过了它。  如果您在重新启用 McBSP 之前看到有效的 src 地址= base +2、那么这将确认这一理论

    如果我们确实看到上述情况、也许我们可以在 RUNSTS = 0时将 DMA 通道1的触发源更改为 McBSP 之外的其他内容、然后在设置 RUNSTS = 1之前再次返回、尝试重置此本地锁存器。

    最棒的

    Matthew

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

    Matthew、您好!

    [引用 USER="MatthewPaate">从 LA 图中、我们缺少0xB0/A0/B1/A1、我认为这是应该发生的第一个32位传输。  [/报价]

    是的、这应该是第一个32位传输。  

    以下是首次启用 DMA 之前和之后通道1的 DMA 地址寄存器(正确传输):

    • 以前:
      • 源地址:0x00000000
      • 源地址(影子):0x0000C01A
      • 目的地址:0x00000000
      • 目的地址:0x00005002
    • 之后:
      • 源地址 :0x00000000
      • 源地址(影子): 0x0000C01A
      • 目的地址 :0x00000000
      • 目的地址 :0x00005002

    以下是重新启用 DMA 之前和之后通道1的 DMA 地址寄存器(传输不完整):

    • 以前:
      • 源地址 :0x0000C020
      • 源地址(影子):0x0000C01A
      • 目的地址 :0x00005002
      • 目的地址:0x00005002
    • 之后:
      • 源地址 :0x0000C01B
      • 源地址(影子): 0x0000C01A
      • 目的地址 :0x00005002
      • 目的地址 :0x00005002

    [引用 USER="MatthewRate"]如果我们确实看到了上述内容,也许我们可以在 RUNSTS = 0时将 DMA 通道1的触发源更改为 McBSP 以外的其他内容,然后在设置 RUNSTS = 1之前再次返回,尝试重置此本地锁存器。[/QUERE]

    我尝试将 DMA 通道1的触发源设置为"无":

    • "DMA RX ISR"->"no effect
      enable_protected_register_write_mode;
      m_halHandle->dmaHandle->CH1.mode &&~0x001FU;
      disable_protected_register_write_mode; 

    • 设置 RUNSTS (none、然后选择 McBSP 源)->无效
    enable_protected_register_write_mode;
    m_halHandle->dmaHandle->CH1.mode &&~0x001FU;
    m_halHandle->dmaHandle->CH1.mode |=(14U << 0);// DMA 中断源:MXEVTA (McBSP 传输)。
    disable_protected_register_write_mode;
    
    HAL_startMcBspADma (m_halHandle); 

    你有其他想法吗?

    此致

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

    Johann、

    感谢您进行实验、我认为这个问题的原因是我在上一篇文章中所假设的。  我们必须弄清楚如何清除最后一个中断事件(McBSP 就绪 X-mit)。  从上面更改源不足以清除闩锁。

    我将要求设计团队中的同事了解逻辑是如何构建的、但我想同时尝试一些事情、以免我们陷入困境。  如果我们找到了合适的器件、我们可以通过设计确认这是正确/可重复的行为。

    这里有两种可能、具体取决于来自 McBSP 的信号是边缘还是电平检测。  如果它的边沿、那么我们应该能够在 DMA 中局部清除锁存器。  如果是其电平、那么我们需要了解如何将信号复位到 McBSP 的本地。

    1:DMA 寄存器修改)我们不更改 PERINTSEL 源、而是通过将 PERINTE 位设置为0来禁用外设中断、然后在写入 RUNSTS 位之前将其设置回1。  这肯定会清除 DMA 中的任何本地锁存器。

    2:McBSP 寄存器修改)在传输之间通过向 SPCR2寄存器的 XRST 位写"0"、然后通过写"1"重新启用发送器、使其复位并退出复位状态。  读取 TRM 我不认为这会重置您的 McBSP 设置。

    最棒的
    Matthew