External SPI flash interfere with SiP programming

Hello,

I am currently developing on a custom board with a nRF9160. So far so good.

I need to store some data in an external 8MB flash memory, via SPI (Windbond W25Q64JV). It took me some time to figure out the DeviceTree declaration, but it's finally working. I haven't tested much yet, but I can read/write data at the base address, using flash_write() and flash_read().

However, since I added the code for flash management, I am struggling to program my board. Once programmed, any subsequent programming attempt result in the following:

Flashing build_ns to 51001355
C:\Windows\system32\cmd.exe /d /s /c "west flash -d c:\Users\vince\OneDrive\Documents\GitLab_Firmware_Cellulaire\firmware_wna618\build_ns --skip-rebuild --dev-id 51001355"

-- west flash: using runner nrfjprog
-- runners.nrfjprog: Flashing file: c:\Users\vince\OneDrive\Documents\GitLab_Firmware_Cellulaire\firmware_wna618\build_ns\zephyr\merged.hex
[error] [ Client] - Encountered error -102: Command erase_file executed for 293 milliseconds with result -102          
[error] [  nRF91] - Failed while performing 'Erase' operation on target address 0x00000000.
-102: JLinkARM.dll WriteU32 returned error -1.
[error] [  nRF91] - Failed while erasing device. -102: JLinkARM.dll WriteU32 returned error -1.
[error] [ Worker] - JLinkARM.dll WriteU32 returned error -1.
ERROR: JLinkARM DLL reported an error. Try again. If error condition
ERROR: persists, run the same command again with argument --log, contact Nordic
ERROR: Semiconductor and provide the generated log.log file to them.
NOTE: For additional output, try running again with logging enabled (--log).
NOTE: Any generated log error messages will be displayed.
FATAL ERROR: command exited with status 33: nrfjprog --program 'c:\Users\vince\OneDrive\Documents\GitLab_Firmware_Cellulaire\firmware_wna618\build_ns\zephyr\merged.hex' --sectorerase --verify -f NRF91 --snr 51001355

Repeating the flashing attempt several times does not work. The workaround is to manually erase the SiP before programming again.

I am pretty sure that the SDK is storing the data to the external memory, because I can see some SPI frames on an oscilloscope. However, I have the feeling that it's interfering with the nRF9160 internal memory somehow ...

Here is the code I added for the memory management. When all this code is commented out, I can program and re-program normally.

prj.conf

# External FLASH memory on SPI
CONFIG_FLASH=y
CONFIG_SPI=y

devicetree

//----------------------------------------------------------------
// SPI 3 on P0.11, P0.12 and P0.13
// This SPI is used for the the external FLASH memory
//----------------------------------------------------------------
&spi3 {
	compatible = "nordic,nrf-spim"; //, "nordic,nrf-spim"; 
	status = "okay";
	pinctrl-0 = <&spi3_default>;
	pinctrl-1 = <&spi3_sleep>;
	pinctrl-names = "default", "sleep";
	cs-gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;

	extflash0: extflash0@0 {
		compatible =  "jedec,spi-nor";
		reg = <0>;
		spi-max-frequency = <1000000>;	// Max supported by the flash is 133MHz
		jedec-id = [EF 40 17];	// JEDEC ID is [MF 7-0]=0xEF [ID 15-8]= [ID 7-0 = Size]=
		size = <DT_SIZE_M(64)>;
		has-dpd;
		t-enter-dpd = <3000>;	// TODO : Vérifier si ce timing est correct. DPD = Deep Power Down
		t-exit-dpd = <5000>;	// TODO : Vérifier si ce timing est correct		
		wp-gpios = <&gpio0 9 GPIO_ACTIVE_LOW>;
		hold-gpios = <&gpio0 10 GPIO_ACTIVE_LOW>;
	};						
};


&pinctrl {
	spi3_default: spi3_default {
		group1 {
			psels = <NRF_PSEL(SPIM_SCK, 0, 13)>,
					<NRF_PSEL(SPIM_MOSI, 0, 11)>,
					<NRF_PSEL(SPIM_MISO, 0, 12)>;
		};
	};

	spi3_sleep: spi3_sleep {
		group1 {
			psels = <NRF_PSEL(SPIM_SCK, 0, 13)>,
					<NRF_PSEL(SPIM_MOSI, 0, 11)>,
					<NRF_PSEL(SPIM_MISO, 0, 12)>;
					low-power-enable;
		};
	};
};

[ ... ]

aliases {
	myspiflash= &extflash0;
};

The device tree also contains some definitions for the internal flash. Those were automatically generated when creating the project.

// Internal flash. Automatically generated by nRF
&flash0 {
	partitions {
		compatible = "fixed-partitions";
		#address-cells = <1>;
		#size-cells = <1>;

		boot_partition: partition@0 {
			label = "mcuboot";
			reg = <0x0 0x10000>;
		};
		slot0_partition: partition@10000 {
			label = "image-0";
			reg = <0x10000 0x40000>;
		};
		slot0_ns_partition: partition@50000 {
			label = "image-0-nonsecure";
			reg = <0x50000 0x30000>;
		};
		slot1_partition: partition@80000 {
			label = "image-1";
			reg = <0x80000 0x40000>;
		};
		slot1_ns_partition: partition@c0000 {
			label = "image-1-nonsecure";
			reg = <0xc0000 0x30000>;
		};
		scratch_partition: partition@f0000 {
			label = "image-scratch";
			reg = <0xf0000 0xa000>;
		};
		storage_partition: partition@fa000 {
			label = "storage";
			reg = <0xfa000 0x6000>;
		};
	};
};

My test code. Note that even when is removed, I still get the same programming error, which makes me think that the issue is on the DT.

static const struct device *flash_dev = DEVICE_DT_GET(DT_ALIAS(myspiflash));

void EXTERNAL_FLASH_Init(void)
{
    uint8_t i ;
    uint8_t buff_write [] = {10, 11, 12, 13, 14, 15 };
    uint8_t buff_read[10];
    

    struct flash_pages_info pageInfo ;


    if(device_is_ready(flash_dev))
    {   
    
        DEBUG_PRINT("External flash is composed of %d pages.\r\n", flash_get_page_count(flash_dev)) ;

        flash_get_page_info_by_offs(flash_dev, 0, &pageInfo) ;
        DEBUG_PRINT("First page size is %d \r\n", pageInfo.size) ;
        

        if(flash_write(flash_dev, 0, buff_write, sizeof(buff_write)) !=0){
            DEBUG_PRINT("Write failed !\r\n") ;
        } 
        
        if( flash_read(flash_dev, 0, buff_read, sizeof(buff_write)) != 0){
            DEBUG_PRINT("Read failed !\r\n") ;
        }

        for(i=0;i<sizeof(buff_write);i++)
        {
            DEBUG_PRINT("Index %d - Write: %d\tRead: %d\r\n", i, buff_write[i], buff_read[i]);            
        } 
    }
}

Thanks for your help.

  • Hello again,

    Vincent44 said:
    Since I am working on a custom board, any sample code will require to add some configuration

    Yeah they would at minimum require you to to add the board configuration, though I think you can go without Kconfigs like CONFIG_FLASH. As config flash seems to break something, I figured it would be good test to see if you can build and flash something like blinky with it enabled.

    Vincent44 said:
    I am able to control my external memory (which I use to store some log). Read/write is working fine. The issue is only when programming : the device should be manually erased first, which is not the case when the FLASH is not used.

    This seems odd to me, as flashing from the command line doesn't work either way. Could you try and test if also this work with something default?

    Regards,

    Elfving

Related