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

Segmentation fault after enabling BLE stack

I have my system working with softdevice compiled in but not enabled. System communicates with external chip using SPIM peripheral, everything is working fine until I enable the softdevice.

As soon as I issue

    ret_code_t err_code;
    err_code = nrf_sdh_enable_request();

the first spim_xfer ends with segmentation fault:

#0  0x000257ae in ?? ()
#1  <signal handler called>
#2  nrf_spim_event_clear (spim_event=NRF_SPIM_EVENT_END, p_reg=<optimized out>) at /home/miceuz/nrf/nRF5_SDK/modules/nrfx/hal/nrf_spim.h:517
#3  spim_xfer (flags=0, p_xfer_desc=0x2003ff9c, p_cb=0x20004220 <m_cb+44>, p_spim=<optimized out>) at /home/miceuz/nrf/nRF5_SDK/modules/nrfx/drivers/src/nrfx_spim.c:501
#4  nrfx_spim_xfer (p_instance=<optimized out>, p_xfer_desc=0x2003ff9c, flags=0) at /home/miceuz/nrf/nRF5_SDK/modules/nrfx/drivers/src/nrfx_spim.c:607
#5  0x0000000e in ?? ()
#6  0x000373b0 in _fini ()

I am sure I am missing something simple here, but I can't remember what. Any tips?

Parents
  • Hi.

    Which SDK and SoftDevice do you use?

    Have you tried to debug the project and looked at what happend when you enabled the SoftDevice?

    Best regards,

    Andreas

  • I am attaching some code that demonstrates the problem. Note, I am running it on my own board, so logging is on different pins than devboards

      segfault.zip

  • I am not sure - my design pretty much depends on use of SPIM3 because all the additional functionality it has - now I can fill my 40kb buffer completely with no CPU using hardware CS control, also I am using 16MHz - very cool functionality and doing it manually on lower frequency will severely impact my battery life and general design (which is nearing production at fast pace)

    Did I stumble on some kind of undiscovered errata?

  • Hi Andreas,

    I have looked into my code history - indeed, last time SPI and BLE was working together I have used SPI driver, not SPIM and I have used SPI instance 0.

    I have tried running the same segfault example I have posted before changing SPIM instance from 3 to 1 and it worked flawlessly.

    So yes, I can confirm, SoftDevice has problems working together with SPIM3.

    SPIM3 is pretty critical for our application as I have mentioned in previous post. Please let me know how I could be of assistance in solving this issue.

  • Hi.

    I have found the same results as you and reported it to the SDK team.

    In the mean time, I think I have a workaround hack that solves the problem somehow:

    In your main.c file:

    void spi_write() {
        ret_code_t error_code2;
    	m_tx_buf[0] = 0x42;
    	m_tx_buf[1] = 0x42;
    	nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(m_tx_buf, 2, m_rx_buf, 2);
    	error_code2 = nrfx_spim_xfer(&spim, &xfer, 0);
        APP_ERROR_CHECK(error_code2);
    }
    
    void app_mwu_enable(void)
    {
      NRF_MWU->REGIONENSET
        = ((MWU_REGIONENSET_RGN0WA_Set << MWU_REGIONENSET_RGN0WA_Pos) | (MWU_REGIONENSET_PRGN0WA_Set << MWU_REGIONENSET_PRGN0WA_Pos));
    }
    
    void app_mwu_disable(void)
    {
      NRF_MWU->REGIONENCLR
        = ((MWU_REGIONENCLR_RGN0WA_Clear << MWU_REGIONENCLR_RGN0WA_Pos) | (MWU_REGIONENCLR_PRGN0WA_Clear << MWU_REGIONENCLR_PRGN0WA_Pos));
    }
    
    
    
    int main(void) {
    
        power_management_init();
        log_init();
        NRF_LOG_INFO("Hello");
    	ble_stack_init();
        app_mwu_disable();
        spi_init();
        spi_write();
        app_mwu_enable();
        while(1) {
    	    NRF_LOG_INFO("I am fine");
            idle_state_handle();
        }
    }

    The problem with Invalid Access Memory was that an area protected by the memory watch unit is attempting to be written to when nrfx_spim_xfer() is called. I've avoided the error by disabling the memory watch unit before calling any SPIM related API calls, and enabling it afterwards.

    Could this help you perhaps?

    Best regards,

    Andreas

  • Hi Andreas

    Thank you for your post, I have tested the suggestion and we are getting somewhere, but the issue is not fully resolved yet. Simple SPIM initialization and xfer works fine with the MWU workaround you have specified, but more sophisticated initialization still segfaults.

    I have tracked it down to spim handler specification -- if handler is provided for nrfx_spim_init function it still segfaults.

    Maybe another memory region has to be unprotected also?

    This is the code that illustrates the fault:

    #include <ble_infrastructure.h>
    #include <stdbool.h>
    #include <stdint.h>
    
    #include "nrf.h"
    #include "nordic_common.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "nrfx_spim.h"
    #include "nrf_gpio.h"
    
    #include "ble_infrastructure.h"
    #include "power.h"
    
    static void log_init(void) {
    	ret_code_t err_code = NRF_LOG_INIT(NULL);
    	APP_ERROR_CHECK(err_code);
    
    	NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    static const nrfx_spim_t spim = NRFX_SPIM_INSTANCE(3);
    static uint8_t       m_tx_buf[2];           /**< TX buffer. */
    static uint8_t       m_rx_buf[3];    /**< RX buffer. */
    
    void spim_event_handler(nrfx_spim_evt_t const * p_event, void *p_context) {
    }
    
    void spi_init() {
        nrfx_spim_config_t config  =NRFX_SPIM_DEFAULT_CONFIG;
        config.frequency = NRF_SPIM_FREQ_16M;
        config.ss_pin   = SPI_SS_PIN;
        config.miso_pin = SPI_MISO_PIN;
        config.mosi_pin = SPI_MOSI_PIN;
        config.sck_pin  = SPI_SCK_PIN;
        config.use_hw_ss= true;
        config.rx_delay = 0;
        config.ss_duration = 0;
        config.orc = 0;
    
        APP_ERROR_CHECK(nrfx_spim_init(&spim, &config, spim_event_handler, NULL));
    }
    
    #define LED_GREEN_PIN 24
    #define LED_RED_PIN 25
    
    void leds_init(void) {
        nrf_gpio_cfg_output(LED_GREEN_PIN);
        nrf_gpio_cfg_output(LED_RED_PIN);
    }
    
    void spi_write() {
    	m_tx_buf[0] = 0x42;
    	m_tx_buf[1] = 0x42;
    	nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(m_tx_buf, 2, m_rx_buf, 2);
    	APP_ERROR_CHECK(nrfx_spim_xfer(&spim, &xfer, 0));
    }
    
    void app_mwu_enable(void)
    {
      NRF_MWU->REGIONENSET
        = ((MWU_REGIONENSET_RGN0WA_Set << MWU_REGIONENSET_RGN0WA_Pos) | (MWU_REGIONENSET_PRGN0WA_Set << MWU_REGIONENSET_PRGN0WA_Pos));
    }
    
    void app_mwu_disable(void)
    {
      NRF_MWU->REGIONENCLR
        = ((MWU_REGIONENCLR_RGN0WA_Clear << MWU_REGIONENCLR_RGN0WA_Pos) | (MWU_REGIONENCLR_PRGN0WA_Clear << MWU_REGIONENCLR_PRGN0WA_Pos));
    }
    int main(void) {
    
        power_management_init();
        log_init();
        leds_init();
        NRF_LOG_INFO("Hello");
        nrf_gpio_pin_set(LED_RED_PIN);
    	ble_init();
        app_mwu_disable();
        spi_init();
        spi_write();
        app_mwu_enable();
        nrf_gpio_pin_clear(LED_RED_PIN);
        nrf_gpio_pin_set(LED_GREEN_PIN);
        while(1) {
    	    NRF_LOG_INFO("I am fine");
            idle_state_handle();
        }
    }
    
    

  • Also, if this makes a difference, the most complicated form of nrfx_spim_xfer I use is like this:

    	nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(spi_txbuf, 1, curr_buffer, 4);
        nrfx_spim_xfer(&spim, &xfer, NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER | NRFX_SPIM_FLAG_RX_POSTINC | NRFX_SPIM_FLAG_HOLD_XFER | NRFX_SPIM_FLAG_REPEATED_XFER));

Reply Children
  • Hi.

    I just wanted to keep you updated on this issue.I have recompiled the project with code your previous reply and I also experience the invalid memory access. I am still waiting on more information from the SDK team on this issue. If you find anything please let me know, I will do the same of course.

    Best regards,

    Andreas

  • Hi again.

    I've found this workaround to work without any issues so far:

    THIS WORKAROUND ONLY WORKS WITHOUT THE SOFTDEVICE

    I made the following modifications in the driver file modules\nrfx\drivers\src\nrfx_spim.c:

    (Starting from line 129)

    void app_mwu_enable(void) //WORKAROUND ADDED 2-1-2019
    {
      NRF_MWU->REGIONENSET
        = ((MWU_REGIONENSET_RGN0WA_Set << MWU_REGIONENSET_RGN0WA_Pos) | (MWU_REGIONENSET_PRGN0WA_Set << MWU_REGIONENSET_PRGN0WA_Pos));
      NRF_MWU->REGIONEN;
    }
    
    void app_mwu_disable(void) //WORKAROUND ADDED 2-1-2019
    {
      NRF_MWU->REGIONENCLR
        = ((MWU_REGIONENCLR_RGN0WA_Clear << MWU_REGIONENCLR_RGN0WA_Pos) | (MWU_REGIONENCLR_PRGN0WA_Clear << MWU_REGIONENCLR_PRGN0WA_Pos));
      NRF_MWU->REGIONEN;
    }
    
    static uint32_t m_anomaly_198_preserved_value;
    
    static void anomaly_198_enable(uint8_t const * p_buffer, size_t buf_len)
    {
        m_anomaly_198_preserved_value = *((volatile uint32_t *)0x40000E00);
    
        if (buf_len == 0)
        {
            return;
        }
        uint32_t buffer_end_addr = ((uint32_t)p_buffer) + buf_len;
        uint32_t block_addr      = ((uint32_t)p_buffer) & ~0x1FFF;
        uint32_t block_flag      = (1UL << ((block_addr >> 13) & 0xFFFF));
        uint32_t occupied_blocks = 0;
    
        if (block_addr >= 0x20010000)
        {
            occupied_blocks = (1UL << 8);
        }
        else
        {
            do {
                occupied_blocks |= block_flag;
                block_flag <<= 1;
                block_addr  += 0x2000;
            } while ((block_addr < buffer_end_addr) && (block_addr < 0x20012000));
        }
    
        app_mwu_disable(); //WORKAROUND ADDED 2-1-2019
        *((volatile uint32_t *)0x40000E00) = occupied_blocks;
        app_mwu_enable(); //WORKAROUND ADDED 2-1-2019
    }
    
    static void anomaly_198_disable(void)
    {
        app_mwu_disable(); //WORKAROUND ADDED 2-1-2019
        *((volatile uint32_t *)0x40000E00) = m_anomaly_198_preserved_value;
        app_mwu_enable(); //WORKAROUND ADDED 2-1-2019
    }
    #endif // NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)

    My main file looks like this now:

    #include <ble_infrastructure.h>
    #include <stdbool.h>
    #include <stdint.h>
    
    #include "nrf.h"
    #include "nordic_common.h"
    
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    #include "nrfx_spim.h"
    #include "nrf_gpio.h"
    
    #include "ble_infrastructure.h"
    #include "power.h"
    
    static void log_init(void) {
    	ret_code_t err_code = NRF_LOG_INIT(NULL);
    	APP_ERROR_CHECK(err_code);
    
    	NRF_LOG_DEFAULT_BACKENDS_INIT();
    }
    
    static const nrfx_spim_t spim = NRFX_SPIM_INSTANCE(3);
    static uint8_t       m_tx_buf[2];           /**< TX buffer. */
    static uint8_t       m_rx_buf[3];    /**< RX buffer. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    void spim_event_handler(nrfx_spim_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));
        }
    }
    
    void spi_init() {
    
        ret_code_t err_code;
        nrfx_spim_config_t config = NRFX_SPIM_DEFAULT_CONFIG;
        config.frequency = NRF_SPIM_FREQ_16M;
        config.ss_pin   = SPI_SS_PIN;
        config.miso_pin = SPI_MISO_PIN;
        config.mosi_pin = SPI_MOSI_PIN;
        config.sck_pin  = SPI_SCK_PIN;
        config.use_hw_ss= true;
        config.rx_delay = 0;
        config.ss_duration = 0;
        config.orc = 0;
    
        err_code = nrfx_spim_init(&spim, &config, spim_event_handler, NULL);
        APP_ERROR_CHECK(err_code);
    }
    
    
    #define LED_GREEN_PIN 13
    #define LED_RED_PIN 14
    
    void leds_init(void) {
        nrf_gpio_cfg_output(LED_GREEN_PIN);
        nrf_gpio_cfg_output(LED_RED_PIN);
    }
    
    void spi_write() {
        ret_code_t error_code2;
    	m_tx_buf[0] = 0x42;
    	m_tx_buf[1] = 0x42;
    	nrfx_spim_xfer_desc_t xfer = NRFX_SPIM_SINGLE_XFER(m_tx_buf, 2, m_rx_buf, 2);
    	error_code2 = nrfx_spim_xfer(&spim, &xfer, 0);
        APP_ERROR_CHECK(error_code2);
    }
    
    int main(void) {
    
        power_management_init();
        log_init();
        leds_init();
        NRF_LOG_INFO("Hello");
        nrf_gpio_pin_set(LED_RED_PIN);
    	ble_stack_init();
        spi_init();
        spi_write();
        nrf_gpio_pin_clear(LED_RED_PIN);
        nrf_gpio_pin_set(LED_GREEN_PIN);
        while(1) {
    	    NRF_LOG_INFO("I am fine");
            idle_state_handle();
        }
    }
    
    

    RTT-Viewer output:

    I hope this works for you as well.

    Best regards,

    Andreas

  • Thank you Andreas!

    With this workaround I have no issues running both the isolated test code or my production code.

Related