adding Softdevice BLE (S140) with GPIO attached coprocessor to project without softdevice. hardfault calling existing code after Softdevice active

I am extending one of Qorvo's UWB platforms.. adding Softdevice BLE functions..  (which work ok) (this is on sdk 17_1_0)


the coprocessor uses a GPIO connected signaling mechanism,  using interrupts..

calling the existing code after BLE is active causes a hardfault.. 

this is running freetos,  we are in a freetos task. 

I've debugged (using ozone) it to  attempting to setup the interrupt handler for the GPIO pins. 

the existing code calls the nrfx libs 

       return qgpio_pin_irq_configure(&qm33_irq, QGPIO_IRQ_DISABLED);  //according to the doc, a gpio interrupt disable shouldn't impact softdevice.. 

```

enum qerr qgpio_pin_irq_configure(const struct qgpio *qgpio_pin, uint32_t flags)
{
nrfx_err_t r;
enum qerr err;
struct qgpio_cb_data *cb_data;
nrfx_gpiote_in_config_t trigger_config;
uint32_t abs_pin = NRF_GPIO_PIN_MAP(qgpio_pin->port, qgpio_pin->pin_number);  // this sets abs_pin = 25 

/* Init GPIOTE at least once. */
if (!nrfx_gpiote_is_init()) {   // this causes the hardfault.   
   r = nrfx_gpiote_init();
   if (r)
   return QERR_EBUSY;
}

if (flags & QGPIO_IRQ_DISABLED) {
   nrfx_gpiote_in_event_disable(abs_pin);
   nrfx_gpiote_in_uninit(abs_pin);
   return QERR_SUCCESS;
}
```
hardfault window
```
The target stopped in HardFault exception state.

Reason: A fault with configurable priority has been escalated to a HardFault exception at 0x00000000.
```

I don't see any mechanism to cause hardfault on a GPIO pin  with SD active. 
if SD is not active this code works as written 

what am I missing

if I run this code BEFORE setup of softdevice, it works, but softdevice init fails. 

Parents
  • in their build make file they have this , which overrides sdk_config.h
    ```

    target_compile_definitions(
    ProjectDefinition PUBLIC GPIOTE_ENABLED=1 NRFX_GPIOTE_ENABLED=0 NRFX_GPIOTE_CONFIG_IRQ_PRIORITY=6
    GPIOTE_CONFIG_NUM_OF_LOW_POWER_EVENTS=1
    )
    ```
    they do not use either define in their code anywhere. 
  • It's strange that nrfx_gpiote_is_init() can cause a hardfault, have you stepped inside that function ? 
    You may also want to debug the hardfault using a handler: 
    An introduction to error handling in nRF5 projects

    What do you do in the GPIOTE interrupt ? 

  • I don't know, not my code.. it is the Qorvo UWB handling code which works..
    another implementation has BLE Softdevice using S113 sd..   uses a different approach to interrupt setup, but that source is not provided.. 

  • Hi Sam, th
    As showed in the documentation there are some requirement on how interrupt handling should be implemented when using softdevice. You would need to check if there is any other interrupt that may violate the requirement. 

    Please try to step the code or use log to see what exactly cause the problem. Have you checked the hardfault handling instruction that I pointed to ? 
    I would suggest to get Qorvo support involved as they should have sample that has Softdevice included. 

  • Qorvo doesn't provide support for single startup developers like me.. 

    i have two different results from debugging

    1.

    so, if I stop in the weak app_error_fault_handler
    id = 0x1001  = NRF_FAULT_ID_APP_MEMACC
    and the PC s 8093a , which is about halfway thru nrfx_spim_xfer

    the info value is 1

    from the build link map 

    ```text

    .text.nrfx_spim_uninit
    0x00000000000807b8 0xc8 Nordic/libSDK.a(nrfx_spim.c.obj)
    0x00000000000807b8 nrfx_spim_uninit
    .text.nrfx_spim_xfer
    0x0000000000080880 0x218 Nordic/libSDK.a(nrfx_spim.c.obj)
    0x0000000000080880 nrfx_spim_xfer <------- after 80880
    .text.nrfx_nvmc_page_erase
    0x0000000000080a98 0x38 Nordic/libSDK.a(nrfx_nvmc.c.obj)
    0x0000000000080a98 nrfx_nvmc_page_erase <----- before here
    .text.nrfx_nvmc_words_write
    ```
    ```

    interesting.. but 
    2.
      I step thru the code and get to this routine. 
    ```
    static int32_t qplatform_uwb_spi_read(uint16_t header_length, uint8_t *header_buffer,
    uint16_t read_length, uint8_t *read_buffer)
    {
    /* Read always bring header length on return. */
    uint32_t rxtx_size = read_length + header_length;
    uint8_t *temp_buf = temp_tx_buf;
    enum qerr r;

    if (rxtx_size > DATA_BUFFER_SIZE)
    return QERR_ENOMEM;

    memcpy(temp_buf, header_buffer, header_length);
    temp_buf += header_length;
    memset(temp_buf, 0x00, read_length);  <-------------------------------------

    r = qplatform_uwb_spi_transfer(rxtx_size, temp_tx_buf, rxtx_size, temp_rx_buf);
    if (r)
    return r;

    temp_buf = temp_rx_buf + header_length;

    /* Remove received address character. */
    memcpy(read_buffer, temp_buf, read_length);

    return QERR_SUCCESS;
    }
    ```

    on entry, header_length=1, read_length=4
    at the if (rxtx_size , rxtx_size = 4 ????? say what , should be 5???
    at the memcpy(temp_buf, header_buffer,     temp_buf points to the variable temp_tx_buf , found in the link map at 
    ```
    .bss.temp_tx_buf
    0x00000000200271e4 0xc8 qplatform/libqplatform.a(qplatform.c.obj)
    ```
    ```
    at the memset(temp_buf, 0x00, temp_buf is 0x00000001!!!!!! <--------===========
    and causes a memory access fault. 

    EVERY SINGLE TIME... 
    I cannot stop at the temp_buf+=, so I think this is a code optimization problem.   I changed build def to -o1 from -o3, but no change in results.. 
    I just updated my gcc from 10.3 to 14.3..   no change 


    as these variables are on the stack, I increased this FREETOS stack size to 7k from 6, no change
  • I moved the code around,  memset the whole buffer, then copied in the data, didnt increment the pointer as its not used after that 
    and got all the way to qplatform qspi_transceive

    and nrfx_spim_xfer(&spi->type.spim, &xfer_desc, xfer->flags);


    which faults, per the above  item 1.   the send and receive buffers are valid. 

    if I step in more 

    rfx_err_t nrfx_spim_xfer(nrfx_spim_t const * const p_instance,
    nrfx_spim_xfer_desc_t const * p_xfer_desc,
    uint32_t flags)
    {
    spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];  <-------- this drv_inst_idx member doesn't appear in the popup for p_instance, I can see it before the call to  xfer


    NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
    NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
    NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
    NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
    p_xfer_desc->rx_length,
    p_xfer_desc->tx_length));

    nrfx_err_t err_code = NRFX_SUCCESS;

    if (p_cb->transfer_in_progress)  <---- p_cb = 0x00000002
    {
    err_code = NRFX_ERROR_BUSY;
    NRFX_LOG_WARNING("Function: %s, error code: %s.",
    __func__,
    NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
    }
    else
    {
    if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
    NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
    {
    p_cb->transfer_in_progress = true;   // this faults... setting low memory.(0x00000002). 
    }
    }

    I see in the popup, its m_cb[2].. so it saw drv_inst_idx

    but p_cb ends up being 2?????

Reply
  • I moved the code around,  memset the whole buffer, then copied in the data, didnt increment the pointer as its not used after that 
    and got all the way to qplatform qspi_transceive

    and nrfx_spim_xfer(&spi->type.spim, &xfer_desc, xfer->flags);


    which faults, per the above  item 1.   the send and receive buffers are valid. 

    if I step in more 

    rfx_err_t nrfx_spim_xfer(nrfx_spim_t const * const p_instance,
    nrfx_spim_xfer_desc_t const * p_xfer_desc,
    uint32_t flags)
    {
    spim_control_block_t * p_cb = &m_cb[p_instance->drv_inst_idx];  <-------- this drv_inst_idx member doesn't appear in the popup for p_instance, I can see it before the call to  xfer


    NRFX_ASSERT(p_cb->state != NRFX_DRV_STATE_UNINITIALIZED);
    NRFX_ASSERT(p_xfer_desc->p_tx_buffer != NULL || p_xfer_desc->tx_length == 0);
    NRFX_ASSERT(p_xfer_desc->p_rx_buffer != NULL || p_xfer_desc->rx_length == 0);
    NRFX_ASSERT(SPIM_LENGTH_VALIDATE(p_instance->drv_inst_idx,
    p_xfer_desc->rx_length,
    p_xfer_desc->tx_length));

    nrfx_err_t err_code = NRFX_SUCCESS;

    if (p_cb->transfer_in_progress)  <---- p_cb = 0x00000002
    {
    err_code = NRFX_ERROR_BUSY;
    NRFX_LOG_WARNING("Function: %s, error code: %s.",
    __func__,
    NRFX_LOG_ERROR_STRING_GET(err_code));
    return err_code;
    }
    else
    {
    if (p_cb->handler && !(flags & (NRFX_SPIM_FLAG_REPEATED_XFER |
    NRFX_SPIM_FLAG_NO_XFER_EVT_HANDLER)))
    {
    p_cb->transfer_in_progress = true;   // this faults... setting low memory.(0x00000002). 
    }
    }

    I see in the popup, its m_cb[2].. so it saw drv_inst_idx

    but p_cb ends up being 2?????

Children
  • redoing the code  for * p_cb  like this 

    spim_control_block_t * p_cb = m_cb+p_instance->drv_inst_idx; // array +type increment vs [index]
    if I step thru I get a hardfault from SD, id=1

    if I don't step thru, I get the memory access error again, pc 7a34c

    still in 

    from the map
    .text.nrfx_spim_xfer
    0x0007a294 0x204 Nordic/libSDK.a(nrfx_spim.c.obj)
    0x0007a294 nrfx_spim_xfer
    from the code disassembly window  at the pc of the fault 
    {
    anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);
    0007A3C0 LDR.W R5, [LR]
    0007A3C4 LDR.W R1, [LR, #4]
    source
    ```
    #if NRFX_CHECK(NRFX_SPIM3_NRF52840_ANOMALY_198_WORKAROUND_ENABLED)
    if (p_spim == NRF_SPIM3)
    {
    anomaly_198_enable(p_xfer_desc->p_tx_buffer, p_xfer_desc->tx_length);  <---- fault here
    }
    #endif
    ```
  • if I comment out the 198 anomaly test

    it hardfaults in the nrfx_spim, irq_handler, 

    if (nrf_spim_event_check(p_spim, NRF_SPIM_EVENT_END))
    __STATIC_INLINE bool nrf_spim_event_check(NRF_SPIM_Type * p_reg,
    return (bool)*(volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event);
    00079E94 F8D0 3118 LDR.W R3, [R0, #0x0118]
    00079E98 2B00 CMP R3, #0
    00079E9A D03A BEQ 0x00079F12 ; <irq_handler>+0x7E
    00079E9C B500 PUSH {LR}
    00079E9E B083 SUB SP, SP, #12
    if (p_spim == NRF_SPIM3)
    00079EA0 4B1C LDR R3, =0x4002F000 ; [PC, #112] [0x00079F14]
    00079EA2 4298 CMP R0, R3
    00079EA4 D022 BEQ 0x00079EEC ; <irq_handler>+0x58
    nrf_spim_event_clear(p_spim, NRF_SPIM_EVENT_END);
    __STATIC_INLINE void nrf_spim_event_clear(NRF_SPIM_Type * p_reg,
    *((volatile uint32_t *)((uint8_t *)p_reg + (uint32_t)event)) = 0x0UL;
    00079EA6 2300 MOVS R3, #0
    00079EA8 F8C0 3118 STR.W R3, [R0, #0x0118] <-------- hardfault here

Related