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.

[参考译文] MSP430FR5969:SPI DMA 全双工主/从

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/913249/msp430fr5969-spi-dma-full-duplex-master-slave

器件型号:MSP430FR5969

我一直在使用 DMA 在一对以16MHz 运行的 MSP430FR5969 LaunchPad 套件主/从(MCLK 和 SMCLK)之间进行全双工 SPI 传输。  最终、我将使用非 MSP 主设备和 MSP430FR5969从设备之间的需要全双工 SPI 通信。  MSP430在2.67MHz 至3.2MHz 的位速率范围内正常工作、然后开始分解。  我注意到、当我向上发送时钟时、主器件正在发送额外的字节。  我找不到任何确定的最大 SPI 速度、但我认为它应该在高达8MHz 的频率下工作(我在 DMA 中使用的其他一些控制器在一半的系统时钟速率下没有问题)。 我已经使用协议分析器验证了额外的字节。

现在、无论以何种速率、我都只将主器件连接到协议分析器。  我将使用一个4字节的缓冲区进行测试。  时钟频率为16MHz、分频值为8、7和6时、MSP430发送4个字节。   在位速率分频值为5、4和3的情况下、MSP430发送5个字节、当分频值为2时、它发送7个字节。  主器件处于3线制模式、当我改变位速率分频值时、我确实将 DMA 保持在复位状态。

我很难理解的是、为什么 MSP430发送的字节会比它应该发送的字节多。

我可以理解速度限制(仍然不确定应该是什么)、我需要一个8MHz 全双工链路、从我可以告诉 DMA 需要2个时钟来存储数据(每字节8个)、并且有一个发送/接收缓冲器。

我已经尝试了几种启动传输的方法(初始写入 SPI Tx 和切换 Tx IFG)、只要您在写入 Tx 寄存器时进行大小调整、这两种方法都能正常工作。

我可以动态更改消息和之间的位速率、并且我的全双工设置在6-8分频时继续正常工作。  永远运行、我还在一个实现方案上实现了校验和、以确保不会发生其他奇怪的情况。

我可以共享的最小代码/项目集。  如果有人提出建议,我会很乐意尝试。  希望它只是一个简单的东西。

此致

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

    DMA 需要2个以上的周期。 有关详细信息、请参阅11.2.7。 最少4个周期、并且可能更多取决于低功耗模式。(还请记住、如果 FRAM 处于 FRAM 中、FRAM 等待状态几乎肯定会增加访问数据的时间。)

    USCI 的最大输入时钟速度为16MHz、因此8Mbps 不会成为问题、尽管这样每字节只有16个 MCLK。 这使得数据的输入和输出速度非常复杂。

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

    如果您有测试用例(尤其是一个小测试用例)、我建议您将其发布。 这里有很多眼睛、有人可能会看到一些东西。

    您是否有可能使用 DMALEVEL=1? 我这样做(但我对此感到内疚!) 但我总是想知道是否会在极高的速度下与 TXIFG 竞争。  

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

    我看了11.2.7、但在这些速度下(例如、4或8 MHz)、它看起来不像一个展示挡块。

    缓冲器位于 RAM 中(如果我正在正确读取链接器和调试信息)、并且我不处于低功耗模式。

    事务在32字节帧(我的测试为4字节)内以10毫秒的顺序定期发生。 SPI 总线的运行频率为8MHz、总线上还有几个其他器件。

    谢谢

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

    首选的发布方法是什么?  我可以使用其中一个选项从 CCS 导出。

    我使用 DMALEVEL 1、TxIFG 作为触发器。  实际消息是一个32字节帧、每隔几十毫秒在与多个其他器件一起工作的8MHz SPI 总线上传输一次。

    我在测试代码中使用的是一条4字节消息、因为在协议分析器上更容易看到、而且每隔几秒只传输一次。

    就比赛条件而言... 这似乎是合理的。  我注意到、额外的字节是消息开头的副本(看起来是换行)。  这意味着源地址正在重新初始化、但直到很晚才会识别终端计数。  这可能意味着解决方法不是很好。

    我正在以重复单模式运行。  我还尝试了几种不同的方法来启动传输。

    此外、当主器件和从器件都连接时、从器件也会"看到"额外的字节。

    谢谢

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

    如果您的代码只是一个.c 文件、您只需附加它即可。 (我个人被困在 CCS V8上、因此无法导入 v9/v10项目。)

    DMALEVEL 只是一个怀疑、我没有证据。 用户指南第11.2.3.2节第1段中的句子(几乎在每个用户指南中都有)"为了正常运行、只能在选择外部触发 DMAE0作为触发器时使用电平触发器"、没有进一步的解释。 我可以想象一些危险、但在某些/大多数情况下、它似乎正常运行。 (这就是我在上面开玩笑说"感到有罪"的原因。)

    DMALEVEL=1非常方便接近 TXIFG 边沿要求、但这并不是真正的必要。 替代方法是在第二个字节启动 DMA、并将第一个字节显式写入 TXBUF 以获得该初始上升沿。  

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

    您不需要发布所有代码、甚至很多代码。 DMA 的设置以及您开始发送的位置。 例如、我就是通过这种方式实现它的、尽管在更低的比特率和 UART 模式下:

    /*
    一次 DMAC 设置。
    
    由 UCA0发送寄存器空 IFG 触发。
    每次触发单次传输、源增量、字节。
    目的是 UCA0发送寄存器。
    
    请注意、TI GCC 编译器会生成一些非常糟糕的代码
    设置源地址和目的地址。 我添加了16位寄存器
    器件头文件的定义。
    *
    DMACTL0 = DMA0TSEL__UCA0TXIFG;
    DMA0CTL = DMADD_0|DMASRCINCR_3|DMADSTBYTE|DMASRCBYTE;
    DMA0DAL =(int)&UCA0TXBUF;
    

    /*
    使用 DMA0将数据包传输到发送寄存器。 大多数
    初始化期间执行了设置。 前两个字节是
    传输到 UART。 DMAC 将处理其余部分。
    */
    DMA0SAL =(int) bufp;
    DMA0SZ = I; //要传输
    
    UCA0TXBUF 的字节数= 0xff;
    //发送保持寄存器应该几乎立即清零
    while (!(UCA0IFG&UCTXIFG))
    ;
    
    DMA0CTL |= DMAEN; //启用 DMAC
    UCA0TXBUF = SYNC; //发送数据包的第一个字节
    
    

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

    我的错、DMALEVEL0、很抱歉让人困惑。  我在开场白中提到我使用的是 TxIFG、然后说 DMALEVEL 1是不正确的。

    我已经尝试将第一个字节写入发送器和切换标志、这两个字节都可以使用适当的计数正常工作。

    下面是设置:

    DMA_DMACTL0
    0013.
    DMA_DMACTL1
    0000
    DMA_DMACTL2
    0000
    DMA_DMACTL3
    0000
    DMA_DMACTL4
    0000   0000   0000 0000
    DMA_DMAIV
    0000
    DMA_DMA0CTL
    43C0
    DMA_DMA0SA
    1CA8   0000
    DMA_DMA0DA
    064E   0000
    DMA_DMA0SZ
    0004   0000   0000

    我将查看发布代码或上传构成测试代码的3个文件。  今天早上有点忙、很快就会尝试。

    谢谢

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

    设置和协议屏幕截图。

    那么、这里是设置...

     #define SRC_TRIGGERSOURCE_19   //发送中断标志

     静态 DMA_initParam DMAsourceMSaddr=   //传出字节
          {   //向从设备发送缓冲区
          通道选择=dma_channel_0、   //从通道
          .transfermodeSelect=dma_transfer_ere重复 单字、   // CPU OPS SLAU37O 11.2.2.3
          triggerSourceSelect=SRC_TRIGGER、   // SLAS704G 6.10.8 (OPT 19、发送)
          transferSize=sizeof (DMAmessageType)-(KICK 开始?0:1)、   //取决于启动方式
          .transferUnitSelect=DMA_SIZE_SRCBYTE_DSTBYTE、   //字节大小
          triggerTypeSelect=DMA_TRIGGER_RISINGEDGE   //SLAU367O 11.2.3.1/2
          };

       HWREG16 (EUSCI_B0_BASK+OFS_UCBxCTLW0)=MS_SPI_MASTER_RUN|一个;
       HWREG16 (EUSCI_B0_BASH+OFS_UCBxBRW)=BAUDRATE_DIV_DMA;   //开始的慢速率
       HWREG16 (EUSCI_B0_BASK+OFS_UCBxCTLW0)=MS_SPI_MASTER_RUN;

       DMA_setDstAddress (   //通过 SPI 端口命令到从器件
          DMA_CHANGE_0、//数据通道输出
          EUSCI_B_SPI_getTransmitBufferAddress (EUSCI_B0_BASE)、//目标为 SPI B TX 寄存器
          dma_direction 不变);   //固定位置

       DMA_setSrcAddress (   //命令缓冲器到从器件
          DMA_CHANGE_0、//数据通道输出
          (uint32_t)(&(DMAmsg.bytes[Zero])+(KICK 开始?0:1))、   // Kick ^预加载第一个字节
          dma_direction 增量);   //递增地址



    下面是 三个4字节 DMA 传输的示例(慢时钟、中时钟和快速时钟)、唯一改变的是 SPI 时钟速率。

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

    我不知道屏幕快照的位置、我使用切断工具将它们粘贴到消息中。  在我点击"回复"按钮之前、我就在那里。

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

    PNG SPI 波形捕获。

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

    我认为您使用了错误的传输模式。 我使用的是单个、其中您使用的是重复单个。 单次传输在计数变为零时结束、而单次重复传输则不会结束。 由于 SPI 端口将继续发送数据并在 TXIFG 上生成边沿、因此您必须执行一些操作来停止它。

    您的代码中缺少的是您开始传输的方式、它看起来传输的结束方式也很重要。 在较高的位速率下、DMA 可能会在抛出传输完成中断后以及关闭气泡机之前处理更多的字节。

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

    未经请求:如果(正如您的描述所示)您在两个方向(Rx/Tx)使用 DMA、请确保为 Rx 端提供更高的优先级、以避免溢出。 戴维指出的事情可能已经掩盖了这一症状。

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

    我将尝试单次传输模式。  今天对我来说是一个短暂的日子,可能是下周,我才可以去。  但是、我在重复单个上读取文档的方式以及它看起来的工作方式是、它会递减计数。 否则、它将无法在较低速度下工作。  我认为协议分析器显示了这一点。  正如我提到的、在速度高达低于3MHz 时、工作正常。

    在开始传输时、我在将第一个字节写入 SPI 时将传输的计数修改为(长度为1、请参阅上面的小 Kickstart 部分)、并在切换 TxIFG 时将其保持为全计数。  这两种启动方法都起作用、并且两者的结果完全相同。

    #if !kick 开始
          EUSCI_B_SPI_transmitData (EUSCI_B0_BASE、TestBuffer[Zero].bytes[Zero]);   //发送第一个字节
    #endif
    #if KICK 启动
          UCB0IFG&=~UCTXIFG;   // Kickstart (可选)
          UCB0IFG|=UCTXIFG;   // Kickstart (可选)
    #endif

    我使用 DMA 完成中断使片选(CS)无效。  这有一点问题、在低速时、DMA 传输在最后几个位移出之前完成。  因此、为了进行测试、我只需坐在中断中并观察 SPI 的忙标志。  更好的解决方案是再发送一个(虚拟)字节并让 DMA 完成中断清除 CS。

             DMA0CTL&=~DMAEN;
             DMA_clearInterrupt (DMA_CHANNEL);
             DMAzeroCount++;//传输数
             while (UCB0STATW&UCBUSY)   //必须在这里等待或截断最后一个字节(用于测试)
             {
                ;//也可以发送额外的字节,可能更干净
             }

    对于我的测试用例、这是可以正常工作的。  现在回顾一下:

    • 当我使用两个评估板并设置为主/从模式时、频率最高可达2.67MHz+
      • 我在两个板之间实现了完美的全双工通信
      • 它们运行数天而没有错误、有效载荷是一个带有校验和的32字节帧
      • 电路板设置如上所述。
    • 我有一个 LabView 程序、它也用作主器件
      • 我有一些有趣的从器件行为(仍然需要查看)、这就是我使用 MSP430主器件的原因
      • 在从器件无法跟上时获得相同的结果(但我现在有信息)

    如果有人想深入了解、我仍然可以发送所有测试代码。

    谢谢

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

    这一点很有道理、这是一个简单的改变。

    谢谢

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

    [在大卫的嘴里说的话:]在较低的速度下、DMA 中断有足够的时间进入并在 DMA 发送更多字节之前停止 DMA、但在较高的速度下、它没有。 我还投票选择 DMADD=0 (DMA_TRANSFERS_SINGLE)。

    尝试使用 Rx 端作为 DMA 完成中断。 然后、您就知道 SPI 已完成。

    [编辑:我个人认为 DMADD=0的名称"单次传输"是不直观的。 它实际上是"单次传输到 DMASZ、然后停止"。 我始终参考流程图、在本例中为 UG (SLAU367P)图11-3、您可以在其中看到 DMADD=0与4之间的两条路径。]

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

    dma_transfer_single 确实解决了传输的额外字节。 非直观是一个很好的描述、在浏览文档和流程图时、我再次看到额外字节来自何处。

    现在、由于我有一个 SPI 主器件、我可以将可靠的字节数作为仿真发送到实际系统。  我可以在 SPI 从站上工作、SPI 从站是工作的真正目标。  

    此致、谢谢。