nRF52840 SPIS semaphore acquire and release

Hi All,

I am using the nRF52840, with SDK140 v15.0. I have configured the nRF52840 to be a SPI slave to a NXP processor. When I connect the logic analyzer I see signals on the SCK line and MOSI lines as well as the CS line going low. I also see the expected data on the MOSI line which the NXP SPI Master is sending, but the MISO line is always set to the DEF character which is 255 or HIGH. After reading the other posts and debugging my code I find that the issue is related to semaphore Aquire/ release. In my code the nRF52840 always gets stuck at the nrfx_spis_buffers_set function call. After putting in printfs for debugging I am able to trace the code all the way down to  nrf_spis_task_trigger(p_spis, NRF_SPIS_TASK_ACQUIRE); The code gets stuck at nrf_spis_task_trigger.

I have made sure that there are no hardware issues here at all.

Can anyone please explain what is happening here? Why is the SPI slave unable to acquire the semaphore at all?


  • You write that you can see the CS line goes low, but I don't see it in the logic trace. When does it happen? Is it possible that your problem is related to this? You will need to pull the CS pin low after SPIS is initialized in order to aquire the semaphore. 

    Furthermore, by "gets stuck at nrf_spis_task_trigger" I assume you mean that the code is "stuck" waiting for the semaphore and not actually crashing inside that function? There doesn't seem to be much that can go wrong inside it:

    __STATIC_INLINE void nrf_spis_task_trigger(NRF_SPIS_Type * p_reg,
                                               nrf_spis_task_t spis_task)
        *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)spis_task)) = 0x1UL;

    If neither of this is helping:

    1. Are you checking the return code of all the functions in your code?
    2. Can you upload your code?
  • Hi,

    The "Enable" trace in the scope capture above is the CS line, which is low in the trace. I posted a zoomed in version so that the data sent on the MOSI line was visible/ readable. Here is a zoomed out version showing the CS line (Enable trace) going low before the start of transaction and going high after the end of SPI transaction. Attached is the zoomed out trace.

    The code does not crash but just is waiting for ever. And yes, like you pointed out there is not much that can go wrong with the function that is why I am stumped. I am also checking the error codes but I might be missing something, hence I have attached the code.

    static void _run_spi_slave_loopback_test(void)
        uint32_t nrf_err = NRF_SUCCESS;
        LOG_INFO("Starting SPIS demo, press button 3 to exit...");
        if (!_spi_slave_initialized)
            static const nrfx_gpiote_out_config_t slave_pin_config = NRFX_GPIOTE_CONFIG_OUT_SIMPLE(true);
            snprintf((char *)_m_tx_buf, 127, "%s", TEST_STRING);
            if (nrfx_gpiote_out_init(PIN_MAP_SPIS_SLAVE_READY_PIN, &slave_pin_config) != (ret_code_t) NRF_SUCCESS)
                LOG_ERROR("Failed to initialize SRDY pin");
                goto rsslt_exit;
            // initialize the SPI slave driver
            nrfx_spis_config_t spis_config = { .sck_pin = PIN_MAP_SPIS1_CONFIG_SCK_PIN,
                                                  .mosi_pin = PIN_MAP_SPIS1_CONFIG_MOSI_PIN,
                                                  .miso_pin = PIN_MAP_SPIS1_CONFIG_MISO_PIN,
                                                  .csn_pin = PIN_MAP_SPIS1_CONFIG_PCS_PIN,
                                                  .miso_drive = NRFX_SPIS_DEFAULT_MISO_DRIVE,
                                                  .csn_pullup = NRFX_SPIS_DEFAULT_CSN_PULLUP,
                                                  .orc = SPIS_DEFAULT_ORC,
                                                  .def = SPIS_DEFAULT_DEF,
                                                  .mode = NRF_SPIS_MODE_0,
                                                  .bit_order = NRF_SPIS_BIT_ORDER_MSB_FIRST,
                                                  .irq_priority = PIN_MAP_SPIS1_CONFIG_IRQ_PRIORITY };
            nrf_err = nrfx_spis_init(&_spis, &spis_config, _spis_event_handler, NULL);
            if (nrf_err != NRF_SUCCESS)
                LOG_ERROR("Failed to initialize SPIS");
                goto rsslt_exit;
            _spi_slave_initialized = true;
        while (1)
            memset(_m_rx_buf, 0, _m_length);
            _spis_xfer_done = false;
            nrf_err = nrfx_spis_buffers_set(&_spis, _m_tx_buf, _m_length, _m_rx_buf, _m_length);
            if (nrf_err != NRF_SUCCESS)
                LOG_ERROR("Failed to set SPIS buffers");
                goto rsslt_exit;
            while (!_spis_xfer_done)
                if (bsp_button_pressed(BSP_BUTTON_3))
                    LOG_INFO("Button 3 pressed, stopping demo");
                    goto rsslt_exit;
            if (_spis_xfer_done)
                LOG_INFO("Transfer completed. Received: %s", _m_rx_buf);
                LOG_INFO("Toggling SRDY pin for 1ms as a test.");

  • Is the code getting stuck at the very first transmission?

    Can you confirm that the SPIS has been successfully configured before the CS line is being pulled low?

    If you debug your application (using a debugger and not printfs), where exactly does your code end up?

Reply Children
  • Is there any chance or a hardware or resource conflict based on the SPI in use - I had different behavior result from using SPI1 vs using SPI 0 - in SPIS1 I never entered the handler (tried using a breakpoint in ozone as well as an NRF LOG). When I switched to 0, it entered handler. When I added code to refresh the buffer pointers in the event handler it started working as expected.