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

Bluetooth bare metal implementation without binary blob

Hello,

I have a question regarding the nRF5340 microcontroller or similar.
Usually, when programming UART, I2C or SPI bare metal, one is using interrupts, register and buffers in RAM.
Even more complex transmission channels such as ETH with the TCPIP protocol or USB can be programmed bare metal,
for example data pages are allocated in the memory and their pointers are written to the corresponding registers in the µC.
Next step is then to implement the protocol.
But is it also possible to program the bluetooth module of a Nordic Semiconductor microcontroller bare metal?
Without binary blobs, just by using registers, interrupts and internal RAM?
I understand that the next layer (protocol) can be complex. However, I would really like to recreate the Bluetooth stack with interrupts and registers. Many thanks.
Parents
  • However, I would really like to recreate the Bluetooth stack with interrupts and registers.

    I strongly advice you not to attempt to create your own bluetooth stack. It requires a lot of engineering resources to create a proper one. 

    If however you're interested in creating a proprietary protocol using the 2.4GHz RADIO peripheral you're looking at a much easier goal. You can study the sample in NCS/nrf/samples/peripheral/radio_test.

    -edit:
    You can take a look at zephyr's BLE controller, it's open source, but lacks optimizations for the nRF series RADIO. Also the SoftDevice contains radio optimizations that are not available to the public. 

  • For those of us that prefer bare metal, Nordic has provided the "nrfx" modules. These headers and source files help a lot to get code up and running with minimal bloat. I wish the same concept can be applied when writing a Bluetooth application. In the case of a Bluetooth application you want to start with one of the Nordic examples and pair it  down to the essentials. Unfortunately, this is extremely difficult since the examples are really tied to almost every part of the SDK. The file dependencies get out of hand quickly and then you spend days just to get the basic example running in your code base.

    In my view the SDK and its examples are good to get you started with nice looking demos but when you really try to do production code ... well good luck.

  • This where IOsonata library comes into play.  It encapsulate the difficulties of the SDK to provide a simple way to write Bluetooth firmware.  Here is an example of how much code you need to write to advertise an incremental number every second.  The whole firmware code you need to write is 4 function calls and a configuration data.  More details on this blog page

    /**-------------------------------------------------------------------------
    @example	BleAdvertiser.cpp
    
    @brief	BLE non-connectable advertiser
    
    This demo show how to advertise an incremental counter in the manufacturer
    specific data.  The counter increments every second.
    
    @author	Hoang Nguyen Hoan
    @date	Dec. 19, 2017
    
    @license
    
    MIT License
    
    Copyright (c) 2017, I-SYST inc., all rights reserved
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    
    ----------------------------------------------------------------------------*/
    #include <string.h>
    
    #include "app_util.h"
    
    #include "istddef.h"
    #include "ble_app.h"
    #include "iopinctrl.h"
    
    #define DEVICE_NAME                     "Advertiser"
    
    #define APP_ADV_INTERVAL                MSEC_TO_UNITS(100, UNIT_0_625_MS)
    #define APP_ADV_TIMEOUT_IN_SECONDS      MSEC_TO_UNITS(1000, UNIT_10_MS)
    
    uint32_t g_AdvCnt = 0;
    
    const BLEAPP_CFG s_BleAppCfg = {
    	{ // Clock config nrf_clock_lf_cfg_t
    #ifdef IMM_NRF51822
    		NRF_CLOCK_LF_SRC_RC,	// Source RC
    		1, 1, 0
    #else
    		NRF_CLOCK_LF_SRC_XTAL,	// Source 32KHz XTAL
    		//NRF_CLOCK_LF_SRC_RC,
    #ifdef NRF51
    		0, 0, NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM
    #else
    		0, 0, NRF_CLOCK_LF_ACCURACY_20_PPM
    #endif
    #endif
    	},
    	0,						// Number of central link
    	1,						// Number of peripheral link
    	BLEAPP_MODE_NOCONNECT,	// Connectionless beacon type
    	DEVICE_NAME,			// Device name
    	ISYST_BLUETOOTH_ID,		// PnP Bluetooth/USB vendor id
    	1,                      // PnP Product ID
    	0,						// Pnp prod version
    	false,					// Enable device information service (DIS)
    	NULL,					// Pointer device info descriptor
    	(uint8_t*)&g_AdvCnt,   	// Manufacture specific data to advertise
    	sizeof(g_AdvCnt),      	// Length of manufacture specific data
    	NULL,
    	0,
    	BLEAPP_SECTYPE_NONE,    // Secure connection type
    	BLEAPP_SECEXCHG_NONE,   // Security key exchange
    	NULL,      				// Service uuids to advertise
    	0, 						// Total number of uuids
    	APP_ADV_INTERVAL,       	// Advertising interval in msec
    	APP_ADV_TIMEOUT_IN_SECONDS,	// Advertising timeout in sec
    	0,							// Slow advertising interval, if > 0, fallback to
    								// slow interval on adv timeout and advertise until connected
    	0,		// Min. connection interval
    	0,		// Max. connection interval
    	-1,		// Led port nuber
    	-1,		// Led pin number
    	0,
    	0,		// Tx power
    	NULL	// RTOS Softdevice handler
    };
    
    void BlePeriphEvtUserHandler(ble_evt_t * p_ble_evt)
    {
    }
    
    void BleAppAdvTimeoutHandler()
    {
    	g_AdvCnt++;
    
    	BleAppAdvManDataSet((uint8_t*)&g_AdvCnt, sizeof(g_AdvCnt), NULL, 0);
    	BleAppAdvStart(BLEAPP_ADVMODE_FAST);
    }
    
    int main()
    {
        BleAppInit((const BLEAPP_CFG *)&s_BleAppCfg, true);
    
        BleAppRun();
    
    	return 0;
    }
    

Reply
  • This where IOsonata library comes into play.  It encapsulate the difficulties of the SDK to provide a simple way to write Bluetooth firmware.  Here is an example of how much code you need to write to advertise an incremental number every second.  The whole firmware code you need to write is 4 function calls and a configuration data.  More details on this blog page

    /**-------------------------------------------------------------------------
    @example	BleAdvertiser.cpp
    
    @brief	BLE non-connectable advertiser
    
    This demo show how to advertise an incremental counter in the manufacturer
    specific data.  The counter increments every second.
    
    @author	Hoang Nguyen Hoan
    @date	Dec. 19, 2017
    
    @license
    
    MIT License
    
    Copyright (c) 2017, I-SYST inc., all rights reserved
    
    Permission is hereby granted, free of charge, to any person obtaining a copy
    of this software and associated documentation files (the "Software"), to deal
    in the Software without restriction, including without limitation the rights
    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    copies of the Software, and to permit persons to whom the Software is
    furnished to do so, subject to the following conditions:
    
    The above copyright notice and this permission notice shall be included in all
    copies or substantial portions of the Software.
    
    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
    SOFTWARE.
    
    ----------------------------------------------------------------------------*/
    #include <string.h>
    
    #include "app_util.h"
    
    #include "istddef.h"
    #include "ble_app.h"
    #include "iopinctrl.h"
    
    #define DEVICE_NAME                     "Advertiser"
    
    #define APP_ADV_INTERVAL                MSEC_TO_UNITS(100, UNIT_0_625_MS)
    #define APP_ADV_TIMEOUT_IN_SECONDS      MSEC_TO_UNITS(1000, UNIT_10_MS)
    
    uint32_t g_AdvCnt = 0;
    
    const BLEAPP_CFG s_BleAppCfg = {
    	{ // Clock config nrf_clock_lf_cfg_t
    #ifdef IMM_NRF51822
    		NRF_CLOCK_LF_SRC_RC,	// Source RC
    		1, 1, 0
    #else
    		NRF_CLOCK_LF_SRC_XTAL,	// Source 32KHz XTAL
    		//NRF_CLOCK_LF_SRC_RC,
    #ifdef NRF51
    		0, 0, NRF_CLOCK_LF_XTAL_ACCURACY_20_PPM
    #else
    		0, 0, NRF_CLOCK_LF_ACCURACY_20_PPM
    #endif
    #endif
    	},
    	0,						// Number of central link
    	1,						// Number of peripheral link
    	BLEAPP_MODE_NOCONNECT,	// Connectionless beacon type
    	DEVICE_NAME,			// Device name
    	ISYST_BLUETOOTH_ID,		// PnP Bluetooth/USB vendor id
    	1,                      // PnP Product ID
    	0,						// Pnp prod version
    	false,					// Enable device information service (DIS)
    	NULL,					// Pointer device info descriptor
    	(uint8_t*)&g_AdvCnt,   	// Manufacture specific data to advertise
    	sizeof(g_AdvCnt),      	// Length of manufacture specific data
    	NULL,
    	0,
    	BLEAPP_SECTYPE_NONE,    // Secure connection type
    	BLEAPP_SECEXCHG_NONE,   // Security key exchange
    	NULL,      				// Service uuids to advertise
    	0, 						// Total number of uuids
    	APP_ADV_INTERVAL,       	// Advertising interval in msec
    	APP_ADV_TIMEOUT_IN_SECONDS,	// Advertising timeout in sec
    	0,							// Slow advertising interval, if > 0, fallback to
    								// slow interval on adv timeout and advertise until connected
    	0,		// Min. connection interval
    	0,		// Max. connection interval
    	-1,		// Led port nuber
    	-1,		// Led pin number
    	0,
    	0,		// Tx power
    	NULL	// RTOS Softdevice handler
    };
    
    void BlePeriphEvtUserHandler(ble_evt_t * p_ble_evt)
    {
    }
    
    void BleAppAdvTimeoutHandler()
    {
    	g_AdvCnt++;
    
    	BleAppAdvManDataSet((uint8_t*)&g_AdvCnt, sizeof(g_AdvCnt), NULL, 0);
    	BleAppAdvStart(BLEAPP_ADVMODE_FAST);
    }
    
    int main()
    {
        BleAppInit((const BLEAPP_CFG *)&s_BleAppCfg, true);
    
        BleAppRun();
    
    	return 0;
    }
    

Children
  • That's the point with bare metal development. We do not want it simple way.

    We need a detailed description of the registers and how to initialize the module. That means which peripheral clock, which GPIOs in which order etc. Which interrupts are triggered when, how do you initialize DMA for the module.

    Understanding how the data flow is designed is also very important. You actually always understand this in the process when you read the register descriptions and examples, but it already existed before, when the developers wrote VHDL / Verilog, they had an idea of ​​how the module should work and how the interaction between PHY, registers, interrupts, DMA and memory is. Why not write it down?

    That's what bare metal is about.

Related