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

Using the SD API directly - is it straightforward, or too much hassle?

I am experienced with ARM Cortex-M devices, but new to Nordic. I am using C++, and have a publisher-subcriber event driven framework of my own in place already. My own software timers are integrated with this (driven by SysTick or RTCx or whatever). My question relates to how best to integrate all this with the NRF52 SDK. I've just started working through some of the BLE examples. I'm slightly hampered by also being new to BLE...

There seems to be a huge layer of abstraction between the application and the actual SoftDevice API. I try to never use macros which generate lines of code, and the SDK appears to be riddled with them. Is it *practical* to just use the SD API directly, and where might I find examples of this? I can see the documentation online for the SD API, including a lot of useful-looking sequence charts, but no PDF. In principle, it looks like a relatively small number of API calls to set up my advertising, services and whatnot, implementing an ISR to receive events, and then pressing go. I'll need to make sure my application's vector table is at the right location, and to give the SoftDevice enough RAM, but that's about it. Is that a fair assessment?   

For context, I found it *much* simpler and cleaner to configure and operate the hardware peripherals directly through registers. I dispensed with the HAL and drivers entirely (except for the convenient definitions of bitmasks and so on). And my driver classes are integrated with my application framework...

Thanks.


Al

  • Hi,

    You have some valid points, but I likely would have used the app blinky example as a starting point, and then merged in the required peripheral example project, e.g.:
    \nRF5_SDK_15.2.0_9412b96\examples\ble_peripheral\ble_app_blinky 
    +
    \nRF5_SDK_15.2.0_9412b96\examples\peripheral\spi 

    If you still want to work low level, I suggested to check out:
    (softdevice spec) http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s132.sds/dita/softdevices/s130/s130sds.html?cp=2_3_1_0
    (message sequence charts) http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.s132.api.v6.1.0/s132_msc_overview.html?cp=2_3_1_1_0_1 
    (low level hardware drivers) http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v15.2.0/nrf52832_drivers.html?cp=4_0_0_2_3 

    However if you plan to support bonding, then my recommendation is to base you example on a project with peer manager, and use it "as-is", since getting it right without peer manager I suspect can be an overwhelming task.

    Best regards,
    Kenneth

  • Thanks for the reply. I've been reading more source, and reading the API documentation. I'll implement something and see how it works out. A beacon seems pretty simple to get the ball rolling.

  • It seems I have fallen at the first hurdle. I cannot even enable the SD.

    I have an application which basically does this:

        // main.cpp

        void my_fault_handler(uint32_t id, uint32_t pc, uint32_t info)
        {
           // Currently empty - perhaps that's an issue.
        }

        extern "C" void SD_EVENT_IRQHandler()
        {
           // Currently empty
        }

        void main()
        {
            // Zero initialise
            nrf_clock_lf_cfg_t clock = {};
            
            // Set up LF clock - contents identical to beacon example.
            clock.source = ...
            ...    
            
            // Enable the SD. This call does not return, but apparently enters an infinite loop.
            // It does not appear to call my_fault_handler() before doing that.
            uint32_t err_code = sd_softdevice_enable(&clock, my_fault_handler);
            
            // Other API calls
            ...
         
            while (true);
        }

        
    The same code (in C) works in the beacon example. I'm using the same board (PCA10040), with the same SD (132) installed, and the same linker script. The only difference is that my file is main.cpp rather than main.c. The startup assembler and SystemInit() are the same. Hmm... now that I think about it, the toolchain *might* be different. I used Keil5 for the example, but my project is CMake sitting over the GNU ARM tools (debugging with Ozone). Pretty sure Keil is configured to use the same compiler and linker, but I'll have to check. Maybe Ozone is the problem - doesn't like SVC or something... I'll try GCC build for the example when I return to work to eliminate some of these questions, but would be grateful for any other insights I can try out.

    I briefly worried about whether extern "C" (or the lack of it) might be an issue, but it appears the SD API is C++-aware. My code doesn't declare any observers: is that an issue?

    I've spent a good while trawling the beacon and HRS examples to work out what API calls I need to set them up. Populating some of the data structures looks a bit convoluted, but in principle at least, it seems as I suspected: I'll need a sequence of API calls to configure the stack, construct the advertisement, services, characteristics, and so on. Peer management nontwithstanding, it all seems pretty straightforward. Or should be. So I'm a bit puzzled at the moment. What subtlety might have I missed?



    Al  




  • Fellow traveler. Please have a look here:

    https://github.com/natersoz/nrf

    I have coded the peripherals side of the equation using the SD with limited SDK dependencies. This code is on master, is working and has issues written against it.

    I am currently working on the central side of the implementation.

    After that: The security manager (there is no bonding nor security handshakes being executed).

    Under docs/nordic/NORDIC.md you might find some other interesting information.

    This is a hobby project for me and it gets attention during winter weekends.  :)

  • I am currently trying to modify my project to include the FreeRTOS example. I am using CMake, and have all the same include paths and files as in the example Makefile. I'm pretty sure I have all the same compiler options and am using an identical linker script. The example dies when it "calls" NRF_LOG_DEFAULT_BACKENDS_INIT() - more macro magic. Why? Because it appears the linker has not included the data for UARTE0 in .bss, so the peripheral m_cb[] control block thingy is uninitiliased. I found that this peripheral was not enabled in the 12,000 line configuration file. I enabled it, which should cause it to be initialised, but it is still broken.

    I've taken a pretty deep dive into the code for the SDK now, and I think I can honestly say it is hands down the worst SDK I have ever tried to use in more than 30 years of software development. The whole point of the SoftDevice seems to be a clean separation between the stack and the application. That's a really attractive, open, non-intrusive model which would allow me to implement my application however I like, and to call the appropriate API methods in the right places, and to handle events via an ISR.

    I expected the SDK to be similar: maybe a bunch a higher level convenience functions and libraries which wrap up the low level details of calling API functions. A sane implementation would allow me to painlessly integrate, for example, a peer manager without affecting any other aspect my application. It seems instead to be a closed all-or-nothing deal which forces a horrible implementation of the observer pattern on me, and forces me to use some of the horrible peripheral drivers (used within the SDK). It appears that the only way to make progress is to take an example and modify it. And I have my doubts about that.

    In my view, this SDK is a very severe impediment to progress with a really, *really* nice chip with a really, *really* nice implementation of the BLE stack, and Nordic simply should discard this entire pile of garbage and start over.


    Al

Related