This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

SPI connection with external flash LE25U40CMDTWG

Hi,

I have a device based on the board nrf9160 with an external peripheral which is the flash LE25U40CMDTWG and that communicates with the controller through the next pins (configuration on the dts):

&spi3 {
compatible = "nordic,nrf-spim";
status = "okay";
sck-pin = <23>;
mosi-pin = <27>;
miso-pin = <24>;
};

I'm creating a driver of the flash and, according its datasheet, when I send some commands I should receive in the rx buffer some responses from the peripheral. I attach an example of the most important parts of the code:

#include "le25u40cmdtwg.h"
#include <logging/log.h>
#include "string.h"
#include "../../hw_config.h"

/**
 * DEFINES
 */

#define MODULE_NAME le25u40cmdtwg
LOG_MODULE_REGISTER(MODULE_NAME, LOG_LEVEL_INF);

static le25u40cmdtwg_t* config;
const struct device* spi_dev;
static volatile bool spim_xfer_done; /**< Flag used to indicate that SPIM instance completed the transfer. */

#define SPI_INSTANCE 3

static const struct spi_config spi_cfg = {
    .operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_MODE_CPOL | SPI_MODE_CPHA,
    .frequency = 4000000,
    .slave = 0,
};

/**
 * @brief SPI user event handler.
 * @param event
 */
void spim_event_handler(nrfx_spim_evt_t const* p_event, void* p_context) {
  if (p_event->type == NRFX_SPIM_EVENT_DONE) {
    spim_xfer_done = true;
    printk("Transfer completed.");
  }
}

void le25u40cmdtwg_init(le25u40cmdtwg_t* le25u40cmdtwg) {
  config = le25u40cmdtwg;
}

uint8_t le25u40cmdtwg_spiTransfer(le25u40cmdtwg_t* le25u40cmdtwg) {
  int err;

  static uint8_t tx_buffer[20];
  tx_buffer[0] = le25u40cmdtwg->command;
  static uint8_t rx_buffer[] = "IFMMP GSPN BCDEFGHI!";

  struct spi_buf tx_buf = {.buf = tx_buffer, .len = sizeof(tx_buffer)};
  struct spi_buf_set tx = {.buffers = &tx_buf, .count = 1};

  struct spi_buf rx_buf = {
      .buf = rx_buffer,
      .len = sizeof(rx_buffer),
  };
  struct spi_buf_set rx = {.buffers = &rx_buf, .count = 1};

  //   nrf_gpio_pin_clear(LE25U40CMDTWG_SPI_CS_PIN);
  err = gpio_pin_configure(le25u40cmdtwg->gpio_dev, LE25U40CMDTWG_SPI_CS_PIN, 0U);

  err |= spi_transceive(le25u40cmdtwg->spi_dev, &spi_cfg, &tx, &rx);
  if (err) {
    printk("SPI error: %d\n", err);
  } else {
    printk("TX sent: %p\n", tx_buf.buf);
  }

  err |= gpio_pin_configure(le25u40cmdtwg->gpio_dev, LE25U40CMDTWG_SPI_CS_PIN, 1U);

  return err;
}

The initialization of the spi is as follows on the main.c of the project:

const struct device *spi_dev;

spi_dev = device_get_binding(SPI3_LABEL);
if (spi_dev == NULL) {
  LOG_ERR("Could not bind SPI 3");
  return;
}

My question is, after using the API spi_transceive(), it returns err=0, which from the SW point of view means that the execution was correct and the tx buffer contains the command as I would expect it, but the rx buffer of the function le25u40cmdtwg_spiTransfer() keeps always empty. Due to the design of the board, I cannot use any external HW as a logical analyzer for testing if the frames are being correctly sent through the MISO/MOSI lines of the spi configuration.

Is there any other way of testing, from SW point of view, if the flash is at least receiving the commands that I send?
Is there anything on my driver that could be clearly wrong and could cause that the Rx buffer keeps always empty?

Many thanks in advance,

Ángel

  • I've tried a similar driver based on the nrfx_spi APIs and the behaviour is the same one.

    nrfx_spim_xfer(&spim, &xfer_desc, 0) returns NRFX_SUCCESS but the Rx buffer is always empty.

    I attach the main part of the source code:

    /**
     * INCLUDES
     */
    
    #include "le25u40cmdtwg.h"
    #include <logging/log.h>
    #include "string.h"
    #include "../../hw_config.h"
    
    /**
     * DEFINES
     */
    
    #define MODULE_NAME le25u40cmdtwg
    LOG_MODULE_REGISTER(MODULE_NAME, LOG_LEVEL_INF);
    
    static const le25u40cmdtwg_t* config;
    const struct device* spi_dev;
    static volatile bool spim_xfer_done; /**< Flag used to indicate that SPIM instance completed the transfer. */
    static nrfx_spim_config_t spi_config = {.sck_pin = LE25U40CMDTWG_SPI_SCK_PIN,
                                            .mosi_pin = LE25U40CMDTWG_SPI_MOSI_PIN,
                                            .miso_pin = LE25U40CMDTWG_SPI_MISO_PIN,
                                            .ss_pin = LE25U40CMDTWG_SPI_CS_PIN,
                                            .ss_active_high = false,
                                            .irq_priority = NRFX_SPIM_DEFAULT_CONFIG_IRQ_PRIORITY,
                                            .orc = 0xFF,
                                            .frequency = NRF_SPIM_FREQ_1M,
                                            .mode = NRF_SPIM_MODE_3,
                                            .bit_order = NRF_SPIM_BIT_ORDER_MSB_FIRST,
                                            NRFX_SPIM_DEFAULT_EXTENDED_CONFIG};
    
    #define SPI_INSTANCE 3
    static const nrfx_spim_t spim = NRFX_SPIM_INSTANCE(SPI_INSTANCE);
    
    // static uint8_t m_rx_buf[sizeof(TEST_STRING) + 1];
    // static const uint8_t m_length = sizeof(m_tx_buf);
    
    /**
     * @brief SPI user event handler.
     * @param event
     */
    void spim_event_handler(nrfx_spim_evt_t const* p_event, void* p_context) {
      if (p_event->type == NRFX_SPIM_EVENT_DONE) {
        spim_xfer_done = true;
        printk("Transfer completed.");
      }
    }
    
    uint8_t le25u40cmdtwg_init(const le25u40cmdtwg_t* le25u40cmdtwg) {
      printk("El init del driver de SPI ya se hace realmente en el main");
    
      config = le25u40cmdtwg;
      uint8_t ret = 0;
    
      // Application specific configuration
      if (gpio_pin_configure(config->gpio_dev, LE25U40CMDTWG_SPI_CS_PIN, GPIO_OUTPUT_ACTIVE)) {
        printk("Error while enabling pin %u.", LE25U40CMDTWG_SPI_CS_PIN);
        return -1;
      }
    
      ret = nrfx_spim_init(&spim, &spi_config, spim_event_handler, NULL);
    
      /*while (!spim_xfer_done) {
        __WFE();
      }*/
    
      return ret;
      return 0;
    }
    
    uint8_t le25u40cmdtwg_spiTransfer(uint8_t tx_buffer, const le25u40cmdtwg_t* le25u40cmdtwg) {
      nrfx_err_t err_code = 0;
    
      uint8_t tx[2] = {tx_buffer, 0};  //{0x00 | 0x80, 0};
      uint8_t rx[2] = {0};
    
      nrfx_spim_xfer_desc_t xfer_desc = {
          .p_tx_buffer = tx,
          .tx_length = 2,
          .p_rx_buffer = rx,
          .rx_length = 2,
      };
    
      nrf_gpio_pin_clear(LE25U40CMDTWG_SPI_CS_PIN);  // Manual control of the chip select pin
    
      err_code = nrfx_spim_xfer(&spim, &xfer_desc, 0);
    
      if (err_code != NRFX_SUCCESS) {
        printk("SPI error: %d\n", err_code);
      }
    
      nrf_gpio_pin_set(LE25U40CMDTWG_SPI_CS_PIN);
    
      return rx[1];
    }

  • Hi,

    Due to the design of the board, I cannot use any external HW as a logical analyzer for testing if the frames are being correctly sent through the MISO/MOSI lines of the spi configuration.

    You are not able to probe some signals either?

    I took a quick look at your code, and I did not spot anything immediately wrong. But I have a simple SPI sample here you can compare with.

    Make sure that the external flash is powered and the correct pins are configured.

  • Hi Sigurd,

    thanks for the shared sample. The problem was on the chip select. I was tried to manage it manually and with a logical analyzer I saw that the pin was always high. After initializing it as follows,

    struct spi_cs_control spi_cs = {
        .gpio_pin = LE25U40CMDTWG_SPI_CS_PIN,
        .gpio_dt_flags = GPIO_ACTIVE_LOW,
        .delay = 0,
    };
    
    void le25u40cmdtwg_init(le25u40cmdtwg_t* le25u40cmdtwg) {
      config = le25u40cmdtwg;
    
      spi_cs.gpio_dev = device_get_binding(GPIO0_LABEL);
      if (gpio_dev == NULL) {
        LOG_ERR("Could not bind GPIO 0");
        return;
      }
    }

    the problem is solved and the Rx buffers are filled with the expected values.

Related