I originally posted this message with regard to using the UART: https://e2e.ti.com/support/wireless_connectivity/bluetooth_low_energy/f/538/t/558238 The problem was that I wanted to disable/close the UART after a some time, but at soon as I did, any BLE connection would become unstable and drop, as would further connection attempts (advertising seems to be unaffected, and the device always returns to advertising after a connection drop). But I have since found that the problem is not specifically with the UART, but more generally about timing when using power constraints and their interaction with the BLE stack. I am hoping that someone at TI can follow up and see if there is a real issue, or if this is just an operator-error thing on my part!
I still have the same setup described in the other posting: simple_peripheral_cc2650em_app with POWER_SAVING defined, running on a SmartRF06; Software versions are BLE SDK 2.02.00.31, TI-RTOS 2.18.00.03, and XDCtools 3.32.00.0. Here is a simple experiment to reproduce the problem. I modified the original version of simple_peripheral.c and main.c with the following (everything else, including the drivers, is unmodified):
simple_peripheral.c:
#define SBP_DLY_START_EVT 0x0010
#define SBP_DLY_STOP_EVT 0x0020
static Clock_Struct pcTimer;
uint8_t pctype = 0;
.
.
.
static void SimpleBLEPeripheral_taskFxn(UArg a0, UArg a1)
{
// Initialize application
SimpleBLEPeripheral_init();
if (pctype == 1)
{
unsigned int ikey = Hwi_disable(); // Disable interrupts
Power_setConstraint(PowerCC26XX_SB_DISALLOW);
Hwi_restore(ikey); // Re-enable interrupts
PIN_setOutputValue(hSbpPins, Board_LED4, 1);
Util_constructClock(&pcTimer, SimpleBLEPeripheral_clockHandler,
10000, 0, false, SBP_DLY_STOP_EVT);
Util_startClock(&pcTimer);
}
else if (pctype == 2)
{
Util_constructClock(&pcTimer, SimpleBLEPeripheral_clockHandler,
10000, 0, false, SBP_DLY_START_EVT);
Util_startClock(&pcTimer);
}
// Application main loop
for (;;)
{
.
.
.
if (events & SBP_DLY_START_EVT)
{
unsigned int ikey = Hwi_disable(); // Disable interrupts
events &= ~SBP_DLY_START_EVT; //clear event
Power_setConstraint(PowerCC26XX_SB_DISALLOW);
Hwi_restore(ikey); // Re-enable interrupts
PIN_setOutputValue(hSbpPins, Board_LED4, 1);
Clock_destruct(&pcTimer);
Util_constructClock(&pcTimer, SimpleBLEPeripheral_clockHandler,
10000, 0, false, SBP_DLY_STOP_EVT);
Util_startClock(&pcTimer);
}
if (events & SBP_DLY_STOP_EVT)
{
unsigned int ikey = Hwi_disable(); // Disable interrupts
events &= ~SBP_DLY_STOP_EVT; //clear event
Power_releaseConstraint(PowerCC26XX_SB_DISALLOW);
Hwi_restore(ikey); // Re-enable interrupts
PIN_setOutputValue(hSbpPins, Board_LED4, 0);
Clock_destruct(&pcTimer);
}
.
.
.
I also added some code to main.c to monitor when the device goes into standby from the debugger:
#ifdef POWER_SAVING
// Power Notify Object for wake-up callbacks
static Power_NotifyObj powerNotifyObj;
static uint8_t powerNotifyCb(uint8_t eventType, uint32_t *eventArg, uint32_t *clientArg);
#endif //POWER_SAVING
int main()
{
.
.
.
#ifndef POWER_SAVING
/* Set constraints for Standby, powerdown and idle mode */
Power_setConstraint(PowerCC26XX_SB_DISALLOW);
Power_setConstraint(PowerCC26XX_IDLE_PD_DISALLOW);
#endif // POWER_SAVING
#ifdef POWER_SAVING
Power_registerNotify(&powerNotifyObj,
PowerCC26XX_ENTERING_STANDBY,//| PowerCC26XX_AWAKE_STANDBY,
(Power_NotifyFxn)powerNotifyCb, NULL);
#endif //POWER_SAVING
.
.
.
#ifdef POWER_SAVING
int standbycnt=0;
static uint8_t powerNotifyCb(uint8_t eventType, uint32_t *eventArg, uint32_t *clientArg)
{
if (eventType == PowerCC26XX_ENTERING_STANDBY)
{
standbycnt++;
}
// Notification handled successfully
return Power_NOTIFYDONE;
}
#endif
With these modifications, while in the debugger, standbycnt and pctype can be watched, and the latter modified:
pctype = 0: this is the original configuration of simpleBLEPeripheral
pctype = 1: The device is initially constrained from entering standby for 10 seconds, after which the constraint is released
pctype = 2: The device is constrained from entering standby after 10 seconds (by which time the device is up and advertising), and released from that constraint after another 10 seconds.
With pctype = 1, connections to the client have a significant number of missed SimpleBLEPeripheral packets, and depending upon the client, the connection make actually drop with new GAProle state GAPROLE_WAITING_AFTER_TIMEOUT. (I am using LightBlue on Mac OS, which sometimes seems more tolerant of the missing packets, even though the—default—connection parameters are set for slave latency of 0.) Because the connection may not drop (or make take a while to drop), the problem is best viewed using some kind of BLE sniffer. (I use a adafruit/WireShark combination.)
pctype = 2 is a workaround that allows the constraint to be used as long as it delayed “sufficiently”. I do not know what the minimum time is. I do know that it has to come with advertising enabled, and after advertising has begun. If I try it with advertising initially disabled, the connection problem still exists regardless of delay(s).
My current solution is a variation of pctype = 2, but in my mind that is kind of a kludge. I am hoping there is a better solution or at least an explanation of why my assumptions about power constraint use (including the ones in the UART driver) are wrong. Any help would be greatly appreciated.
dave