Setting SPI.frequency, how does it work?

Hi,

I’m running a master-slave communication with the boards: Nucleo STM32-F746ZG (master) and F103RB (slave).

Now, when I set spi.frecuency() below 1.125MHz, I actually get a frequency of ~ 0.56MHz, if I set it higher, I get ~ 1.12MHz. Why are there only two modes, why can’t I “tune” it to the frequency I want (0.8MHz)?

I looked at the spi.frequency implementation code and it looks like this:

  void spi_frequency(spi_t *obj, int hz)
{
    ssp_disable(obj);

    uint32_t PCLK = SystemCoreClock;

    int prescaler;

    for (prescaler = 2; prescaler <= 254; prescaler += 2) {
        int prescale_hz = PCLK / prescaler;

        // calculate the divider
        int divider = floor(((float)prescale_hz / (float)hz) + 0.5f);

        // check we can support the divider
        if (divider < 256) {
            // prescaler
            obj->spi->CPSR = prescaler;

            // divider
            obj->spi->CR0 &= ~(0xFFFF << 8);
            obj->spi->CR0 |= (divider - 1) << 8;
            ssp_enable(obj);
            return;
        }
    }
    error("Couldn't setup requested SPI frequency");
}

Can anyone help me understand the reason why the frequency in reality seems to shift between two different values when I set it below and above a certain threshold?

More details about my setup:
*The slave code uses the low level HAL functions, but the master uses the normal mbed spi API
*The two boards are connected through isoSPI interface boards on each side

Many thanks in advance to whoever can give me any input on this,
Julia

This is something I wrote for our team a while back, it might be helpful :slight_smile:

SPI

SPI Clock Frequency

Source: Mbed ST Wiki / SPI output clock frequency

Based on the source documentation, we are able to define the SPI clock frequency for the STM32F7 family of MCUs:

// [...]

case SPI_6:
    /* SPI_1, SPI_4, SPI_5 and SPI_6. Source CLK is PCKL2 */
    spi_hz = HAL_RCC_GetPCLK2Freq();
    break;
case SPI_2:
case SPI_3:
    /* SPI_2 and SPI_3. Source CLK is PCKL1 */
    spi_hz = HAL_RCC_GetPCLK1Freq();
    break;

// [...]
#if ((CLOCK_SOURCE) & USE_PLL_HSI) // <-- we are using USE_PLL_HSI

// [...]

RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;           //  54 MHz
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;           // 108 MHz

// [...]
Clock PCKL1 PCKL2
SPI SPI_1, SPI_4,
SPI_5, SPI_6
SPI_2,
SPI_3
Base Clock 54 MHz 108 MHz
Scalar PCKL1 PCKL2
2 27 MHz 54 MHz
4 13.5 MHz 27 MHz
8 6.75 MHz 13.5 MHz
16 3.38 MHz 6.75 MHz
32 1.69 MHz 3.38 MHz
64 843.75 kHz 1.69 MHz
128 421.88 kHz 843.75 kHz
256 210.94 kHz 421.88 kHz

Now if you want to have a SPI output frequency around 1.5 MHz, you will need to pass a value above 1.69 MHz and below 3.38 MHz when you call the SPI frequency method.

SPI mydevice(SPI_MOSI, SPI_MISO, SPI_SCK);
mydevice.frequency(1800000); // real value = 1.69 MHz
1 Like

The frequency setting is limited by the hardware, the divider is 2 ^n. On other controllers, e. g. NXP LPC, it can be a decimal value and you get a finer graduation.
Some STM controllers have also the choice of a different clock source, but this is not handled by the default SPI class.

1 Like

Thank you, that explains it very well!