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.

Parents
  • Hello Vincent,

    Could you provide the complete logs for this run?

    Here is the code I added for the memory management. When all this code is commented out, I can program and re-program normally.
    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.

    Would you have to remove both the memory related configs and DTS additions for it to work?

    Have you tried this using a DK? How are you flashing it?

    Regards,

    Elfving

  • Hi Elfving,

    I am flashing the board using a J-LINK Base, directly from VS Code. I've had not issue so far.

    I've tried the following :
    - Removing only the .c code, and keeping DTS and prj.conf  -> Can't program without manually erasing
    - Removing the .c code and DTS, and keeping and prj.conf -> Can't program without manually erasing
    - Removing the .c code, DTS and CONFIG_FLASH=y from prj.conf -> Programming works
    - Removing the .c code and CONFIG_FLASH=y, keeping DTS -> Programming works
    - Removing CONFIG_FLASH=y, and keeping the .c code and DTS -> Can't build, because functions such as flash_erase() are not defined.

    The CONFIG_FLASH=y seem to be the cause of my problem. However, I need it to enable the flash() functions.

    I am not not sur how to get the log. Where should I add "-- log" ?

    All these results are when clicking on the "Flash" text (orange circle). I just noticed that using the flash logo (green circle) works in all cases. I am confused about this, since both provide the same output on the terminal, and both initiate a flash erase of the nRF9160 prior to programming.

    Note that this is only possible for flashing, but not for debugging.

Reply
  • Hi Elfving,

    I am flashing the board using a J-LINK Base, directly from VS Code. I've had not issue so far.

    I've tried the following :
    - Removing only the .c code, and keeping DTS and prj.conf  -> Can't program without manually erasing
    - Removing the .c code and DTS, and keeping and prj.conf -> Can't program without manually erasing
    - Removing the .c code, DTS and CONFIG_FLASH=y from prj.conf -> Programming works
    - Removing the .c code and CONFIG_FLASH=y, keeping DTS -> Programming works
    - Removing CONFIG_FLASH=y, and keeping the .c code and DTS -> Can't build, because functions such as flash_erase() are not defined.

    The CONFIG_FLASH=y seem to be the cause of my problem. However, I need it to enable the flash() functions.

    I am not not sur how to get the log. Where should I add "-- log" ?

    All these results are when clicking on the "Flash" text (orange circle). I just noticed that using the flash logo (green circle) works in all cases. I am confused about this, since both provide the same output on the terminal, and both initiate a flash erase of the nRF9160 prior to programming.

    Note that this is only possible for flashing, but not for debugging.

Children
Related