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

SPI problem with nRF52832 and MPU-9250

Hi!

I'm trying to get the MPU-9250 chip working through SPI with my nRF52832. But I don't seem to have much luck.

I have created a basic program for testing, based on the peripheral/spi example from the SDK. It's supposed to make the LED I have on GPIO 3 blink, but the LED stays constant on.

Could i get a helping hand with this?

  /* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
   *
   * The information contained herein is property of Nordic Semiconductor ASA.
   * Terms and conditions of usage are described in detail in NORDIC
   * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
   *
   * Licensees are granted free, non-transferable use of the information. NO
   * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
   * the file.
   *
   */

#include "nrf_drv_spi.h"
#include "app_util_platform.h"
#include "nrf_gpio.h"
#include "nrf_delay.h"
#include "nrf_log.h"
#include "boards.h"
#include "app_error.h"
#include <string.h>

#define SPI_INSTANCE  0 /* SPI instance index. */
static const nrf_drv_spi_t spi = NRF_DRV_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_tx_buf[] = { 245 }; // The WHO_AM_I register + read bit
static uint8_t       m_rx_buf[2];    /* RX buffer. */
static const uint8_t m_length = 2;        /* Transfer length. */

/**
 * @brief SPI user event handler.
 * @param event
 */
void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
{
    spi_xfer_done = true;
    NRF_LOG_PRINTF(" Transfer completed.\r\n");
    nrf_gpio_pin_clear(3);
    NRF_LOG_PRINTF(" Received: %s\r\n",m_rx_buf);
}

int main(void)
{
    nrf_gpio_cfg_output(3); // CH1, LED used for debug

    nrf_drv_spi_config_t spi_config = {
        .sck_pin        = 10,
        .mosi_pin       = 9,
        .miso_pin       = 8,
        .ss_pin         = 7,
        .irq_priority   = CONCAT_3(SPI, 0, _CONFIG_IRQ_PRIORITY),
        .orc            = 0xFF,
        .frequency      = NRF_DRV_SPI_FREQ_125K,
        .mode           = NRF_DRV_SPI_MODE_3,
        .bit_order      = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST
    };

    APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));
    nrf_gpio_pin_clear(3);
    nrf_delay_ms(200);

    while(1)
    {
        spi_xfer_done = false;
        nrf_gpio_pin_set(3);

        APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, m_tx_buf, 1, m_rx_buf, m_length));

        while (!spi_xfer_done)
        {
            __WFE();
        }

        nrf_delay_ms(200);
    }
}

Edit:

So I've tried running Øyvind's code, and I find the behavior quite peculiar. I have made some changes to his code, to better understand the state of the program. The state of the program is indicated by LEDs on the GPIOs 3, 2, 31, 30, 29, 28. Note that I'm not using the standard nRF52 DK, but a custom board.

void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
{
    nrf_gpio_pin_set(3);
    nrf_delay_ms(200);
}

int main(void)
{
    nrf_gpio_cfg_output(3);  // CH1, LED used for debug
    nrf_gpio_cfg_output(2);  // CH2, LED used for debug
    nrf_gpio_cfg_output(31); // CH3, LED used for debug
    nrf_gpio_cfg_output(30); // CH4, LED used for debug
    nrf_gpio_cfg_output(29); // CH5, LED used for debug
    nrf_gpio_cfg_output(28); // CH6, LED used for debug

    nrf_drv_spi_config_t spi_config = {
        .sck_pin        = 10,
        .mosi_pin       = 9,
        .miso_pin       = 8,
        .ss_pin         = 7,
        .irq_priority   = 3,
        .orc            = 0xFF,
        .frequency      = NRF_DRV_SPI_FREQ_125K,
        .mode           = NRF_DRV_SPI_MODE_3,
        .bit_order      = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,
    };

    uint32_t err_code = nrf_drv_spi_init(&spi, &spi_config, spi_event_handler);
    if (err_code != NRF_SUCCESS)
    {
        nrf_gpio_pin_set(2);
    }

    while(1)
    {
        nrf_gpio_pin_set(31);
        nrf_delay_ms(200);
        while(nrf_drv_spi_transfer(&spi, m_tx_buf, 1, m_rx_buf, m_length) != NRF_SUCCESS)
        {
            nrf_gpio_pin_set(30);
            nrf_delay_ms(200); //Wait for the previous transfer to finish
        } 
        nrf_gpio_pin_set(29);
        __WFE();       
        nrf_gpio_pin_set(28);
    }
}

The state of the LEDs when I run the code: 31 and 29 are constant active, while 3, 2, 30 and 28 are constant off.

  • Hi,

    Are you getting SPI events? Try setting breakpoints inside the spi_event_handler and see if they trigger, if so, just add a delay before nrf_gpio_pin_clear(3);. The current implementation will set and then immediately clear the pin.

  • Hmm no, it doesn't seem like I get SPI events. My breaking point inside the spi_event_handler isn't triggered.

  • Hi,

    If you are using the nRF52 DK be aware of a couple of things, LEDs are active low. Pins 7 and 8 are used as CTS and RXD in the UART module and 9 and 10 are used in the NFC module.

    Since the event handler is never called it is likely that either initialization or transfer fails, the event handler will be called even with no SPI device connected. To monitor this you can use APP_ERROR_CHECK along with the information from this post to find which error you are experiencing.

    Doing this we find that both nrf_drv_spi_transfer sometimes fail with the return code NRF_ERROR_BUSY, this happens when the transfer function is called before the previous transfer is finished. When you get a returncode with APP_ERROR_CHECK that is different from NRF_SUCCESS and DEBUG is not defined in the list of preprocessors your application will reset.

    Try the following code:

    void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
    {
        nrf_gpio_pin_toggle(17);
        nrf_delay_ms(200);
    }
    
    int main(void)
    {
        nrf_gpio_cfg_output(17); // CH1, LED used for debug
    
        nrf_drv_spi_config_t spi_config = {
            .sck_pin        = 13,
            .mosi_pin       = 12,
            .miso_pin       = 11,
            .ss_pin         = 10,
            .irq_priority   = 3,
            .orc            = 0xFF,
            .frequency      = NRF_DRV_SPI_FREQ_125K,
            .mode           = NRF_DRV_SPI_MODE_3,
            .bit_order      = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST,
        };
    
        uint32_t err_code = nrf_drv_spi_init(&spi, &spi_config, spi_event_handler);
        if (err_code != NRF_SUCCESS)
        {
            nrf_gpio_cfg_output(18); //Initialization failed, light LED as warning
        }
    
        while(1)
        {
            while(nrf_drv_spi_transfer(&spi, m_tx_buf, 1, m_rx_buf, m_length) != NRF_SUCCESS)
            {
                nrf_delay_ms(200); //Wait for the previous transfer to finish
            } 
            __WFE();       
        }
    }
    

    I also removed the calls to NRF_LOG_PRINTF which will not work unless you initialize the UART module, and changed to different pins. Note that using nrf_delay_ms is not a good way to wait in a final application. nrf_delay_ms uses __NOP to keep the time, this means that the CPU is active causing high current consumption. Implementing a timer is a better solution, for example by using the application timer as shown in this tutorial.

    Best regards,

    Øyvind

  • Great answer, but still not much luck. See the original post for the latest update.

  • Are you getting SPI events now?

    What toolchain are you using?

    Are your LEDs active high or active low?

    Have you done any changes to the nrf_drv_config file found in \examples\peripheral\spi\config\spi_pca10040

Related