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.

[参考译文] MSPM0G3507:在 DMA 模式下、无法让 SPI 自动计时接收数据

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

https://e2e.ti.com/support/microcontrollers/arm-based-microcontrollers-group/arm-based-microcontrollers/f/arm-based-microcontrollers-forum/1439766/mspm0g3507-cant-get-spi-to-automatically-clock-in-receive-data-in-dma-mode

器件型号:MSPM0G3507

工具与软件:

我正在使用  spi_controller_fifo_dma_interrupts 示例代码、但进行了一些小改动。  最佳做法是将 TX 长度设置为要发送的字节数、将 RX 长度设置为要接收的字节数。  我非常确信能够按预期运行。  我更改了一些代码、将示例转变为传递 TX 和 RX 长度的函数、现在它将无法接收并挂起、等待 DL_SPI_IIDX_DMA_DONE_RX 中断。  我可以通过将 RX 长度添加到 TX 长度来解决此问题、从而强制使用更多的 SPI 时钟、但我以前不必这样做、这样我就很确定我损坏了某个东西。  

我有这样的说法吗?如果我告诉 DMA 控制器接收10个字节、它将自动为这些数据生成 SPI 时钟。  或者、我是否必须通过向 TX 长度添加虚拟字节来手动创建所需的时钟、以便从外设为数据计时?

谢谢!

Chris

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

    SCLK 周期由(控制器) Tx 侧生成。 Tx 和 Rx 大小应相同。

    对于仅 Tx 或仅 Rx 事务、一种选择是将相反端(您不感兴趣的事务)指向某个位置的单字节并使用非递增(DMASRCINCR=0或 DMADSTINCR=0)。

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

    因此、为了清楚地说明我发送了一个4字节的命令、然后需要读取10字节响应、我必须将 TX 和 Rx 长度设置为14、并接受 TX 将需要10个虚拟填充字节、并且 Rx 的前4个字节也是虚拟/填充。  并非完美的解决方案。  我最终重写了  spi_controller_fifo_dma_interrupts。  由于4线模式中的一项"功能"在使用模式0时会在两个字节之间发出 CS 高脉冲、因此我还必须手动控制 CS 引脚并使用3线模式。  这肯定看起来像一个错误、除非你能解释它吗?  我看到至少有一个报告称它是"故障",但它肯定是做它(贫穷?) 大家电。   

    下面是一个用户更加友好的函数、用于发送 XX 字节和接收 YY 字节而不进行虚拟填充。

    void send_spi_data (int cs_pinint tx_len、int rx_len)
      内部 I;

      gSPIDataTransmitted = false
      gDMATXDataTransfer= false
      gDMARXDataTransferred = false

      /*
       *配置要从中传输数据的 DMA 源、目标和大小
       * tx_pbuf 到 TXDATA。 当 TX 中断为时、DMA 传输将开始
       *设置、它应该已设置(表示 SPI 是
       *准备好传输)、这样 DMA 将在通道时开始该传输
       *已启用。
       */
      DL_DMA_setSrcAddr (DMA、DMA_CH0_CHAN_ID、(uint32_t)&TX_pbuf[0]);
      DL_DMA_setDestAddr (DMA、DMA_CH0_CHAN_ID、(uint32_t)(&SPI_0_INST->TXDATA));
      DL_DMA_setTransferSize (DMA、DMA_CH0_CHAN_ID、TX_LEN);

      DL_SYSCTL_disableSleepOnExit ();
      NVIC_EnableIRQ (SPI_0_INST_INT_IRQN);

      //启用芯片选择
      DL_GPIO_clearPins (GPIOA、cs_pin);
      
      /*
       * SPI TX 中断已设置、表示 SPI 准备就绪
       *传输数据,因此启用 DMA 将开始传输
       */
      DL_DMA_enableChannel (DMA、DMA_CH0_CHAN_ID);

      /*
       *在睡眠模式下等待、直到 SPI_PACKET_SIZE 字节已传输
       *从 tx_pbuf 到 SPI TXFIFO、并且触发 DMA 中断
       */
      while (false == gDMATXDataTransferred){
        __ WFE ();
      }

      /*
       *等待直到 SPI 发送完所有数据和 TXFIFO
       *是空的
       */
      while (false == gSPIDataTransmitted){
        __ WFE ();
      }

      //虚拟读取清除 SPI TX 导致的 SPI 数据等待中断
      DL_SPI_receiveData8 (SPI_0_INST);
      
      /*
       *配置 DMA 源、目标和从 RXDATA 到 rx_pbuf 的大小。
       *在设置 RX 中断时、DMA 传输将开始、发生这种情况
       设备接收到数据时。
       */
      DL_DMA_setSrcAddr (DMA、DMA_CH1_CHAN_ID、(uint32_t)(&SPI_0_INST->RXDATA));
      DL_DMA_setDestAddr (DMA、DMA_CH1_CHAN_ID、(uint32_t)&rx_pbuf[0])
      DL_DMA_setTransferSize (dma、dma_ch1_chan_ID、rx_len);
      DL_DMA_enableChannel (DMA、DMA_CH1_CHAN_ID);

      /*
       *在睡眠模式下等待、直到 SPI_PACKET_SIZE 字节已传输
       *从 SPI TXFIFO 到 rx_pbuf、同时触发 DMA 中断
       */
      while ((false == gDMARXDataTransfered)&&(rx_len > 0)){
        //生成 SCLK、直到 rx_len 请求的字节数已被读取
        DL_SPI_transmitData8 (SPI_0_INST、0x00);
      }

      DL_GPIO_setPins (GPIOA、cs_pin);

      返回;
    }