Skip to content

Custom GATT service with u64 characteristic causes the application to stuck/crash in build-release mode #253

@igiona

Description

@igiona

I have a pretty basic application (peripheral only) which has a GATT server containing a BAS, DeviceInfo and a custom service.
The custom service is defined as follows:

#[nrf_softdevice::gatt_service(uuid = "my-service-uuid")]
pub struct CustomService {
    #[characteristic(
        uuid = "my-char1-uuid",
        security = "justworks",
        read,
        write
    )]
    u64_value: u64,

    #[characteristic(
        uuid = "my-char2-uuid",
        security = "justworks",
        read,
        notify
    )]
    data: heapless::Vec<u8, 17>,

    #[characteristic(
        uuid = "my-char3-uuid",
        security = "justworks",
        write
    )]
    u8_value: u8,
}

My GATT server runs in a dedicated task as follow:

#[embassy_executor::task]
async fn gatt_server_task(connection: Connection, server: &'static Server) {
    let handle = connection.handle();
    let e = gatt_server::run(&connection, server, |evt| match evt {
        ServerEvent::DeviceInfo(_) => { /* Read-only service */ }
        ServerEvent::Bas(bas_evt) => { /* do something */,
        ServerEvent::CustomService(custom_service_event) => {
            match custom_service_event {
                CustomServiceEvent::U64ValueWrite(val) => {
                    // WARNING! Accessing val here stalls the application in release mode!
                    info!("Got new u64 value {}", val);
                },
                _ => { /* ... */ }
            }
        }
    })
    .await;

In debug-mode, the code performs as expected.
When I build and run my code in release mode though, everything runs as expected until the point in which I access the GATT value in the OnWrite event: info!("Got new u64 value {}", val);
As soon as the BLE client writes the u64_value characteristic, the whole MCU stalls and nothing runs anymore.
A reset is required to recover from that state.
If I do not access the val at all (log message commented out) in the event (just a debugging step, not really a valuable workaround), the MCU doesn't stuck anymore.

My build-release configuration is as follow:

[profile.release]
codegen-units = 1
debug = 2
debug-assertions = false
incremental = false
lto = "fat"
opt-level = 's'
overflow-checks = false

I have been able to work around this issue with the usage of a heapless::Vec<u8, 8> instead of a u64, and a manual (de-)serialization of the byte array into/from a u64 value.

Can someone explain this behaviour or has ideas on how further debug this?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions