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

Hard fault in Connection Parameter Update when changing ATT_MTU

Hi!

I started to modify the ble_app_blinky example. I need to increase ATT_MTU, so I modified NRF_SDH_BLE_GATT_MAX_MTU_SIZE. For this, I needed to increase the RAM of the softdevice. Now, the firmware is hard faults, exactly when FIRST_CONN_PARAMS_UPDATE_DELAY expires. I see the stack trace as this:

#0 prvGetRegistersFromStack (pulFaultStackAddress= ) at /home/hollosi/projects/sa/firmware/firmware/main.c:218
#1
#2 scheduled_timeout_handler (p_event_data=0x20002f7a , event_size=8) at /home/hollosi/projects/sa/sdk/nRF5/components/libraries/timer/app_timer2.c:146
#3 0x0002b9e6 in app_sched_execute () at /home/hollosi/projects/sa/sdk/nRF5/components/libraries/scheduler/app_scheduler.c:280
#4 0x00000000 in ?? ()

The hardfault is in app_timer2.c, at the line when calling the timeout_handler (I am using the scheduler):

static void scheduled_timeout_handler(void * p_event_data, uint16_t event_size)
{
ASSERT(event_size == sizeof(app_timer_event_t));
app_timer_event_t const * p_timer_event = (app_timer_event_t *)p_event_data;

p_timer_event->timeout_handler(p_timer_event->p_context);
}

p_timer_event is not NULL, however, p_context is NULL:

(gdb) p *(app_timer_event_t*)0x20002f7a
$1 = {timeout_handler = 0x2f5a9 , p_context = 0x0}

It is interesting, that using the default ATT_MTU, hard fault disappears, so does, when I disable optimization fully.

I was aware that update_timeout_handler() uses p_context as conn_handle, however, the code does not enter into the function (I tried it with GDB and a LED flashing).

I hope someone can help me to debug this, I would not like to disable Connection Parameter Updates (which also solves the problem, since the hardfault happens there)!

  • I have some new information about the topic. When using -O3, compiler generates code as this:

    0002b850 <scheduled_timeout_handler>:
      2b850:       e9d0 3000       ldrd    r3, r0, [r0]
      2b854:       4718            bx      r3
      2b856:       bf00            nop

    The hard fault is at 2b850, having the issue:

    <error> hardfault: HARD FAULT at 0x0002B850
    <error> hardfault:   R0:  0x20003052  R1:  0x00000008  R2:  0x20002EC4  R3:  0x0002B851
    <error> hardfault:   R12: 0x20002EEC  LR:  0x0002B7F3  PSR: 0x810B0000
    <error> hardfault: Cause: The processor has made an unaligned memory access.

    Of course, R0 cannot be divided by 4 bytes, so unaligned access is present. However, I'm still searching for the solution.

  • Okay, I have managed to solve the problem, but I think it is a BUG in the nRF SDK. I have used the scheduler, so the BLE Connection Parameter Update timer (the APP_TIMER) used the scheduler also.

    The main problem is the interaction between APP_TIMER and APP_SCHEDULER. If we choose APP_SCHEDULER's event size not mod 4 (i. e. 62, as I did), the APP_TIMER's timeout_handler is not forced to fall on 32 bit boundary, see app_scheduler.c:

    uint32_t app_sched_event_put(void const              * p_event_data,
                                 uint16_t                  event_data_size,
                                 app_sched_event_handler_t handler)
    {
    ...
    memcpy(&m_queue_event_data[event_index * m_queue_event_size],
                           p_event_data,
                           event_data_size);

    Of course, scheduler callbacks are properly aligned, however, app_timer callbacks stored in scheduler queues are not.

    The solution for the problem is using event_size multiple of 4 bytes (words). I would be pleased if the SDK would not allow using event_size in scheduler not multiple of 4 bytes!

Related