Skip to content

Instantly share code, notes, and snippets.

@lupyuen
Last active March 20, 2021 13:23
Show Gist options
  • Save lupyuen/1539f9dd52e9a83d4fbe7724481112bf to your computer and use it in GitHub Desktop.
Save lupyuen/1539f9dd52e9a83d4fbe7724481112bf to your computer and use it in GitHub Desktop.
Mynewt LoRa Ping Stack Issue

Mynewt LoRa Ping Stack Issue

The LoRa Ping demo app in Mynewt passes a stack object that is referenced by the SX1276 interrupt handlers. This causes problems for other platforms, like FreeRTOS on BL602.

Here's the main function in LoRa Ping that allocates radio_events on the stack...

From https://github.com/apache/mynewt-core/blob/master/apps/loraping/src/main.c#L218-L235

int main(void) {
    //  radio_events lives on the stack
    RadioEvents_t radio_events;
    ...
    /* Radio initialization. */
    radio_events.TxDone = on_tx_done;
    radio_events.RxDone = on_rx_done;
    radio_events.TxTimeout = on_tx_timeout;
    radio_events.RxTimeout = on_rx_timeout;
    radio_events.RxError = on_rx_error;

    //  This passes a pointer to radio_events, which lives on the stack
    Radio.Init(&radio_events);

This passes the pointer of radio_events (which lives on the stack) to the function Radio.Init.

Radio.Init points to SX1276Init, which is defined here...

From https://github.com/apache/mynewt-core/blob/master/hw/drivers/lora/sx1276/src/sx1276.c#L288-L293

//  RadioEvents is a static var
static RadioEvents_t *RadioEvents;

//  We receive a pointer to radio_events, which lives on the stack
void SX1276Init(RadioEvents_t *events) {
    ...
    //  Problem here: We store a pointer to a stack object (radio_events) 
    //  and use it later in interrupt handlers
    RadioEvents = events;

This stores into RadioEvents the pointer to a stack object (radio_events).

The stored pointer RadioEvents will be used later by Interrupt Handlers...

From https://github.com/apache/mynewt-core/blob/master/hw/drivers/lora/sx1276/src/sx1276.c#L245-L251

//  SX1276RxDone is called by the GPIO Interrupt Handler SX1276OnDio0Irq
static void SX1276RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) {
    if ((RadioEvents != NULL) && (RadioEvents->RxDone != NULL)) {
        RadioEvents->RxDone(payload, size, rssi, snr);
    }
}

This works OK for Mynewt, because radio_events lives on the stack of the main function. And the program runs within the lifetime of the main function.

But it doesn't work if radio_events lives on the stack outside of the main function.

For FreeRTOS on BL602 we fix this problem by copying the struct instead of the pointer...

From https://github.com/lupyuen/bl_iot_sdk/blob/lorarecv/customer_app/sdk_app_lora/sdk_app_lora/sx1276.c#L360-L370

static RadioEvents_t RadioEvents;  ////  Stores a copy of the callbacks
////  Previously: static RadioEvents_t *RadioEvents;

void SX1276Init(RadioEvents_t *events) {
    ...
    ////  We copy the Event Callbacks from "events", because
    ////  "events" may be stored on the stack
    assert(events != NULL);
    memcpy(&RadioEvents, events, sizeof(RadioEvents));

    ////  Previously: RadioEvents = events;
    ...
}

static void SX1276RxDone(uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr) {
    ////  Previously: RadioEvents->RxDone
    if (RadioEvents.RxDone != NULL) {
        RadioEvents.RxDone(payload, size, rssi, snr);
    }
}

See https://github.com/lupyuen/bl_iot_sdk/commit/5ca7946da1f795fd53aa7937ae87f3fbea2bce2a#diff-96c07c83d9cb748e9326fc2de5671debed63687a1fc984ff73cada89001a96fa

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment