No changes
Fork of nRF51822 by
Diff: source/nRF5xGap.h
- Revision:
- 471:945e53179855
- Parent:
- 470:2c1d3b1fe249
- Child:
- 475:fe3d08b3a8e9
--- a/source/nRF5xGap.h Thu Nov 26 14:33:45 2015 +0000 +++ b/source/nRF5xGap.h Thu Nov 26 14:33:45 2015 +0000 @@ -110,36 +110,50 @@ private: #ifdef YOTTA_CFG_MBED_OS - /* Store the current radio notification value that will be used in the next callback */ - bool radioNotificationCallbackParam; - /* - * In mbed OS, the idea is to post all callbacks through minar scheduler. However, the radio notifications - * are handled in IRQs with very high priority. Trying to post a minar callback directly in - * processRadioNotification() will result in a hard-fault. This is because minar asumes that all callbacks - * are posted from low priority context, so when minar schedules the callback it attempts to enter a - * critical section and disable all interrupts. The problem is that minar tries to do this by invoking the - * SoftDevice with a call to sd_nvic_critical_region_enter() while already running in high priority. This - * results in the SoftDevice generating a hard-fault. - * A solution is to reduce the priority from which the callback is posted to minar. Unfortunately, there - * are not clean ways to do this. The solution implemented uses a Timeout to call - * postRadioNotificationCallback() after a very short delay (1 us) and post the minar callback there. + * In mbed OS, all user-facing BLE events (interrupts) are posted to the + * MINAR scheduler to be executed as callbacks in thread mode. MINAR guards + * its critical sections from interrupts by acquiring CriticalSectionLock, + * which results in a call to sd_nvic_critical_region_enter(). Thus, it is + * safe to invoke MINAR APIs from interrupt context as long as those + * interrupts are blocked by sd_nvic_critical_region_enter(). + * + * Radio notifications are a special case for the above. The Radio + * Notification IRQ is handled at a very high priority--higher than the + * level blocked by sd_nvic_critical_region_enter(). Thus Radio Notification + * events can preempt MINAR's critical sections. Using MINAR APIs (such as + * posting an event) directly in processRadioNotification() may result in a + * race condition ending in a hard-fault. * - * !!!WARNING!!! Radio notifications are very time critical events. The current solution is expected to - * work under the assumption that postRadioNotificationCalback() will be executed BEFORE the next radio + * The solution is to *not* call MINAR APIs directly from the Radio + * Notification handling; i.e. to do the bulk of RadioNotification + * processing at a reduced priority which respects MINAR's critical + * sections. Unfortunately, on a cortex-M0, there is no clean way to demote + * priority for the currently executing interrupt--we wouldn't want to + * demote the radio notification handling anyway because it is sensitive to + * timing, and the system expects to finish this handling very quickly. The + * workaround is to employ a Timeout to trigger + * postRadioNotificationCallback() after a very short delay (~0 us) and post + * the MINAR callback that context. + * + * !!!WARNING!!! Radio notifications are very time critical events. The + * current solution is expected to work under the assumption that + * postRadioNotificationCalback() will be executed BEFORE the next radio * notification event is generated. */ + + bool radioNotificationCallbackParam; /* parameter to be passed into the Timeout-generated radio notification callback. */ Timeout radioNotificationTimeout; /* - * A helper function to post radio notification callbacks through minar when using mbed OS. + * A helper function to post radio notification callbacks through MINAR when using mbed OS. */ void postRadioNotificationCallback(void) { minar::Scheduler::postCallback( mbed::util::FunctionPointer1<void, bool>(&radioNotificationCallback, &FunctionPointerWithContext<bool>::call).bind(radioNotificationCallbackParam) ); } -#endif +#endif /* #ifdef YOTTA_CFG_MBED_OS */ /** * A helper function to process radio-notification events; to be called internally.