Using external flash W25Q64JV with nrf52840

We are using W25Q64JV with nrf52840 on our custom board.
Here, we are able to Read/Write using QSPI but we are not able to write beyond a certain address.
For example, we are able to write on address 0x1000 but we are not able to write on address 0x10000.

We are using nrfx_qspi_lfm_start and nrfx_qspi_lfm_xfer for page writing.

Can you help us with this ASAP?

I am attaching my main.c here.

/**
 * Copyright (c) 2017 - 2020, Nordic Semiconductor ASA
 *
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this
 *    list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form, except as embedded into a Nordic
 *    Semiconductor ASA integrated circuit in a product or a software update for
 *    such product, must reproduce the above copyright notice, this list of
 *    conditions and the following disclaimer in the documentation and/or other
 *    materials provided with the distribution.
 *
 * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
 *    contributors may be used to endorse or promote products derived from this
 *    software without specific prior written permission.
 *
 * 4. This software, with or without modification, must only be used with a
 *    Nordic Semiconductor ASA integrated circuit.
 *
 * 5. Any software provided in binary form under this license must not be reverse
 *    engineered, decompiled, modified and/or disassembled.
 *
 * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/** @file
 * @defgroup qspi_bootloader_example_main main.c
 * @{
 * @ingroup qspi_bootloader_example
 *
 * @brief QSPI Bootloader Example Application main file.
 *
 * This file contains the source code for a sample bootloader starting application from QSPI.
 */

#include <nrfx_qspi.h>
#include <boards.h>

#include <nrf_log.h>
#include <nrf_gpio.h>
#include <nrf_log_ctrl.h>
#include <nrf_delay.h>
#include <nrf_log_default_backends.h>

#define NRFX_QSPI_PIN_IO1 NRF_GPIO_PIN_MAP(1,8)
#define QSPI_PIN_IO1 NRF_GPIO_PIN_MAP(1,8)   
#define QSPI_STD_CMD_WRSR        0x01 //Write status register
#define QSPI_STD_CMD_WRSR2        0x31 //Write status register
#define QSPI_STD_CMD_WRSR3        0x11 //Write status register
#define QSPI_STD_CMD_RSTEN       0x66 //Reset Enable
#define QSPI_STD_CMD_RST         0x99 //Reset
#define QSPI_MANUFACTURE_ID      0x90 
#define QSPI_JEDEC_ID            0x9F 
#define QSPI_ERASE_64KB          0x20
#define QSPI_WRITE_ENABLE        0x06
#define QSPI_FASTREAD_QUADIO     0xEB
#define W25QXX_DUMMY_BYTE        0xA5
#define QSPI_SR_QUAD_ENABLE_BYTE 0x02

#define QSPI_XIP_START_ADDR      0x12000000

#define QSPI_TEST_DATA_SIZE      256
#define START_ADDRESS   0x400000
nrf_qspi_cinstr_conf_t cinstr_cfg = {
  .opcode    = QSPI_STD_CMD_RSTEN,
  .length    = NRF_QSPI_CINSTR_LEN_1B,
  .io2_level = true,
  .io3_level = true,
  .wipwait   = true,
  .wren      = true
  };


typedef struct {
	char name[20];
	uint8_t age;
	uint8_t height;
	uint8_t weight;
} Player, *PlayerPtr;




static uint32_t volatile m_qspi_base_address = 0;
static uint32_t m_buffer_tx[QSPI_TEST_DATA_SIZE];
static uint32_t m_buffer_tx_8[QSPI_TEST_DATA_SIZE];
static uint32_t m_buffer[QSPI_TEST_DATA_SIZE];
static uint32_t m_data_buffer[QSPI_TEST_DATA_SIZE+1];
static uint8_t m_buffer_rx[QSPI_TEST_DATA_SIZE];
static uint8_t StatusRegister1;
static uint8_t StatusRegister2;
static uint8_t StatusRegister3;

static void qspi_write(void);
void configure_flash_settings(void);

static void configure_memory(void)
{
    uint32_t err_code;
    uint8_t data;
    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);

    // Send reset enable
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
    APP_ERROR_CHECK(err_code);
    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);
    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);
    // Send reset command
    cinstr_cfg.opcode = QSPI_STD_CMD_RST;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
    APP_ERROR_CHECK(err_code);
    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);

    nrf_delay_ms(100);
}
uint8_t W25qxx_Spi(uint8_t Data)
{
    uint8_t ret;
    uint32_t err_code;
    cinstr_cfg.opcode = Data;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, &Data, &ret);
    APP_ERROR_CHECK(err_code);
    return ret;
}

uint8_t W25qxx_ReadStatusRegister(uint8_t SelectStatusRegister_1_2_3)
{
	uint8_t status = 0;
	uint8_t ret = 0;
	nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);
	if (SelectStatusRegister_1_2_3 == 1)
	{
		ret = W25qxx_Spi(0x05);
		printf("\nStatusRegister1 = %x\n",ret);
	}
	else if (SelectStatusRegister_1_2_3 == 2)
	{
		ret = W25qxx_Spi(0x35);
		printf("\nStatusRegister2 = %x\n",ret);
	}
	else
	{
		ret = W25qxx_Spi(0x15);
                printf("\nStatusRegister3 = %x\n",ret);
	}
        nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);
	return status;
}
void qspi_write_enable (void)
{
    uint32_t err_code;
    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);
    cinstr_cfg.opcode = 0x06;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_1B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, NULL);
    APP_ERROR_CHECK(err_code);
    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);
    nrf_delay_ms(1);
}

static void qspi_erase (void)
{
    
    uint32_t err_code;
    //nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);


    //m_buffer_tx[0] = 0x02;
 
    //cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
    //cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
    //err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, m_buffer_tx, NULL);
    //APP_ERROR_CHECK(err_code);
    //nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);

    err_code =nrfx_qspi_erase(QSPI_ERASE_LEN_LEN_64KB, 0x00);
    APP_ERROR_CHECK(err_code);

    while (nrfx_qspi_mem_busy_check())
    {}
    //err_code =nrfx_qspi_read(m_buffer,QSPI_TEST_DATA_SIZE, 0x00);
    //APP_ERROR_CHECK(err_code);

    //while (nrfx_qspi_mem_busy_check())
    //{}

    //for (int i = 0; i < QSPI_TEST_DATA_SIZE; ++i)
    //{
    //   printf("m_buffer[i] = %x\n",m_buffer[i]);
    //}
}

static void qspi_check(void)
{
    uint32_t err_code;
    memset(&m_buffer_tx, 0, sizeof(m_buffer_tx));
    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);
    cinstr_cfg.opcode = QSPI_JEDEC_ID;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_4B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg,NULL,m_buffer_tx);
    APP_ERROR_CHECK(err_code);
    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);

    for (int i = 0; i < (QSPI_TEST_DATA_SIZE)/4; i++)
    {
       printf("\nm_buffer_tx[i] = %x\n",m_buffer_tx[i]);
    }

}

static void qspi_write(void)
{
    //nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);
    uint32_t err_code;
    //qspi_write_enable();
    //m_buffer_tx[0] = 0x02;
 
    //cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
    //cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_1B;
    //err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, m_buffer_tx, NULL);
    //APP_ERROR_CHECK(err_code);

    //nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);

    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);

    m_buffer_tx[0] = 0x10000;
    m_buffer_tx[1] = 0x444144;
    //m_buffer_tx[2] = 0x00;
    //m_buffer_tx[3] = 0x9;
    //m_buffer_tx[4] = 0xaa;
    //m_buffer_tx[5] = 0x00;
    //m_buffer_tx[6] = 0x11;


    //for (int i = 3; i < (QSPI_TEST_DATA_SIZE-3); ++i)
    //{
    //   m_buffer_tx[i] = 0xab;
    //}

    
    cinstr_cfg.opcode = 0x02;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_9B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, m_buffer_tx, NULL);
    APP_ERROR_CHECK(err_code);
 

    while (nrfx_qspi_mem_busy_check())
    {}

    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN); 
    nrf_delay_ms(1000);
    err_code =nrfx_qspi_read(m_buffer,4, 0x10000);
    APP_ERROR_CHECK(err_code);

    while (nrfx_qspi_mem_busy_check())
    {}

    for (int i = 0; i < 4; ++i)
    {
       printf("m_buffer[i] = %x\n",m_buffer[i]);
    }
    
}


static void qspi_page_write(uint32_t dst_address)
{
       
    uint32_t err_code;
    uint8_t m_read_buffer[10]={0};

    //qspi_write_enable();

    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);


    uint32_t write_address = m_qspi_base_address + dst_address;

    cinstr_cfg.opcode = 0x02;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_1B;
    printf("OPCODE  %x\n",cinstr_cfg.opcode);

    err_code = nrfx_qspi_lfm_start(&cinstr_cfg);
    APP_ERROR_CHECK(err_code);
 

    m_data_buffer[0] = write_address;
    for (int i = 1; i < QSPI_TEST_DATA_SIZE+1; i++)
    {
       m_data_buffer[i] = 0x4414;
    }

    err_code = nrfx_qspi_lfm_xfer(m_data_buffer,NULL, QSPI_TEST_DATA_SIZE,true);
    APP_ERROR_CHECK(err_code);
    
    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN);


    nrf_delay_ms(100);
    err_code =nrfx_qspi_read(m_buffer,QSPI_TEST_DATA_SIZE, write_address);
    APP_ERROR_CHECK(err_code);
    //while (nrfx_qspi_mem_busy_check())
    //{}
    nrf_delay_ms(100);
    for (int i = 0; i < QSPI_TEST_DATA_SIZE/4; ++i)
    {
       m_buffer[i] = m_buffer[i]>>8;
       NRF_LOG_INFO("m_buffer[%d] =  %x\n",i,m_buffer[i]);
       printf("m_buffer[%d] =  %x\n",i,m_buffer[i]);
       nrf_delay_ms(5);
    }
        W25qxx_ReadStatusRegister(1);
        W25qxx_ReadStatusRegister(2);
        W25qxx_ReadStatusRegister(3);

    
}

void configure_flash_settings(void)
{
    uint32_t err_code;
    uint8_t m_read_buffer[10]={0};


    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);

    //m_buffer_tx_8[0] = 0x02;
    m_buffer_tx_8[0] = 0x1E;
 
    cinstr_cfg.opcode = QSPI_STD_CMD_WRSR;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, m_buffer_tx_8, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN); 
    nrf_delay_ms(200);
    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);

    m_buffer_tx_8[0] = 0x00;
 
    cinstr_cfg.opcode = QSPI_STD_CMD_WRSR3;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, m_buffer_tx_8, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN); 
    nrf_delay_ms(200);
    nrf_gpio_pin_clear(NRFX_QSPI_PIN_CSN);

    m_buffer_tx_8[0] = 0x43;
    //m_buffer_tx_8[0] = 0x02;
 
    cinstr_cfg.opcode = QSPI_STD_CMD_WRSR2;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, m_buffer_tx_8, NULL);
    APP_ERROR_CHECK(err_code);

    nrf_gpio_pin_set(NRFX_QSPI_PIN_CSN); 
    nrf_delay_ms(200);
    cinstr_cfg.opcode = 0x15;
    cinstr_cfg.length = NRF_QSPI_CINSTR_LEN_2B;
    err_code = nrfx_qspi_cinstr_xfer(&cinstr_cfg, NULL, m_read_buffer);
    APP_ERROR_CHECK(err_code);
}

int main(void)
{
    uint32_t err_code = NRF_SUCCESS;
    err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();

    // Set QSPI peripheral with default configuration.
    nrfx_qspi_config_t config = NRFX_QSPI_DEFAULT_CONFIG;

    // Set QSPI pins to pins related to connected board.
    config.pins.sck_pin = NRFX_QSPI_PIN_SCK;//BSP_QSPI_SCK_PIN;
    config.pins.csn_pin = NRFX_QSPI_PIN_CSN;
    config.pins.io0_pin = NRFX_QSPI_PIN_IO0;
    config.pins.io1_pin = NRFX_QSPI_PIN_IO1;
    config.pins.io2_pin = NRFX_QSPI_PIN_IO2;
    config.pins.io3_pin = NRFX_QSPI_PIN_IO3;

    // Try to initialize QSPI peripheral in blocking mode.
    err_code = nrfx_qspi_init(&config, NULL, NULL);
    APP_ERROR_CHECK(err_code);
    //NRF_LOG_INFO("QSPI Bootloader started.");

    W25qxx_ReadStatusRegister(1);
    W25qxx_ReadStatusRegister(2);
    W25qxx_ReadStatusRegister(3);

    NRF_LOG_INFO("Memory device configured. Quad Mode activated.");

    //NRF_LOG_INFO("Jumping to address 0x%x", QSPI_XIP_START_ADDR);
    NRF_LOG_FLUSH();

    //qspi_check();
    configure_flash_settings();
    qspi_erase();
    W25qxx_ReadStatusRegister(1);
    W25qxx_ReadStatusRegister(2);
    W25qxx_ReadStatusRegister(3);


    {
      qspi_page_write(0x10000);
      nrf_delay_ms(1000);

    }

}

/** @} */




Related