Issue with SPI4 RX buffer - always 0xFF data

Hi,

I got strange behavior of the SPI4 nrfx driver on nRF5340 (using nRF SDK v2.6.1 non-secure build with BLE enabled on NET core). Namely, every time I try to receive bytes from external MEMS, the RX buffer contain a 0xFF value. The external device response correctly, I checked it with logic analyzer.

My devicetree configuration looks like this:

spi4_default: spi4_default {
    group1 {
        psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
                <NRF_PSEL(SPIM_MOSI, 0, 9)>,
                <NRF_PSEL(SPIM_MISO, 0, 10)>;
        nordic,drive-mode = <NRF_DRIVE_H0H1>;
    };
};

spi4_sleep: spi4_sleep {
    group1 {
        psels = <NRF_PSEL(SPIM_SCK, 0, 8)>,
                <NRF_PSEL(SPIM_MOSI, 0, 9)>,
                <NRF_PSEL(SPIM_MISO, 0, 10)>;
        low-power-enable;
    };
};

&spi4 {
    compatible = "nordic,nrf-spim";
    status = "okay";
    pinctrl-0 = <&spi4_default>;
    pinctrl-1 = <&spi4_sleep>;
    pinctrl-names = "default", "sleep";
    cs-gpios = <&gpio0 11 GPIO_ACTIVE_LOW>;
};

I'm using nrfx driver with the following initialization and receive:

int spi_Init(void)
{
   int ret = 0;
   nrfx_err_t err_code;

   if (_isSpiInit)
   {
      return NRFX_ERROR_ALREADY_INITIALIZED;
   }

   nrfx_spim_uninit(&spiInst);

#if defined(__ZEPHYR__)
   IRQ_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_SPIM_INST_GET(SPI_INST)), IRQ_PRIO_LOWEST,
               NRFX_SPIM_INST_HANDLER_GET(SPI_INST), 0, 0);
#endif

#if USE_SPI_HARDWARE_CS == 1
   nrfx_spim_config_t spiConfig = NRFX_SPIM_DEFAULT_CONFIG(SPI_SCK_PIN, SPI_MOSI_PIN, SPI_MISO_PIN, SPI_CS_PIN);
   spiConfig.use_hw_ss = true;
#else
   nrfx_gpiote_output_config_t config = NRFX_GPIOTE_DEFAULT_OUTPUT_CONFIG;

   err_code = nrfx_gpiote_output_configure(&gpioteInst, SPI_CS_PIN, &config, NULL);
   if (err_code != NRFX_SUCCESS)
   {
      LOG_ERR("Output configure failed: %d", err_code);
      return -1;
   }

   nrfx_gpiote_out_set(&gpioteInst, SPI_CS_PIN);
   spiConfig.use_hw_ss = false;
#endif
   spiConfig.mode = NRF_SPIM_MODE_0;
   spiConfig.ss_duration = 0x01;
   spiConfig.miso_pin = SPI_MISO_PIN;
   // spiConfig.frequency = NRFX_MHZ_TO_HZ(8);

   err_code = nrfx_spim_init(&spiInst, &spiConfig, NULL, NULL);
   if (err_code != NRFX_SUCCESS)
   {
      LOG_ERR("Init MEMS SPI failed: %d", err_code);
      return -1;
   }
   else
   {
      LOG_INF("MEMS SPIM configured");
      _isSpiInit = true;
   }

   return ret;
}

int spi_Read(uint8_t *data, uint16_t bytes_number)
{
   int err_code;
   uint8_t tx = *data;
   uint8_t rx[1 + 3] = {0}; // test

   // nrfx_spim_xfer_desc_t xfer_desc = NRFX_SPIM_XFER_TRX(&tx, 1, rx, bytes_number + 1);
   nrfx_spim_xfer_desc_t xfer_desc_tx = NRFX_SPIM_XFER_TX(&tx, 1);
   nrfx_spim_xfer_desc_t xfer_desc_rx = NRFX_SPIM_XFER_RX(rx, 1);

   spimXferDesc.rx_length = 0;
   spimXferDesc.tx_length = 1;
   txBuff[0] = 0x01;
#if USE_SPI_HARDWARE_CS == 0
   nrfx_gpiote_out_clear(&gpioteInst, SPI_CS_PIN);
#endif
   err_code = nrfx_spim_xfer(&spiInst, &spimXferDesc, 0);
   if (err_code != NRFX_SUCCESS)
   {
      LOG_ERR("MEMS SPI transfer failed: %d", err_code);
      return -1;
   }
   
   spimXferDesc.rx_length = 1;
   spimXferDesc.tx_length = 0;

   err_code = nrfx_spim_xfer(&spiInst, &spimXferDesc, 0);
   if (err_code != NRFX_SUCCESS)
   {
      LOG_ERR("MEMS SPI transfer failed: %d", err_code);
      return -1;
   }

#if USE_SPI_HARDWARE_CS == 0
   nrfx_gpiote_out_set(&gpioteInst, SPI_CS_PIN);
#endif
   memcpy(&data[1], &rx[0], 1);

   return 0;
}

I tried different compilation, with static RX buffer, single TX/RX buffer, single TRX transfer, TX and RX transfer, CS drived by hardware, changing MISO pin, using IRQs, blocking mode but nothing helped. I was wondering, if the NET core can do something with the P0.10, but I deleted node with gpio_forwarder, changed it's gpios, but it also did nothing better.

I found related ticket (devzone.nordicsemi.com/.../spi-communication-issue-zephyr-driver-works-nrfx-driver-returns-0xff), but it was solved by fixing MISO gpio configuration.

I had added a devicetree overlay for hci_ipc project for NET core with different UART0 RTS pin than P0.10, also didn't help.
 In my case, the pinout is correct. In prj.conf I have CONFIG_NRFX_SPIM4=y, CONFIG_NFCT_PINS_AS_GPIOS=y

What else can I do to receive a correct value and what is a source of that issue? 

Parents
  • The NCS SDK ships quite a few drivers for MEMS devices already, I strongly recommend using those if available. Requires you to learn how DT works.

    Your code does not look functional to me at all. Look into the datasheet of the MEMS device how an SPI read transaction is supposed to look like.

    No idea why this is supposed to look  "correct" in the LA output, there should be only one byte transferred.

    The Zephyr SPI drivers do use interrupt mode and may cause problems with your code that tries to work around them for some reason. Note that your DT overlay turns them ON for SPIM4.

    EDIT: Disregard, the small code window and the line similarity was hiding the fact that you called nrfx_spim_xfer() twice

Reply
  • The NCS SDK ships quite a few drivers for MEMS devices already, I strongly recommend using those if available. Requires you to learn how DT works.

    Your code does not look functional to me at all. Look into the datasheet of the MEMS device how an SPI read transaction is supposed to look like.

    No idea why this is supposed to look  "correct" in the LA output, there should be only one byte transferred.

    The Zephyr SPI drivers do use interrupt mode and may cause problems with your code that tries to work around them for some reason. Note that your DT overlay turns them ON for SPIM4.

    EDIT: Disregard, the small code window and the line similarity was hiding the fact that you called nrfx_spim_xfer() twice

Children
Related