cancel
Showing results for 
Search instead for 
Did you mean: 

HAL_SPI_Transmit takes too long

e d
Associate II
Posted on May 22, 2017 at 19:51

Hi guys,

I am working with the STM32L486 using the CubeMX tool and running into some SPI issue that I can't seem to figure out (I am new to ST chipsets btw). Specifically the

HAL_SPI_Transmit routine takes to long compared to the fraction of the time the data is transmitted, as can be seen in the scope image below with yellow being the clock, blue being the data and pink the test point PA0_SET I wiggle (code below). The scope shows that theHAL_SPI_Transmit takes up to 4uS, which is ridiculous. Any idea how to speed this up close to the time it takes for the data to transmit (around 1.44uS)?

Thanks,

ED

PA0_SET;

Spi.Status = HAL_SPI_Transmit(&hspi2,(uint8_t *) &DDS_Cmd, sizeof(DDS_Cmd)>>1, 2);

PA0_CLEAR;

0690X000006072dQAA.png

#hal_spi_transmit

Note: this post was migrated and contained many threaded conversations, some content may be missing.
1 ACCEPTED SOLUTION

Accepted Solutions
Posted on May 24, 2017 at 16:09

I used the higher level initialization function HAL_SPI_Init(); followed by LL_SPI_Enable(SPI2);

The latter may be what you are missing.  Also, you may need to enable the clock for GPIOB.

View solution in original post

10 REPLIES 10
Chris1
Senior III
Posted on May 23, 2017 at 16:05

Consider use of the Low Level HAL functions, especially if you are writing a small number of bytes.

For example:

static void SPI2_WriteByte (uint8_t tx_byte)

{

    uint32_t start_time_w;

    uint32_t this_time_w;

    while (!LL_SPI_IsActiveFlag_TXE(SPI2))

    {

        ;

    }

    start_time_w = HAL_GetTick();

    LL_SPI_TransmitData8(SPI2, tx_byte);

    while (LL_SPI_IsActiveFlag_BSY(SPI2))

    {

        this_time_w = HAL_GetTick() - start_time_w;

        if (this_time_w > SPI2_READ_TIMEOUT)

        {

            // timeout error!

            break; 

        }

    }

    LL_SPI_ClearFlag_OVR(SPI2); // clear overrun flag

}
e d
Associate II
Posted on May 23, 2017 at 20:02

Thanks Chris for the tip!

I tried to use LL with CubeMX to generate SPI instead of HAL and it wouldn't run (I don't see the clock coming). I think I am missing something simple but cannot put my finger on. The SPI init runs as follows:

/* SPI2 init function */

static void MX_SPI2_Init(void)

{

LL_SPI_InitTypeDef SPI_InitStruct;

LL_GPIO_InitTypeDef GPIO_InitStruct;

/* Peripheral clock enable */

LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_SPI2);

/**SPI2 GPIO Configuration

PB13 ------> SPI2_SCK

PB14 ------> SPI2_MISO

PB15 ------> SPI2_MOSI

*/

GPIO_InitStruct.Pin = LL_GPIO_PIN_13|LL_GPIO_PIN_14|LL_GPIO_PIN_15;

GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;

GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;

GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL;

GPIO_InitStruct.Pull = LL_GPIO_PULL_NO;

GPIO_InitStruct.Alternate = LL_GPIO_AF_5;

LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

SPI_InitStruct.TransferDirection = LL_SPI_FULL_DUPLEX;

SPI_InitStruct.Mode = LL_SPI_MODE_MASTER;

SPI_InitStruct.DataWidth = LL_SPI_DATAWIDTH_16BIT;

SPI_InitStruct.ClockPolarity = LL_SPI_POLARITY_HIGH;

SPI_InitStruct.ClockPhase = LL_SPI_PHASE_1EDGE;

SPI_InitStruct.NSS = LL_SPI_NSS_SOFT;

SPI_InitStruct.BaudRate = LL_SPI_BAUDRATEPRESCALER_DIV8;

SPI_InitStruct.BitOrder = LL_SPI_MSB_FIRST;

SPI_InitStruct.CRCCalculation = LL_SPI_CRCCALCULATION_DISABLE;

SPI_InitStruct.CRCPoly = 7;

LL_SPI_Init(SPI2, &SPI_InitStruct);

LL_SPI_SetStandard(SPI2, LL_SPI_PROTOCOL_MOTOROLA);

LL_SPI_EnableNSSPulseMgt(SPI2);

}

I send a simpel 0x5A5A (16 bit SPI) but see no clocks running. Please let me know what else is needed to get it going.

ED

Posted on May 24, 2017 at 16:09

I used the higher level initialization function HAL_SPI_Init(); followed by LL_SPI_Enable(SPI2);

The latter may be what you are missing.  Also, you may need to enable the clock for GPIOB.

e d
Associate II
Posted on May 25, 2017 at 23:57

Thank you so much Chris! I was missing the command:

LL_SPI_Enable(SPI2);

It runs twice as fast now, taking about 5uS instead of 11.4uS. Would love to run faster but you can never get away completely from all the flag checking customary with SPI I guess.

Posted on May 26, 2017 at 10:42

Hello Ed,

There is an alternative to implement a more real time solution : The Low Layer fonctions (LL) have been added in the STM32CubeL4 since v1.4.0 to drive the IPs more directly than the HAL Drivers. You can find these LL interface in the same Inc directory than HAL and discover several dedicated application examples in the Projects/''Board''/Examples_LL/SPI directory (for pure LL usage) or in the Projects/''Board''/Examples_MIX/SPI for an implementation based on HAL (for the control) and LL (for the data transfer)

Regards, Christophe

Posted on May 26, 2017 at 16:08

Hi Christophe, isn't that what Chris and I have been talking about or it is something else? I've switched my SPI from HAL to LL and it seems to run twice as fast using LL_SPI_TransmitData16() vs HAL_SPI_Transmit(). If you think I can do better with your suggestion please let me know.

Now I am battling another mystery with SysTick. After I changed the SPI to LL, it's seemed to run 3 times as fast at 330uS instead of 1ms. I think it is related to the LL SPI somehow. Any clue? Thanks!

Posted on May 26, 2017 at 20:04

SysTick operation should be unrelated to SPI functions.

Check the clock value definition that you are using (e.g., HSE_VALUE).  Sometimes this is defined as a compiler preprocessor symbol.

Similarly check the definition if you are using a symbol like OS_TICK_RATE_HZ.

Also look at the RCC clock configuration code.

If you want faster SPI operation, you could use LL_SPI_BAUDRATEPRESCALER_DIV2 rather than LL_SPI_BAUDRATEPRESCALER_DIV8, if your component can tolerate that.

It is possible to drive the SPI with a timer and DMA channel (e.g., memory to SPI transfer), this could achieve faster transmission but operates blindly (without checking SPI status) and handling the chip select can be a challenge (which can be overcome).

e d
Associate II
Posted on May 26, 2017 at 20:25

I don't see anything wrong with the HSE settings which is at 25MHz. My HCLK is at 50MHz, as is with all my peripheral and timer clocks. The other timers 2 and 3 run as expected so I disable the SysTick and run the 1ms ticks on timer 2 instead, without any issue.

Regarding the SPI are you referring to bit banging with the timer? I will take a look into the DMA suggestion later. Thanks

Amez-Droz.Philippe
Associate II
Posted on September 12, 2017 at 22:31

Hello,

I use the HAL Library (not the low level LL) on a STM32F407VGT which is a master of a communication with STM32F410RBT through SPI.

The communication is mainly OK but sometimes it's seems that there is a problem when an intterupt occurs during tje HAL_SPI_transmit execution.

What can I do?

How can I replace with the minimum of change trhe HAL Library with the LL Library?

Is the problem known or not?

I use the V1.4.4 version of the HAL Library. I am affraid to change to a new version because my soft is big and I am affraid to introduce new bugs.

Thank you for you help

Best regards