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...
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);
}
}