How to maximize WIFI throughput when using SPI4 between nRF5340 and nRF7002

We are trying to max out the wifi throughput via nRF7002 when connected to SPI4. Currently we only achieve around 6.3Mbits/sec (TCP Upload to peer).

When measuring the SPI4 CLK we only see 16Mhz despite configuring 32Mhz in app overlay.

Question: What can we do to configure SPI4 for 32Mhz? Will this lead to higher throughput?

Hardware:

  • nRF5340-DK
  • nRF7002-EK
    • Modifikations: CLK, MISO and MOSI pins are connected to P0.08, P0.10 and P0.09 

Software:

  • nrf connect sdk version: 2.9.1
  • sample: wifi/throughput
  • EXTRA_CONF_FILE: overlay-high-performance.conf
  • SHIELD: nrf7002ek
  • custom app.overlay:

&pinctrl {
	spi4_default: spi4_default {
		group1 {
			psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
					<NRF_PSEL(SPIM_MISO, 0, 10)>,
					<NRF_PSEL(SPIM_MOSI, 0, 9)>;
			nordic,drive-mode = <NRF_DRIVE_H0H1>;
		};
	};

	spi4_sleep: spi4_sleep {
		group1 {
			psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
					<NRF_PSEL(SPIM_MISO, 0, 10)>,
					<NRF_PSEL(SPIM_MOSI, 0, 9)>;
			low-power-enable;
		};
	};
};

&spi4 {
	max-frequency = <33000000>;
	clock-frequency = <32000000>;

	nrf70: nrf7002-spi@0 {
		spi-max-frequency = <33000000>;
	};
};

Commandline:

west build -p -b nrf5340dk/nrf5340/cpuapp -- -DSHIELD=nrf7002ek -DEXTRA_CONF_FILE=overlay-high-performance.conf

Zperf:

zperf tcp upload XXX.XXX.XXX.XXX 5001 60 1024

Update 20.03.2025:

  • Setting either &spi4 max-frequency or nrf70 spi-max-frequency  to <8000000> leads to 8Mhz frequency on the oscilloscope
  • Setting &spi4 clock-frequency to <8000000> has no effect

This was done only to verify the setup. We are still unable to set the SPI4 frequency to 32Mhz as desired.

If we are commenting out lines 160-163 in ~/ncs/v2.9.1/zephyr/drivers/spi/spi_nrfx_spim.c we are actually seeing roughly 32Mhz and have a better throughput of 7.9Mbits/sec (TCP Upload to peer). This is however a brutal hack as it reconfigures the SPI on every transceive operation.

diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c
index aacf863e3b4..2fae79168b1 100644
--- a/drivers/spi/spi_nrfx_spim.c
+++ b/drivers/spi/spi_nrfx_spim.c
@@ -157,10 +157,10 @@ static int configure(const struct device *dev,
        nrfx_spim_config_t config;
        nrfx_err_t result;
 
-       if (dev_data->initialized && spi_context_configured(ctx, spi_cfg)) {
-               /* Already configured. No need to do it again. */
-               return 0;
-       }
+       // if (dev_data->initialized && spi_context_configured(ctx, spi_cfg)) {
+       //      /* Already configured. No need to do it again. */
+       //      return 0;
+       // }
 
        if (spi_cfg->operation & SPI_HALF_DUPLEX) {
                LOG_ERR("Half-duplex not supported");

Update:

We are running in the following condition (lines 196-205 in ~/ncs/v2.9.1/zephyr/drivers/spi/spi_nrfx_spim.c) that limits SPI4 frequency to 16Mhz

#if defined(CONFIG_SOC_NRF5340_CPUAPP)
	/* On nRF5340, the 32 Mbps speed is supported by the application core
	 * when it is running at 128 MHz (see the Timing specifications section
	 * in the nRF5340 PS).
	 */
	if (max_freq > 16000000 &&
	    nrf_clock_hfclk_div_get(NRF_CLOCK) != NRF_CLOCK_HFCLK_DIV_1) {
		max_freq = 16000000;
	}
#endif

This happens despite setting the clock divider to 1 first thing in main():

int main(void)
{
#if NRFX_CLOCK_ENABLED && (defined(CLOCK_FEATURE_HFCLK_DIVIDE_PRESENT) || NRF_CLOCK_HAS_HFCLK192M)
	/* For now hardcode to 128MHz */
	nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK,
			       NRF_CLOCK_HFCLK_DIV_1);
#endif
	printk("Starting %s with CPU frequency: %d MHz\n", CONFIG_BOARD, SystemCoreClock/MHZ(1));

	return 0;
}

Parents
  • Hi Moritz,

    Thanks for reaching out with your questions.

    I recall that it is also critical to use a 128MHz system clock to make SPI4 work with 32MHz. Could you confirm if you have made this change?

    Jørgen is currently unavailable. I will try this myself tomorrow to see if it is possible and get back to you.

    Best regards,
    Charlie

  • Hi Charlie,

    I think we are running at 128Mhz:

    SystemCoreClock / MHZ(1) = 128
  • Hi Moritz,

    I observed the same results as you. I suspect this could be due to long wiring causing the SPI timing requirements to not be met.

    We have had customers successfully use SPI4 at 32MHz on their custom boards before. I will spend more time investigating this next week and update you accordingly.

    Best regards,
    Charlie

  • Hi Charlie,

    thanks for looking into the problem!

    When forcing a reconfiguration from main.c after the clock has been successfully set to 128Mhz we are able to see 32Mhz on the SPI4 CLK via oscilloscope as well as observing 7.78 Mbps throughput. The modification to spi_nrfx_spim.c look like the following:

    diff --git a/drivers/spi/spi_nrfx_spim.c b/drivers/spi/spi_nrfx_spim.c
    index aacf863e3b4..9b0c8b2a2d6 100644
    --- a/drivers/spi/spi_nrfx_spim.c
    +++ b/drivers/spi/spi_nrfx_spim.c
    @@ -157,9 +157,16 @@ static int configure(const struct device *dev,
            nrfx_spim_config_t config;
            nrfx_err_t result;
     
    -       if (dev_data->initialized && spi_context_configured(ctx, spi_cfg)) {
    -               /* Already configured. No need to do it again. */
    -               return 0;
    +       extern bool UGLY_FORCE_RECONFIGURE_SPIM;
    +
    +       if (!UGLY_FORCE_RECONFIGURE_SPIM) {
    +               if (dev_data->initialized && spi_context_configured(ctx, spi_cfg)) {
    +                       /* Already configured. No need to do it again. */
    +                       return 0;
    +               }
    +       } else {
    +               LOG_ERR("Reconfiguring SPIM %s", dev->name);
    +               UGLY_FORCE_RECONFIGURE_SPIM = false;
            }
     
            if (spi_cfg->operation & SPI_HALF_DUPLEX) {

    From our point of view it looks like the SPI4 is configured before entering `main()` so spi_nrfx_spim.c:160-163

    if (dev_data->initialized && spi_context_configured(ctx, spi_cfg)) {
    	/* Already configured. No need to do it again. */
    	return 0;
    }

    always leads to an early exit, even though the clock might have been reconfigured after SPIM4's initial initialization.

    I hope this helps,

    best regards,

    Moritz

  • Hi Moritz,

    Thanks for sharing your finding.

    32MHz is not a safe choice at current moment, you may encounter an issue mentioned here (+) Nordic DevZone.

    Best regards,

    Charlie

  • Hi Charlie,

    I found a way boost the SPI4 frequency to 32Mhz without hacking. I can use https://docs.zephyrproject.org/apidoc/latest/group__sys__init.html to set the system clock to 128Mhz before SPIM4 is configured.

    diff --git a/src/main.c b/src/main.c
    index 231f206..5d2db35 100644
    --- a/src/main.c
    +++ b/src/main.c
    @@ -15,14 +15,20 @@
     #endif
     #include <stdio.h>
     
    -int main(void)
    -{
     #if NRFX_CLOCK_ENABLED && (defined(CLOCK_FEATURE_HFCLK_DIVIDE_PRESENT) || NRF_CLOCK_HAS_HFCLK192M)
    +static int clock_set_128Mhz(void)
    +{
            /* For now hardcode to 128MHz */
    -       nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK,
    -                              NRF_CLOCK_HFCLK_DIV_1);
    +       nrfx_clock_divider_set(NRF_CLOCK_DOMAIN_HFCLK, NRF_CLOCK_HFCLK_DIV_1);
    +
    +       return 0;
    +}
    +SYS_INIT(clock_set_128Mhz, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT);
     #endif
    -       printk("Starting %s with CPU frequency: %d MHz\n", CONFIG_BOARD, SystemCoreClock/MHZ(1));
    +
    +int main(void)
    +{
    +       printk("Starting %s with CPU frequency: %d MHz\n", CONFIG_BOARD, SystemCoreClock / MHZ(1));
     
            return 0;
     }
    

    I consider this however just a workaround.

    I did not understand the connection to the ticket you linked, am I missing something?

    Specifically I'm interested as to why "32Mhz is not a safe choice at current moment":

    • will it be in the future?
    • besides from difficulties in setting it up, are there known problems further down the road?

    Best regards,

    Moritz

  • Hi Moritz,

    Thanks for sharing your new solution.

    The corncern seems to be solved here nrf70: Implement SPI clock switching by krish2718 · Pull Request #87706 · zephyrproject-rtos/zephyr

    We plan to include this fix with the coming release NCS v3.0.0.

    Best regards,

    Charlie

Reply Children
No Data
Related