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?

  • 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.
  • Very interesting, this could very well be the issue.

    The network core is being automatically built/flashed using the "CONFIG_BT_RPMSG" config option, which uses the Bluetooth: HCI IPC sample as a child image for the network core. This is done automatically by Zephyr when I build/flash the parent/main project to the application core.

    What I cannot seem to find is a way to specify which board definition the child image should use. I have a complete board definition for the network core, from which I can remove the uart0 pin bindings, but I need to tell the child image to build for that board instead of whatever it's using as the default (I think it defaults to "nrf5340dk_nrf5340_cpunet"?).

    And to clarify, if I'm using the network core for nothing other than to be the Bluetooth controller, it should be safe to disable ALL peripherals for the network core (gpiote, gpio0, gpio1, uart0, etc.), correct?

Related