SPI写STM32很慢

Very slow SPI writing STM32

我目前正在编写代码,逐个像素地在 LCD 屏幕上书写。代码工作正常,但是处理代码的速度非常慢。目标只是在 LCD 屏幕上写数字,所以我使用 "switch" 函数和 "for loop" 来读取我将激活的每个位。我想知道是否有人可以告诉我一种加速我的代码的方法...

int* switch_library_number_1(int num, int octet) {

switch(num)
{

case 0 : ;
    int number_0 [] = {0x80, 0x08,
              0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x88,
              0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x00, 0x00, 0x00, ...};

        int * pNumber_0 = &number_0[octet];

        return pNumber_0;
          break;

case 1 : ;
    int number_1 [] = {0x80, 0x08,
              0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x88, ...};

    int * pNumber_1 = &number_1[octet];

    return pNumber_1;
      break;
}

然后就这样上升到九个,我认为您不需要查看所有案例。另外,即使我删除了其中的大部分,我也有 522 个字节的数字。其余代码作为休假:

int main(void)
{
ADC_Initialization();
SPI_Initialization();
int nombre_octet = 522;
int premier_nombre;
int deuxieme_nombre;

while(1)
{
    GPIOA->BSRRL = CS;
    for(int i = 0; i < nombre_octet; i++)
    {
        write_spi(*switch_library_number_1(0, i));
    }
    GPIOA -> BSRRH = CS;

    for(int i = 0; i < 100; i++)
            {
            }

    GPIOA->BSRRL = CS;
    for(int i = 0; i < nombre_octet; i++)
    {
        write_spi(*switch_library_number_2(1, i));
    }
    GPIOA -> BSRRH = CS;

    }
}

最后,这里是 write_SPI 函数,但由于它的简单性,我不认为这是问题所在。

void write_spi(char data)
{
    SPI1->DR = data;

    while (!(SPI1->SR & SPI_I2S_FLAG_TXE));
    while (!(SPI1->SR & SPI_I2S_FLAG_RXNE));
    while (SPI1->SR & SPI_I2S_FLAG_BSY);
}

提前致谢!

我非常喜欢您将代码分成三个片段的方式。我可以为他们每个人提出改进建议:

switch_library_number_1():

  • 这可能只是一个二维数组,number[][],或者如果 number_0number_1... 的长度不同,它可能是指向的指针数组这些。需要检查有效的 numoffset。这可能是一个小的速度改进。
  • 您的 number_0... 数组当前在堆栈上,并且是可读写的。让它们 const,这样它们就不会使用 RAM。
  • 目前您正在返回指向堆栈上内存位置的指针 - 这通常不会起作用,如果它起作用,那是出于运气和意外。当您超出定义范围(功能)时,您不应访问堆栈数据。 static const 将使它安全,因为它不再在堆栈上。

主循环:

  • 在每次循环迭代中调用 switch_library_number_1/2 有点奇怪。你知道你的数据只是在数组中。如果 number 数组设置正确,这可能会被 write_spi(number[0][i]); 取代。这应该可以提高您的速度,因为它大大简化了数据获取。
  • 您的循环似乎很忙。这是一个棘手的做法(我打赌 100 是一个猜测,请注意编译器可以优化这个循环)。如果可能使用某些库提供的延迟函数或计时器来获得精确的延迟。这是 SPI 从设备的实际要求吗?

write_spi(字符数据):

  • char 这里应该是 unsigned charchars 可能是有符号的或无符号的,所以当您将它们用作字节(而不是实际的字符串字符)时,您应该指定有符号。
  • 你似乎在等待每个字节传输完成,这是安全的,但有点慢。通常这可以重写为 wait_for_SPI_ready_for_TX; SPI_TX 的更快替代方案,您只需在发送下一个字节之前等待。请注意,您还需要等待字节完全传输后再将 CS 拉回高电平。这可能是一个很大的速度提升。

其他一些需要考虑的事情:

  • 实际的 SPI 时钟是多少?如果增加时钟,速度可能会有很大的提高。
  • 你是如何衡量这个 "slow" 的?它是否指向代码的缓慢部分(那是什么?如果从 C 中不明显,它们被组装成什么?)
  • 您有 oscilloscope/logic 分析仪来查看线路上的实际信号吗?这可能会提供有用的数据。

我在 STM32F207 系列 Cortex-M3 控制器上遇到了类似的问题,当我通过振荡器观察 TX 线时,我看到 CHIP_SELECT disable 设置的时间太长了,毕竟所有数据都有sent.I 发现它与标志控制有关所以我稍微玩了一下控制标志,这对我来说效果很好;

static void SPI_Send(uint16_t len,uint8_t* data)
{
   uint16_t i;

   for(i = 0;i<len;i++)
   {        
     SPI_I2S_SendData(SPI1,*(data+i));
     while(!(SPI1->SR & SPI_SR_TXE));   
   }    
   while(SPI1->SR & SPI_SR_BSY);
   CHIP_SEL_DISABLE;
}

我认为它很慢,因为您还在检查不需要的 'Receive Buffer Not Empty'。