cancel
Showing results for 
Search instead for 
Did you mean: 

NUCLEO-STM32F429 SPI at MAX speed (45 MHz)

AP_040
Senior

Hello,

I have NUCLEO-STM32F429ZI kit and I want to operate the SPI as max speed. So, I design one simple example like make SPI1 as Slave and SPI4 as a master mode.

This is worked for SPI_BAUDRATEPRESCALER_8 (11.25 MHz), SPI_BAUDRATEPRESCALER_16 (5.625 MHZ) however, when I changes this prescaler to SPI_BAUDRATEPRESCALER_4 (22.5 MHz) and SPI_BAUDRATEPRESCALER_2 (45 MHz), it is not working.

Any additional setting may required to operate at 45 MHz frequency?.

Can some one help me.

1 ACCEPTED SOLUTION

Accepted Solutions
berendi
Principal

> Instead of using the HAL driver, I used direct transmit/receive by DR.

The attached code still uses the HAL driver.

> Can you please give some further help to do this?

Count the cycles first. If the core frequency is 180 MHz and the SPI bitrate is 45 MHz, then one bit is sent every 4 cycles, one byte in every 32 cycles.

With 5 flash wait states, an optimized interrupt handler might be able to read the data register in time, but I'm not entirely sure. HAL interrupt handlers are as far from being optimized as you can get without inserting deliberate delays.

Read about DMA in the reference manual, both its own chapter and the section titled SPI communication using DMA. There is no other way for a slave to receive at 45 MHz.

You might have to set the SPI_CR1_RXONLY bit for it to work as well.

View solution in original post

9 REPLIES 9
S.Ma
Principal

In general, max slave speed is 1/2 of master's ==> DIV4

When above 20 MHz, you will need a scope to check signal integrity (especially through flying wires)

The GPIO SPEED parameter needs to be tuned.

Application test: 12MHz SPI over a meter and talking to 12 slaves through daisy chain connector is working fine. (SYSCLK 48MHz on STM32L4R)

0693W000000X2IhQAK.jpg

AP_040
Senior

Yes, I already configured the GPIO at very High speed.

Due to the WFH, I can't test on scope.

I configured the NUCLEO-STM32F429ZI to 180 MHz clock and for SPI we can use (APB2 = 180/2) , SPI Clock = APBx / prescaler (45 MHz) as per prescaler setting.

My requirement is to just connect only one slave. Is there any additional settings may required in firmware to working the SPI at 45 MHz?.

berendi
Principal

1. SPI slave mode transmit or full duplex mode is supported only up to 38 MHz, see the datasheet.

2. PA7 SPI1 MOSI is connected to the onboard ethernet controller. Try it with an alternate pin.

3. The code might be too slow to handle the data rate.

You can test some aspects with an experiment. Start with the project generated from the attached .ioc file. Locate the PLLP setting in the SystemClock_Config() function in main.c, and replace it with 8 (original value should have been 2). Does it work now?

(Adjusting the PLL configuration in CubeMX is not exactly the same, because CubeMX tries to be smarter, and lowers the number of flash wait states, resulting in faster code execution).

Now the SPI clock should be 11.25 MHz like in your working case, but the software runs at exactly 1/4 of the speed. If it starts working, then the hardware is at fault. If it doesn't, then get rid of HAL SPI functions, and rewrite them using direct register accesses as documented in the reference manual.

(Adjusting the PLL configuration in CubeMX is not exactly the same, because Cube tries to be smarter, and lowers the number of flash wait states, resulting in faster code execution).

AP_040
Senior

Hello @berendi​ , Thank you so much for your suggestion.

I tested with all three suggestion but it didn't worked.

I changed the PA7 SPI1 MOSI pin to PB5. Instead of using the HAL driver, I used direct transmit/receive by DR.

Can you please give some further help to do this?.

berendi
Principal

> Instead of using the HAL driver, I used direct transmit/receive by DR.

The attached code still uses the HAL driver.

> Can you please give some further help to do this?

Count the cycles first. If the core frequency is 180 MHz and the SPI bitrate is 45 MHz, then one bit is sent every 4 cycles, one byte in every 32 cycles.

With 5 flash wait states, an optimized interrupt handler might be able to read the data register in time, but I'm not entirely sure. HAL interrupt handlers are as far from being optimized as you can get without inserting deliberate delays.

Read about DMA in the reference manual, both its own chapter and the section titled SPI communication using DMA. There is no other way for a slave to receive at 45 MHz.

You might have to set the SPI_CR1_RXONLY bit for it to work as well.

S.Ma
Principal

I only use full duplex as in this mode, master has control of sck generation. trick for slave is to use DMA in circular mode for both rx and tx channel, and get EXTI interrupts only, from the NSS gpio. make sure your protocol and implementation takes care of interrupt latency so put small delay when toggling NSS, for example.

AP_040
Senior

Hello @berendi​ Thank you so much for your valuable feedback.

In my existing code, I changed the polarity and phase (High/2edge - SPI MODE 3) and it is working. SPI4 is master send a data and SP1 slave is received that data (master is not receive any data and slave is not transmit any data in this demo example).

On the other hand, when I used same in my application with SPI master can send/receive by using the interrupt somehow it is not working. I used this three API HAL_SPI_Transmit_IT(), HAL_SPI_Receive_IT(), and HAL_SPI_TransmitReceive_IT().

I have not more knowledge about how to handle interrupt for this. Can you give some hint.

AP_040
Senior

Hello @berendi​ , After a few days, I have worked for this and as per your suggestion, I have read the SPI communication using DMA section in the reference manual.

By implementing the same (DMA) in the firmware, I got the success.

Thank you..!!!

AP_040
Senior

Hello Community members,

As by enabling the DMA, I successfully communicate with SPI slave at 22.5 MHz. However, my requirement is to work at 45MHz.

Here is my DMA settings:

  /* SPI1 DMA Init */

/* SPI1_RX Init */

hdma_spi1_rx.Instance = DMA2_Stream0;

hdma_spi1_rx.Init.Channel = DMA_CHANNEL_3;

hdma_spi1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;

hdma_spi1_rx.Init.PeriphInc = DMA_PINC_DISABLE;

hdma_spi1_rx.Init.MemInc = DMA_MINC_ENABLE;

hdma_spi1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

hdma_spi1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

hdma_spi1_rx.Init.Mode = DMA_NORMAL;

hdma_spi1_rx.Init.Priority = DMA_PRIORITY_VERY_HIGH;

hdma_spi1_rx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

if (HAL_DMA_Init(&hdma_spi1_rx) != HAL_OK)

{

Error_Handler(__FILE__,__LINE__);

}

__HAL_LINKDMA(hspi,hdmarx,hdma_spi1_rx);

/* SPI1_TX Init */

hdma_spi1_tx.Instance = DMA2_Stream3;

hdma_spi1_tx.Init.Channel = DMA_CHANNEL_3;

hdma_spi1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

hdma_spi1_tx.Init.PeriphInc = DMA_PINC_DISABLE;

hdma_spi1_tx.Init.MemInc = DMA_MINC_ENABLE;

hdma_spi1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

hdma_spi1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

hdma_spi1_tx.Init.Mode = DMA_NORMAL;

hdma_spi1_tx.Init.Priority = DMA_PRIORITY_VERY_HIGH;

hdma_spi1_tx.Init.FIFOMode = DMA_FIFOMODE_DISABLE;

if (HAL_DMA_Init(&hdma_spi1_tx) != HAL_OK)

{

Error_Handler(__FILE__,__LINE__);

}

__HAL_LINKDMA(hspi,hdmatx,hdma_spi1_tx);

Do I need to change it to some settings. I tried with circular mode, not working.

Can someone help me.