3 years, 10 months ago.

SPI SCLK frequency could not be changed on NUCLEO-F103RB

Hello, I tried to test SPI interface on NUCLEO-F103RB with mbed OS. And I faced strange behavior of the board something like the frequency of the SCLK pin was completely different from what I specify in the code, 100kHz. I confirmed that the SCLK frequency from the pin was 281kHz when the code was run on NUCLEO-F103RB.

I just specify the SCLK frequency other than 100kHz, like 1kHz, 1MHz and also default. but it did not work, NO effect on the frequency of the SCLK pin. that was stuck on 281kHz.

Does any one have ideas to solve this problem?

Thanks,

The code i tested on the board

#include "mbed.h"

    SPI device_1(D4, D5, D3);
    DigitalOut device_1_ss(PB_6);
    int main() {    
        device_1_ss = 0;
        device_1.frequency(100000);
        device_1.format(16,1);

        device_1_ss = 1;
        device_1.write(0x1111);
        device_1_ss = 0;
    }

This is a comment to myself.

I found the lowest frequency of the SPIs on the F103RB board was 250 - - 281kHz.

https://os.mbed.com/users/mbed_official/code/mbed-src/file/a11c0372f0ba/targets/hal/TARGET_STM/TARGET_STM32F1/spi_api.c

targets-hal-TARGET_STM-TARGET_STM32F1-spi_api.c

:
:
void spi_frequency(spi_t *obj, int hz)
{
    if (obj->spi == SPI_1) {
        // Values depend of PCLK2: 64 MHz if HSI is used, 72 MHz if HSE is used
        if (hz < 500000) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_256; // 250 kHz - 281 kHz
        } else if ((hz >= 500000) && (hz < 1000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_128; // 500 kHz - 563 kHz
        } else if ((hz >= 1000000) && (hz < 2000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_64; // 1 MHz - 1.13 MHz
        } else if ((hz >= 2000000) && (hz < 4000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_32; // 2 MHz - 2.25 MHz
        } else if ((hz >= 4000000) && (hz < 8000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_16; // 4 MHz - 4.5 MHz
        } else if ((hz >= 8000000) && (hz < 16000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_8; // 8 MHz - 9 MHz
        } else if ((hz >= 16000000) && (hz < 32000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_4; // 16 MHz - 18 MHz
        } else { // >= 32000000
            obj->br_presc = SPI_BAUDRATEPRESCALER_2; // 32 MHz - 36 MHz
        }
    }
 
    if (obj->spi == SPI_2) {
        // Values depend of PCLK1: 32 MHz if HSI is used, 36 MHz if HSE is used
        if (hz < 250000) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_256; // 125 kHz - 141 kHz
        } else if ((hz >= 250000) && (hz < 500000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_128; // 250 kHz - 281 kHz
        } else if ((hz >= 500000) && (hz < 1000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_64; // 500 kHz - 563 kHz
        } else if ((hz >= 1000000) && (hz < 2000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_32; // 1 MHz - 1.13 MHz
        } else if ((hz >= 2000000) && (hz < 4000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_16; // 2 MHz - 2.25 MHz
        } else if ((hz >= 4000000) && (hz < 8000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_8; // 4 MHz - 4.5 MHz
        } else if ((hz >= 8000000) && (hz < 16000000)) {
            obj->br_presc = SPI_BAUDRATEPRESCALER_4; // 8 MHz - 9 MHz
        } else { // >= 16000000
            obj->br_presc = SPI_BAUDRATEPRESCALER_2; // 16 MHz - 18 MHz
        }
    }
 
    init_spi(obj);
}
:
:

Detailed frequency is depend on the MCO speed, but on this board, the MCO frequency is 8MHz which coming from STLINK part and internal clock frequency would be 72MHz. It clearly describes the situation of this SPI SCLK problem.

I will try to check out that the more higher frequency works.

thanks,

posted by Masa Miyamoto 13 Nov 2017

1 Answer

3 years, 10 months ago.

Hi

The file you are mentioning is very old. Please use latest version of mbed-dev library instead (mbed-src is deprecated).

Now the spi_frequency function calculates the prescaler:

void spi_frequency(spi_t *obj, int hz) {
    struct spi_s *spiobj = SPI_S(obj);
    int spi_hz = 0;
    uint8_t prescaler_rank = 0;
    uint8_t last_index = (sizeof(baudrate_prescaler_table)/sizeof(baudrate_prescaler_table[0])) - 1;
    SPI_HandleTypeDef *handle = &(spiobj->handle);

    /* Calculate the spi clock for prescaler_rank 0: SPI_BAUDRATEPRESCALER_2 */
    spi_hz = spi_get_clock_freq(obj) / 2;

    /* Define pre-scaler in order to get highest available frequency below requested frequency */
    while ((spi_hz > hz) && (prescaler_rank < last_index)) {
        spi_hz = spi_hz / 2;
        prescaler_rank++;
    }

    /*  Use the best fit pre-scaler */
    handle->Init.BaudRatePrescaler = baudrate_prescaler_table[prescaler_rank];

    /*  In case maximum pre-scaler still gives too high freq, raise an error */
    if (spi_hz > hz) {
        DEBUG_PRINTF("WARNING: lowest SPI freq (%d)  higher than requested (%d)\r\n", spi_hz, hz);
    }

    DEBUG_PRINTF("spi_frequency, request:%d, select:%d\r\n", hz, spi_hz);

    init_spi(obj);
}

Accepted Answer

Hello, Thank you for giving me very useful information.

In any case, the lowest frequency of the SPIs is determined by the frequency of the SYSCLK ( 72Mhz in my case) and the number of digit(=8) of the prescaler, and it is 281kHz.

posted by Masa Miyamoto 14 Nov 2017