nRF54LM20 sQSPI lock ups

Simple sQSPI test app locks up on LM20

We've got a simple display driver working for the nRF54L15. We used the mspi_sqspi driver for reference. As far as I can tell, there is still no sQSPI example available but the docs. However, the same driver does not work on the nrf54LM20. 

The documentation does suggest the LM20 is supported for v1.2.1, although the docs are very light on actual implementation and device tree set-up : https://docs.nordicsemi.com/bundle/ncs-latest/page/nrfxlib/softperipheral/doc/sQSPI/sqspi_nrf54L_series_porting_v1_2_1.html 

We've stripped it down to a simple example, to be run on the L15 and LM20 development kits. It runs fine on the L15 DK but locks up and stops running after a short time on the LM20 DK. 

This happens on SDK v3.2.3 and on the latest main (nrf 2545d8b308)

Zip file attached:



Code snippets:

Here are the most relevant code snippets for reference, see the zip for the actual sample application

prj.conf:

CONFIG_CONSOLE=y
CONFIG_GPIO=y
CONFIG_PINCTRL=y
CONFIG_LOG=y
CONFIG_LOG_DEFAULT_LEVEL=3
CONFIG_MAIN_STACK_SIZE=4096
CONFIG_LOG_MODE_IMMEDIATE=y

main.c

// Very stripped down, this obv won't compile

nrf_oscillators_pll_freq_set(NRF_OSCILLATORS, NRF_OSCILLATORS_PLL_FREQ_128M);

nrf_spu_periph_perm_secattr_set(NRF_SPU00, nrf_address_slave_get(DT_REG_ADDR(VPR_NODE)), true);

static nrf_sqspi_cfg_t qspi_config = {
    .skip_gpio_cfg = false,
    .skip_pmux_cfg = false,
};
    
nrf_sqspi_init(&m_sqspi, qspi_config);

nrf_sqspi_data_fmt_t data_fmt = {
    .cmd_bit_order = NRF_SQSPI_DATA_FMT_BIT_ORDER_MSB_FIRST,
    .addr_bit_order = NRF_SQSPI_DATA_FMT_BIT_ORDER_MSB_FIRST,
    .data_bit_order = NRF_SQSPI_DATA_FMT_BIT_ORDER_MSB_FIRST,
    .data_bit_reorder_unit = 8,
    .data_container = 32,
    .data_swap_unit = 8,
    .data_padding = NRF_SQSPI_DATA_FMT_PAD_RAW,
};

nrf_sqspi_dev_data_fmt_set(&m_sqspi, &data_fmt);

static const nrf_sqspi_dev_cfg_t dev_cfg = {
    .protocol = NRF_SQSPI_PROTO_SPI_C, // Multi-line SPI protocol
    .sample_sync = NRF_SQSPI_SAMPLE_SYNC_DELAY,
    .sample_delay_cyc = 1,                        // Compensate for trace length
    .mspi_lines = NRF_SQSPI_SPI_LINES_QUAD_1_1_4, // IO0/1 for cmd+addr, IO0/1/2/3 for data
    .spi_cpolpha = NRF_SQSPI_SPI_CPOLPHA_0,       // Mode 0
    .sck_freq_khz = 8000,                         // 8 MHz SCK frequency
    .csn_pin = NRF_PIN_PORT_TO_PIN_NUMBER(5, 2),
};

nrf_sqspi_dev_cfg(&m_sqspi, &dev_cfg, sqspi_event_handler, NULL);

nrf_sqspi_activate(&m_sqspi);

IRQ_CONNECT(DT_IRQN(VPR_NODE), DT_IRQ(VPR_NODE, priority), nrfx_isr, nrf_sqspi_irq_handler, 0);

while(true) {
    dmm_buffer_out_prepare(sqspi_mem_reg, test_data, sizeof(test_data) - 1, &sqspi_buffer);
    
    nrf_sqspi_xfer_t xfer = {
                .dir = NRF_SQSPI_XFER_DIR_TX,
                .cmd = 0x00,
                .address = 0,
                .data_length = sizeof(test_data) - 1,
                .cmd_length = 8,
                .addr_length = 0,
                .dummy_length = 0,
                .p_data = sqspi_buffer,
            };
    
    nrfx_err_t err = nrf_sqspi_xfer(&m_sqspi, &xfer, 1, 0);
    
    // wait for semaphore release
    
    dmm_buffer_out_release(sqspi_mem_reg, sqspi_buffer);
}


nrf54lm20dk_nrf54lm20a_cpuapp.overlay

#include <zephyr/dt-bindings/pinctrl/nrf-pinctrl.h>

&pinctrl {
	sqspi_default: sqspi_default {
		group1 {
			psels = <NRF_PSEL(SDP_MSPI_SCK, 2, 1)>,
					<NRF_PSEL(SDP_MSPI_CS0, 2, 5)>;
			nordic,drive-mode = <NRF_DRIVE_E0E1>;
		};
		group2 {
			psels = <NRF_PSEL(SDP_MSPI_DQ0, 2, 2)>,
					<NRF_PSEL(SDP_MSPI_DQ1, 2, 4)>,
					<NRF_PSEL(SDP_MSPI_DQ2, 2, 3)>,
					<NRF_PSEL(SDP_MSPI_DQ3, 2, 0)>;
			nordic,drive-mode = <NRF_DRIVE_E0E1>;
			bias-pull-up;
		};
	};

	sqspi_sleep: sqspi_sleep {
		group1 {
			psels = <NRF_PSEL(SDP_MSPI_SCK, 2, 1)>,
					<NRF_PSEL(SDP_MSPI_CS0, 2, 5)>,
					<NRF_PSEL(SDP_MSPI_DQ0, 2, 2)>,
					<NRF_PSEL(SDP_MSPI_DQ1, 2, 4)>,
					<NRF_PSEL(SDP_MSPI_DQ2, 2, 3)>,
					<NRF_PSEL(SDP_MSPI_DQ3, 2, 0)>;
			low-power-enable;
		};
	};
};

&cpuflpr_vpr {
	pinctrl-0 = <&sqspi_default>;
	pinctrl-1 = <&sqspi_sleep>;
	pinctrl-names = "default", "sleep";
	interrupts = <76 NRF_DEFAULT_IRQ_PRIORITY>;
	status = "okay";
};

/ {
	reserved-memory {
		#address-cells = <1>;
		#size-cells = <1>;
		ranges;

		softperipheral_ram: memory@2007c000 {
			reg = <0x2007c000 0x4000>;
			ranges = <0 0x2007c000 0x4000>;
			#address-cells = <1>;
			#size-cells = <1>;

			sqspi: sqspi@3b40 {
				compatible = "nordic,nrf-sqspi";
				#address-cells = <1>;
				#size-cells = <0>;
				reg = <0x3b40 0x200>;
				status = "okay";
				zephyr,pm-device-runtime-auto;
			};
		};
	};
};

Observations

L15 after 40 minute:


[00:39:22.338,822] <inf> main: sQSPI transfers completed: 23460


LM20 stalls after a few seconds (i press the reset button to restart it):
[00:00:08.992,409] <inf> main: sQSPI transfers completed: 90
[00:00:09.999,171] <inf> main: sQSPI transfers completed: 100
[00:00:11.006,026] <inf> main: sQSPI transfers completed: 110
*** Booting nRF Connect SDK v3.2.99-2545d8b308d9 ***
*** Using Zephyr OS v4.3.99-52c60f297ee1 ***
[00:00:00.010,846] <inf> main: sQSPI minimal example starting
[00:00:00.016,967] <inf> main: NRF_SQSPI_SP_FIRMWARE_ADDR: 0x2007c000
[00:00:00.023,777] <inf> main: Setting SPU permissions for VPR access
[00:00:00.031,438] <inf> main: sQSPI initialized successfully
[00:00:00.938,245] <inf> main: sQSPI transfers completed: 10
[00:00:01.945,011] <inf> main: sQSPI transfers completed: 20
[00:00:02.951,777] <inf> main: sQSPI transfers completed: 30
[00:00:03.958,543] <inf> main: sQSPI transfers completed: 40
[00:00:04.965,306] <inf> main: sQSPI transfers completed: 50
[00:00:05.972,073] <inf> main: sQSPI transfers completed: 60
*** Booting nRF Connect SDK v3.2.99-2545d8b308d9 ***
*** Using Zephyr OS v4.3.99-52c60f297ee1 ***

When Debugging, it seems to be stuck at __ASB


Edit: This may be a red herring but if I change the log / printk output to every transfer, it runs for a lot longer:


// This works
if (transfer_count % 1 == 0) {
    printk("sQSPI transfers completed: %u\n", transfer_count);
}
k_msleep(100);

// This does not ???
if (transfer_count % 2 == 0) {
    printk("sQSPI transfers completed: %u\n", transfer_count);
}
k_msleep(100);



Parents Reply Children
Related