SPI not working

Dear Ladies and Gentlemen,

I am trying to get a DPS310 pressure sensor to work via SPI. As I use I2C for other purposes, I chose SPI1 channel. The given SPI example in SDK 17.02 sadly still uses the legacy driver, I wanted to use the new nrfx interface described in:

https://infocenter.nordicsemi.com/topic/sdk_nrf5_v17.0.2/group__nrf__spi.html

So I coded:

#include "spi.h"

#define strLen 64
enum pin_t{_red=0, _green=1, __red=4, __green=8, __bt1=31, __sck=26, __mosi=27, __miso=7, __csbar=22};

#define SPI_INSTANCE  1 /**< SPI instance index. */
static const nrfx_spi_t spi = NRFX_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */

static uint8_t       m_rx_buf[strLen + 1];    /**< RX buffer. */
static const uint8_t m_length = strLen;       /**< Transfer length. */

/**
 * @brief SPI user event handler.
 * @param event
 */
void spi_event_handler(nrfx_spi_evt_t const* p_event, void* p_context)
{
    spi_xfer_done = true;
    NRF_LOG_INFO("Transfer completed.");
    if (m_rx_buf[0] != 0)
    {
        NRF_LOG_INFO(" Received:");
        NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
    }
}

char* DPS_reg_read(uint8_t regIndex)
{
    ret_code_t err_code;
    uint8_t regSel[1];
    regSel[0]=regIndex;
    memset(m_rx_buf, 0, m_length);
    spi_xfer_done = false;

    nrfx_spi_xfer_desc_t m_pos_write;
    m_pos_write.p_tx_buffer = regSel;
    m_pos_write.tx_length = sizeof(regSel);
    m_pos_write.p_rx_buffer = m_rx_buf;
    m_pos_write.rx_length = m_length;

    //nrf_gpio_pin_clear(__csbar);   //Set CS to 0 (on)

    err_code=nrfx_spi_xfer(&spi, &m_pos_write, 0);
    APP_ERROR_CHECK(err_code);
    while (!spi_xfer_done)
    {
        __WFE();
    }
    //nrf_gpio_pin_set(__csbar);   //Set CS to 1 (off)
    return m_rx_buf;
}

/**@brief Function for initializing the nrf log module. */
static void log_init(void)
{
    ret_code_t err_code = NRF_LOG_INIT(NULL);
    APP_ERROR_CHECK(err_code);

    NRF_LOG_DEFAULT_BACKENDS_INIT();
}

int main(void)
{
    log_init();
    NRF_LOG_INFO("Log on.");
    nrfx_spi_config_t spi_config = NRFX_SPI_DEFAULT_CONFIG;
    spi_config.ss_pin   = __csbar;//SPI_SS_PIN;
    spi_config.miso_pin = __miso;//SPI_MISO_PIN;
    spi_config.mosi_pin = __mosi;//SPI_MOSI_PIN;
    spi_config.sck_pin  = __sck;//SPI_SCK_PIN;
    err_code = nrfx_spi_init(&spi, &spi_config, spi_event_handler, NULL);
    APP_ERROR_CHECK(err_code);
    char* res=DPS_reg_read(0x28);
    NRF_LOG_INFO("Read: %d", res[0]);
    // Enter main loop.
    for (;;)
    {
        idle_state_handle();
    }
    return 0;
}

But the example never puts out anything as soon as I call DPS_reg_read(); I also tried commenting out the __WFE(); in completion loop, but this also failed. I never saw, that the spi event handler reported transfer complete. Can you give advice, what must be done to get SPI to run?

Best regards,

Richard

  • Can you first make sure that the legacy spi driver works? I do not see any benefit of using the nrfx driver directly for spi transfer, it's just an api wrapper that doesn't really provide any additional functionality or features.

    Best regards,
    Kenneth

  • Dear Kenneth,

    Do you suggest a test using the event handler or should I go with manual line-activation, __WFE, result reading and line-deactivation?

    Best regards, Richard

  • I think the first goal is to make this work, for instance using the spi example as-is from the nRF5 SDK. It's difficult comment on why your code doesn't work, it could in theory be that some of the pins allocated for spi is forced low externaly, this could prevent the clock from toggling, and would cause the spi handler to never return. At the moment it could be anything, have you got a logic analyzer to see if there is any data on spi?

    Kenneh

  • Solved.

    The solution is indicated here:

    https://devzone.nordicsemi.com/f/nordic-q-a/17002/spi-rx-problem

    The answere is:

    The first byte (received in the spi-event handler) is NOT the answere, but, dependant on the Pull-up mode either 0x00 or 0xff FOLLOWED by the register-date byte in a read access. Furthermore, it is relevant to consider that every register read should be marked with a set high bit (regSel | 0x80) in order to inform the reg about a read, while a write requires a cleared high bit.

    Best regards,

    Richard

  • Reopening needed:

    I can read the registers of the DPS310 with my configuration, but I fail to write. As I can read now, I assume, that my configuration (HW/SW) is correct, because reading requires the DPS310 to be informed about which register is to be read (Data-line to SPI slave) and the Nordic BM833 to obtain the value (Data-line from slave). There is one major thing I wonder about now:

    Currently, I have the following enabled:

    // <e> NRFX_SPI_ENABLED - nrfx_spi - SPI peripheral driver
    //==========================================================
    #ifndef NRFX_SPI_ENABLED
    #define NRFX_SPI_ENABLED 1
    #endif
    // <q> NRFX_SPI0_ENABLED  - Enable SPI0 instance
     
    
    #ifndef NRFX_SPI0_ENABLED
    #define NRFX_SPI0_ENABLED 0
    #endif
    
    // <q> NRFX_SPI1_ENABLED  - Enable SPI1 instance
     
    
    #ifndef NRFX_SPI1_ENABLED
    #define NRFX_SPI1_ENABLED 1
    #endif
    

    But i did not include/enable SPIM. Is that additionally required?

    Finally:

    If there is a secondary SPI slave connected to the same SPI bus (using same sck/miso/mosi pins but, of course, another ss_pin), what is programming best-practice to repeatedly (with fixed-interval) switch between devices?

    Best regards,

    Richard

Related