Search code examples
cperformancestm32stm32ldiscovery

Very slow SPI writing STM32


I am currently writing a code to write on an LCD screen pixel by pixel. The code works fine, however the speed at which the code is processed is incredibly slow. The goal is simply to write number on the LCD screen so I am using the "switch" function with a "for loop" to read each of the bit I will activate. I am wondering if someone could tell me a way to speed up my code...

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;
}

Then it goes up to nine like that, I don't think you need to seem all the cases. Plus even if I deleted most of them, I have 522 bytes by number. The rest of the code goes as fallow :

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;

    }
}

Finally, here is the write_SPI function, but due to it's simplicity, I don't think that it is the problem.

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);
}

Thanks in advance!


Solution

  • I quite like the way you split your code into three snippets. I can suggest improvements for each of them:

    switch_library_number_1():

    • This could be just a 2D array, number[][], or if number_0, number_1... are not of the same length, it could be an array of pointers to these. There would need to be checks for valid num and offset. This might be a minor speed improvement.
    • Your number_0... arrays are currently on stack, and read-write. Make them const, so they won't use RAM.
    • Currently you are returning a pointer to memory location on stack - this doesn't normally work, if it does it's by luck and accident. You should not access stack data when you're out of scope (function) where it's been defined. static const would make this safe, as it wouldn't be on stack anymore.

    main loop:

    • It's a bit odd to call switch_library_number_1/2 on each loop iteration. You know your data will just be in array. This could probably be replaced by write_spi(number[0][i]); if number array is properly set up. This should get you some speed improvement, as it very much simplifies data fetching.
    • You appear to have a busy loop. That's a tricky practice (I bet 100 is a guess, and note that compiler could optimise this loop away). If possibly use some library provided delay function or a timer to get precise delays. Is this an actual requirement of SPI slave?

    write_spi(char data):

    • char should be unsigned char here. chars might be signed or unsigned, so when you're using them as bytes (not actual string characters), you should specify signedness.
    • You seem to wait for every byte transmission to finish, which is safe, but a bit slow. Normally this can be rewritten into a faster alternative of wait_for_SPI_ready_for_TX; SPI_TX, where you only wait before sending next byte. Note that you will also need to wait for byte to be transmitted fully before pulling CS back high again. This could be a big speed improvement.

    Some other things to consider:

    • What's the actual SPI clock? There may be huge speed improvements if clock is increased.
    • How did you measure this to be "slow"? Does it point to slow parts of code (what are those then? If not obvious from C, what are they assembled to?)
    • Have you got an oscilloscope/logic analyser to look at actual signals on wire? This may provide useful data.