diff --git a/components/BLE/COMPONENT_BlueNRG_MS/BlueNrgMsHCIDriver.cpp b/components/BLE/COMPONENT_BlueNRG_MS/BlueNrgMsHCIDriver.cpp deleted file mode 100644 index 8676c15..0000000 --- a/components/BLE/COMPONENT_BlueNRG_MS/BlueNrgMsHCIDriver.cpp +++ /dev/null @@ -1,624 +0,0 @@ -/* - * Copyright (c) 2017-2020 ARM Limited - * Copyright (c) 2017-2020 STMicroelectronics - * SPDX-License-Identifier: Apache-2.0 - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include - -// drivers -#include "drivers/DigitalOut.h" -#include "drivers/SPI.h" -#include "drivers/InterruptIn.h" - -// platform -#include "platform/mbed_wait_api.h" - -// FEATURE_BLE/targets/TARGET_CORDIO -#include "BLEInstanceBase.h" -#include "CordioHCIDriver.h" -#include "CordioHCITransportDriver.h" -#include "hci_api.h" -#include "hci_cmd.h" -#include "hci_core.h" -#include "dm_api.h" -#include "bstream.h" -#include "hci_mbed_os_adaptation.h" - -// rtos -#include "Thread.h" -#include "Semaphore.h" -#include "Mutex.h" - -#define HCI_RESET_RAND_CNT 4 - -#define VENDOR_SPECIFIC_EVENT 0xFF -#define EVT_BLUENRG_MS_INITIALIZED 0x0001 -#define ACI_READ_CONFIG_DATA_OPCODE 0xFC0D -#define ACI_WRITE_CONFIG_DATA_OPCODE 0xFC0C -#define ACI_GATT_INIT_OPCODE 0xFD01 -#define ACI_GAP_INIT_OPCODE 0xFC8A - -#define PUBLIC_ADDRESS_OFFSET 0x00 -#define RANDOM_STATIC_ADDRESS_OFFSET 0x80 -#define LL_WITHOUT_HOST_OFFSET 0x2C -#define ROLE_OFFSET 0x2D - -#define SPI_STACK_SIZE 1024 - -namespace ble { -namespace vendor { -namespace bluenrg_ms { - -/** - * BlueNRG_MS HCI driver implementation. - * @see CordioHCIDriver - */ -class HCIDriver : public CordioHCIDriver { -public: - /** - * Construction of the BlueNRG_MS HCIDriver. - * @param transport: Transport of the HCI commands. - * @param rst: Name of the reset pin - */ - HCIDriver(CordioHCITransportDriver &transport_driver, PinName rst) : - CordioHCIDriver(transport_driver), rst(rst) { } - - /** - * @see CordioHCIDriver::do_initialize - */ - virtual void do_initialize() - { - bluenrg_ms_reset(); - } - - /** - * @see CordioHCIDriver::get_buffer_pool_description - */ - ble::buf_pool_desc_t get_buffer_pool_description() - { - // Use default buffer pool - return ble::CordioHCIDriver::get_default_buffer_pool_description(); - } - - /** - * @see CordioHCIDriver::start_reset_sequence - */ - virtual void start_reset_sequence() - { - reset_received = false; - bluenrg_ms_initialized = false; - enable_link_layer_mode_ongoing = false; - /* send an HCI Reset command to start the sequence */ - HciResetCmd(); - } - - /** - * @see CordioHCIDriver::do_terminate - */ - virtual void do_terminate() - { - - } - - /** - * @see CordioHCIDriver::handle_reset_sequence - */ - virtual void handle_reset_sequence(uint8_t *pMsg) - { - uint16_t opcode; - static uint8_t randCnt; - - /* if event is a command complete event */ - if (*pMsg == HCI_CMD_CMPL_EVT) { - /* parse parameters */ - pMsg += HCI_EVT_HDR_LEN; - pMsg++; /* skip num packets */ - BSTREAM_TO_UINT16(opcode, pMsg); - pMsg++; /* skip status */ - - /* decode opcode */ - switch (opcode) { - case HCI_OPCODE_RESET: { - /* initialize rand command count */ - randCnt = 0; - reset_received = true; - // bluenrg_ms_initialized event has to come after the hci reset event - bluenrg_ms_initialized = false; - } - break; - - // ACL packet - case ACI_WRITE_CONFIG_DATA_OPCODE: - if (enable_link_layer_mode_ongoing) { - enable_link_layer_mode_ongoing = false; - aciSetRole(); - } else { - aciGattInit(); - } - break; - - case ACI_GATT_INIT_OPCODE: - aciGapInit(); - break; - - case ACI_GAP_INIT_OPCODE: - aciReadConfigParameter(RANDOM_STATIC_ADDRESS_OFFSET); - break; - - case ACI_READ_CONFIG_DATA_OPCODE: - // note: will send the HCI command to send the random address - set_random_static_address(pMsg); - break; - - case HCI_OPCODE_LE_SET_RAND_ADDR: - HciSetEventMaskCmd((uint8_t *) hciEventMask); - break; - - case HCI_OPCODE_SET_EVENT_MASK: - /* send next command in sequence */ - HciLeSetEventMaskCmd((uint8_t *) hciLeEventMask); - break; - - case HCI_OPCODE_LE_SET_EVENT_MASK: -// Note: the public address is not read because there is no valid public address provisioned by default on the target -// You can enable it thanks to json "valid-public-bd-address" config value -#if MBED_CONF_BLUENRG_MS_VALID_PUBLIC_BD_ADDRESS == 1 - /* send next command in sequence */ - HciReadBdAddrCmd(); - break; - - case HCI_OPCODE_READ_BD_ADDR: - /* parse and store event parameters */ - BdaCpy(hciCoreCb.bdAddr, pMsg); - - /* send next command in sequence */ -#endif - HciLeReadBufSizeCmd(); - break; - - case HCI_OPCODE_LE_READ_BUF_SIZE: - /* parse and store event parameters */ - BSTREAM_TO_UINT16(hciCoreCb.bufSize, pMsg); - BSTREAM_TO_UINT8(hciCoreCb.numBufs, pMsg); - - /* initialize ACL buffer accounting */ - hciCoreCb.availBufs = hciCoreCb.numBufs; - - /* send next command in sequence */ - HciLeReadSupStatesCmd(); - break; - - case HCI_OPCODE_LE_READ_SUP_STATES: - /* parse and store event parameters */ - memcpy(hciCoreCb.leStates, pMsg, HCI_LE_STATES_LEN); - - /* send next command in sequence */ - HciLeReadWhiteListSizeCmd(); - break; - - case HCI_OPCODE_LE_READ_WHITE_LIST_SIZE: - /* parse and store event parameters */ - BSTREAM_TO_UINT8(hciCoreCb.whiteListSize, pMsg); - - /* send next command in sequence */ - HciLeReadLocalSupFeatCmd(); - break; - - case HCI_OPCODE_LE_READ_LOCAL_SUP_FEAT: - /* parse and store event parameters */ - BSTREAM_TO_UINT16(hciCoreCb.leSupFeat, pMsg); - - /* send next command in sequence */ - hciCoreReadResolvingListSize(); - break; - - case HCI_OPCODE_LE_READ_RES_LIST_SIZE: - /* parse and store event parameters */ - BSTREAM_TO_UINT8(hciCoreCb.resListSize, pMsg); - - /* send next command in sequence */ - hciCoreReadMaxDataLen(); - break; - - case HCI_OPCODE_LE_READ_MAX_DATA_LEN: { - uint16_t maxTxOctets; - uint16_t maxTxTime; - - BSTREAM_TO_UINT16(maxTxOctets, pMsg); - BSTREAM_TO_UINT16(maxTxTime, pMsg); - - /* use Controller's maximum supported payload octets and packet duration times - * for transmission as Host's suggested values for maximum transmission number - * of payload octets and maximum packet transmission time for new connections. - */ - HciLeWriteDefDataLen(maxTxOctets, maxTxTime); - } - break; - - case HCI_OPCODE_LE_WRITE_DEF_DATA_LEN: - if (hciCoreCb.extResetSeq) { - /* send first extended command */ - (*hciCoreCb.extResetSeq)(pMsg, opcode); - } else { - /* initialize extended parameters */ - hciCoreCb.maxAdvDataLen = 0; - hciCoreCb.numSupAdvSets = 0; - hciCoreCb.perAdvListSize = 0; - - /* send next command in sequence */ - HciLeRandCmd(); - } - break; - - case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN: - case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS: - case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE: - if (hciCoreCb.extResetSeq) { - /* send next extended command in sequence */ - (*hciCoreCb.extResetSeq)(pMsg, opcode); - } - break; - - case HCI_OPCODE_LE_RAND: - /* check if need to send second rand command */ - if (randCnt < (HCI_RESET_RAND_CNT - 1)) { - randCnt++; - HciLeRandCmd(); - } else { - signal_reset_sequence_done(); - } - break; - - default: - break; - } - } else { - /** - * vendor specific event - */ - if (pMsg[0] == VENDOR_SPECIFIC_EVENT) { - /* parse parameters */ - pMsg += HCI_EVT_HDR_LEN; - BSTREAM_TO_UINT16(opcode, pMsg); - - if (opcode == EVT_BLUENRG_MS_INITIALIZED) { - if (bluenrg_ms_initialized) { - return; - } - bluenrg_ms_initialized = true; - if (reset_received) { - aciEnableLinkLayerModeOnly(); - } - } - - } - } - } - -private: - void aciEnableLinkLayerModeOnly() - { - uint8_t data[1] = { 0x01 }; - enable_link_layer_mode_ongoing = true; - aciWriteConfigData(LL_WITHOUT_HOST_OFFSET, data); - } - - void aciSetRole() - { - // master and slave, simultaneous advertising and scanning - // (up to 4 connections) - uint8_t data[1] = { 0x04 }; - aciWriteConfigData(ROLE_OFFSET, data); - } - - void aciGattInit() - { - uint8_t *pBuf = hciCmdAlloc(ACI_GATT_INIT_OPCODE, 0); - if (!pBuf) { - return; - } - hciCmdSend(pBuf); - } - - void aciGapInit() - { - uint8_t *pBuf = hciCmdAlloc(ACI_GAP_INIT_OPCODE, 3); - if (!pBuf) { - return; - } - pBuf[3] = 0xF; - pBuf[4] = 0; - pBuf[5] = 0; - hciCmdSend(pBuf); - } - - void aciReadConfigParameter(uint8_t offset) - { - uint8_t *pBuf = hciCmdAlloc(ACI_READ_CONFIG_DATA_OPCODE, 1); - if (!pBuf) { - return; - } - - pBuf[3] = offset; - hciCmdSend(pBuf); - } - - template - void aciWriteConfigData(uint8_t offset, uint8_t (&buf)[N]) - { - uint8_t *pBuf = hciCmdAlloc(ACI_WRITE_CONFIG_DATA_OPCODE, 2 + N); - if (!pBuf) { - return; - } - - pBuf[3] = offset; - pBuf[4] = N; - memcpy(pBuf + 5, buf, N); - hciCmdSend(pBuf); - } - - void hciCoreReadResolvingListSize(void) - { - /* if LL Privacy is supported by Controller and included */ - if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_PRIVACY) && - (hciLeSupFeatCfg & HCI_LE_SUP_FEAT_PRIVACY)) { - /* send next command in sequence */ - HciLeReadResolvingListSize(); - } else { - hciCoreCb.resListSize = 0; - - /* send next command in sequence */ - hciCoreReadMaxDataLen(); - } - } - - void hciCoreReadMaxDataLen(void) - { - /* if LE Data Packet Length Extensions is supported by Controller and included */ - if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_DATA_LEN_EXT) && - (hciLeSupFeatCfg & HCI_LE_SUP_FEAT_DATA_LEN_EXT)) { - /* send next command in sequence */ - HciLeReadMaxDataLen(); - } else { - /* send next command in sequence */ - HciLeRandCmd(); - } - } - - void bluenrg_ms_reset() - { - /* Reset BlueNRG_MS SPI interface. Hold reset line to 0 for 1500ms */ - rst = 0; - wait_us(1500); - rst = 1; - - /* Wait for the radio to come back up */ - wait_us(100000); - } - - mbed::DigitalOut rst; - bool reset_received; - bool bluenrg_ms_initialized; - bool enable_link_layer_mode_ongoing; -}; - -/** - * Transport driver of the ST BlueNRG_MS shield. - * @important: With that driver, it is assumed that the SPI bus used is not shared - * with other SPI peripherals. The reasons behind this choice are simplicity and - * performance: - * - Reading from the peripheral SPI can be challenging especially if other - * threads access the same SPI bus. Indeed it is common that the function - * spiRead yield nothings even if the chip has signaled data with the irq - * line. Sharing would make the situation worse and increase the risk of - * timeout of HCI commands / response. - * - This driver can be used even if the RTOS is disabled or not present it may - * may be usefull for some targets. - * - * If The SPI is shared with other peripherals then the best option would be to - * handle SPI read in a real time thread woken up by an event flag. - * - * Other mechanisms might also be added in the future to handle data read as an - * event from the stack. This might not be the best solution for all BLE chip; - * especially this one. - */ -class TransportDriver : public CordioHCITransportDriver { -public: - /** - * Construct the transport driver required by a BlueNRG_MS module. - * @param mosi Pin of the SPI mosi - * @param miso Pin of the SPI miso - * @param sclk Pin of the SPI clock - * @param irq Pin used by the module to signal data are available. - */ - TransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ncs, PinName irq) - : spi(mosi, miso, sclk), nCS(ncs), irq(irq), _spi_thread(osPriorityNormal, SPI_STACK_SIZE, _spi_thread_stack) - { - _spi_thread.start(mbed::callback(this, &TransportDriver::spi_read_cb)); - } - - virtual ~TransportDriver() { } - - /** - * @see CordioHCITransportDriver::initialize - */ - virtual void initialize() - { - // Setup the spi for 8 bit data, low clock polarity, - // 1-edge phase, with an 8MHz clock rate - spi.format(8, 0); - spi.frequency(8000000); - - // Deselect the BlueNRG_MS chip by keeping its nCS signal high - nCS = 1; - - wait_us(500); - - // Set the interrupt handler for the device - irq.mode(PullDown); // set irq mode - irq.rise(mbed::callback(this, &TransportDriver::HCI_Isr)); - } - - /** - * @see CordioHCITransportDriver::terminate - */ - virtual void terminate() { } - - /** - * @see CordioHCITransportDriver::write - */ - virtual uint16_t write(uint8_t type, uint16_t len, uint8_t *pData) - { - // repeat write until successfull. A number of attempt or timeout might - // be useful - while (spiWrite(type, pData, len) == 0) { } - return len; - } - -private: - uint16_t spiWrite(uint8_t type, const uint8_t *data, uint16_t data_length) - { - static const uint8_t header_master[] = { - 0x0A, 0x00, 0x00, 0x00, 0x00 - }; - uint8_t header_slave[] = { 0xaa, 0x00, 0x00, 0x00, 0x00 }; - uint16_t data_written = 0; - uint16_t write_buffer_size = 0; - - _spi_mutex.lock(); - - /* CS reset */ - nCS = 0; - - /* Exchange header */ - for (uint8_t i = 0; i < sizeof(header_master); ++i) { - header_slave[i] = spi.write(header_master[i]); - } - - if (header_slave[0] != 0x02) { - goto exit; - } - - write_buffer_size = header_slave[2] << 8 | header_slave[1]; - - if (write_buffer_size == 0 || write_buffer_size < (data_length + 1)) { - goto exit; - } - - spi.write(type); - - data_written = data_length; - for (uint16_t i = 0; i < data_length; ++i) { - spi.write(data[i]); - } - -exit: - nCS = 1; - - _spi_mutex.unlock(); - - return data_written; - } - - uint16_t spiRead(uint8_t *data_buffer, const uint16_t buffer_size) - { - static const uint8_t header_master[] = {0x0b, 0x00, 0x00, 0x00, 0x00}; - uint8_t header_slave[5] = { 0xaa, 0x00, 0x00, 0x00, 0x00}; - uint16_t read_length = 0; - uint16_t data_available = 0; - - nCS = 0; - - /* Read the header */ - for (size_t i = 0; i < sizeof(header_master); i++) { - header_slave[i] = spi.write(header_master[i]); - } - - if (header_slave[0] != 0x02) { - goto exit; - } - - data_available = (header_slave[4] << 8) | header_slave[3]; - read_length = data_available > buffer_size ? buffer_size : data_available; - - for (uint16_t i = 0; i < read_length; ++i) { - data_buffer[i] = spi.write(0xFF); - } - -exit: - nCS = 1; - - return read_length; - } - - /* - * might be split into two parts: the IRQ signaling a real time thread and - * the real time thread reading data from the SPI. - */ - void HCI_Isr(void) - { - _spi_read_sem.release(); - } - - void spi_read_cb() - { - uint8_t data_buffer[256]; - while (true) { - _spi_read_sem.acquire(); - - _spi_mutex.lock(); - while (irq == 1) { - uint16_t data_read = spiRead(data_buffer, sizeof(data_buffer)); - on_data_received(data_buffer, data_read); - } - _spi_mutex.unlock(); - } - } - - /** - * Unsafe SPI, does not lock when SPI access happens. - */ - ::mbed::SPI spi; - mbed::DigitalOut nCS; - mbed::InterruptIn irq; - rtos::Thread _spi_thread; - uint8_t _spi_thread_stack[SPI_STACK_SIZE]; - rtos::Semaphore _spi_read_sem; - rtos::Mutex _spi_mutex; -}; - -} // namespace bluenrg_ms -} // namespace vendor -} // namespace ble - -/** - * Cordio HCI driver factory - */ -ble::CordioHCIDriver &ble_cordio_get_hci_driver() -{ - static ble::vendor::bluenrg_ms::TransportDriver transport_driver( - MBED_CONF_BLUENRG_MS_SPI_MOSI, - MBED_CONF_BLUENRG_MS_SPI_MISO, - MBED_CONF_BLUENRG_MS_SPI_SCK, - MBED_CONF_BLUENRG_MS_SPI_NCS, - MBED_CONF_BLUENRG_MS_SPI_IRQ - ); - static ble::vendor::bluenrg_ms::HCIDriver hci_driver( - transport_driver, - MBED_CONF_BLUENRG_MS_SPI_RESET - ); - return hci_driver; -} diff --git a/components/BLE/COMPONENT_BlueNRG_MS/README.md b/components/BLE/COMPONENT_BlueNRG_MS/README.md deleted file mode 100644 index 434a58a..0000000 --- a/components/BLE/COMPONENT_BlueNRG_MS/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# BlueNRG_MS - -BLE API wrapper Library for BlueNRG (Bluetooth Low Energy) - -Maybe a simple table like this could help: - -|Name|Type|Bluetooth compliance|Status|Used in shields & boards|Link| -|-----------|----------|-----|-|-|-| -|SPBTLE-RF |Module |v4.1 |Not recommended for new designs |X-NUCLEO-IDB05A1, DISCO-L475VG-IOT01A, DISCO-L562QE | https://www.st.com/en/wireless-transceivers-mcus-and-modules/spbtle-rf.html | -|BlueNRG-M0 |Module |v4.2 |Active (included in ST's Longevity Program) |No | https://www.st.com/en/wireless-transceivers-mcus-and-modules/bluenrg-m0.html | -|BlueNRG-MS |Processor |v4.2 |Active (included in ST's Longevity Program) |X-NUCLEO-IDB05A2 (coming soon) | https://www.st.com/en/wireless-transceivers-mcus-and-modules/bluenrg-ms.html | - - -It uses ARM Cordio stack instead of the ST BlueNRG stack. - -## History - -- deprecated ST BLE port: https://github.com/ARMmbed/ble-x-nucleo-idb0xa1 -- deprecated X-NUCLEO-IDB05A1 BlueNRG : https://github.com/ARMmbed/cordio-ble-x-nucleo-idb0xa1 - - -## Boards - -### X-NUCLEO-IDB05A1 - -Bluetooth Low Energy Nucleo Expansion Board: - -https://developer.mbed.org/components/X-NUCLEO-IDB05A1-Bluetooth-Low-Energy/ - -### DISCO-L475VG-IOT01A - -STM32L4 Discovery kit IoT node, low-power wireless, Bluetooth V4.1 module (SPBTLE-RF) - -https://os.mbed.com/platforms/ST-Discovery-L475E-IOT01A/ - - -### DISCO-L562QE - -STM32L562E-DK Discovery kit with Bluetooth V4.1 low energy module and Arm Cortex-M33 with TrustZone - -https://os.mbed.com/platforms/ST-Discovery-L562QE/ - - -## Driver configuration - -In order to use the BlueNRG-MS module together with other targets, -you may need to override default settings in your local `mbed_app.json` file - -### ST-DISCO boards - -Default settings for `DISCO-L475VG-IOT01A` and `DISCO-L562QE` are configured - -### Arduino Connector Compatibility Warning - -Default Arduino connection is using: - -``` - "SPI_MOSI": "D11", - "SPI_MISO": "D12", - "SPI_nCS": "A1", - "SPI_RESET": "D7", - "SPI_IRQ": "A0", - "SPI_SCK": "D3", - "valid-public-bd-address": false -``` - -X-NUCLEO-IDB05A1 is Arduino compatible with an exception: instead of using pin **D13** for the SPI clock, pin **D3** is used. -The default configuration for this library is having the SPI clock on pin **D3**. - -To be fully Arduino compatible, X-NUCLEO-IDB05A1 needs a small HW patch. - -For X-NUCLEO-IDB05A1 this patch consists in removing zero resistor **R4** and instead soldering zero resistor **R6**. - -In case you patch your board, then you also have to configure this library to use pin **D13** to drive the SPI clock. -To this aim you need to update your local mbed_app.json file with: - -``` - "target_overrides": { - "XXXX": { - "bluenrg_ms.SPI_SCK": "D13" - }, -``` - -If you use pin **D13** for the SPI clock, please be aware that on some STM32 Nucleo boards you may **not** drive the LED, -otherwise you will get a conflict: the LED on STM32 Nucleo boards is connected to pin **D13**. - -Referring to the current list of tested platforms (see [X-NUCLEO-IDB05A1](https://developer.mbed.org/components/X-NUCLEO-IDB05A1-Bluetooth-Low-Energy/) page), -the patch is required for -- [ST-Nucleo-F103RB](https://developer.mbed.org/platforms/ST-Nucleo-F103RB/) -- [ST-Nucleo-F411RE](https://developer.mbed.org/platforms/ST-Nucleo-F411RE/) -- [ST-Nucleo-F446RE](https://developer.mbed.org/platforms/ST-Nucleo-F446RE/) -- [FRDM-K64F](https://developer.mbed.org/platforms/FRDM-K64F/) - -### Target Configuration - -To use that library, the target requires some extra configuration in the application `mbed_app.json`. In the `target_overides` section: - -* BLE feature has to be enabled - -```json -"target.features_add": ["BLE"] -``` - -* BlueNRG module has to be enabled - -```json -"target.components_add": ["BlueNRG_MS"] -``` - -* Extra labels have to be defined to include the cordio stack and this library: - -```json -"target.extra_labels_add": ["CORDIO"] -``` - -As an example, the target overide section for the `NUCLEO_F401RE` would be: - -```json - "NUCLEO_F401RE": { - "target.features_add": ["BLE"], - "target.components_add": ["BlueNRG_MS"], - "target.extra_labels_add": ["CORDIO"] - } -``` diff --git a/components/BLE/COMPONENT_BlueNRG_MS/mbed_lib.json b/components/BLE/COMPONENT_BlueNRG_MS/mbed_lib.json deleted file mode 100644 index 610edcc..0000000 --- a/components/BLE/COMPONENT_BlueNRG_MS/mbed_lib.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "bluenrg_ms", - "config": { - "SPI_MOSI": "D11", - "SPI_MISO": "D12", - "SPI_nCS": "A1", - "SPI_RESET": "D7", - "SPI_IRQ": "A0", - "SPI_SCK": "D3", - "valid-public-bd-address": { - "help": "Read the BD public address at startup", - "value": false - } - }, - "target_overrides": { - "K64F": { - "SPI_SCK": "D13" - }, - "DISCO_L475VG_IOT01A": { - "SPI_MOSI": "PC_12", - "SPI_MISO": "PC_11", - "SPI_nCS": "PD_13", - "SPI_RESET": "PA_8", - "SPI_IRQ": "PE_6", - "SPI_SCK": "PC_10" - }, - "DISCO_L562QE": { - "SPI_MOSI": "PG_4", - "SPI_MISO": "PG_3", - "SPI_nCS": "PG_5", - "SPI_RESET": "PG_8", - "SPI_IRQ": "PG_6", - "SPI_SCK": "PG_2" - } - } -} diff --git a/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/BlueNrgMsHCIDriver.cpp b/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/BlueNrgMsHCIDriver.cpp new file mode 100644 index 0000000..8676c15 --- /dev/null +++ b/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/BlueNrgMsHCIDriver.cpp @@ -0,0 +1,624 @@ +/* + * Copyright (c) 2017-2020 ARM Limited + * Copyright (c) 2017-2020 STMicroelectronics + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +// drivers +#include "drivers/DigitalOut.h" +#include "drivers/SPI.h" +#include "drivers/InterruptIn.h" + +// platform +#include "platform/mbed_wait_api.h" + +// FEATURE_BLE/targets/TARGET_CORDIO +#include "BLEInstanceBase.h" +#include "CordioHCIDriver.h" +#include "CordioHCITransportDriver.h" +#include "hci_api.h" +#include "hci_cmd.h" +#include "hci_core.h" +#include "dm_api.h" +#include "bstream.h" +#include "hci_mbed_os_adaptation.h" + +// rtos +#include "Thread.h" +#include "Semaphore.h" +#include "Mutex.h" + +#define HCI_RESET_RAND_CNT 4 + +#define VENDOR_SPECIFIC_EVENT 0xFF +#define EVT_BLUENRG_MS_INITIALIZED 0x0001 +#define ACI_READ_CONFIG_DATA_OPCODE 0xFC0D +#define ACI_WRITE_CONFIG_DATA_OPCODE 0xFC0C +#define ACI_GATT_INIT_OPCODE 0xFD01 +#define ACI_GAP_INIT_OPCODE 0xFC8A + +#define PUBLIC_ADDRESS_OFFSET 0x00 +#define RANDOM_STATIC_ADDRESS_OFFSET 0x80 +#define LL_WITHOUT_HOST_OFFSET 0x2C +#define ROLE_OFFSET 0x2D + +#define SPI_STACK_SIZE 1024 + +namespace ble { +namespace vendor { +namespace bluenrg_ms { + +/** + * BlueNRG_MS HCI driver implementation. + * @see CordioHCIDriver + */ +class HCIDriver : public CordioHCIDriver { +public: + /** + * Construction of the BlueNRG_MS HCIDriver. + * @param transport: Transport of the HCI commands. + * @param rst: Name of the reset pin + */ + HCIDriver(CordioHCITransportDriver &transport_driver, PinName rst) : + CordioHCIDriver(transport_driver), rst(rst) { } + + /** + * @see CordioHCIDriver::do_initialize + */ + virtual void do_initialize() + { + bluenrg_ms_reset(); + } + + /** + * @see CordioHCIDriver::get_buffer_pool_description + */ + ble::buf_pool_desc_t get_buffer_pool_description() + { + // Use default buffer pool + return ble::CordioHCIDriver::get_default_buffer_pool_description(); + } + + /** + * @see CordioHCIDriver::start_reset_sequence + */ + virtual void start_reset_sequence() + { + reset_received = false; + bluenrg_ms_initialized = false; + enable_link_layer_mode_ongoing = false; + /* send an HCI Reset command to start the sequence */ + HciResetCmd(); + } + + /** + * @see CordioHCIDriver::do_terminate + */ + virtual void do_terminate() + { + + } + + /** + * @see CordioHCIDriver::handle_reset_sequence + */ + virtual void handle_reset_sequence(uint8_t *pMsg) + { + uint16_t opcode; + static uint8_t randCnt; + + /* if event is a command complete event */ + if (*pMsg == HCI_CMD_CMPL_EVT) { + /* parse parameters */ + pMsg += HCI_EVT_HDR_LEN; + pMsg++; /* skip num packets */ + BSTREAM_TO_UINT16(opcode, pMsg); + pMsg++; /* skip status */ + + /* decode opcode */ + switch (opcode) { + case HCI_OPCODE_RESET: { + /* initialize rand command count */ + randCnt = 0; + reset_received = true; + // bluenrg_ms_initialized event has to come after the hci reset event + bluenrg_ms_initialized = false; + } + break; + + // ACL packet + case ACI_WRITE_CONFIG_DATA_OPCODE: + if (enable_link_layer_mode_ongoing) { + enable_link_layer_mode_ongoing = false; + aciSetRole(); + } else { + aciGattInit(); + } + break; + + case ACI_GATT_INIT_OPCODE: + aciGapInit(); + break; + + case ACI_GAP_INIT_OPCODE: + aciReadConfigParameter(RANDOM_STATIC_ADDRESS_OFFSET); + break; + + case ACI_READ_CONFIG_DATA_OPCODE: + // note: will send the HCI command to send the random address + set_random_static_address(pMsg); + break; + + case HCI_OPCODE_LE_SET_RAND_ADDR: + HciSetEventMaskCmd((uint8_t *) hciEventMask); + break; + + case HCI_OPCODE_SET_EVENT_MASK: + /* send next command in sequence */ + HciLeSetEventMaskCmd((uint8_t *) hciLeEventMask); + break; + + case HCI_OPCODE_LE_SET_EVENT_MASK: +// Note: the public address is not read because there is no valid public address provisioned by default on the target +// You can enable it thanks to json "valid-public-bd-address" config value +#if MBED_CONF_BLUENRG_MS_VALID_PUBLIC_BD_ADDRESS == 1 + /* send next command in sequence */ + HciReadBdAddrCmd(); + break; + + case HCI_OPCODE_READ_BD_ADDR: + /* parse and store event parameters */ + BdaCpy(hciCoreCb.bdAddr, pMsg); + + /* send next command in sequence */ +#endif + HciLeReadBufSizeCmd(); + break; + + case HCI_OPCODE_LE_READ_BUF_SIZE: + /* parse and store event parameters */ + BSTREAM_TO_UINT16(hciCoreCb.bufSize, pMsg); + BSTREAM_TO_UINT8(hciCoreCb.numBufs, pMsg); + + /* initialize ACL buffer accounting */ + hciCoreCb.availBufs = hciCoreCb.numBufs; + + /* send next command in sequence */ + HciLeReadSupStatesCmd(); + break; + + case HCI_OPCODE_LE_READ_SUP_STATES: + /* parse and store event parameters */ + memcpy(hciCoreCb.leStates, pMsg, HCI_LE_STATES_LEN); + + /* send next command in sequence */ + HciLeReadWhiteListSizeCmd(); + break; + + case HCI_OPCODE_LE_READ_WHITE_LIST_SIZE: + /* parse and store event parameters */ + BSTREAM_TO_UINT8(hciCoreCb.whiteListSize, pMsg); + + /* send next command in sequence */ + HciLeReadLocalSupFeatCmd(); + break; + + case HCI_OPCODE_LE_READ_LOCAL_SUP_FEAT: + /* parse and store event parameters */ + BSTREAM_TO_UINT16(hciCoreCb.leSupFeat, pMsg); + + /* send next command in sequence */ + hciCoreReadResolvingListSize(); + break; + + case HCI_OPCODE_LE_READ_RES_LIST_SIZE: + /* parse and store event parameters */ + BSTREAM_TO_UINT8(hciCoreCb.resListSize, pMsg); + + /* send next command in sequence */ + hciCoreReadMaxDataLen(); + break; + + case HCI_OPCODE_LE_READ_MAX_DATA_LEN: { + uint16_t maxTxOctets; + uint16_t maxTxTime; + + BSTREAM_TO_UINT16(maxTxOctets, pMsg); + BSTREAM_TO_UINT16(maxTxTime, pMsg); + + /* use Controller's maximum supported payload octets and packet duration times + * for transmission as Host's suggested values for maximum transmission number + * of payload octets and maximum packet transmission time for new connections. + */ + HciLeWriteDefDataLen(maxTxOctets, maxTxTime); + } + break; + + case HCI_OPCODE_LE_WRITE_DEF_DATA_LEN: + if (hciCoreCb.extResetSeq) { + /* send first extended command */ + (*hciCoreCb.extResetSeq)(pMsg, opcode); + } else { + /* initialize extended parameters */ + hciCoreCb.maxAdvDataLen = 0; + hciCoreCb.numSupAdvSets = 0; + hciCoreCb.perAdvListSize = 0; + + /* send next command in sequence */ + HciLeRandCmd(); + } + break; + + case HCI_OPCODE_LE_READ_MAX_ADV_DATA_LEN: + case HCI_OPCODE_LE_READ_NUM_SUP_ADV_SETS: + case HCI_OPCODE_LE_READ_PER_ADV_LIST_SIZE: + if (hciCoreCb.extResetSeq) { + /* send next extended command in sequence */ + (*hciCoreCb.extResetSeq)(pMsg, opcode); + } + break; + + case HCI_OPCODE_LE_RAND: + /* check if need to send second rand command */ + if (randCnt < (HCI_RESET_RAND_CNT - 1)) { + randCnt++; + HciLeRandCmd(); + } else { + signal_reset_sequence_done(); + } + break; + + default: + break; + } + } else { + /** + * vendor specific event + */ + if (pMsg[0] == VENDOR_SPECIFIC_EVENT) { + /* parse parameters */ + pMsg += HCI_EVT_HDR_LEN; + BSTREAM_TO_UINT16(opcode, pMsg); + + if (opcode == EVT_BLUENRG_MS_INITIALIZED) { + if (bluenrg_ms_initialized) { + return; + } + bluenrg_ms_initialized = true; + if (reset_received) { + aciEnableLinkLayerModeOnly(); + } + } + + } + } + } + +private: + void aciEnableLinkLayerModeOnly() + { + uint8_t data[1] = { 0x01 }; + enable_link_layer_mode_ongoing = true; + aciWriteConfigData(LL_WITHOUT_HOST_OFFSET, data); + } + + void aciSetRole() + { + // master and slave, simultaneous advertising and scanning + // (up to 4 connections) + uint8_t data[1] = { 0x04 }; + aciWriteConfigData(ROLE_OFFSET, data); + } + + void aciGattInit() + { + uint8_t *pBuf = hciCmdAlloc(ACI_GATT_INIT_OPCODE, 0); + if (!pBuf) { + return; + } + hciCmdSend(pBuf); + } + + void aciGapInit() + { + uint8_t *pBuf = hciCmdAlloc(ACI_GAP_INIT_OPCODE, 3); + if (!pBuf) { + return; + } + pBuf[3] = 0xF; + pBuf[4] = 0; + pBuf[5] = 0; + hciCmdSend(pBuf); + } + + void aciReadConfigParameter(uint8_t offset) + { + uint8_t *pBuf = hciCmdAlloc(ACI_READ_CONFIG_DATA_OPCODE, 1); + if (!pBuf) { + return; + } + + pBuf[3] = offset; + hciCmdSend(pBuf); + } + + template + void aciWriteConfigData(uint8_t offset, uint8_t (&buf)[N]) + { + uint8_t *pBuf = hciCmdAlloc(ACI_WRITE_CONFIG_DATA_OPCODE, 2 + N); + if (!pBuf) { + return; + } + + pBuf[3] = offset; + pBuf[4] = N; + memcpy(pBuf + 5, buf, N); + hciCmdSend(pBuf); + } + + void hciCoreReadResolvingListSize(void) + { + /* if LL Privacy is supported by Controller and included */ + if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_PRIVACY) && + (hciLeSupFeatCfg & HCI_LE_SUP_FEAT_PRIVACY)) { + /* send next command in sequence */ + HciLeReadResolvingListSize(); + } else { + hciCoreCb.resListSize = 0; + + /* send next command in sequence */ + hciCoreReadMaxDataLen(); + } + } + + void hciCoreReadMaxDataLen(void) + { + /* if LE Data Packet Length Extensions is supported by Controller and included */ + if ((hciCoreCb.leSupFeat & HCI_LE_SUP_FEAT_DATA_LEN_EXT) && + (hciLeSupFeatCfg & HCI_LE_SUP_FEAT_DATA_LEN_EXT)) { + /* send next command in sequence */ + HciLeReadMaxDataLen(); + } else { + /* send next command in sequence */ + HciLeRandCmd(); + } + } + + void bluenrg_ms_reset() + { + /* Reset BlueNRG_MS SPI interface. Hold reset line to 0 for 1500ms */ + rst = 0; + wait_us(1500); + rst = 1; + + /* Wait for the radio to come back up */ + wait_us(100000); + } + + mbed::DigitalOut rst; + bool reset_received; + bool bluenrg_ms_initialized; + bool enable_link_layer_mode_ongoing; +}; + +/** + * Transport driver of the ST BlueNRG_MS shield. + * @important: With that driver, it is assumed that the SPI bus used is not shared + * with other SPI peripherals. The reasons behind this choice are simplicity and + * performance: + * - Reading from the peripheral SPI can be challenging especially if other + * threads access the same SPI bus. Indeed it is common that the function + * spiRead yield nothings even if the chip has signaled data with the irq + * line. Sharing would make the situation worse and increase the risk of + * timeout of HCI commands / response. + * - This driver can be used even if the RTOS is disabled or not present it may + * may be usefull for some targets. + * + * If The SPI is shared with other peripherals then the best option would be to + * handle SPI read in a real time thread woken up by an event flag. + * + * Other mechanisms might also be added in the future to handle data read as an + * event from the stack. This might not be the best solution for all BLE chip; + * especially this one. + */ +class TransportDriver : public CordioHCITransportDriver { +public: + /** + * Construct the transport driver required by a BlueNRG_MS module. + * @param mosi Pin of the SPI mosi + * @param miso Pin of the SPI miso + * @param sclk Pin of the SPI clock + * @param irq Pin used by the module to signal data are available. + */ + TransportDriver(PinName mosi, PinName miso, PinName sclk, PinName ncs, PinName irq) + : spi(mosi, miso, sclk), nCS(ncs), irq(irq), _spi_thread(osPriorityNormal, SPI_STACK_SIZE, _spi_thread_stack) + { + _spi_thread.start(mbed::callback(this, &TransportDriver::spi_read_cb)); + } + + virtual ~TransportDriver() { } + + /** + * @see CordioHCITransportDriver::initialize + */ + virtual void initialize() + { + // Setup the spi for 8 bit data, low clock polarity, + // 1-edge phase, with an 8MHz clock rate + spi.format(8, 0); + spi.frequency(8000000); + + // Deselect the BlueNRG_MS chip by keeping its nCS signal high + nCS = 1; + + wait_us(500); + + // Set the interrupt handler for the device + irq.mode(PullDown); // set irq mode + irq.rise(mbed::callback(this, &TransportDriver::HCI_Isr)); + } + + /** + * @see CordioHCITransportDriver::terminate + */ + virtual void terminate() { } + + /** + * @see CordioHCITransportDriver::write + */ + virtual uint16_t write(uint8_t type, uint16_t len, uint8_t *pData) + { + // repeat write until successfull. A number of attempt or timeout might + // be useful + while (spiWrite(type, pData, len) == 0) { } + return len; + } + +private: + uint16_t spiWrite(uint8_t type, const uint8_t *data, uint16_t data_length) + { + static const uint8_t header_master[] = { + 0x0A, 0x00, 0x00, 0x00, 0x00 + }; + uint8_t header_slave[] = { 0xaa, 0x00, 0x00, 0x00, 0x00 }; + uint16_t data_written = 0; + uint16_t write_buffer_size = 0; + + _spi_mutex.lock(); + + /* CS reset */ + nCS = 0; + + /* Exchange header */ + for (uint8_t i = 0; i < sizeof(header_master); ++i) { + header_slave[i] = spi.write(header_master[i]); + } + + if (header_slave[0] != 0x02) { + goto exit; + } + + write_buffer_size = header_slave[2] << 8 | header_slave[1]; + + if (write_buffer_size == 0 || write_buffer_size < (data_length + 1)) { + goto exit; + } + + spi.write(type); + + data_written = data_length; + for (uint16_t i = 0; i < data_length; ++i) { + spi.write(data[i]); + } + +exit: + nCS = 1; + + _spi_mutex.unlock(); + + return data_written; + } + + uint16_t spiRead(uint8_t *data_buffer, const uint16_t buffer_size) + { + static const uint8_t header_master[] = {0x0b, 0x00, 0x00, 0x00, 0x00}; + uint8_t header_slave[5] = { 0xaa, 0x00, 0x00, 0x00, 0x00}; + uint16_t read_length = 0; + uint16_t data_available = 0; + + nCS = 0; + + /* Read the header */ + for (size_t i = 0; i < sizeof(header_master); i++) { + header_slave[i] = spi.write(header_master[i]); + } + + if (header_slave[0] != 0x02) { + goto exit; + } + + data_available = (header_slave[4] << 8) | header_slave[3]; + read_length = data_available > buffer_size ? buffer_size : data_available; + + for (uint16_t i = 0; i < read_length; ++i) { + data_buffer[i] = spi.write(0xFF); + } + +exit: + nCS = 1; + + return read_length; + } + + /* + * might be split into two parts: the IRQ signaling a real time thread and + * the real time thread reading data from the SPI. + */ + void HCI_Isr(void) + { + _spi_read_sem.release(); + } + + void spi_read_cb() + { + uint8_t data_buffer[256]; + while (true) { + _spi_read_sem.acquire(); + + _spi_mutex.lock(); + while (irq == 1) { + uint16_t data_read = spiRead(data_buffer, sizeof(data_buffer)); + on_data_received(data_buffer, data_read); + } + _spi_mutex.unlock(); + } + } + + /** + * Unsafe SPI, does not lock when SPI access happens. + */ + ::mbed::SPI spi; + mbed::DigitalOut nCS; + mbed::InterruptIn irq; + rtos::Thread _spi_thread; + uint8_t _spi_thread_stack[SPI_STACK_SIZE]; + rtos::Semaphore _spi_read_sem; + rtos::Mutex _spi_mutex; +}; + +} // namespace bluenrg_ms +} // namespace vendor +} // namespace ble + +/** + * Cordio HCI driver factory + */ +ble::CordioHCIDriver &ble_cordio_get_hci_driver() +{ + static ble::vendor::bluenrg_ms::TransportDriver transport_driver( + MBED_CONF_BLUENRG_MS_SPI_MOSI, + MBED_CONF_BLUENRG_MS_SPI_MISO, + MBED_CONF_BLUENRG_MS_SPI_SCK, + MBED_CONF_BLUENRG_MS_SPI_NCS, + MBED_CONF_BLUENRG_MS_SPI_IRQ + ); + static ble::vendor::bluenrg_ms::HCIDriver hci_driver( + transport_driver, + MBED_CONF_BLUENRG_MS_SPI_RESET + ); + return hci_driver; +} diff --git a/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/README.md b/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/README.md new file mode 100644 index 0000000..434a58a --- /dev/null +++ b/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/README.md @@ -0,0 +1,124 @@ +# BlueNRG_MS + +BLE API wrapper Library for BlueNRG (Bluetooth Low Energy) + +Maybe a simple table like this could help: + +|Name|Type|Bluetooth compliance|Status|Used in shields & boards|Link| +|-----------|----------|-----|-|-|-| +|SPBTLE-RF |Module |v4.1 |Not recommended for new designs |X-NUCLEO-IDB05A1, DISCO-L475VG-IOT01A, DISCO-L562QE | https://www.st.com/en/wireless-transceivers-mcus-and-modules/spbtle-rf.html | +|BlueNRG-M0 |Module |v4.2 |Active (included in ST's Longevity Program) |No | https://www.st.com/en/wireless-transceivers-mcus-and-modules/bluenrg-m0.html | +|BlueNRG-MS |Processor |v4.2 |Active (included in ST's Longevity Program) |X-NUCLEO-IDB05A2 (coming soon) | https://www.st.com/en/wireless-transceivers-mcus-and-modules/bluenrg-ms.html | + + +It uses ARM Cordio stack instead of the ST BlueNRG stack. + +## History + +- deprecated ST BLE port: https://github.com/ARMmbed/ble-x-nucleo-idb0xa1 +- deprecated X-NUCLEO-IDB05A1 BlueNRG : https://github.com/ARMmbed/cordio-ble-x-nucleo-idb0xa1 + + +## Boards + +### X-NUCLEO-IDB05A1 + +Bluetooth Low Energy Nucleo Expansion Board: + +https://developer.mbed.org/components/X-NUCLEO-IDB05A1-Bluetooth-Low-Energy/ + +### DISCO-L475VG-IOT01A + +STM32L4 Discovery kit IoT node, low-power wireless, Bluetooth V4.1 module (SPBTLE-RF) + +https://os.mbed.com/platforms/ST-Discovery-L475E-IOT01A/ + + +### DISCO-L562QE + +STM32L562E-DK Discovery kit with Bluetooth V4.1 low energy module and Arm Cortex-M33 with TrustZone + +https://os.mbed.com/platforms/ST-Discovery-L562QE/ + + +## Driver configuration + +In order to use the BlueNRG-MS module together with other targets, +you may need to override default settings in your local `mbed_app.json` file + +### ST-DISCO boards + +Default settings for `DISCO-L475VG-IOT01A` and `DISCO-L562QE` are configured + +### Arduino Connector Compatibility Warning + +Default Arduino connection is using: + +``` + "SPI_MOSI": "D11", + "SPI_MISO": "D12", + "SPI_nCS": "A1", + "SPI_RESET": "D7", + "SPI_IRQ": "A0", + "SPI_SCK": "D3", + "valid-public-bd-address": false +``` + +X-NUCLEO-IDB05A1 is Arduino compatible with an exception: instead of using pin **D13** for the SPI clock, pin **D3** is used. +The default configuration for this library is having the SPI clock on pin **D3**. + +To be fully Arduino compatible, X-NUCLEO-IDB05A1 needs a small HW patch. + +For X-NUCLEO-IDB05A1 this patch consists in removing zero resistor **R4** and instead soldering zero resistor **R6**. + +In case you patch your board, then you also have to configure this library to use pin **D13** to drive the SPI clock. +To this aim you need to update your local mbed_app.json file with: + +``` + "target_overrides": { + "XXXX": { + "bluenrg_ms.SPI_SCK": "D13" + }, +``` + +If you use pin **D13** for the SPI clock, please be aware that on some STM32 Nucleo boards you may **not** drive the LED, +otherwise you will get a conflict: the LED on STM32 Nucleo boards is connected to pin **D13**. + +Referring to the current list of tested platforms (see [X-NUCLEO-IDB05A1](https://developer.mbed.org/components/X-NUCLEO-IDB05A1-Bluetooth-Low-Energy/) page), +the patch is required for +- [ST-Nucleo-F103RB](https://developer.mbed.org/platforms/ST-Nucleo-F103RB/) +- [ST-Nucleo-F411RE](https://developer.mbed.org/platforms/ST-Nucleo-F411RE/) +- [ST-Nucleo-F446RE](https://developer.mbed.org/platforms/ST-Nucleo-F446RE/) +- [FRDM-K64F](https://developer.mbed.org/platforms/FRDM-K64F/) + +### Target Configuration + +To use that library, the target requires some extra configuration in the application `mbed_app.json`. In the `target_overides` section: + +* BLE feature has to be enabled + +```json +"target.features_add": ["BLE"] +``` + +* BlueNRG module has to be enabled + +```json +"target.components_add": ["BlueNRG_MS"] +``` + +* Extra labels have to be defined to include the cordio stack and this library: + +```json +"target.extra_labels_add": ["CORDIO"] +``` + +As an example, the target overide section for the `NUCLEO_F401RE` would be: + +```json + "NUCLEO_F401RE": { + "target.features_add": ["BLE"], + "target.components_add": ["BlueNRG_MS"], + "target.extra_labels_add": ["CORDIO"] + } +``` diff --git a/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/mbed_lib.json b/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/mbed_lib.json new file mode 100644 index 0000000..610edcc --- /dev/null +++ b/connectivity/drivers/ble/FEATURE_BLE/COMPONENT_BlueNRG_MS/mbed_lib.json @@ -0,0 +1,36 @@ +{ + "name": "bluenrg_ms", + "config": { + "SPI_MOSI": "D11", + "SPI_MISO": "D12", + "SPI_nCS": "A1", + "SPI_RESET": "D7", + "SPI_IRQ": "A0", + "SPI_SCK": "D3", + "valid-public-bd-address": { + "help": "Read the BD public address at startup", + "value": false + } + }, + "target_overrides": { + "K64F": { + "SPI_SCK": "D13" + }, + "DISCO_L475VG_IOT01A": { + "SPI_MOSI": "PC_12", + "SPI_MISO": "PC_11", + "SPI_nCS": "PD_13", + "SPI_RESET": "PA_8", + "SPI_IRQ": "PE_6", + "SPI_SCK": "PC_10" + }, + "DISCO_L562QE": { + "SPI_MOSI": "PG_4", + "SPI_MISO": "PG_3", + "SPI_nCS": "PG_5", + "SPI_RESET": "PG_8", + "SPI_IRQ": "PG_6", + "SPI_SCK": "PG_2" + } + } +}