This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts
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

Using SPI Master on nRF52

I am trying to communicate with a SPI peripheral acting slave to the nRF52 master. I am using v0.9.1 of the SDK, the example is called spi_master, with the uVision project named spi_master_pca10036.uvprojx

One thing I now know, is that the settings indicated at: infocenter.nordicsemi.com/.../hardware_driver_spi_master.html , namely:

#define SPI0_CONFIG_SCK_PIN        2/*4*/
#define SPI0_CONFIG_MOSI_PIN       3/*29*/
#define SPI0_CONFIG_MISO_PIN       4/*28*/
#define SPI0_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW

Are all wrong - in that that they actually don't do anything in this example. Rather, the file pca10036.h contains settings that actually do something. The settings below, in the file pca10036.h need to be changed to match your connection:

#define SPIM0_SCK_PIN   4 /*29*/  // SPI clock GPIO pin number.
#define SPIM0_MOSI_PIN  29 /*25*/  // SPI Master Out Slave In GPIO pin number.
#define SPIM0_MISO_PIN  28  // SPI Master In Slave Out GPIO pin number.
#define SPIM0_SS_PIN    30 /*12*/  // SPI Slave Select GPIO pin number.

So I have verified with an oscilloscope that the clock signal is actually being output, and that pin, 4 in my case, and that the MOSI is sending the correct data on pin 29. It is the MISO that is not working. I thought at first it was that the pin was not configured as an input, so I did so, but the data edges are not correct in that they don't go high enough as seen on the scope trace below (top signal is CLK, bottom is MISO):

image description

I have tried various configurations of the input pin (NOPULL, PULLUP, PULLDOWN), same result.

I have used the example project, but removed the loopback features of it as I want to communicate with a peripheral, not a loopback.

I need help understanding two things:

1) Why does the MISO seem to not work, electrically AND

2) Why does the program persistently create an error condition. It does the first nrf_drv_spi_transfer() call okay, but trying another call creates an error condition that halts to program.

My main function looks like:

int main(void)
{
    // Setup bsp module.
    bsp_configuration();
    unsigned char reg = 0x3F; //IC Identity Register
    nrf_gpio_cfg_output(30); //for the CS pin
    nrf_gpio_cfg_input(SPIM0_MISO_PIN,NRF_GPIO_PIN_NOPULL);	
    nrf_drv_gpiote_out_clear(30);   //This should assert the CS for the SPI peripheral
    spi_master_init( &m_spi_master_0, false);

    m_tx_data_spi[0] = reg | AS3911_READ_MODE;
    m_tx_data_spi[1] = 0x00;
    m_rx_data_spi[0] = 0x00;
    m_rx_data_spi[1] = 0x00;

    nrf_drv_spi_transfer(&m_spi_master_0,m_tx_data_spi, 2, m_rx_data_spi, 2);
    nrf_drv_spi_transfer(&m_spi_master_0,m_tx_data_spi, 2, m_rx_data_spi, 2); //code reaches here
    nrf_drv_spi_transfer(&m_spi_master_0,m_tx_data_spi, 2, m_rx_data_spi, 2); //code always creates a fault before getting here
    nrf_drv_spi_transfer(&m_spi_master_0,m_tx_data_spi, 2, m_rx_data_spi, 2);
}

With the function implementations being:

void bsp_configuration()
{
    uint32_t err_code = NRF_SUCCESS;

    NRF_CLOCK->LFCLKSRC            = (CLOCK_LFCLKSRC_SRC_Xtal << CLOCK_LFCLKSRC_SRC_Pos);
    NRF_CLOCK->EVENTS_LFCLKSTARTED = 0;
    NRF_CLOCK->TASKS_LFCLKSTART    = 1;

    while (NRF_CLOCK->EVENTS_LFCLKSTARTED == 0)
    {
        // Do nothing.
    }

    APP_TIMER_INIT(APP_TIMER_PRESCALER, APP_TIMER_MAX_TIMERS, APP_TIMER_OP_QUEUE_SIZE, NULL);

    err_code = bsp_init(BSP_INIT_LED, APP_TIMER_TICKS(100, APP_TIMER_PRESCALER), NULL);
    APP_ERROR_CHECK(err_code);
}
static void spi_master_init(nrf_drv_spi_t const * p_instance, bool lsb)
{
    uint32_t err_code = NRF_SUCCESS;

    nrf_drv_spi_config_t config =
    {
        .ss_pin       = NRF_DRV_SPI_PIN_NOT_USED,
        .irq_priority = APP_IRQ_PRIORITY_LOW,
        .orc          = 0xCC,
        .frequency    = NRF_DRV_SPI_FREQ_1M,
			.mode         = NRF_DRV_SPI_MODE_0,    		
        .bit_order    = (lsb ?
            NRF_DRV_SPI_BIT_ORDER_LSB_FIRST : NRF_DRV_SPI_BIT_ORDER_MSB_FIRST),
    };

    #if (SPI0_ENABLED == 1)
    if (p_instance == &m_spi_master_0)
    {
        config.sck_pin  = SPIM0_SCK_PIN;
        config.mosi_pin = SPIM0_MOSI_PIN;
        config.miso_pin = SPIM0_MISO_PIN;
        err_code = nrf_drv_spi_init(p_instance, &config,
            spi_master_0_event_handler);
    }
    else
    #endif // (SPI0_ENABLED == 1)

    #if (SPI1_ENABLED == 1)
    if (p_instance == &m_spi_master_1)
    {
        config.sck_pin  = SPIM1_SCK_PIN;
        config.mosi_pin = SPIM1_MOSI_PIN;
        config.miso_pin = SPIM1_MISO_PIN;
        err_code = nrf_drv_spi_init(p_instance, &config,
            spi_master_1_event_handler);
    }
    else
    #endif // (SPI1_ENABLED == 1)

    #if (SPI2_ENABLED == 1)
    if (p_instance == &m_spi_master_2)
    {
        config.sck_pin  = SPIM2_SCK_PIN;
        config.mosi_pin = SPIM2_MOSI_PIN;
        config.miso_pin = SPIM2_MISO_PIN;
        err_code = nrf_drv_spi_init(p_instance, &config,
            spi_master_2_event_handler);
    }
    else
    #endif // (SPI2_ENABLED == 1)

    {}

    APP_ERROR_CHECK(err_code);
}

My nrf_drv_config.h SPI section looks like:

   /* SPI */      
  #define SPI0_ENABLED 1
    
    #if (SPI0_ENABLED == 1)
    #define SPI0_USE_EASY_DMA 0
    //for DK w/ AS3911 Dev Kit - 
    /*THESE DO NOTHING IN THIS EXAMPLE EVEN THOUGH NORDIC DOCUMENTATION POINTS YOU HERE, THE ACTUAL SETTINGS ARE IN pca10036.h*/
    #define SPI0_CONFIG_SCK_PIN        2/*4*/
    #define SPI0_CONFIG_MOSI_PIN       3/*29*/
    #define SPI0_CONFIG_MISO_PIN       4/*28*/
    #define SPI0_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
    
    #define SPI0_INSTANCE_INDEX 0
    #endif
    
    #define SPI1_ENABLED 0
    
    #if (SPI1_ENABLED == 1)
    #define SPI1_USE_EASY_DMA 0
    
    #define SPI1_CONFIG_SCK_PIN         2
    #define SPI1_CONFIG_MOSI_PIN        3
    #define SPI1_CONFIG_MISO_PIN        4
    #define SPI1_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
    
    #define SPI1_INSTANCE_INDEX (SPI0_ENABLED)
    #endif
    
    #define SPI2_ENABLED 0
    
    #if (SPI2_ENABLED == 1)
    #define SPI2_USE_EASY_DMA 0
    
    #define SPI2_CONFIG_SCK_PIN         2
    #define SPI2_CONFIG_MOSI_PIN        3
    #define SPI2_CONFIG_MISO_PIN        4
    #define SPI2_CONFIG_IRQ_PRIORITY    APP_IRQ_PRIORITY_LOW
    
    #define SPI2_INSTANCE_INDEX (SPI0_ENABLED + SPI1_ENABLED)
    #endif
    
    #define SPI_COUNT   (SPI0_ENABLED + SPI1_ENABLED + SPI2_ENABLED)
  • Hi

    1. I agree with you that the "double definitions" are confusing. I have reported it to our SDK team.

    2. As I'm sure you know MISO is Master Input/Slave Output meaning it is the slave that is driving the line. Hence, my suspicion is that your slave is not working or configured properly. The MISO pin on the nRF52 should be properly configured by the drivers. The waveform you see might be some sort of interference from the MOSI or CLK line.

    3. I suspect that this is because there is a function call to check_buf_equal() inside the spi_master_x_event_handler(). This function is comparing the TX and RX buffers and if they are not the same the function will return an error condition. So, if you have not removed these two lines:

      result = check_buf_equal(m_tx_data_spi, m_rx_data_spi, TX_RX_MSG_LENGTH); APP_ERROR_CHECK_BOOL(result);

    and if you are not doing a loopback or a have slave device that returns exactly what it receives your application will stall in the app_error_handler() function. If you have already taken care of this it might be because you are trying to transmit too fast and the SPI module is busy. This is a quote from the nrf_drv_spi_transfer() documentation:

    If an event handler was provided in nrf_drv_spi_init() call, this function returns immediately and the handler is called when the transfer is done.

    In other words, if you are using an error handler like spi_master_x_event_handler() and you don't make sure that the SPI is not busy before you start another transmission then nrf_drv_spi_transfer() will return NRF_ERROR_BUSY.

    EDIT: Here is a relevant thread: SPI Master Example on nRF52 DK consistently fails.

  • Hi Marin,

    Thanks for your clarification here. I have tried the loopback example with my pin configuration, and that works. Thus, I have taken your advise and not used this example as a starting pont for communication with a slave, rather I am using spi_master_with_spi_slave. Unfortunately there are similar problems in that the processor consistently and persistently faults out. To keep things clean, I have posted a new question so this one does not become unruly and overcomplicated :)

    devzone.nordicsemi.com/.../

    Hopefully the post above is a better starting point to troubleshoot my project.

  • I'm glad it works. I answered your post in the other thread. Feel free to accept and close this thread if you don't have more questions related to this.

Related