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.

TMS320F28377D: 使用spi与外设进行通讯时通信速度很慢

Part Number: TMS320F28377D
Other Parts Discussed in Thread: C2000WARE

 最近在使用spi方式与w5500外设芯片进行通信时发现通信速度非常慢,以下是我的spi配置程序:


GpioCtrlRegs.GPBPUD.bit.GPIO63 = 0; // Enable pull-up on (SPISIMOA)
GpioCtrlRegs.GPCPUD.bit.GPIO64 = 0; // Enable pull-up on (SPISOMIA)
GpioCtrlRegs.GPCPUD.bit.GPIO65 = 0; // Enable pull-up on (SPICLKA)

GpioCtrlRegs.GPBQSEL2.bit.GPIO63 = 3; // Asynch input GPIO (SPISIMOA)
GpioCtrlRegs.GPCQSEL1.bit.GPIO64 = 3; // Asynch input GPIO (SPISOMIA)
GpioCtrlRegs.GPCQSEL1.bit.GPIO65 = 3; // Asynch input GPIO (SPICLKA)

GpioCtrlRegs.GPBGMUX2.bit.GPIO63 = 3;
GpioCtrlRegs.GPCGMUX1.bit.GPIO64 = 3;
GpioCtrlRegs.GPCGMUX1.bit.GPIO65 = 3;

GpioCtrlRegs.GPBMUX2.bit.GPIO63 = 3; // Configure GPIO63 as SPISIMOA
GpioCtrlRegs.GPCMUX1.bit.GPIO64 = 3; // Configure GPIO64 as SPISOMIA
GpioCtrlRegs.GPCMUX1.bit.GPIO65 = 3; // Configure GPIO65 as SPICLKA

DevCfgRegs.CPUSEL6.bit.SPI_B = 0x1;//配置spi为CPU2所有
ClkCfgRegs.LOSPCP.bit.LSPCLKDIV = 0x0;//设置低速外设时钟为200mhz
EDIS;

GPIO_SetupPinMux(66, GPIO_MUX_CPU2, 0);
GPIO_SetupPinOptions(66, GPIO_OUTPUT, GPIO_PULLUP);//配置SCSN为普通io口

void spi_init()
{
SpibRegs.SPICCR.all =0x0067; // 先复位
SpibRegs.SPICTL.all =0x0006; // Enable master mode, normal phase,
// enable talk, and SPI int disabled.
SpibRegs.SPIBRR.all =0x3;
SpibRegs.SPICCR.all =0x00E7; // 使能 高速模式 下降沿输出 8位字符长度
SpibRegs.SPIPRI.bit.FREE = 1; // Set so breakpoints don't disturb xmission
}

我查询了ti官方给的器件手册,理论上来说spi的波特率应该能达到最高50mhz,后来发现不能超过gpio口的切换速率也就是25mhz,经过我自己的计算如果是25mhz整个发送流程下来应该在17us左右,而用示波器测量发现需要30us。而且最让我疑惑的一点是如果波特率上限为25mhz,当我将lspclk分别设置为200mhz和100mhz,分频后对应波特率50mhz和25mhz,两者最终需要的时间为30us和42us,也就是说我设置波特率为25mhz跟50mhz应该是差不了多少的(因为波特率上限为25mhz),结果却与我所想的相差很多,希望有前辈能解答疑惑。

  • 您好,我们已收到您的问题并升级到英文论坛寻求帮助,如有答复将尽快回复您。谢谢!

  • 您好,

    理论上来说spi的波特率应该能达到最高50mhz,后来发现不能超过gpio口的切换速率也就是25mhz,

    多路复用器设置看起来没问题,设置了 HS_MODE 位,因此配置是ok的。 您的意思是,您已经把所有器件配置为50MHz,但 SPICLK 信号在示波器上看起来不对劲吗?此外请问您电路板上连接的 SPI 总线是连接到哪里。 高速模式的所有数据表规格假设 SPI 引脚上的负载电容为5pF。 

    经过我自己的计算如果是25mhz整个发送流程下来应该在17us左右,而用示波器测量发现需要30us。

    您在这里指的应该是要传输的多个 SPI 字符。 请记住整个传输时间取决于 CPU/DMA 效率,而不仅仅是 SPI 时钟速率。  请问您看过 SPI 信号吗? 如果字符之间存在间隙,那么就表示吞吐量效率低下,需要进行调整。 

  • 你好,我电路板上spi总线连接到了w5500的以太网芯片,引脚之间是直接连在一起的。至于spiclk信号由于电路板上没有过孔,测试时很容易和其他引脚搭在一起因此还没有测试,我之后会注意测量一下该信号的波形。你提到的传输速率不仅取决于spi速率还和CPU的处理效率有关,如果字符之间有着较大的间隔时间,那应该要如何解决呢。

  • 好的,我们跟进给工程师看下,应该会在下个工作日给到您答复。

  • 您好,

    您可以使能 SPI FIFO 来提高传输效率。 C2000ware 中有提供如何使能 FIFO 的示例。 

  • 你好,我按照你的提示使能了SPI FIFO,但测试结果发现使用FIFO后比之前的标准模式速度还要慢,请帮我看一下spi配置和发送函数有无问题。

    spi配置:

    SpibRegs.SPICCR.all =0x0067; // 先复位,数据下降沿输出,上升沿输入,8位字符长度
    SpibRegs.SPICTL.all =0x0006; // Enable master mode, normal phase,
    // enable talk, and SPI int disabled.
    SpibRegs.SPIBRR.all =0x3;

    //FIFO模式设置
    SpibRegs.SPIFFTX.all=0x4004; //发送FIFO使能,txfifo中数据少于4个字符时触发中断
    SpibRegs.SPIFFRX.all=0x0061; //接收FIFO使能,rxfifo中有数据时触发中断

    SpibRegs.SPIPRI.bit.FREE = 1; // Set so breakpoints don't disturb xmission

    SpibRegs.SPIFFTX.all=0xE004; //离开复位
    SpibRegs.SPIFFRX.all=0x2061; //离开复位
    SpibRegs.SPICCR.all =0x00E7; // 使能 高速模式 下降沿输出 8位字符长度

    spi发送函数:

    uint8 IINCHIP_SpiSendData(uint8 dat)
    {
    uint8 SPIRXD;
    while(SpibRegs.SPISTS.bit.BUFFULL_FLAG == 1);//保证上一个字符已经传入移位寄存器
    SpibRegs.SPITXBUF=(dat<<8);
    //while(SpibRegs.SPIFFRX.bit.RXFFST !=1);//Wait until data is received
    SPIRXD = SpibRegs.SPIRXBUF;
    return SPIRXD;
    }

  • 好的,我们跟进给工程师看下是否有问题。

  • 您好,

    SPI FIFO 允许您一次写入多个字符,从而提高传输效率。 一个空的 TX FIFO 最多可写入16个字符。 例如,您可以poll,直到 SpibRegs.SPIFFTX.bit.TXFFST < 4,然后向 TX FIFO 写入12个字符。 或者您可以使用 SPI TX 中断在 TXFFST < 4时收到通知。 

    在您提供的代码中,似乎只向 TX FIFO 写入一个字符,并不能充分利用 FIFO。 您还在将数据写入 SPI 之前进行polling,这也会增加延迟。 

    想请问下您想为 w5500生成的命令或帧序列是什么?而在这其中传输效率是最重要的?此外请注意,对于短帧/小帧来说,会始终存在开销,因此始终无法实现100%的传输效率(即50Mbps)。 

  • 你好,以我目前的理解数据是从spitxbuf-->spififo-->spidat。那么我应该怎么一次性向spififo中写入多个字符呢,给5500生成的命令包括4个8位的字符,生成的数据帧包含23个8位的字符(20个数据和3个地址位)

  • 我们跟进给工程师看下哈。

  • 您好,

    任何对 SPITXBUF 寄存器的back-to-back写入操作都将会直接进入 FIFO 的顶部。 您可以参考下图:

  • 以下是我修改后的代码:

    uint8 IINCHIP_SpiSendData(uint8 dat)
    {
    uint8 SPIRXD;
    SpibRegs.SPITXBUF=(dat<<8);
    while(SpibRegs.SPIFFRX.bit.RXFFST == 0);//Wait until data is received
    SPIRXD = SpibRegs.SPIRXBUF;
    return SPIRXD;
    }

    void IINCHIP_WRITE( uint32 addrbsb, uint8 data)//向5500中写入spi数据帧,其中addbsb为32位的偏移地址+8位的控制段,有效数据为后24位
    {
    //FIFO模式命令写入
    IINCHIP_CSoff(); // CS=0, SPI start
    while(SpibRegs.SPIFFTX.bit.TXFFINT != 1);//保证上一个命令已经传入移位寄存器
    IINCHIP_SpiSendData((addrbsb & 0x00FF0000)>>16);
    IINCHIP_SpiSendData((addrbsb & 0x0000FF00)>> 8);
    IINCHIP_SpiSendData((addrbsb & 0x000000F8) + 4);
    IINCHIP_SpiSendData(data);
    IINCHIP_CSon(); // CS=1, SPI end

    }

    所以FIFO模式是否只是减少了读标志位判断字符是否传输完成的次数,因为每次数据写入之前都需要确保上一次的数据传输完成,而每次传输完一个字符之后还要读取5500外设发送过来的数据值,那感觉比标准模式并快不到哪去啊。

  • 工程师会按照如下方式编写 SpiSendData: 

    Fullscreen
    1
    2
    3
    4
    5
    void IINCHIP_SpiSendData(uint8 dat)
    {
    while(SpibRegs.SPIFFTX.bit.TXFFST >= 16);//Wait until there is space in TX FIFO
    SpibRegs.SPITXBUF=(dat<<8);
    }
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    由于 RX 数据未被使用,您可以使用单独的函数从 RX FIFO 虚拟读取数据或复位 RX FIFO 来回收数据。

    这可以略微点提高性能,因为字符之间不会出现断点。 但是,总体性能提升将取决于使用 IINCHIP_WRITE 的次数。 如果一段时间内只使用一次,那么可能不会有太大改进。