Beware that this post is related to an SDK in maintenance mode
More Info: Consider nRF Connect SDK for new designs
This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

The nrfx_spim driver toggles random pin when chip select pin of the driver is not used.

The nrfx_spim driver has an issue when chip select pin of the driver is not used. 

When nrfx_spim_init is called with a nrfx_spim_config_t whose ss_pin is set to NRFX_SPIM_PIN_NOT_USED the value is not assigned to the ss_pin of the spim_control_block_t in the driver.

This results in a toggle of the ss_pin, which has not been initialized, when nrfx_spim_xfer is called.

This problem is present in nrf-sdk version 15.2 and 15.0. 

Parents
  • Hi,

    Can you upload some project files that I can use to recreate this? Or point me to exactly where in the driver the ss pin is being toggled?

    When I test this with the basic SPI example in SDK 15.2.0 the p_cb->ss_pin is set to 0xFF (NRFX_SPIM_PIN_NOT_USED) inside nrfx_spim_init(). Then there is an if-statement inside nrfx_spim_xfer() that checks this and skips the toggling of the ss_pin if it is not used:

    if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
    {
    #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
        if (!p_cb->use_hw_ss)
    #endif
        {
            if (p_cb->ss_active_high)
            {
                nrf_gpio_pin_set(p_cb->ss_pin);
            }
            else
            {
                nrf_gpio_pin_clear(p_cb->ss_pin);
            }

  • In the nrfx_spim_init() function the ss_pin of the driver instance in the m_cb array is set if the ss_pin in the config is not NRFX_SPIM_PIN_NOT_USED. If however the p_config->ss_pin is NRFX_SPIM_PIN_NOT_USED the ss_pin of the driver (m_cb[p_instance->drv_inst_idx].ss_pin) instance is not set. The relevant if clause is included below, it starts at line 281 in the driver code.

        if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
        {
            if (p_config->ss_active_high)
            {
                nrf_gpio_pin_clear(p_config->ss_pin);
            }
            else
            {
                nrf_gpio_pin_set(p_config->ss_pin);
            }
            //nrf_gpio_cfg_output(p_config->ss_pin);
    			 nrf_gpio_cfg(p_config->ss_pin,
    				  NRF_GPIO_PIN_DIR_OUTPUT,
    				  NRF_GPIO_PIN_INPUT_DISCONNECT,
    				  NRF_GPIO_PIN_NOPULL,
    				  NRF_GPIO_PIN_H0H1,
    				  NRF_GPIO_PIN_NOSENSE);
    #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
            if (p_config->use_hw_ss)
            {
                m_cb[p_instance->drv_inst_idx].use_hw_ss = p_config->use_hw_ss;
                nrf_spim_csn_configure(p_spim,
                                       p_config->ss_pin,
                                       (p_config->ss_active_high == true ?
                                            NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
                                       p_config->ss_duration);
            }
    #endif
            m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin;
            m_cb[p_instance->drv_inst_idx].ss_active_high = p_config->ss_active_high;
        } 

    When nrfx_spim_xfer() is called, after initializing the spim driver with ss_pin ==NRFX_SPIM_PIN_NOT_USED in the config, the ss_pin of the driver has not been initialized. In the code below p_cb->ss_pin is therefore not NRFX_SPIM_PIN_NOT_USED and the code in the if cluase is executed. I am not using the extended mode so the use_hw_ss flag is not checked.

        if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
        {
    #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
            if (!p_cb->use_hw_ss)
    #endif
            {
                if (p_cb->ss_active_high)
                {
                    nrf_gpio_pin_set(p_cb->ss_pin);
                }
                else
                {
                    nrf_gpio_pin_clear(p_cb->ss_pin);
                }
            }
        }

Reply
  • In the nrfx_spim_init() function the ss_pin of the driver instance in the m_cb array is set if the ss_pin in the config is not NRFX_SPIM_PIN_NOT_USED. If however the p_config->ss_pin is NRFX_SPIM_PIN_NOT_USED the ss_pin of the driver (m_cb[p_instance->drv_inst_idx].ss_pin) instance is not set. The relevant if clause is included below, it starts at line 281 in the driver code.

        if (p_config->ss_pin != NRFX_SPIM_PIN_NOT_USED)
        {
            if (p_config->ss_active_high)
            {
                nrf_gpio_pin_clear(p_config->ss_pin);
            }
            else
            {
                nrf_gpio_pin_set(p_config->ss_pin);
            }
            //nrf_gpio_cfg_output(p_config->ss_pin);
    			 nrf_gpio_cfg(p_config->ss_pin,
    				  NRF_GPIO_PIN_DIR_OUTPUT,
    				  NRF_GPIO_PIN_INPUT_DISCONNECT,
    				  NRF_GPIO_PIN_NOPULL,
    				  NRF_GPIO_PIN_H0H1,
    				  NRF_GPIO_PIN_NOSENSE);
    #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
            if (p_config->use_hw_ss)
            {
                m_cb[p_instance->drv_inst_idx].use_hw_ss = p_config->use_hw_ss;
                nrf_spim_csn_configure(p_spim,
                                       p_config->ss_pin,
                                       (p_config->ss_active_high == true ?
                                            NRF_SPIM_CSN_POL_HIGH : NRF_SPIM_CSN_POL_LOW),
                                       p_config->ss_duration);
            }
    #endif
            m_cb[p_instance->drv_inst_idx].ss_pin = p_config->ss_pin;
            m_cb[p_instance->drv_inst_idx].ss_active_high = p_config->ss_active_high;
        } 

    When nrfx_spim_xfer() is called, after initializing the spim driver with ss_pin ==NRFX_SPIM_PIN_NOT_USED in the config, the ss_pin of the driver has not been initialized. In the code below p_cb->ss_pin is therefore not NRFX_SPIM_PIN_NOT_USED and the code in the if cluase is executed. I am not using the extended mode so the use_hw_ss flag is not checked.

        if (p_cb->ss_pin != NRFX_SPIM_PIN_NOT_USED)
        {
    #if NRFX_CHECK(NRFX_SPIM_EXTENDED_ENABLED)
            if (!p_cb->use_hw_ss)
    #endif
            {
                if (p_cb->ss_active_high)
                {
                    nrf_gpio_pin_set(p_cb->ss_pin);
                }
                else
                {
                    nrf_gpio_pin_clear(p_cb->ss_pin);
                }
            }
        }

Children
Related