This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

Cannot write/read a byte from external Flash via SPI

I am using a BMD 349 module based on nRF52840. 

I am interfacing with AT25SF041 flash memory.

I am using SDK 14.2.

I am writing a byte to a specific address in Flash. 

But when I try to read the memory location, On the debug window I only see "00". 

I don't see any error messages.

I can read the status registers and Device ID completely fine, so I know SPI read function is working.

Can someone help?

Thanks

Below is flash_mem.c 

#include "flash_mem.h"
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"

static const nrf_drv_spi_t m_spi_at = NRF_DRV_SPI_INSTANCE(0);

static uint32_t spi_config(void)
{
    uint32_t err_code;
    nrf_drv_spi_config_t config = NRF_DRV_SPI_DEFAULT_CONFIG;
    config.frequency = NRF_DRV_SPI_FREQ_1M;
    config.mode      = NRF_DRV_SPI_MODE_3;
    config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
    config.mosi_pin  = AT_PIN_MOSI;
    config.miso_pin  = AT_PIN_MISO;
    config.sck_pin   = AT_PIN_SCK;
    config.ss_pin    = AT_PIN_CS; 
    err_code = nrf_drv_spi_init(&m_spi_at, &config, NULL, NULL);
    if (err_code != NRF_SUCCESS)
    {
        // Initialization failed. Take recovery action.
    }   
    nrf_gpio_cfg_output(AT_PIN_CS);
    nrf_gpio_pin_set(AT_PIN_CS);
    return err_code;
}


uint32_t at_init(void)
{
    return spi_config();
}

void at_read_rems(uint8_t * manufacturer_id, uint8_t * device_id)
{
    uint8_t spi_tx_cmd[] = {0x9F};
    uint8_t spi_rx_response[3];
    nrf_gpio_pin_clear(AT_PIN_CS);
    nrf_drv_spi_transfer(&m_spi_at, spi_tx_cmd, sizeof(spi_tx_cmd), spi_rx_response, sizeof(spi_rx_response));
    nrf_gpio_pin_set(AT_PIN_CS);
    *manufacturer_id = spi_rx_response[1]; 
    *device_id = spi_rx_response[2];
}


void at_write_enable(void)
{
    static uint8_t spi_tx_cmd[] = {CMD_WREN};
    nrf_gpio_pin_clear(AT_PIN_CS);
    nrf_drv_spi_transfer(&m_spi_at, spi_tx_cmd, sizeof(spi_tx_cmd), 0, 0);
    nrf_gpio_pin_set(AT_PIN_CS);
}

void at_program(uint32_t address, uint8_t * data_ptr, uint32_t data_length)
{
    uint8_t spi_tx_cmd[] = {CMD_PROGRAM, (address >> 16) & 0xFF, (address >> 8) & 0xFF, (address >> 0) & 0xFF};
    nrf_gpio_pin_clear(AT_PIN_CS);
    nrf_drv_spi_transfer(&m_spi_at, spi_tx_cmd, sizeof(spi_tx_cmd),NULL, NULL);
    while(data_length > 255)
    {
        nrf_drv_spi_transfer(&m_spi_at, data_ptr, 255, NULL, NULL);
        data_ptr += 255;
        data_length -= 255;
    }
    nrf_drv_spi_transfer(&m_spi_at, data_ptr, data_length, NULL, NULL);
    nrf_gpio_pin_set(AT_PIN_CS);
}


void at_read(uint32_t address, uint8_t * data_ptr, uint32_t data_length)
{
    uint8_t spi_tx_cmd[] = {CMD_READ, (address >> 16) & 0xFF, (address >> 8) & 0xFF, (address >> 0) & 0xFF};
    nrf_gpio_pin_clear(AT_PIN_CS);
    nrf_drv_spi_transfer(&m_spi_at, spi_tx_cmd, sizeof(spi_tx_cmd), NULL, NULL);
    while(data_length > 255)
    {
        nrf_drv_spi_transfer(&m_spi_at, 0, 0, data_ptr, 255);
        data_ptr += 255;
        data_length -= 255;
    }
    nrf_drv_spi_transfer(&m_spi_at, NULL, NULL , data_ptr, data_length);
    nrf_gpio_pin_set(AT_PIN_CS);
}

Below is part of main.c

int main(void)
{

    uint8_t status_register, man_id, dev_id;
    uint8_t data_buf = 0x23;
    uint8_t read_buf;
    at_init();
    at_write_enable();

    uint32_t address = 0x01A8FF;
            //for(int i = 0; i < READ_WRITE_LENGTH; i++) data_buf[i] = i;
            at_program(address, &data_buf, 1);
            
        at_read(address, &read_buf, 1);
       NRF_LOG_INFO("Reading address %.8x: ", address);
       NRF_LOG_INFO("%.2X-" ,(int)read_buf);
}

Parents Reply Children
  • I don't know what external flash you use. You should check in the data sheet for the flash. Have you tried analyzing the SPI wires to see that the data that you are sending and receiving is actually being sent correctly? Have you tried lowering the SPI frequency? Perhaps the traces/wires are too long for 1M? Perhaps you are using the wrong config.mode?

  • I don't have access to a logic analyzer yet. The fact that I can read manufacturer and device ID over SPI, doesn't that prove that SPI connection has been correctly established?
    I tried with 500k frequency, and the config mode is correct too. For some reason I'm only reading zeros..

  • RO said:
    The fact that I can read manufacturer and device ID over SPI, doesn't that prove that SPI connection has been correctly established?

     I agree. Again, I don't know what flash you are using. Did you check the datasheet to double check that you are sending the correct read commands? If you use an invalid command, it may be that the external flash doesn't give any replies, which probably will look like a lot of 0's on the SPI.

  • Dumb question: Which read command did you use, and did you try reading more than one byte?

  • I finally got a logic analyzer and found the the issue. The problem was with the  CS line.

    I am manually operating it in my code. But the nrf_xfer() function in nrf_drv_spi.c also operates on it once it detects a transfer is finished.

    So it used to pull the CS line high between the SPI transfer function to send the Flash opcode & address and the SPI transfer function for the actual byte.

    So I commented out the line which was pulling the CS pin high in the nrf_drv_spi.c

    if (!p_cb->handler)
        {
            while (!nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END)){}
            if (p_cb->ss_pin != NRF_DRV_SPI_PIN_NOT_USED)
            {
                //nrf_gpio_pin_set(p_cb->ss_pin);        
            }
        }

    Maybe a note can be mentioned in documentation regarding the operation of CS pin.

    Thanks

Related