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.

[参考译文] MSP432P401R:如何在 SPI 上加快传输速度?

Guru**** 2401325 points
Other Parts Discussed in Thread: ADS131A04

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/627319/msp432p401r-how-to-transmit-faster-on-spi

器件型号:MSP432P401R
主题中讨论的其他器件:ADS131A04

 

您好! 我正在使用 MSP432与 ADS131A04 ADC 进行通信、 我希望以10.24kHz 数据速率使用 ADC。

问题是、在新数据可用之前、我无法足够快地读取通道数据。 在10.24kHz 时、我需要读取最大值~100us。 在读取函数中、我在 while 环路中等待下一个 DRDY 中断。

我已附加以下逻辑分析仪捕获(可以使用免费的 Salae Logic Pro 软件打开它们;通道4为 DRDY):

1kHz  数据速率、1MHz SPI 时钟-字节时间为8us、字节之间的时间为~8us、字时间~314us;

2.  1kHz 数据速率、4MHz SPI 时钟-字节时间为4us、字节之间的时间为~10us、字时间~253us;

3kHz  数据速率、8MHz SPI 时钟- 字节时间为1us、字节之间的时间为~7us、字时间~170us;

10.24kHz 数据速率、8MHz SPI 时钟- 字节时间为1us、字节之间的时间为~7us、字时间~170us;您可以在读取所有数据之前看到 DRDY 发生变化;

您可以找到所附的示波器屏幕截图、其中显示了 1kHz 数据速率、24MHz SPI 时钟下的 MISO。 这些行是构成字的20个字节、字的传输持续时间为~170us。

我需要一个小于100us 的字传输时间、以便能够及时读取下一个样本。 24MHz 是 MSP432可以提供的最大 SPI 时钟、25MHz 是 ADC 接受的最大 SPI 时钟。 7us 表示在48MHz 下 MSP432为336个周期。 这些周期花费在何处?

这是我的代码:

对于(i = 0;i < noSamples;i++)
    {
        while (adcSampleAvailable=false)//等待!DRDY
        {
            //map_PCM_gotoLPM0InterruptSafe ();
            //map_Interrupt_enableMaster ();
        }
        adcSampleable = false;

        //读取样本
        = ADS1304_enable_read (ADS1304); // rxSTAT_1 x 4字节+ 4通道 x 4字节

        *(readDataCh1 + I)=(*(rxData + 4)<< 16)|(*(rxData + 5)<< 8)|(*(rxData + 6));
        *(readDataCh2 + I)=(*(rxData + 8)<< 16)|(rxData + 8)|(*(rxData + 8)+ 8)
        *(readDataCh3 + I)=(*(rxData + 12)<< 16)|(*(rxData + 13)<< 8)|(*(rxData + 14));
        *(readDataCh4 + I)=(*(rxData + 16)<< 16)|(*(rxData + 17)<< 8)|(rxOutputchar +
    


1
    )*(rnunsigned p1) p1)*(rnat_r_rgp1) p1 (r_rgp1)/rgp1 (rnat_r_r_out1) //!ADC_SPI_CS = 0

    int byte = 0;
    int count = bytesNumber;
    if (bytesNumber > ADS131A04_MAX_RX_Bytes) count = ADS131A04_MAX_RX_Bytes;

    for (byte = 0;byte < count;byte++)
    {
        while (adctxFlag = false)
        {
            // tobl_transmit_0_trap_transmit_trap_b.0_transmit_trap_b.0_transmit_b./trap_transmit_trap_b.0_transmit_trap_transmit_b.0_transmit_trap./trap_transmit_transl./
            
        
        

        //虚拟写入时钟输出数据

        ,同时(adcRxFlag = false)
        {
            //map_PCM_receivoLPM0InterruptSafe ();
            // map_Interrupt_enableMaster ();
        }
        adcRxFlag = false;

        rxData[byte]= map_spi_receiveData (eUSCI_B0_BASE);}map_enable_at_port
    

    

    




    
    = void);}adcrupt_at_at_at_at_p4 (p1)
    ;// p2_gpio_at_en_rupt_at_at_rupt_at_at_p1 (p1);// p4 pio_en_en_at_at_rupt_at_at_e+!
    if (status & GPIO_PIN0)// ADC!DRDY
    {
        if (MAP_GPIO_getInputPinValue (GPIO_PORT_P4、GPIO_PIN0)=0)
        {
            adcSampleAvailable= true;
            MAP_Interruptable_disableSlepOnIsExit ();
        }
    


}void EUSCIB0_IRQHandler
=
   
   
   
   
   
       
   
   
   {ad_Interrupt_SPI = true;ap_disable_transmit = void (v_disableSPI);ap_interrupt_transmit = void (v_bspi_status_is_is_translupt_transmit);}(v_is_is_is_is_is_is_is_is_transmit
       
   
   MAP_Interrupt_disableSlepOnIsrExit();
} 

我该怎么做才能更快地读取数据? 它是 MSP432的限制吗?

e2e.ti.com/.../Captures.zip

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    复杂性增加:
    1) 1)免除中断。 在 SPI 时钟速度较高的情况下、中断只会减慢您的速度。
    2)放弃库调用(可能很便宜、可能不便宜)并直接检查寄存器位。
    3) 3)使用 DMA。 对于20字节的事务、设置开销会发生摊销。 您可能可以通过预先设置大多数 DMA 块字段并在正确的时间进行(最小)记账来改进此功能。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    感谢您的建议。 在不使用 DMA 的情况下、我设法将字持续时间减少到22us @ 24MHz SPI 时钟(字节时间为0.33us、字节之间的时间为0.87us)。 我删除了等待 TX/RX 中断的 while 循环、禁用了这些中断、并在写入和读取之间添加了7个周期的延迟(周期更少、不起作用)。

    这是我的代码、以防对任何人都有帮助:

    unsigned char* ADS131A04_read (unsigned char bytesNumber)
    {
    MAP_GPIO_setOutputLowOnPin (GPIO_PORT_P1、GPIO_PIN4);//!ADC_SPI_CS = 0
    
    int byte = 0;
    int count = bytesNumber;
    if (bytesNumber > ADS131A04_MAX_RX_Bytes) count = ADS131A04_MAX_RX_Bytes;
    
    for (byte = 0;
    + byte)
    /*while (adcTxFlag == false)
    {
    //map_PCM_gotoLPM0InterruptSafe ();
    //map_Interrupt_enableMaster();
    }
    adcTxFlag = false;*
    
    //MAP_SPI_transmitData (EUSCI_B0_BASE、0x00);//虚拟写入以时钟输出数据
    EUSCI_B0->TXBUF = 0x00;//速度更快
    
    _DELAY_CYCLLES (7);// 24MHz 时为7;4MHz 时为40、1MHz 时为150
    /*while (adcRxFlag == false)
    {
    //map_PCM_gotoLPM0InterruptSafe ();
    //map_Interrupt_enableMaster();
    }
    adcRxFlag = false;*
    
    //rxData[Byte]= MAP_SPI_receiveData (EUSCI_B0_BASE);
    rxData[byte]= EUSCI_B0->RXBUF;//更快
    }
    
    MAP_GPIO_setOutputHighOnPin (GPIO_PORT_P1、GPIO_PIN4);//!ADC_SPI_CS = 1
    
    返回 rxData;
    } 

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

    我将在中指出这一点:您应该考虑将__delay_cycles 替换为"while (!(EUSCI_B0->IFG & UCRXIFG))/*empty*/;"

    这样做会使代码针对任何 SPI 时钟和优化级别设置正确、代价是介于"0"和"小"之间。

    (注:读取 RXBUF 会将 UCRXIFG 清零。 通常、您也希望检查 TXIFG、但(正如您明显注意到的)通过保持"管道"大小<=1字节、您可以保证 TXIFG 在需要时始终置位。)

    可能会(或可能不会)对此造成小的(< 5个时钟或左右)损失:如果根据编译器生成的代码、IFG 的首次获取时间少于7个时钟、您将"错过"第一个循环和(始终)循环两次。 一旦、当我真正关心它时、我在循环中使用了"do{_NOP();}while (!(EUSCI_B0->IFG & UCRXIFG));"等类似的操作、并调整了_ NOP 的数量。 这使它第一次在最高速度下"命中"、但在任何其他速度下仍然是正确的。

    我建议您进行 UCRXIFG 检查、因为它将避免许多未来的麻烦。 您是否要进一步弄乱取决于您是要寻找"更好"还是"足够好"。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    再次感谢您! 使用 while 循环、字的持续时间从22us 增加到~31us、这是可以接受的。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    这比我预期的要大。

    另一方面,"足够好"有很多话要说。