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.

