This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52810 app optimization ble_app_uart

Hello ...

Our BLE peripheral product (nRF52810, SDK 15.3.0, SD 112 6.1.1) is relatively simple. iOS device (central) connects to peripheral. Data is exchanged between the central and peripheral. Peripheral watches a sensor and responds to events (by sending data to the central). The size of data sent between central and peripheral does not exceed 16 bytes (future expansion might increase this by a few bytes). Encryption unnecessary. Peripheral device is powered by 2 AA batteries with adequate battery life. Power optimization is not needed.

I'm new to Nordic SDK and started with the ble_app_uart example. I would like to learn about important considerations in moving towards a final app. Here's, generally, how I've migrated ble_app_uart:

1) Removed all use and reference of/to UART as it's not needed. Simply sending data between central and peripheral.

2) Removed all use and reference of/to Board Support Package, and use nrf_gpio directly for IO.

3) Removed Board.c.

4) Replaced NUS UUIDs with our UUIDs.

App functionality is complete and is working well. I'm able to flash to our custom nRF52810 board using the debug out port of the nRF52 dev kit. All appears good.

Given basic requirements, is there more that can be trimmed to reduce app size and complexity?

Is the Queued Write module necessary?

Low and relatively consistent latency of delivery of messages between central and peripheral is important. Is there anything I can do to reduce message delivery latency? I understand there are many factors out of my control, such as the BLE stack on the iOS device and its sharing of RF resources, etc.

I'm using the Logger module (NRF_LOG_INIT, etc.) for debugging. To build and flash release product, how do I essentially turn off logging? Should I be using #define DEBUG and then surround all NRF_LOG statements with #ifdef DEBUG ... #endif, then remove #define DEBUG for building release app?

Anything else for building/flashing a release app?

Enjoying the learning ... thanks for any guidance.

Tim

  • Thanks for sharing your code. I think everything is starting to make a bit more sense now.  The idle_state_handle() will not enter sleep (i.e., call nrf_power_mgmt_run()) until all log messages has been processed by the NRF_LOG_PROCESS macro. That means your program will get to run through the scheduler loop a few times more before going to sleep when you have logging enabled compared to when it's disabled. And I think this is what prevents it from getting in this "sleep forever" state.

    I would consider moving the initialization parts out of the main loop to avoid potential race conditions like this. Maybe something like this (note: is untested):

        do
        {
    
            if (onLoopQueuedTask != onLoopNoOp)
            {
                if (onLoopQueuedTask == onLoopReadEEPROMData)
                {
                    onLoopQueuedTask = onLoopNoOp;
                    read_EEPROM_data();
                }
                else if (onLoopQueuedTask == onLoopExamineEEPROMData)
                {
                    onLoopQueuedTask = onLoopNoOp;
                    examine_EEPROM_data();
                }
            }
        } while (onLoopQueuedTask != onLoopCompleteInitialization);
        onLoopQueuedTask = onLoopNoOp;
        complete_initialization();
    
    
        // Enter main loop.
        for (;;)
        {
            idle_state_handle();
        }

    Hope this helps.

    Vidar 

  • Thanks Vidar. Solved. You deserve a free one-year supply of ice cream. Where shall I send it? :-)

    Once initialized, my app generally responds to 1) GPIOTE interrupt calls, and 2) messages received via BLE from the connected central. It generally uses the approach shown where not much happens in the main loop. In the case of #1, the GPIOTE_IRQHandler() routine will capture some sensor data to globals, then set onLoopQueuedTask to an appropriate value to have the main loop call a routine to do something. For #2, nus_data_handler() is invoked when the connected BLE central sends data. nus_data_handler() saves the data to globals then sets onLoopQueuedTask to an appropriate value so, again, the main loop calls a routine to do something.

    I don't fully understand how a race condition occurs (and what it is) and what caused in my initial code caused it. I'd like to understand and also be sure that the same thing won't happen given the approach I've used for the app to respond to nus_data_handler() and GPIOTE_IRQHandler().

    Phew, I think I'm very close to finally closing this thread. Again, thank you for your help, Vidar.

    Tim

    P.S. Haven't heard back from Håkon regarding my other open thread.

  • Excellent, glad to hear that it's working now:) I'm actually not sure if it's a race condition or if it's more a logical error (the latter seems more likely now when I think about it) that causes the program to enter sleep without having a wake-up source to ever wake it up again. If I recall correctly, it was only the TWIM peripheral that could wake the chip during the startup phase. So it would be possible to get into this sleep forever state if the program did not initiate a TWIM transaction before going to sleep. If you want to get to the bottom of this, I would suggest starting by checking if "read_EEPROM_data()" and "examine_EEPROM_data()" get executed. We know it didn't reach the final init function. In any case, this is not going to cause any problems when you have completed the initialization. The app will always wake up to process Sensor and BLE events whenever it receives them. 

    I can check with Håkon, but could you try to add the busy-wait after task stop as I suggested first? The app should ensure a minimum delay of 46 us before attempting to update the Prescaler value, see TASK and EVENT jitter/delay for more details about this requirement. Also, from the same chapter: "The PRESCALER register is read-only once the RTC is STARTed. Writing to the PRESCALER register when the RTC is started has no effect."

    Vidar

Related