SPI4 with multiple CS

I have an nRF5340 and need to use the

spi4
device for an SPI bus with multiple devices on it. Each, of course, has a CS pin.

I have to use spi4 because I have uart0, uart1, i2c2, and i2c3 (and there is no "4" device for either UART or I2C). I don't necessarily care about the > 8MHz high-speed capabilities of SPI4, I just need it to act like a regular SPI device with multiple CS pins.

It's rather unclear from the documentation and other posts on this forum how to configure this properly. It appears there's a hardware CS pin (P0.11), which suggests that only a single device can be used (one hardware CS pin means 1 device)? Is it possible to disregard that hardware pin though, and instead use multiple GPIOs for CS pins, like so:

&spi4 {
	status = "okay";
	pinctrl-0 = <&spi0_default>;
	pinctrl-1 = <&spi0_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>, // 0
	<&gpio0 30 GPIO_ACTIVE_LOW>, // 1
	<&gpio0 7 GPIO_ACTIVE_LOW>, // 2
	<&gpio1 0 GPIO_ACTIVE_LOW>, // 3
	<&gpio0 26 GPIO_ACTIVE_LOW>, // 4
	<&gpio0 27 GPIO_ACTIVE_LOW>; // 5
	
	...
	
};

If I want to use SPI4 in this way (regular speed, multiple CS/devices), and that's actually possible, how would I configure the PIN_CNF[p].MCUSEL and H0H1 values that are mentioned in the "SPI4" bullet at the top of the nRF5340 pinout page? i.e. what values should they have, and as importantly, how do I set them?

Parents
  • Hi,

    Is it possible to disregard that hardware pin though, and instead use multiple GPIOs for CS pins, like so:

    The SPIM driver in Zephyr does not currently support the HW SS pin, it is set to NOT_CONNECTED. The SW control of CS pin should work the same for SPIM4 as the other instances when used through Zephyr SPI driver.

    how would I configure the PIN_CNF[p].MCUSEL and H0H1 values that are mentioned in the "SPI4" bullet at the top of the nRF5340 pinout page? i.e. what values should they have, and as importantly, how do I set them?

    By default, all pins are assigned to the Application core. If you do not need the 32 MHz mode and dedicated pins, you can leave the MCUSEL field as is and assigned the SPIM pins using the PSEL registers like other instances. The H0H1 values can be configured in the pinctrl in devicetree, e.g. like this.

    Best regards,
    Jørgen

  • The driver does not support assigning the dedicated pins to SPIM4, so this must be handled outside of the driver. You should be able to use the dedicated pins similar to this:

    #include "nrf_gpio.h"
    
    #define SPIM4_SCK  NRF_GPIO_PIN_MAP(0,8)
    #define SPIM4_MOSI NRF_GPIO_PIN_MAP(0,0)
    #define SPIM4_MISO NRF_GPIO_PIN_MAP(0,10)
    
    nrf_gpio_cfg(SPIM4_SCK, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    nrf_gpio_cfg(SPIM4_MOSI, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    nrf_gpio_cfg(SPIM4_MISO, NRF_GPIO_PIN_DIR_OUTPUT, NRF_GPIO_PIN_INPUT_DISCONNECT, NRF_GPIO_PIN_NOPULL, NRF_GPIO_PIN_H0H1, NRF_GPIO_PIN_NOSENSE);
    
    nrf_gpio_pin_control_select(SPIM4_SCK, NRF_GPIO_PIN_SEL_PERIPHERAL);
    nrf_gpio_pin_control_select(SPIM4_MOSI, NRF_GPIO_PIN_SEL_PERIPHERAL);
    nrf_gpio_pin_control_select(SPIM4_MISO, NRF_GPIO_PIN_SEL_PERIPHERAL);

    The CS/SS pin should still be controlled by SW in the driver.

    I have not tried this, so let me know if it works or not.

  • I'm a bit confused. This manual assignment of the dedicated pins is only necessary for 32MHz mode, or also for 8MHz mode?

    I don't understand why the driver doesn't support assigning the dedicated pins to SPIM4, when (according to the pin assignment table) they are explicitly dedicated to SPIM4. I feel like I'm missing something here.

    Is there a sample somewhere for using 32MHz mode?

Reply Children
  • JordanK said:
    I'm a bit confused. This manual assignment of the dedicated pins is only necessary for 32MHz mode, or also for 8MHz mode?

    32 Mbps mode is only supported on the dedicated pins. 8 Mbps mode and lower can be supported on other pins, but you should make sure to use pins not marked as "standard drive, low frequency IO only" in Pin assignments.

    JordanK said:
    I don't understand why the driver doesn't support assigning the dedicated pins to SPIM4

    The nrfx_spim driver does support setting the dedicated pins, but not through the MCUSEL register. It will simply verify that the correct pins are used if 32 MHz mode is configured. The Zephyr driver uses skip_gpio_cfg/skip_psel_cfg to handle this in the pinctrl library, so this is skipped when using nRF Connect SDK. If you set the dedicated pins correctly in devicetree and enable the drive mode as I stated previously, this should also work.

    JordanK said:
    when (according to the pin assignment table) they are explicitly dedicated to SPIM4.

    The pins are not dedicated to SPIM4, they can be used for any other peripheral when SPIM4 is not used in 32 Mbps mode, and other pins can be used with SPIM4 when lower frequencies are used. Only in high-speed mode is it required to use the dedicated pins with SPIM4.

    JordanK said:
    Is there a sample somewhere for using 32MHz mode?

    Unfortunately, I'm not aware of any official sample showing this.

  • 8 Mbps mode and lower can be supported on other pins, but you should make sure to use pins not marked as "standard drive, low frequency IO only" in Pin assignments.

    I'm not seeing any pins in that linked pin assignment page that mention "standard drive" or "low frequency". Could you provide a pin number that is an example of what you're referring to?

    The SPIM driver in Zephyr does not currently support the HW SS pin

    You mentioned that the HW SS pin is not supported, but in the driver you linked, line 430 verifies that the CS dedicated hardware pin is correctly assigned. Could you clarify this discrepancy?

    Possibly related, but in my current configuration I'm having an issue where the hardware MISO pin (P0.10) does not seem to be functioning. When I use SPI4, configured as follows:

    pinctrl.dtsi

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

    devicetree

    &spi4 {
    	status = "okay";
    	pinctrl-0 = <&spi4_default>;
    	pinctrl-1 = <&spi4_sleep>;
    	pinctrl-names = "default", "sleep";
    	cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
    
    	dac60508_0: dac60508@0 {
    		compatible = "ti,dac60508";
    		reg = <0x0>;
    		status = "okay";
    		...
    	};
    };

    I can see the CS, CLK, and MOSI signals at the target chip, all valid, and the chip responds with MISO valid data. However, the SPIM driver does not detect any incoming MISO data.

    If I change MISO to P0.05 (and re-wire accordingly) though, everything works as expected. There's no conflict in my devicetree with the standard SPI4 MISO pin (P0.10). Any thoughts on why this could be with my given config? It's just using the built-in Zephyr dacx0508 driver.

  • JordanK said:
    I'm not seeing any pins in that linked pin assignment page that mention "standard drive" or "low frequency". Could you provide a pin number that is an example of what you're referring to?

    Sorry, I was mixing this with the nRF52 series chips where many pins are marked "Standard drive, low frequency IO only". I see this is not currently the case for nRF5340.

    JordanK said:
    You mentioned that the HW SS pin is not supported, but in the driver you linked, line 430 verifies that the CS dedicated hardware pin is correctly assigned. Could you clarify this discrepancy?

    I was referring to two different drivers.

    • The nrfx_spim driver, provided by the nrfx driver library, does support the HW SS pin assignment. If you are using the nrfx_spim APIs directly, this is supported.
    • The spi_nrfx_spim driver implementation in Zephyr builds on top of nrf_spim and works as a driver implementation for the nRF platform for the Zephyr SPI driver APIs. This implementation does not support setting the HW SS pin.
    JordanK said:
    Possibly related, but in my current configuration I'm having an issue where the hardware MISO pin (P0.10) does not seem to be functioning.

    By default, P0.10 is used as CTS pin for UARTE0 on the nRF5340 DK. Have you made sure this is not enabled/configured in your devicetree? If this pin does not work, but another pin does work, it is most certainly something else acquiring the pin and preventing you from using it with SPIM4.

  • This clarifies a lot, thanks!

    By default, P0.10 is used as CTS pin for UARTE0 on the nRF5340 DK.

    I have uart0 enabled, but it's configured with pinctrl to use different pins:

    uart_default: uart_default {
    	group1 {
    		psels = <NRF_PSEL(UART_TX, 0, 23)>;
    	};
    	group2 {
    		psels = <NRF_PSEL(UART_RX, 0, 24)>;
    		bias-pull-up;
    	};
    };
    uart_sleep: uart_sleep {
    	group1 {
    		psels = <NRF_PSEL(UART_TX, 0, 23)>,
    				<NRF_PSEL(UART_RX, 0, 24)>;
    		low-power-enable;
    	};
    };

    &uart0 {
    	compatible = "nordic,nrf-uarte";
    	status = "okay";
    	current-speed = <115200>;
    	pinctrl-0 = <&uart_default>;
    	pinctrl-1 = <&uart_sleep>;
    	pinctrl-names = "default", "sleep";
    };

    So I'm explicitly defining different pins for uart0.

    Is there something else I need to do to unbind P0.10 from uart0 though? I can't actually find where it sets P0.10 as the default for uart0 CTS (it's not in the base peripherals DTSI for the nRF5340, which doesn't specify any pins at all for uart0).

  • JordanK said:
    Is there something else I need to do to unbind P0.10 from uart0 though? I can't actually find where it sets P0.10 as the default for uart0 CTS (it's not in the base peripherals DTSI for the nRF5340, which doesn't specify any pins at all for uart0).

    The pins are defined in the board files, since the pin mapping can vary from board to board. The peripheral DTSI you linked is for the chip, which primarily defines which peripherals are available in the chip variant.

    To clarify my previous comment, P0.10 is assigned to UART0 for the network core. Depending on what you have running on the network core, this might still be enabled, although you have assigned different pins to uart0 in the application core.

    You can check the built devicetree ouput (although the pin numbers might be a bit cryptic) in the build folders:

    • build/zephyr/zephyr.dts for application core.
    • build/<child_image>/zephyr/zephyr.dts for network core, where <child_image> might for instance be hci_rpmsg for Bluetooth samples.
Related