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);
}
}
/** @} */