ワイヤレス接続に関するナレッジベース

キャンセル
次の結果を表示 
表示  限定  | 次の代わりに検索 
もしかして: 

Wireless Connectivity Knowledge Base

ディスカッション

ソート順:
Wireless communication systems require several different components or parts to achieve reliable systems. Components like the antenna, radio and XTAL are all key elements in wireless communication. Here however, the XTAL will be discussed. In the Kinetis W series, for example, the XTAL used for wireless operation is usually the oscillator also used as a core clock. Now, while this external oscillator is connected to the MCU, it is also connected to an internal programmable capacitor bank. What is the purpose of these capacitor banks? To allow frequency trimming. And why would you want to trim the frequency provided by this oscillator? Well, to properly adjust the central frequency to where it should be operating. This option exists because not every design is going to be the same: not the same PCB, not the same components, not the same manufacturing process. Thus, having the option to adjust the frequency provided by the external oscillator allows to any possible device to operate under the same conditions is essential. Let’s say your design is using a 32 MHz external oscillator, but because of the conditions of your whole design, the operating frequency ends up being slightly different. Now, if this design transmits over the air through 802.15.4, there could be some consequences to this slight shift in frequency. This capture shows a transmission made without being centered in the desired channel. This signal should be centered exactly on 2405 MHz, as specified by IEEE 802.15.4 channel 11. As you may see, in this case the frequency is actually centered on 2405.0259 MHz. Trimming these capacitors to change the frequency obtained from the oscillator can help to adjust error. In this case, the frequency was adjusted so that it was centered in the central frequency of the desired channel, to prevent any possible mistakes while transmitting to other devices. Once the XTAL is trimmed, the signal is effectively centered on 802.15.4 channel 11's frequency, 2405 MHz. Both transmit and receive are affected by incorrect frequency trim. Receiver performance is degraded when either (or both) of the transmitting or receiving stations have a frequency offset. And if both transmitting and receiving stations have frequency offsets in opposite directions the result is the receiver experiences the sum of the frequency offsets. Now, when trimming the frequency of a design, there are two possibilities: That the board layout design, board manufacturing and component selection have repeatable values of resistance, capacitance and inductance, resulting in a stable XTAL trim – The components and manufacturing process of the board are reliable enough, allowing you to characterize the XTAL trim during the system development and then use it every board during production. That the design and component selection do not result in a stable XTAL trim – If there is considerable variation between different boards of the same design or components used in the board manufacturing, you would need to implement a XTAL trim procedure during the production process, and somehow program that trim value into the device's NVM. For evaluation purposes, a manual adjustment could be done to a single device, modifying the corresponding XTAL trim register, and then including said adjustment in the evaluation application. The two posts linked explain how to modify and use the SMAC Connectivity Test demo to find the proper XTAL trim for KW40Z and KW41Z.
記事全体を表示
In addition of the Design Guideline, PCB hardware package find here the design in check list to build sucessfully your own PCB
記事全体を表示
Introduction When a Bluetooth LE Central and Peripheral devices are in connection, data within the payload can be encrypted. Encryption of the channel can be achieved through pairing with others. Once the communication has been encrypted, the Bluetooth LE devices could distribute the keys to save it for future connections. The last is better known as bonding. When two Bluetooth LE devices are bonded, in a future connection, they do not need to exchange the keys since they already know the shared secret, thus, they can encrypt the channel directly, saving time and power. However, if an attacker is listening to the first time that both (Central and Peripheral) Bluetooth LE devices enter into a connection state, the security of the link could be vulnerated, since the attacker could decipher the original message. Fortunately, Out Of Band (OOB) provides the ability (obviously, if both devices support it) to share the keys on an unknown medium for an attacker listening Bluetooth LE (for instance, NFC, SPI, UART, CAN, etc), increasing the security of the communication. This document explains how to enable OOB pairing on Bluetooth LE connectivity examples, basing on FRDM-KW36 SDK HID Host and HID Device examples.   Dedicated Macros and APIs for OOB Pairing The connectivity software stack contains macros and APIs that developers should implement to interact with the host stack and handle the events necessary for OOB. The following sections explain the main macros, variables, and APIs that manage OOB in our software.   Definitions and Variables gAppUsePairing_d It is used to enable or disable pairing to encrypt the link. Values Result 0 Pairing Disabled 1 Pairing Enabled   gAppUseBonding_d It is used to enable or disable bonding to request and save the keys for future connections. Values Result 0 Bonding Disabled 1 Bonding Enabled   gBleLeScOobHasMitmProtection_c This flag must be set if the application requires Man In the Middle protection, in other words, if the link must be authenticated. You can determine whether your software needs to set or clear this flag from the GAP Security Mode and Level. Red instances of the following table indicate that gBleLeScOobHasMitmProtection_c must be set to 1.   gPairingParameters This struct contains the pairing request or the pairing response (depending on the device's GAP role) payload. To enable and configure OOB pairing, oobAvailable field of the struct must be set to 1.   APIs bleResult_t Gap_ProvideOob (deviceId_t deviceId, uint8_t* aOob) This API must be implemented in response of gConnEvtOobRequest_c event in BleConnManager_GapPeripheralEvent or BleConnManager_GapCentralEvent functions (depending of the GAP role). This event only will be triggered if OOB is enabled and LE Legacy pairing is used. The gConnEvtOobRequest_c event occurs when the stack request the OOB data received from the peer device just after the gConnEvtPairingRequest_c or gConnEvtPairingResponse_c (depending of the GAP role). This API is valid only for LE Legacy pairing. Name of the Parameter Input/Output Description deviceId Input ID of the peer device aOob Input Pointer to OOB data previously received from the peer.   bleResult_t Gap_LeScGetLocalOobData (void) This API must be implemented either in response of gConnEvtPairingRequest_c or gConnEvtPairingResponse_c events  in BleConnManager_GapPeripheralEvent or BleConnManager_GapCentralEvent functions (depending of the GAP role) to get the local OOB data generated from the controller and in response of gLeScPublicKeyRegenerated_c event at BleConnManager_GenericEvent. Each time that Gap_LeScGetLocalOobData is executed in the application to obtain the OOB data, it triggers the gLeScLocalOobData_c generic event to inform that OOB data must be read from pGenericEvent->eventData.localOobData to send it to the peer device. This API is valid only for LE Secure Connections pairing.   bleResult_t Gap_LeScSetPeerOobData (deviceId_t deviceId, gapLeScOobData_t* pPeerOobData) This API must be implemented in response of gConnEvtLeScOobDataRequest_c event in BleConnManager_GapPeripheralEvent or BleConnManager_GapCentralEvent functions(depending of the GAP role). This event occurs when the stack requires the OOB data previously recieved from the peer. This API is valid only for LE Secure Connections pairing. Name of the Parameter Input/Output Description deviceId Input ID of the peer device aOob Input Pointer to gapLeScOobData_t struct that contains the OOB data received from the peer.   Enabling OOB on KW36 Bluetooth LE Peripheral Device The following example is based on the HID Device software included in the FRDM-KW36 SDK. It explains the minimum code needed to enable OOB. In the following sections, brown color indicates that such definition or API takes part in the stack and violet color indicates that such definition does not take part in the stack and its use is only for explanation purposes in this document.   Changes in app_preinclude.h file The app_preinclude.h header file contains definitions for the management of the application. To enable OOB pairing, you must ensure that gAppUseBonding_d and gAppUsePairing_d are set to 1. You can also set the value of the gBleLeScOobHasMitmProtection_c in this file, depending on the security mode and level needed in your application.  This example makes use of two custom definitions: gAppUseOob_d and gAppUseSecureConnections_d. Such definitions are used to explain how to enable/disable OOB and, if OOB is enabled, how to switch between LE Secure Connections pairing or LE Legacy paring.   /*! Enable/disable use of bonding capability */ #define gAppUseBonding_d 1 /*! Enable/disable use of pairing procedure */ #define gAppUsePairing_d 1 /*! Enable/disable use of privacy */ #define gAppUsePrivacy_d 0 #define gPasskeyValue_c 999999 /*! Enable/disable use of OOB pairing */ #define gAppUseOob_d 1 /*! Enable MITM protection when using OOB pairing */ #if (gAppUseOob_d) #define gBleLeScOobHasMitmProtection_c TRUE #endif /*! Enable/disable Secure Connections */ #define gAppUseSecureConnections_d 1‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Using the code above, you can enable or disable OOB using gAppUseOob_d, also you can decide whether to use LE Secure Connections (gAppUseSecureConnections_d = 1) or LE Legacy (gAppUseSecureConnections_d = 0)     Changes in app_config.c file The following portion fo code depicts how to fill gPairingParameters struct depending on which pairing method is used by the application.   /* SMP Data */ gapPairingParameters_t gPairingParameters = { .withBonding = (bool_t)gAppUseBonding_d, /* If Secure Connections pairing is supported, then set Security Mode 1 Level 4 */ /* If Legacy pairing is supported, then set Security Mode 1 Level 3 */ #if (gAppUseSecureConnections_d) .securityModeAndLevel = gSecurityMode_1_Level_4_c, #else .securityModeAndLevel = gSecurityMode_1_Level_3_c, #endif .maxEncryptionKeySize = mcEncryptionKeySize_c, .localIoCapabilities = gIoKeyboardDisplay_c, /* OOB Available enabled when app_preinclude.h file gAppUseOob_d macro is true */ .oobAvailable = (bool_t)gAppUseOob_d, #if (gAppUseSecureConnections_d) .centralKeys = (gapSmpKeyFlags_t) (gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gIrk_c), #else .centralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), #endif /* Secure Connections enabled when app_preinclude.h file gAppUseSecureConnections_d macro is true */ .leSecureConnectionSupported = (bool_t)gAppUseSecureConnections_d, .useKeypressNotifications = FALSE, };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Additionally, the serviceSecurity struct registers which are the security mode and level of each Bluetooth LE service, so if Secure Connections is selected (gAppUseSecureConnections_d = 1), mode = 1 level = 4.   static const gapServiceSecurityRequirements_t serviceSecurity[3] = { { .requirements = { #if (gAppUseSecureConnections_d) .securityModeLevel = gSecurityMode_1_Level_4_c, #else .securityModeLevel = gSecurityMode_1_Level_3_c, #endif .authorization = FALSE, .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d }, .serviceHandle = (uint16_t)service_hid }, { .requirements = { #if (gAppUseSecureConnections_d) .securityModeLevel = gSecurityMode_1_Level_4_c, #else .securityModeLevel = gSecurityMode_1_Level_3_c, #endif .authorization = FALSE, .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d }, .serviceHandle = (uint16_t)service_battery }, { .requirements = { #if (gAppUseSecureConnections_d) .securityModeLevel = gSecurityMode_1_Level_4_c, #else .securityModeLevel = gSecurityMode_1_Level_3_c, #endif .authorization = FALSE, .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d }, .serviceHandle = (uint16_t)service_device_info } };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Changes in ble_conn_manager.c file LE Legacy Pairing If your application will use LE Legacy Pairing, then you have to implement Gap_ProvideOob in response to the gConnEvtOobRequest_c event at the BleConnManager_GapPeripheralEvent function. In this example, gOobReceivedTKDataFromPeer is an array that stores the data previously received OOB from the peer device (using SPI, UART, I2C, etc), therefore, the procedure to fill this array with the data received from the peer depends entirely on your application. Notice that gOobReceivedTKDataFromPeer must contain the data received from the peer before to execute Gap_ProvideOob.   static uint8_t gOobReceivedTKDataFromPeer[16]; void BleConnManager_GapPeripheralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; ... ... ... #if (gAppUseOob_d && !gAppUseSecureConnections_d) case gConnEvtOobRequest_c: { /* The stack has requested the LE Legacy OOB data*/ (void)Gap_ProvideOob(peerDeviceId, &gOobReceivedTKDataFromPeer[0]); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     LE Secure Connections Pairing When using Secure Connections Pairing, the application must handle two events at the BleConnManager_GapPeripheralEvent function. In gConnEvtPairingRequest_c event, you must implement Gap_LeScGetLocalOobData API to generate the local (r, Cr) values. The gConnEvtLeScOobDataRequest_c event indicates that the application is requesting the (r, Cr) values previously received OOB from the peer device (using SPI, UART, I2C, etc). Such values are contained into gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers. You must implement Gap_LeScSetPeerOobData in response to gConnEvtLeScOobDataRequest_c, This function has two parameters, the device ID of the peer and a pointer to a gapLeScOobData_t type struct. This struct is filled with the data contained in gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers.   gapLeScOobData_t gPeerOobData; static uint8_t gOobReceivedRandomValueFromPeer[gSmpLeScRandomValueSize_c]; /*!< LE SC OOB r (Random value) */ static uint8_t gOobReceivedConfirmValueFromPeer[gSmpLeScRandomConfirmValueSize_c]; /*!< LE SC OOB Cr (Random Confirm value) */ void BleConnManager_GapPeripheralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; case gConnEvtPairingRequest_c: { #if (defined(gAppUsePairing_d) && (gAppUsePairing_d == 1U)) gPairingParameters.centralKeys = pConnectionEvent->eventData.pairingEvent.centralKeys; (void)Gap_AcceptPairingRequest(peerDeviceId, &gPairingParameters); #if (gAppUseOob_d && gAppUseSecureConnections_d) /* The central has requested pairing, get local LE Secure Connections OOB data */ (void)Gap_LeScGetLocalOobData(); #endif #else (void)Gap_RejectPairing(peerDeviceId, gPairingNotSupported_c); #endif } break; ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gConnEvtLeScOobDataRequest_c: { /* The stack has requested the peer LE Secure Connections OOB data. Fill the gPeerOobData struct and provide it to the stack */ FLib_MemCpy(gPeerOobData.randomValue, &gOobReceivedRandomValueFromPeer[0], gSmpLeScRandomValueSize_c); FLib_MemCpy(gPeerOobData.confirmValue, &gOobReceivedConfirmValueFromPeer[0], gSmpLeScRandomConfirmValueSize_c); Gap_LeScSetPeerOobData(peerDeviceId, &gPeerOobData); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   The gLeScPublicKeyRegenerated_c event in the BleConnManager_GenericEvent function must be handled using the Gap_LeScGetLocalOobData API as depicted below. Each time that Gap_LeScGetLocalOobData is executed by the software, it generates, asynchronously, the gLeScLocalOobData_c event (also handled in the BleConnManager_GenericEvent function) indicating that the local (r, Cr) values were successfully generated and you can read them using the pGenericEvent->eventData.localOobData pointer to send it OOB to the peer device. In this example, Oob_SendLocalRandomValueToPeer and Oob_SendLocalConfirmValueToPeer  are custom synchronous functions that demonstrate how you can implement a custom API that sends the local (r, Cr) read from pGenericEvent->eventData.localOobData pointer to the peer device using other protocols (SPI, UART, I2C, etc).   void BleConnManager_GenericEvent(gapGenericEvent_t* pGenericEvent) { switch (pGenericEvent->eventType) { case gInitializationComplete_c: { ... ... ... } break; ... ... ... #if (defined(gAppUsePairing_d) && (gAppUsePairing_d == 1U)) case gLeScPublicKeyRegenerated_c: { /* Key pair regenerated -> reset pairing counters */ mFailedPairings = mSuccessfulPairings = 0; /* Local Secure Connections OOB data must be refreshed whenever this event occurs */ #if (gAppUseOob_d && gAppUseSecureConnections_d) (void)Gap_LeScGetLocalOobData(); #endif } break; #endif ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gLeScLocalOobData_c: { /* Get the local Secure Connections OOB data and send to the peer */ Oob_SendLocalRandomValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.randomValue); Oob_SendLocalConfirmValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.confirmValue); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Enabling OOB on KW36 Bluetooth LE Central Device The following example is based on the HID Host software included in the FRDM-KW36 SDK. It explains the minimum code needed to enable OOB. In the following sections, brown color indicates that such definition or API takes part in the stack and violet color indicates that such definition does not take part in the stack and its use is only for explanation purposes in this document.   Changes in app_preinclude.h file The app_preinclude.h header file contains definitions for the management of the application. To enable OOB pairing, you must ensure that gAppUseBonding_d and gAppUsePairing_d are set to 1. You can also set the value of the gBleLeScOobHasMitmProtection_c in this file, depending on the security mode and level needed in your application.  This example makes use of two custom definitions: gAppUseOob_d and gAppUseSecureConnections_d. Such definitions are used to explain how to enable/disable OOB and, if OOB is enabled, how to switch between LE Secure Connections pairing or LE Legacy paring.   /*! Enable/disable use of bonding capability */ #define gAppUseBonding_d 1 /*! Enable/disable use of pairing procedure */ #define gAppUsePairing_d 1 /*! Enable/disable use of privacy */ #define gAppUsePrivacy_d 0 #define gPasskeyValue_c 999999 /*! Enable/disable use of OOB pairing */ #define gAppUseOob_d 1 /*! Enable MITM protection when using OOB pairing */ #if (gAppUseOob_d) #define gBleLeScOobHasMitmProtection_c TRUE #endif /*! Enable/disable Secure Connections */ #define gAppUseSecureConnections_d 1‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Using the code above, you can enable or disable OOB using gAppUseOob_d, also you can decide whether to use LE Secure Connections (gAppUseSecureConnections_d = 1) or LE Legacy (gAppUseSecureConnections_d = 0)     Changes in app_config.c file The following portion fo code depicts how to fill gPairingParameters struct depending on which pairing method is used by the application.   /* SMP Data */ gapPairingParameters_t gPairingParameters = { .withBonding = (bool_t)gAppUseBonding_d, /* If Secure Connections pairing is supported, then set Security Mode 1 Level 4 */ /* If Legacy pairing is supported, then set Security Mode 1 Level 3 */ #if (gAppUseSecureConnections_d) .securityModeAndLevel = gSecurityMode_1_Level_4_c, #else .securityModeAndLevel = gSecurityMode_1_Level_3_c, #endif .maxEncryptionKeySize = mcEncryptionKeySize_c, .localIoCapabilities = gIoKeyboardDisplay_c, /* OOB Available enabled when app_preinclude.h file gAppUseOob_d macro is true */ .oobAvailable = (bool_t)gAppUseOob_d, #if (gAppUseSecureConnections_d) .centralKeys = (gapSmpKeyFlags_t) (gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gIrk_c), #else .centralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), .peripheralKeys = (gapSmpKeyFlags_t) (gLtk_c | gIrk_c), #endif /* Secure Connections enabled when app_preinclude.h file gAppUseSecureConnections_d macro is true */ .leSecureConnectionSupported = (bool_t)gAppUseSecureConnections_d, .useKeypressNotifications = FALSE, };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Changes in ble_conn_manager.c file LE Legacy Pairing If your application will use LE Legacy Pairing, then you have to implement Gap_ProvideOob in response to the gConnEvtOobRequest_c event at the BleConnManager_GapCentralEvent function. In this example, gOobOwnTKData is an array that stores the TK data which will be sent OOB to the peer device (using SPI, UART, I2C, etc)  and, at the same time, is the TK data that will be provided to the stack using Gap_ProvideOob. This data must be common on both Central and Peripheral devices, so the procedure to share the TK depends entirely on your application. Oob_SendLocalTKValueToPeer is a custom synchronous function that demonstrates how you can implement a custom API that sends the local TK to the peer device using other protocols (SPI, UART, I2C, etc).   static uint8_t gOobOwnTKData[16] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; void BleConnManager_GapCentralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; ... ... ... case gConnEvtPairingResponse_c: { /* Send Legacy OOB data to the peer */ #if (gAppUseOob_d & !gAppUseSecureConnections_d) Oob_SendLocalTKValueToPeer(&gOobOwnTKData[0]); #endif } break; ... ... ... #if (gAppUseOob_d && !gAppUseSecureConnections_d) case gConnEvtOobRequest_c: { /* The stack has requested the LE Legacy OOB data*/ (void)Gap_ProvideOob(peerDeviceId, &gOobOwnTKData[0]); } break; #endif‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     LE Secure Connections Pairing When using Secure Connections Pairing, the application must handle two events at the BleConnManager_GapCentralEvent function. In gConnEvtPairingResponse_c event, you must implement Gap_LeScGetLocalOobData API to generate the local (r, Cr) values. The gConnEvtLeScOobDataRequest_c event indicates that the application is requesting the (r, Cr) values previously received OOB from the peer device (using SPI, UART, I2C, etc). Such values are contained into gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers. You must implement Gap_LeScSetPeerOobData in response to gConnEvtLeScOobDataRequest_c, This function has two parameters, the device ID of the peer and a pointer to a gapLeScOobData_t type struct. This struct is filled with the data contained in gOobReceivedRandomValueFromPeer and gOobReceivedConfirmValueFromPeer buffers.   gapLeScOobData_t gPeerOobData; static uint8_t gOobReceivedRandomValueFromPeer[gSmpLeScRandomValueSize_c]; /*!< LE SC OOB r (Random value) */ static uint8_t gOobReceivedConfirmValueFromPeer[gSmpLeScRandomConfirmValueSize_c]; /*!< LE SC OOB Cr (Random Confirm value) */ void BleConnManager_GapCentralEvent(deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) { switch (pConnectionEvent->eventType) { case gConnEvtConnected_c: { ... ... ... } break; ... ... ... case gConnEvtPairingResponse_c: { /* The peripheral has acepted pairing, get local LE Secure Connections OOB data */ #if (gAppUseOob_d && gAppUseSecureConnections_d) (void)Gap_LeScGetLocalOobData(); #endif } break; ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gConnEvtLeScOobDataRequest_c: { /* The stack has requested the peer LE Secure Connections OOB data. Fill the gPeerOobData struct and provide it to the stack */ FLib_MemCpy(gPeerOobData.randomValue, &gOobReceivedRandomValueFromPeer[0], gSmpLeScRandomValueSize_c); FLib_MemCpy(gPeerOobData.confirmValue, &gOobReceivedConfirmValueFromPeer[0], gSmpLeScRandomConfirmValueSize_c); Gap_LeScSetPeerOobData(peerDeviceId, &gPeerOobData); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   The gLeScPublicKeyRegenerated_c event in the BleConnManager_GenericEvent function must be handled using the Gap_LeScGetLocalOobData API as depicted below. Each time that Gap_LeScGetLocalOobData is executed by the software, it generates, asynchronously, the gLeScLocalOobData_c event (also handled in the BleConnManager_GenericEvent function) indicating that the local (r, Cr) values were successfully generated and you can read them using the pGenericEvent->eventData.localOobData pointer to send it OOB to the peer device. In this example, Oob_SendLocalRandomValueToPeer and Oob_SendLocalConfirmValueToPeer  are custom synchronous functions that demonstrate how you can implement a custom API that sends the local (r, Cr) read from pGenericEvent->eventData.localOobData pointer to the peer device using other protocols (SPI, UART, I2C, etc).   void BleConnManager_GenericEvent(gapGenericEvent_t* pGenericEvent) { switch (pGenericEvent->eventType) { case gInitializationComplete_c: { ... ... ... } break; ... ... ... #if (defined(gAppUsePairing_d) && (gAppUsePairing_d == 1U)) case gLeScPublicKeyRegenerated_c: { /* Key pair regenerated -> reset pairing counters */ mFailedPairings = mSuccessfulPairings = 0; /* Local LE Secure Connections OOB data must be refreshed whenever this event occurs */ #if (gAppUseOob_d && gAppUseSecureConnections_d) (void)Gap_LeScGetLocalOobData(); #endif } break; #endif ... ... ... #if (gAppUseOob_d && gAppUseSecureConnections_d) case gLeScLocalOobData_c: { /* Get the local LE Secure Connections OOB data and send to the peer */ Oob_SendLocalRandomValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.randomValue); Oob_SendLocalConfirmValueToPeer((uint8_t*)pGenericEvent->eventData.localOobData.confirmValue); } break; #endif ... ... ... } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     Simplified Flow Diagram of OOB Central and Peripheral Events LE Legacy Pairing The following figure shows a simplified flow diagram of the LE Legacy OOB pairing example in this document. The LE Central device is the one that contains the OOB TK data that will be shared OOB using the custom Oob_SendLocalTKValueToPeer function. It must be implemented at the gConnEvtPairingResponse_c event to ensure that both devices know the OOB TK before to execute Gap_ProvideOob since this function requests this data. If the OOB data is correct on both sides, the pairing procedure ends, and it is noticed through gConnEvtPairingComplete_c. LE Secure Connections Pairing The following figure shows a simplified flow diagram of the LE Secure Connections OOB pairing example in this document. After both devices enter in connection, the data that will be shared OOB using the custom Oob_SendLocalRandomValueToPeer and Oob_SendLocalConfirmValueToPeer  functions is yielded by Gap_LeScGetLocalOobData on both sides. The last one must be implemented at gConnEvtPairingResponse_c and gConnEvtPairingRequest_c events to ensure that both devices know the Peripheral and Central (r, Cr) OOB data before to execute Gap_LeScSetPeerOobData since this function requests this data. If the OOB data is correct on both sides, the pairing procedure ends, and it is noticed through gConnEvtPairingComplete_c. This is how OOB pairing can be implemented in your project. I hope this document will be useful to you. Please, let us know any questions or comments. 
記事全体を表示
Introduction HCI Application is a Host Controller Interface application which provides a serial communication to interface with the KW40/KW41/KW35/KW36/QN9080 BLE radio part. It enables the user to have a way to control the radio through serial commands. The format of the HCI Command Packet it’s composed of the following parts:     Each command is assigned a 2 byte Opcode which it’s divided into two fields, called the OpCode Group Field (OGF) and OpCode Command Field (OCF). The OGF uses the upper 6 bits of the Opcode, while the OCF corresponds to the remaining 10 bits. The OGF of 0x3F is reserved for vendor-specific debug commands. The organization of the opcodes allows additional information to be inferred without fully decoding the entire Opcode. For further information regarding this topic, please check the BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E, 5.4 EXCHANGE OF HCI-SPECIFIC INFORMATION.   Adding HCI Custom Commands Example This document will guide you through the implementation of custom HCI commands in the KW36. For this example, we will include the following set of custom commands: 01 50 FC 00 – This command is to send a continuous unmodulated wave using a defined channel and output power (default: frequency 2.402GHz and PA_POWER register set to 0x3E).  01 4F FC 00 – This command is to stop the continuous unmodulated wave and configure the radio in Bluetooth LE mode again. This way you can continue sending adopted HCI commands. 01 00 FC 00 – Set the Channel 0 Freq 2402 MHz 01 01 FC 00 – Set the Channel 19 Freq 2440 MHz 01 02 FC 00 – Set the Channel 39 Freq 2480 MHz 01 10 FC 00 – Set the PA_POWER 1 01 11 FC 00 – Set the PA_POWER 32 01 12 FC 00 – Set the PA_POWER 62 The changes described in the following sections were based on the HCI Black Box SDK example (it is located at wireless_examples -> bluetooth -> hci_bb)   Changes in hci_transport.h The "hci_transport.h" file is located at bluetooth->hci_transport->interface folder. Include the following macros in ''Public constants and macros" #define gHciCustomCommandOpcodeUpper (0xFC50) #define gHciCustomCommandOpcodeLower (0xFC00) #define gHciInCustomVendorCommandsRange(x) (((x) <= gHciCustomCommandOpcodeUpper) && \ ((x) >= gHciCustomCommandOpcodeLower))‍‍‍‍‍‍‍‍ Declare a function to install the custom command as follows: void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler);‍   Changes in hcit_serial_interface.c The "hci_transport.h" file is located at bluetooth->hci_transport->source folder. Add the following in "Private memory declarations" static hciTransportInterface_t mCustomTransportInterface = NULL;‍ Modify the Hcit_SendMessage function as follows: static inline void Hcit_SendMessage(void) { uint16_t opcode = 0; /* verify if this is an event packet */ if(mHcitData.pktHeader.packetTypeMarker == gHciEventPacket_c) { /* verify if this is a command complete event */ if(mHcitData.pPacket->raw[0] == gHciCommandCompleteEvent_c) { /* extract the first opcode to verify if it is a custom command */ opcode = mHcitData.pPacket->raw[3] | (mHcitData.pPacket->raw[4] << 8); } } /* verify if command packet */ else if(mHcitData.pktHeader.packetTypeMarker == gHciCommandPacket_c) { /* extract opcode */ opcode = mHcitData.pPacket->raw[0] | (mHcitData.pPacket->raw[1] << 8); } if(gHciInCustomVendorCommandsRange(opcode)) { if(mCustomTransportInterface) { mCustomTransportInterface( mHcitData.pktHeader.packetTypeMarker, mHcitData.pPacket, mHcitData.bytesReceived); } } else { /* Send the message to HCI */ (void)mTransportInterface(mHcitData.pktHeader.packetTypeMarker, mHcitData.pPacket, mHcitData.bytesReceived); } mHcitData.pPacket = NULL; mPacketDetectStep = mDetectMarker_c; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Develop the function to install the custom command as follows:   void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler) { OSA_InterruptDisable(); mCustomTransportInterface = mCustomInterfaceHandler; OSA_InterruptEnable(); }‍‍‍‍‍‍   Changes in hci_black_box.c This is the main application file, and it is located at source folder. Include the following files to support our HCI custom commands #include "hci_transport.h" #include "fsl_xcvr.h"‍‍ Define the following macros which represent the opcode for each custom command #define CUSTOM_HCI_CW_ON (0xFC50) #define CUSTOM_HCI_CW_OFF (0xFC4F) #define CUSTOM_HCI_CW_SET_CHN_0 (0xFC00) /*Channel 0 Freq 2402 MHz*/ #define CUSTOM_HCI_CW_SET_CHN_19 (0xFC01) /*Channel 19 Freq 2440 MHz*/ #define CUSTOM_HCI_CW_SET_CHN_39 (0xFC02) /*Channel 39 Freq 2480 MHz*/ #define CUSTOM_HCI_CW_SET_PA_PWR_1 (0xFC10) /*PA_POWER 1 */ #define CUSTOM_HCI_CW_SET_PA_PWR_32 (0xFC11) /*PA_POWER 32 */ #define CUSTOM_HCI_CW_SET_PA_PWR_62 (0xFC12) /*PA_POWER 62 */ #define CUSTOM_HCI_CW_EVENT_SIZE (0x04) #define CUSTOM_HCI_EVENT_SUCCESS (0x00) #define CUSTOM_HCI_EVENT_FAIL (0x01)‍‍‍‍‍‍‍‍‍‍‍ Add the following application variables static uint16_t channelCC = 2402; static uint8_t powerCC = 0x3E; uint8_t eventPacket[6] = {gHciCommandCompleteEvent_c, CUSTOM_HCI_CW_EVENT_SIZE, 1, 0, 0, 0 };‍‍‍‍‍‍ Declare the handler for our custom commands bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize);‍ Find the "main_task" function, and register the handler for the custom commands through "Hcit_InstallCustomCommandHandler" function. You can include it just after BleApp_Init(); /* Initialize peripheral drivers specific to the application */ BleApp_Init(); /* Register the callback for the custom commands */ Hcit_InstallCustomCommandHandler((hciTransportInterface_t)&BleApp_CustomCommandsHandle); /* Create application event */ mAppEvent = OSA_EventCreate(TRUE); if( NULL == mAppEvent ) { panic(0,0,0,0); return; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Develop the handler of our custom commands as follows: bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize) { uint16_t opcode = 0; if(gHciCommandPacket_c == packetType) { opcode = ((uint8_t*)pPacket)[0] | (((uint8_t*)pPacket)[1] << 8); switch(opcode) { /*@CC: Set Channel */ case CUSTOM_HCI_CW_SET_CHN_0: /*@CC: Set Channel 0 Freq 2402 MHz */ channelCC=2402; break; case CUSTOM_HCI_CW_SET_CHN_19: /*@CC: Channel 19 Freq 2440 MHz*/ channelCC=2440; break; case CUSTOM_HCI_CW_SET_CHN_39: /*@CC: Channel 39 Freq 2480 MHz */ channelCC=2480; break; /*@CC: Set PA_POWER */ case CUSTOM_HCI_CW_SET_PA_PWR_1: /*@CC: Set PA_POWER 1 */ powerCC=0x01; break; case CUSTOM_HCI_CW_SET_PA_PWR_32: /*@CC: Set PA_POWER 32 */ powerCC=0x20; break; case CUSTOM_HCI_CW_SET_PA_PWR_62: /*@CC: Set PA_POWER 62 */ powerCC=0x3E; break; /*@CC: Generate a Continuous Unmodulated Signal ON / OFF */ case CUSTOM_HCI_CW_ON: /*@CC: Generate a Continuous Unmodulated Signal when pressing SW3 */ XCVR_DftTxCW(channelCC, 6); XCVR_ForcePAPower(powerCC); break; case CUSTOM_HCI_CW_OFF: /*@CC: Turn OFF the transmitter */ XCVR_ForceTxWd(); /* Initialize the PHY as BLE */ XCVR_Init(BLE_MODE, DR_1MBPS); break; default: eventPacket[5] = CUSTOM_HCI_EVENT_FAIL; break; } eventPacket[3] = (uint8_t)opcode; eventPacket[4] = (uint8_t)(opcode >> 8); eventPacket[5] = CUSTOM_HCI_EVENT_SUCCESS; Hcit_SendPacket(gHciEventPacket_c, eventPacket, sizeof(eventPacket)); } else { return gBleUnexpectedError_c; } return gBleSuccess_c; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Testing Custom HCI Commands Using NXP Test Tool 12 To test HCI Black Box software, we need to install NXP Test Tool 12, from the NXP Semiconductors | Automotive, Security, IoT official web site. Once you have installed Test Tool, attach the FRDM-KW36 board to your PC and open the serial port enumerated in the start page clicking twice on the icon. Then, select "Raw Data" checkbox and type any of our custom commands, for instance, "01 01 FC 00" (Set the Channel 19 Freq 2440 MHz). Shift out the command clicking on the "Send Raw..." button. You will see the HCI Tx and Rx in the right upper corner of your screen
記事全体を表示
This patch fixes some minor issues with the Connectivity Software v1.0.2 when working with the Kinetis BLE Toolbox application for smartphones. Following issues are fixed. BLE OTAP Application: Fixes application failing to download the new image when the previous image upload has been interrupted due a disconnection. BLE Wireless UART: Fixes MTU exchange issue causing some characters not bein shown in the smartphone application in iOS and Android. Hybrid BLE + Thread console: Fixes MTU exchange issue causing some characters not bein shown in the smartphone application console in iOS and Android. Make sure the Connectivity Software version 1.0.2 is installed in your computer before proceeding to install this application.
記事全体を表示
Introduction This document guides to load a new software image in a KW41 device through Over The Air Programming bootloader. Also, are explained the details of how to set up the client software to change the storage method of the image. Software Requirements IAR Embedded Workbench IDE or MCUXpresso IDE Download both, SDK FRDM-KW41Z and SDK USB-KW41Z. Hardware Requirements FRDM-KW41Z board OTAP Memory Management During the Update Process The KW41 has a 512KB Program Flash with a flash address range from 0x0000_0000 to 0x0007_FFFF.     The OTAP application splits the flash into two independent parts, the OTAP Bootloader, and the OTAP Client. The OTAP Bootloader verifies if there is a new image available at the OTAP Client to reprogram the device. The OTAP Client software provides the Bluetooth LE custom service needed to communicate the OTAP Client device with the OTAP Server that contains the new image file (The OTAP Server device could be another FRDM-KW41Z connected to a PC with Test Tool or a Smartphone with IoT Toolbox app). Therefore, the OTAP Client device needs to be programmed twice, first with the OTAP Bootloader, then with the Bluetooth LE application supporting OTAP Client. The mechanism created to have two different software coexisting in the same device is storing each one in different memory regions. This functionality is implemented by the linker file. In the KW41 device, the bootloader has reserved a 16 KB slot of memory from 0x0000_0000 to 0x0003_FFFF, thus the left memory is reserved among other things, by the OTAP Client demo. To create a new image file for the client device, the developer needs to specify to the linker file that the code will be built with an offset of 16 KB since the first addresses must be reserved for the OTAP Bootloader. In connection state, the OTAP server sends the image packets (known as chunks) to the OTAP Client device via Bluetooth LE. The OTAP Client device can store these chunks, in first instance, at the external SPI flash or the On-Chip Flash. The destination of the code is selectable in the OTAP Client software. When the connection has finished and all chunks were sent from the OTAP Server to the OTAP Client device, the OTAP Client software writes information, such as the source of the image update (external flash or internal flash) in a portion of memory known as Bootloader Flags and then resets the MCU to execute the OTAP Bootloader code. The OTAP Bootloader reads the Bootloader Flags to get the information needed to program the device and triggers a commando to reprogram the MCU with the new application. Due to the new application was built with an offset of 16 KB, the OTAP Bootloader programs the device starting from the 0x0000_4000 address and the OTAP Client application is overwritten by the new image, therefore, after the device has been reprogrammed through this method, cannot be programmed a second time as same. Finally, the OTAP Bootloader triggers a command to start the execution of the new code automatically.     Preparing the Software to Test the OTAP Client for KW41Z Device Using IAR Embedded Workbench Program the OTAP Bootloader on the FRDM-KW41Z. Program the OTAP Bootloader software from the project included in the SDK FRDM-KW41Z at the following path, or you can simply drag and drop the pre-built binary from the following path.           OTAP Bootloader Project:          <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\framework\bootloader_otap\bm\iar\bootloader_otap_bm.eww            OTAP Bootloader pre-built binary:            <SDK_2.2.0_FRDM-KW41Z_download_path>\tools\wireless\binaries\bootloader_otap_frdmkw41z.bin   Open the OTAP Client project included in the SDK FRDM-KW41Z located in the following path.          <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\otap_client_att\freertos\iar\otap_client_att_freertos.eww   Customize the OTAP Client software to select the storage method. Locate the app_preinclude.h header file inside the source folder at the workspace. To select the External Flash storage method, set the "gEepromType_d" define to "gEepromDevice_AT45DB041E_c"                      To select the Internal Flash storage method, set the "gEepromType_d" define to "gEepromDevice_InternalFlash_c"   Configure the linker flags. Open the project options window (Alt + F7). In "Linker->Config" window, locate the "Configuration file symbol definitions" pane. To select the External Flash storage method, remove the "gUseInternalStorageLink_d=1" linker flag To select the Internal Flash storage method, add the "gUseInternalStorageLink_d=1" linker flag     Load the OTAP Client software on the FRDM-KW41Z board (Ctrl + D). Stop the debug session (Ctrl + Shift + D). The default linker configurations of the project allow the OTAP Client application to be stored with the proper memory offset.   Preparing the Software to Test the OTAP Client for KW41Z Device Using MCUXpresso IDE Program the OTAP Bootloader on the FRDM-KW41Z. Program the OTAP Bootloader software from the project included in the SDK FRDM-KW41Z at the following path, or you can simply drag and drop the pre-built binary from the following path.           OTAP Bootloader Project:          wireless_examples->framework->bootloader_otap->bm            OTAP Bootloader pre-built binary:            <SDK_2.2.0_FRDM-KW41Z_download_path>\tools\wireless\binaries\bootloader_otap_frdmkw41z.bin   Click on "Import SDK examples(s)" option in the "Quickstart Panel" view. Click twice on the frdmkw41z icon.     Open the OTAP Client project included in the SDK FRDM-KW41Z located in the following path.wireless_examples->bluetooth->otap_client_att->freertos     Customize the OTAP Client software to select the storage method. Locate the app_preinclude.h header file inside the source folder at the workspace. To select the External Flash storage method, set the "gEepromType_d" define to "gEepromDevice_AT45DB041E_c"                      To select the Internal Flash storage method, set the "gEepromType_d" define to "gEepromDevice_InternalFlash_c"   Configure the linker file. To select the External Flash storage method, are not required any changes in the project from this point. You can skip this step. To select the Internal Flash storage method, search the linker file located in the SDK USB-KW41Z at the following path and replace instead of the default linker file at the source folder in the OTAP Client project. You can copy (Ctrl + C) the linker file from SDK USB-KW41Z and paste (Ctrl + V) on the workspace directly. A warning message will be displayed, select "Overwrite".           Linker file at the SDK USB-KW41Z:        <SDK_2.2.0_USB-KW41Z_download_path>\boards\usbkw41z_kw41z\wireless_examples\bluetooth\otap_client_att\freertos\MKW41Z512xxx4_connectivity.ld     Save the changes in the project. Select "Debug" in the "Quickstart Panel". Once the project is already loaded on the device, stop the debug session.   Creating an S-Record Image File for FRDM-KW41Z OTAP Client in IAR Embedded Workbench Open the connectivity project that you want to program using the OTAP Bootloader from your SDK FRDM-KW41Z. This example will make use of the glucose sensor project, this is located at the following path. <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\glucose_sensor\freertos\iar\glucose_sensor_freertos.eww   Open the project options window (Alt+F7). In Linker->Config window, add the following linker flag in the “Configuration file symbol definitions” textbox.         gUseBootloaderLink_d=1     Go to the “Output Converter” window. Deselect the “Override default" checkbox, expand the “Output format” combo box and select Motorola S-records format. Click the OK button.     Rebuild the project. Search the S-Record file (.srec) in the following path.<SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\glucose_sensor\freertos\iar\debug   Creating an S-Record Image File for FRDM-KW41Z OTAP Client in MCUXpresso IDE Open the connectivity project that you want to program using the OTAP Bootloader from MCUXpresso IDE. This example will make use of the glucose sensor project, this is located at the following path.        wireless_examples->bluetooth->glucose_sensor->freertos   Search the linker file located in the SDK FRDM-KW41Z at the path below and replace instead of the default linker file at the source folder in the Glucose Sensor project. You can copy (Ctrl + C) the linker file from SDK FRDM-KW41Z and paste (Ctrl + V) on the workspace directly. A warning message will be displayed, select "Overwrite".          Linker file at the SDK FRDM-KW41Z:        <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\otap_client_att\freertos\MKW41Z512xxx4_connectivity.ld     Open the new "MKW41Z512xxx4_connectivity.ld" linker file. Locate the section placement of the figure below and remove the "FILL" and the "BYTE" statements.         Build the project. Deploy the “Binaries” icon in the workspace. Click the right mouse button on the “.axf” file. Select the “Binary Utilities/Create S-Record” option. The S-Record file will be saved at “Debug” folder in the workspace with “.s19” extension.     Testing OTAP Client Demo Using IoT Toolbox App Save the S-Record file created with the steps in the last section in your smartphone at a known location. Open the IoT Toolbox App and select OTAP demo. Press “SCAN” to start scanning for a suitable advertiser. Press the “SW4” button on the FRDM-KW41Z board to start advertising. Create a connection with the found device. Press “Open” and search the S-Record file. Press “Upload” to start the transfer. Once the transfer is complete, wait a few seconds until the bootloader has finished programming the new image. The new application will start automatically. 
記事全体を表示
This guide will show a way to set up and enable an I2C Serial Interface to send a string of data instances using one of the Wireless Bluetooth SDK examples and the Serial Manager API.
記事全体を表示
I got a question related to best practices to configure a GPIO if the pin is not used. To make it short, the recommendation is to leave the GPIO floating on the PCB and leave the GPIO in its "Default" state as shown in the Signal Multiplexing table in the Reference Manual. The Default state is either “Disabled” or an analog function.   Some Kinetis devices have analog only pins (PGAx/ADCx) while most have GPIO pins with analog functions (PTx/ADCx) or digital GPIO pins   Unused pins, whether analog only or GPIO, should be left floating. Analog only pins do not have input buffers that will cause shoot-through currents when the input floats. GPIO pins with analog functions default to analog functions, which disables the digital input buffer – no shoot-through current.   The digital GPIO pins default to "Disabled", which disables the input buffers - no shoot-through currents with floating inputs.   Finally, unused pins shall not be tied to VDD or VSS. Hence, when designing your board and there are some unused pins, leave them floating on the PCB and then make sure that the software leaves the GPIO in its Default state in the MUX register. 
記事全体を表示
Introduction The MTU (Maximum Transmission Unit) in Bluetooth LE, is an informational parameter that indicates to the remote device, the maximum number of bytes that the local can handle in such channel, for example, the ATT_MTU for KW36 is fixed in 247 bytes. A few applications require to have long characteristics defined in the GATT database, and sometimes the length of the characteristic exceeds the MTU negotiated by the client and server Bluetooth LE devices. For this scenario, the Bluetooth LE specification defines a procedure to write and read the characteristic of interest. In summary, it consists in perform multiple writes and reads on the same characteristic value, using specific commands. For the "write long characteristic value" procedure, these commands are ATT_PREPARE_WRITE_REQ and ATT_EXECUTE_WRITE_REQ. For the "read long characteristic value" procedure, these commands are ATT_READ_REQ and ATT_READ_BLOB_REQ. This document provides an example of how to write and read long characteristic values, from the perspective of Client and Server devices.   APIs to Write and Read Characteristic Values Write Characteristic Values The GattClient_WriteCharacteristicValue API is used to perform any write operation. It is implemented by the GATT Client device. The following table describes the input parameters. Input Parameters Description deviceId_t deviceId Device ID of the peer device. gattCharacteristic_t * pCharacteristic Pointer to a gattCharacteristic struct type. This struct must contain a valid handle of the characteristic value in the "value.handle" field. The handle of the characteristic value that you want to write is commonly obtained after the service discovery procedure.  uint16_t valueLength This value indicates the length of the array pointed by aValue. const uint8_t * aValue Pointer to an array containing the value that will be written to the GATT database. bool_t withoutResponse If true, it means that the application wishes to perform a "Write Without Response", in other words, when the command will be ATT_WRITE_CMD or ATT_SIGNED_WRITE_CMD. bool_t signedWrite If withoutResponse and signedWrite are both true, the command will be ATT_SIGNED_WRITE_CMD. If withoutResponse is false, this parameter is ignored. bool_t doReliableLongCharWrites This field must be set to true if the application needs to write a long characteristic value. const uint8_t * aCsrk If withoutResponse and signedWrite are both true, this pointer must contain the CSRK to sign the data. Otherwise, this parameter is ignored.   Read Characteristic Values The GattClient_ReadCharacteristicValue API is used to perform read operations. It is implemented by the GATT Client device. The following table describes the input parameters. Input Parameters Description deviceId_t deviceId Device ID of the peer device. gattCharacteristic_t * pIoCharacteristic Pointer to a gattCharacteristic struct type. This struct must contain a valid handle of the characteristic value in the "value.handle" field. The handle of the characteristic value that you want to write is commonly obtained after the service discovery procedure. As well, the "value.paValue" field of this struct, must point to an array which will contain the characteristic value read from the peer. unit16_t maxReadBytes The length of the characteristic value that should be read. This API takes care of the long characteristics, so there is no need to worry about a special parameter or configuration. The following sections provide a functional example of how to write and read long characteristics. This example was based on the temperature collector and temperature sensor SDK examples. The example also shows how to create a custom service at the GATT database and how to discover its characteristics.   Bluetooth LE Server (Temperature Sensor) Modifications in gatt_uuid128.h Define the 128 bit UUID of the "custom service" which will be used for this example. Add the following code: /* Custom service */ UUID128(uuid_service_custom, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x00, 0x01, 0xFF, 0x01) UUID128(uuid_char_custom, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x01, 0x01, 0xFF, 0x01)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Modifications in gatt_db.h Define the characteristics of the "custom service", for this example, our service will have just one characteristic, it can be written or read, and it has a variable-length limited to 400 bytes (remember that the ATT_MTU of KW36 is 247 byte, so with this length, we ensure long writes and reads). Add the following code: PRIMARY_SERVICE_UUID128(service_custom, uuid_service_custom) CHARACTERISTIC_UUID128(char_custom, uuid_char_custom, (gGattCharPropWrite_c | gGattCharPropRead_c)) VALUE_UUID128_VARLEN(value_custom, uuid_char_custom, (gPermissionFlagWritable_c | gPermissionFlagReadable_c), 400, 1)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Modifications in app_preinclude.h One of the most important considerations to write and read long characteristics is the memory allocation needed for this. You must increment the current "AppPoolsDetails_c" configuration, the "_block_size_" and "_number_of_blocks_". Please ensure that "_block_size_" is aligned with 4 bytes. Once you have found the configuration that works in your application, please follow the steps in Memory Pool Optimizer on MKW3xA/KW3xZ Application Note, to found the best configuration without waste memory resources. For this example, configure "AppPoolsDetails_c" as follows: /* Defines pools by block size and number of blocks. Must be aligned to 4 bytes.*/ #define AppPoolsDetails_c \ _block_size_ 264 _number_of_blocks_ 8 _eol_‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Bluetooth LE Client (Temperature Collector) Modifications in gatt_uuid128.h Define the 128 bit UUID of the "custom service" which will be used for this example. Add the following code: /* Custom service */ UUID128(uuid_service_custom, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x00, 0x01, 0xFF, 0x01) UUID128(uuid_char_custom, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x01, 0x01, 0xFF, 0x01)‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Modifications in temperature_collector.c 1. Define the following variables at the "Private type definitions" section: typedef struct customServiceConfig_tag { uint16_t hService; uint16_t hCharacteristic; } customServiceConfig_t; typedef struct appCustomInfo_tag { tmcConfig_t tempClientConfig; customServiceConfig_t customServiceClientConfig; }appCustomInfo_t; typedef enum { mCustomServiceWrite = 0, mCustomServiceRead }customServiceState_t;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 2. Add two arrays of 400 bytes, one to send and the other to receive the data from the server in "Private memory declarations" section: /* Dummy array for custom service */ uint8_t mWriteDummyArray[400]; uint8_t mReadDummyArray[400];‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 3. Define a new function in "Private functions prototypes" section, to write and read the characteristic value: static void BleApp_SendReceiveCustomService (customServiceState_t state);‍‍‍‍ 4. Locate the "BleApp_Config" function, add the following code here to fill the "mWriteDummyArray" with a known pattern before to write our custom characteristic. static void BleApp_Config(void) { uint16_t fill_pattern; /* Fill pattern to write long characteristic */ for (fill_pattern = 0; fill_pattern<400; fill_pattern++) { mWriteDummyArray[fill_pattern] = (uint8_t)fill_pattern; } /* Configure as GAP Central */ BleConnManager_GapCommonConfig(); ... ... }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 5. Locate the "BleApp_StoreServiceHandles" function. Modify this function to include our custom service in the service discovery procedure. This is to save the handle of the custom characteristic since it is used by GattClient_WriteCharacteristicValue and GattClient_ReadCharacteristicValue APIs. static void BleApp_StoreServiceHandles ( gattService_t *pService ) { uint8_t i,j; if ((pService->uuidType == gBleUuidType128_c) && FLib_MemCmp(pService->uuid.uuid128, uuid_service_temperature, 16)) { /* Found Temperature Service */ mPeerInformation.customInfo.tempClientConfig.hService = pService->startHandle; for (i = 0; i < pService->cNumCharacteristics; i++) { if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) && (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Temperature_d)) { /* Found Temperature Char */ mPeerInformation.customInfo.tempClientConfig.hTemperature = pService->aCharacteristics[i].value.handle; for (j = 0; j < pService->aCharacteristics[i].cNumDescriptors; j++) { if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType16_c) { switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16) { /* Found Temperature Char Presentation Format Descriptor */ case gBleSig_CharPresFormatDescriptor_d: { mPeerInformation.customInfo.tempClientConfig.hTempDesc = pService->aCharacteristics[i].aDescriptors[j].handle; break; } /* Found Temperature Char CCCD */ case gBleSig_CCCD_d: { mPeerInformation.customInfo.tempClientConfig.hTempCccd = pService->aCharacteristics[i].aDescriptors[j].handle; break; } default: ; /* No action required */ break; } } } } } } else if ((pService->uuidType == gBleUuidType128_c) && FLib_MemCmp(pService->uuid.uuid128, uuid_service_custom, 16)) { /* Found Custom Service */ mPeerInformation.customInfo.customServiceClientConfig.hService = pService->startHandle; if (pService->cNumCharacteristics > 0U && pService->aCharacteristics != NULL) { /* Found Custom Characteristic */ mPeerInformation.customInfo.customServiceClientConfig.hCharacteristic = pService->aCharacteristics[0].value.handle; } } else { ; } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 6. Develop the "BleApp_SendReceiveCustomService" as shown below. This function is used to write and read the custom characteristic values using long operations. Focus your attention in this function, here is the example of how to use GattClient_WriteCharacteristicValue and GattClient_ReadCharacteristicValue APIs to write and read long characteristic values. Note that the "characteristic" struct was filled before to use the last APIs, with the handle of our custom characteristic and a destination address to receive the value read from the peer. Note that the "doReliableLongCharWrites" field must be TRUE to allow long writes using GattClient_WriteCharacteristicValue.  static void BleApp_SendReceiveCustomService (customServiceState_t state) { bleResult_t bleResult; gattCharacteristic_t characteristic; /* Verify if there is a valid peer */ if (gInvalidDeviceId_c != mPeerInformation.deviceId) { /* Fill the characteristic struct with a read destiny and the custom service handle */ characteristic.value.handle = mPeerInformation.customInfo.customServiceClientConfig.hCharacteristic; characteristic.value.paValue = &mReadDummyArray[0]; /* Try to write the custom characteristic value */ if(mCustomServiceWrite == state) { bleResult = GattClient_WriteCharacteristicValue(mPeerInformation.deviceId, &characteristic, (uint16_t)400, &mWriteDummyArray[0], FALSE, FALSE, TRUE, NULL); /* An error occurred while trying to write the custom characteristic value, disconnect */ if(gBleSuccess_c != bleResult) { (void)Gap_Disconnect(mPeerInformation.deviceId); } } /* Try to read the custom characteristic value */ else { bleResult = GattClient_ReadCharacteristicValue(mPeerInformation.deviceId, &characteristic, (uint16_t)400); /* An error occurred while trying to read the custom characteristic value, disconnect */ if(gBleSuccess_c != bleResult) { (void)Gap_Disconnect(mPeerInformation.deviceId); } } } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 7. Modify the "BleApp_GattClientCallback" as shown below. In this function, we implement the "BleApp_SendReceiveCustomService" which writes or reads the characteristic depending on the input parameter "state". The expected behavior of this example is, first, write the 400-byte pattern contained in the mWriteDummyArray to our custom characteristic value, just after to write the characteristic descriptor of the temperature service (which is indicated by this callback in the gGattProcWriteCharacteristicDescriptor_c event). When the write has been executed successfully, it is indicated in this callback, by the "gGattProcWriteCharacteristicValue_c" event, therefore, here we can execute our function to read the characteristic value. Then "gGattProcReadCharacteristicValue_c" event is triggered if the read has been completed, here, we compare the value written with the value read from the GATT server and, if both are the same, the green RGB led should turn on indicating that our long characteristic has been written and read successfully, otherwise, the GATT client disconnects from the GATT server.   static void BleApp_GattClientCallback( deviceId_t serverDeviceId, gattProcedureType_t procedureType, gattProcedureResult_t procedureResult, bleResult_t error ) { if (procedureResult == gGattProcError_c) { attErrorCode_t attError = (attErrorCode_t)(uint8_t)(error); if (attError == gAttErrCodeInsufficientEncryption_c || attError == gAttErrCodeInsufficientAuthorization_c || attError == gAttErrCodeInsufficientAuthentication_c) { /* Start Pairing Procedure */ (void)Gap_Pair(serverDeviceId, &gPairingParameters); } BleApp_StateMachineHandler(serverDeviceId, mAppEvt_GattProcError_c); } else { if (procedureResult == gGattProcSuccess_c) { switch(procedureType) { case gGattProcReadCharacteristicDescriptor_c: { if (mpCharProcBuffer != NULL) { /* Store the value of the descriptor */ BleApp_StoreDescValues(mpCharProcBuffer); } break; } case gGattProcWriteCharacteristicDescriptor_c: { /* Try to write to the custom service */ BleApp_SendReceiveCustomService(mCustomServiceWrite); } break; case gGattProcWriteCharacteristicValue_c: { /* If write to the custom service was completed, try to read the custom service */ BleApp_SendReceiveCustomService(mCustomServiceRead); } break; case gGattProcReadCharacteristicValue_c: { /* If read to the custom service was completed, compare write and read buffers */ if(FLib_MemCmp(&mWriteDummyArray[0], &mReadDummyArray[0], 400)) { Led3On(); } else { (void)Gap_Disconnect(mPeerInformation.deviceId); } } break; default: { ; /* No action required */ break; } } BleApp_StateMachineHandler(serverDeviceId, mAppEvt_GattProcComplete_c); } } /* Signal Service Discovery Module */ BleServDisc_SignalGattClientEvent(serverDeviceId, procedureType, procedureResult, error); }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Modifications in app_preinclude.h One of the most important considerations to write and read long characteristics is the memory allocation needed for this. You must increment the current "AppPoolsDetails_c" configuration, the "_block_size_" and "_number_of_blocks_". Please ensure that "_block_size_" is aligned with 4 bytes. You can know when the current configuration of pools do not satisfy the application requirements if the return value of either "GattClient_WriteCharacteristicValue" or "GattClient_ReadCharacteristicValue " is "gBleOutOfMemory_c" instead of "gBleSuccess_c" (If it is the case, the device will disconnect to the peer according to the code in step 6 in "Modifications in temperature_collector.c"). Once you have found the configuration that works in your application, please follow the steps in Memory Pool Optimizer on MKW3xA/KW3xZ Application Note, to found the best configuration without waste memory resources. For this example, configure "AppPoolsDetails_c" as follows: /* Defines pools by block size and number of blocks. Must be aligned to 4 bytes.*/ #define AppPoolsDetails_c \ _block_size_ 112 _number_of_blocks_ 6 _eol_ \ _block_size_ 256 _number_of_blocks_ 3 _eol_ \ _block_size_ 280 _number_of_blocks_ 2 _eol_ \ _block_size_ 432 _number_of_blocks_ 1 _eol_‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Please let us know any question regarding this topic.
記事全体を表示
The TWR-KW2x board's OpenSDA is programmed with PE Micro's OpenSDA firmware which enables MSD, debugging and CDC Serial port. This firmware can be easily modified by putting the K20 part in bootloader mode and load another firmware to it with a simple drag and drop. Follow these steps to modify the OpenSDA firmware on the TWR-KW2x board. Segger's OpenSDA v2.1 will be used as an example of the new OpenSDA firmware (Instead of the default PE Micro's) 1. Unplug the board 2. Insert a Jumper in J30 to put the device in Bootloader mode 3. Plug in the board (Mini-USB) 4. Device will be enumerated as a "Drive Disk" But now with a "Bootloader" label 5. Drag and Drop the Segger's JLink_OpenSDA_V2_1.bin firmware (https://segger.com/opensda.html) into the Bootloader unit 6. Unplug the board 7. Remove Jumper 8. Plug in the board (Mini-USB) Now you should see the board being enumerated as "JLink CDC UART Port", allowing serial port communication. You should also be able to debug your application using J-Link debugging interface through the OpenSDA interface, no need of external hardware. Note1: Drivers can be found at Segger's website (https://segger.com/opensda.html) Note2: Jumper has to be in place in J29 for debugging Note3: IDE options must be set to use J-Link Driver
記事全体を表示
This guide describes the hardware for the KW38 minimum BoM development board. The KW38 Minimum BoM development board is configurable, low-power, and cost-effective evaluation and development board for application prototyping and demonstration of the KW39A/38A/37A/39Z/38Z family of devices. The KW38 is an ultra-low-power, highly integrated single-chip device that enables Bluetooth Low Energy (Bluetooth LE) or Generic FSK (at 250, 500 and 1000 kbps) for portable, extremely low-power embedded systems. The KW38 integrates a radio transceiver operating in the 2.36 GHz to 2.48 GHz range supporting a range of GFSK, an ARM Cortex-M0+ CPU, up to 512 KB Flash and up to 64 KB SRAM, Bluetooth LE Link Layer hardware and peripherals optimized to meet the requirements of the target applications. MKW38 device is also available on the FRDM-KW38 Freedom Development Board. For more information about the FRDM-KW38 Freedom Development Board, see the FRDM-KW38 Freedom Development Board User's Guide (document FRDMKW38ZUG available in the NXP Connectivity website also).
記事全体を表示
During last week I receive a question about identify a way to notice when the 32kHz oscillator is ready to be able to use it as clock source. In other words, when the 32kHz oscillator is stable to be used as reference clock for the MCG module. Then, system can switch over it. Kinetis devices starts up using its internal clock which is called FEI mode, then, the applications change to a different mode which require an external clock source (i.e. FEE mode). Normally, we have two options which are: Main reference clock. Talking specifically to KW devices, there is the 32MHz external crystal for the main reference clock. The 32kHz external crystal for the 32kHz oscillator which is driven through the RTC registers.  For the first option, there is a register which could be monitored to know when oscillator is ready (RSIM_CONTROL_RF_OSC_READY). So, it can be polled to notice when the oscillator is up and ready.  About the second option, there is no “OSCINIT” bit for the 32 kHz oscillator. However, there is a way to know when the 32kHz Oscillator is running, it is to simply enable the RTC OSC, and configure the RTC to count. After doing that immediately poll (read) the RTC_TPR register and check it until it is greater than 4096. It will roll over once it reaches 32767 so, it is important to the poll this register in a loop doing nothing else or the register could potentially be read when it is less than 4096 but had already rolled over. Once it is greater than 4096, it can be determined that oscillator is running well. If the RTC is not required, the counter can be disabled. Now that the 32kHz clock is available, the application can switch to FEE mode. So, in order to perform the above description, I modified the “CLOCK_CONFIG_EnableRtcOsc()” as shown next: static void CLOCK_CONFIG_EnableRtcOsc(uint32_t capLoad) {        rtc_config_t rtc_basic_config;        uint32_t u32cTPR_counter=0;        /* RTC clock gate enable */     CLOCK_EnableClock(kCLOCK_Rtc0);     if ((RTC->CR & RTC_CR_OSCE_MASK) == 0u)     {       /* Only if the Rtc oscillator is not already enabled */       /* Set the specified capacitor configuration for the RTC oscillator, "capLoad" parameter shall be set          to the value specific to the customer board requirement*/       RTC_SetOscCapLoad(RTC, capLoad);          /*Init the RTC with default configuration*/       RTC_GetDefaultConfig(&rtc_basic_config);       RTC_Init(RTC, &rtc_basic_config);       /* Enable the RTC 32KHz oscillator */       RTC->CR |= RTC_CR_OSCE_MASK;       /* Start the RTC time counter */       RTC_StartTimer(RTC);             /* Verify TPR register reaches 4096 counts */       while(u32cTPR_counter < 4096)       {          u32cTPR_counter= RTC->TPR;       }       /* 32kHz Oscillator is ready. Based on the application requirements, it can let the RTC enabled or disabled.           In this case, we can disable RTC since it is not needed by this application */       RTC_Deinit(RTC);     }     /* RTC clock gate disable  since RTC is not needed anymore*/     CLOCK_DisableClock(kCLOCK_Rtc0); }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Then, using the above function, it can be noticed when the 32kHz oscillator is ready to be used. Hope this helps....
記事全体を表示
For this example, the BLE stack VERSION was configure to create a Custom Profile with the KW40Z. The Custom to create is the Humidity Sensor and is based on the Temperature Sensor. The First thing to know is that the Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules. GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations.    Figure 1. GATT Client-Server       GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors are defined attributes that describe a characteristic value. To define a GATT Database several macros are provided by the GATT_DB API. Figure 2. GATT database      To know if the Profile or service is already defined on the specification, you have to look for on Bluetooth SIG profiles and check on the ble_sig_define module if is already declared on the code. In our case the Service is not declared(because is a Custom Profile) but the characteristic of the humidity it is on the specification but not on ble_sig_define. /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d                      0x2A6F The Humidity Sensor is going to have the GATT Server, because is going to be the device that has all the information for the GATT Client. The Application works like the Temperature Sensor, every time that you press the SW1 on USB is going to send the value. On the Temperature Sensor demo have the Battery Service and Device Information, so you only have to change the Temperature Service to Humidity Service. Figure 3. GATT database of Humidity Sensor      First thing to do is define the Humidity Server that has 16 bytes. To define a new Server or a Characteristic is in gatt_uuid128.h which is located in the application folder. All macros, function or structure in SDK have a common template which helps the application to act accordingly. /* Humidity */ UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)      All the Service and Characteristics is declared in gattdb.h. Descriptors are declared after the Characteristic Value declaration but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units of the Humidity Characteristic is on Percentage that is 0x27AD. Client Characteristic Configuration Descriptor(CCCD) is a descriptor where clients write some of the bits to activate Server notifications and/or indications PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity) CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c)) VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25) DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00) CCCD(cccd_humidity)      After that, create a folder humidity in the next path C:\....\KW40Z_BLE_Software_1.1.2\ConnSw\bluetooth\profiles. Found the temperature folder, copy the temperature_service and paste inside of the humidity folder with another name (humidity_service) Then go back and look for the interface folder, copy temperature_interface and change the name (humidity_interface) in the same path.      On the humidity_interface file should have the following code. The Service structure has the service handle, and the initialization value. /*! Humidity Service - Configuration */ typedef struct humsConfig_tag {     uint16_t serviceHandle;     int16_t initialHumidity;        } humsConfig_t; The next configuration structure is for the Client; in this case we don’t need it. /*! Humidity Client - Configuration */ typedef struct humcConfig_tag {     uint16_t    hService;     uint16_t    hHumidity;     uint16_t    hHumCccd;     uint16_t    hHumDesc;     gattDbCharPresFormat_t  humFormat; } humcConfig_t;      At minimum on humidity_service file, should have the following code. The service stores the device identification for the connected client. This value is changed on subscription and non-subscription events. /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId;      The initialization of the service is made by calling the start procedure. This function is usually called when the application is initialized. In this case is on the BleApp_Config(). On stop function, the unsubscribe function is called. bleResult_t Hums_Start (humsConfig_t *pServiceConfig) {        mHums_SubscribedClientId = gInvalidDeviceId_c;         return Hums_RecordHumidityMeasurement (pServiceConfig->serviceHandle, pServiceConfig->initialHumidity); } bleResult_t Hums_Stop (humsConfig_t *pServiceConfig) {     return Hums_Unsubscribe(); }      Depending on the complexity of the service, the API will implement additional functions. For the Humidity Sensor only have a one characteristic. The measurement will be saving on the GATT database and send the notification to the client. This function will need the service handle and the new value as input parameters. bleResult_t Hums_RecordHumidityMeasurement (uint16_t serviceHandle, int16_t humidity) {     uint16_t handle;     bleResult_t result;     bleUuid_t uuid = Uuid16(gBleSig_Humidity_d);         /* Get handle of Humidity characteristic */     result = GattDb_FindCharValueHandleInService(serviceHandle,         gBleUuidType16_c, &uuid, &handle);     if (result != gBleSuccess_c)         return result;     /* Update characteristic value */     result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t*)&humidity);     if (result != gBleSuccess_c)         return result; Hts_SendHumidityMeasurementNotification(handle);     return gBleSuccess_c; }      After save the measurement on the GATT database with GattDb_WriteAttribute function we send the notification. To send the notification, first have to get the CCCD and after check if the notification is active, if is active send the notification. static void Hts_SendHumidityMeasurementNotification (   uint16_t handle ) {     uint16_t hCccd;     bool_t isNotificationActive;     /* Get handle of CCCD */     if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd) != gBleSuccess_c)         return;     if (gBleSuccess_c == Gap_CheckNotificationStatus         (mHums_SubscribedClientId, hCccd, &isNotificationActive) &&         TRUE == isNotificationActive)     {           GattServer_SendNotification(mHums_SubscribedClientId, handle);     } }      Steps to include the files into the demo. 1. Create a clone of the Temperature_Sensor with the name of Humidity_Sensor 2. Unzip the Humidity_Sensor folder. 3. In the fallowing path <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profiles\interface save the humidity_interface file. 4. In the <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profiles save the humidity folder 5. In the next directory <kw40zConnSoft_intall_dir>\ConnSw\examples\bluetooth\humidity_sensor\common replaces with the common folder.           Steps to include the paths into the demo using IAR Embedded Workbench​ Once you already save the folders in the corresponding path you must to indicate in the demo where are they. 1. Drag the files into the corresponding folder. The principal menu is going to see like this. Figure 4. Principal Menu 2. Then click Option Figure 5. Option 3. Click on the C/C++ Compiler and then on the Preprocessor     Figure 6. Preposcessor Window 4. After that click on  "..." button to edit the include directories and then click to add a new path.      Add the <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profile\humidity path. Figure 7. Add a path Finally compile and enjoy the demo! NOTE: If you want to probe the demo using another board you must to run the humidity_collector demo too. Figure 8. Example of the Humidity Sensor using the Humidity Collector demo.
記事全体を表示
Sniffing is the process of capturing any information from the surrounding environment. In this process, addressing or any other information is ignored, and no interpretation is given to the received data. Freescale provides both means and hardware to create devices capable of performing this kind of operation. For example, a KW01 board can be easily turned into a Sub-GHz sniffer using Test Tool 12.2.0 which can be found at https://www.freescale.com/webapp/sps/download/license.jsp?colCode=TESTTOOL_SETUP&appType=file2&location=null&DOWNLOAD_ID=null After downloading and installing Test Tool 12.2.0 there are several easy steps to create your own sniffer for Sub-GHz bands. 1) How to download the sniffer image file onto KW01.      a) Connect KW01 to PC using the mini-usb cable      b) Connect the J-Link to the PC      c) Open Test Tool 12.2 and go to the Firmware Loaders tab      d) Select Kinetis Firmware Loader. A new tab will pop-up.      e) J-Link will appear under the J-Link devices tab.      f) Select the KW01Z128_Sniffer.srec file and press the upload button.     g) From the Development Board Option menu select KW01Z128.      h) Follow the on-screen instruction and unplug the board. Then plug it back in.      i) Close the Kinetis Firmware Loader tab and open the Protocol Analyzer Tab 2) How to use the Protocol Analyzer feature. Basics.     a) The Protocol Analyzer should automatically detect the KW01 sniffer. If not, close the tab, unplug the board, plug it back and re-open the tab. If this doesn’t work, try restarting Test Tool.     b) To start “sniffing” the desired channel, click the arrow down button from Devices: KW01 (COMx) Off and select the desired mode and channel.     c) The tab will change to ON meaning that KW01 will "sniff" on the specified channel. To select another channel, click the tab again and it will switch back to Off. Then select a new channel.      d) Regarding other configurations, please note that you can specify what decoding will be applied to the received data. Additional information: The sniffer image found in Test Tool is compiled for the 920-928MHz frequency band. Because of this, the present document will have attached to it two sniffer images, for the 863-870MHz and the 902-928MHz frequency bands. To upload a custom image perform the steps described at the beginning of this document, but instead of selecting a *.srec file from the list in Kinetis Firmware Loader click the Browse button and locate the file on disk. After selecting it, redo the steps for uploading an image file. A potential outcome: sometimes, if you load a different frequency band sniffer image, the Protocol Analyzer will display the previously used frequency band. To fix this, close Test Tool, re-open it and go to the Protocol Analyzer tab again. The new frequency band should be displayed. More information on this topic can be found in Test Tool User Guide (..\Freescale\Test Tool 12\Documentation\TTUG.pdf), under Chapter 5 (Protocol Analyzer, page 87).
記事全体を表示
OVERVIEW This document shows how to include the PowerLib to enable low power functionality in connectivity software projects that does not include it. It shows step by step instructions on how to import, configure and use this module. ADD POWER LIBRARY INTO A NEW PROJECT Once you have installed the “Connectivity Software” package, browse for the extracted files (typically located in C:\Freescale\KW40Z_Connectivity_Software_1.0.0). In this location search for the LowPower folder, then copy and paste it into your new project folder. Open your IAR project and create a new group called “Low Power”. Inside this group add two new groups called “Interface” and “Source”. In the Windows explorer, open the LowPower folder copied in the previous step. Drag and drop the contents of the "Interface" folder to the "Interface" group in IAR. Do the same for the "Source" folder. You can also use the option "Add Files" in the group menu to add the files. Note: Do not copy the “PWR_Platform.c” and “PWR_Platform.h” files. Once you have copied the files in their respective folders, you need to add the paths of these files in the project environment. Right click on the project name and select "Options". In Options go to “C/C++Compiler”, select “Preprocessor” and click on the red square. The next window will appear. Click on <Click to add>  to open the windows explorer. Navigate to the folder PowerLib/Interface in your project to add the "Interface" folder path. Repeat this step with the "Source" folder. HOW TO CONFIGURE LOW POWER To use low power in your project you need to define the following macros in the “app_preinclude.h” file: /* Enable/Disable PowerDown functionality in PwrLib */ #define cPWR_UsePowerDownMode           1 /* Enable/Disable BLE Link Layer DSM */ #define cPWR_BLE_LL_Enable              1 /* Default Deep Sleep Mode*/ #define cPWR_DeepSleepMode              4 cPWR_UsePowerDownMode enables the necessary functions to use low power in your project. cPWR_BLE_LL_Enable configures the link layer to work in doze mode when in low power, and cPWR-DeepSleepMode defines the deep sleep mode the MCU will enter when the low power function is executed. There are the six different modes that can be used.   Mode 1: MCU/Radio low power modes:         MCU in LLS3 mode.         BLE_LL in DSM.       Wakeup sources:       GPIO (push button) interrupt using LLWU module.        BLE_LL wake up interrupt(BLE_LL reference clock reaches wake up instance register)  using LLWU module.              - BTE_LL wakeup timeout: controlled by the BLE stack(SoC must be awake before next BLE action).              - BTE_LL reference clock source:   32Khz oscillator              - BTE_LL reference clock resolution:     625us                            Mode 2: MCU/Radio low power modes:         MCU in LLS3 mode.         BLE_LL in DSM.       Wakeup sources:         GPIO (push button) interrupt using LLWU module.         BLE_LL wake up interrupt(BLE_LL reference clock reaches wake up instance register)  using LLWU module.                - BTE_LL wakeup timeout: cPWR_DeepSleepDurationMs by default. Use PWR_SetDeepSleepTimeInMs  to change it at run time. Maximum timeout is 40959 ms. BLE suppose to be idle.                - BTE_LL reference clock source:   32Khz oscillator                - BTE_LL reference clock resolution:     625us   Mode  3: MCU/Radio low power modes:         MCU in LLS3 mode.         BLE_LL in idle.       Wakeup sources:        GPIO (push button) interrupt using LLWU module.        DCDC PowerSwitch - available in buck mode only.        LPTMR interrupt using LLWU module           - LPTMR wakeup timeout: cPWR_DeepSleepDurationMs by default. Use PWR_SetDeepSleepTimeInMs to change it at run time. Maximum timeout is 65535000 ms (18.2 h).           - LPTMR clock source:   32Khz oscillator           - LPTMR resolution:     modified at run time to meet timeout value. Mode 4: MCU/Radio low power modes:         MCU in VLLS0/1 mode(VLLS0 if DCDC bypassed/ VLLS1 otherwise ).        BLE_LL in idle.       Wakeup sources:        GPIO (push button) interrupt using LLWU module.         DCDC PowerSwitch - available in buck mode only. Mode 5: MCU/Radio low power modes:        MCU in VLLS2 (4k Ram retention (0x20000000- 0x20000fff)).        BLE_LL in idle.       Wakeup sources:         GPIO (push button) interrupt using LLWU module.         DCDC PowerSwitch - available in buck mode only.   Mode 6: MCU/Radio low power modes:         MCU in STOP.       Wakeup sources:         GPIO (push button) interrupt using LLWU module.         DCDC PowerSwitch - available in buck mode only.         LPTMR wakeup timeout: cPWR_DeepSleepDurationMs by default. Use PWR_SetDeepSleepTimeInMs to change it at run time. Maximum timeout is 65535000 ms (18.2 h).          - LPTMR clock source:   32Khz oscillator           - LPTMR resolution:     modified at run time to meet timeout value.           - LPTMR resolution:     modified at run time to meet timeout value.         Radio interrupt LL or 802.15.4         UART Configuring Wakeup Source The PowerLib software includes preconfigured wakeup methods for low power. These methods are described below and a couple of examples are included. From Reset: Comming from Reset From PSwitch_UART: Wakeup by UART interrupt From KeyBoard: Wakeup by TSI/Push button interrupt From LPTMR: Wakeup by LPTMR timer interrupt From Radio:  Wakeup by RTC timer interrupt From BLE_LLTimer:  Wakeup by BLE_LL Timer DeepSleepTimeout:  DeepSleep timer overflow. SleepTimeout: Sleep timer overflow. Configure Module Wakeup using LPTMR This example explains how to configure the third deep sleep mode using the LPTMR as wakeup source. The desired low power mode must be configured in the file app_preinclude.h. /* Default Deep Sleep Mode*/ #define cPWR_DeepSleepMode            3 On the same file, the macro cPWR_DeepSleepDurationMs macro must be added. It defines the time the MCU will be in low power mode before being waken by the low power timer. By default it it set to 10 seconds (10000 milliseconds). #define cPWR_DeepSleepDurationMs     10000 This defines the time that the device will remain asleep by default. The PWR_SetDeepSleepTimeInMs function can be used to change this period at run time. Consider that the maximum time period is 65535000 ms (18.2 hours). PWR_SetDeepSleepTimeInMs(10000); Also the deep sleep mode can be changed at run time with the following function. PWR_ChangeDeepSleepMode(3); For further power reduction, all the modules not in use must be turned off . To run in this mode, all the timers except the LPTMR must be turned off. The device enters in low power mode with the following code lines in the main application. PWR_SetDeepSleepTimeInMs(cPWR_DeepSleepDurationMs); PWR_ChangeDeepSleepMode(3); PWR_AllowDeviceToSleep(); Configure GPIO (Push Button) wakeup. In the “PWRLib.c” file, find the “PWRLib_Init” function. It contains the code to initialize the LLWU pins to be used for wakeup. Chip configuration Reference Manual chapter contains information on which LLWU pins are tied to GPIOs on the MCU. For this example LLWU pins 6 and 7 (which are tied to PTA18 and PTA19 in the MCU) are used.   LLWU_PE1 = 0x00;   LLWU_PE2 = LLWU_PE2_WUPE7(0x03) | LLWU_PE2_WUPE6(0x03);   LLWU_PE3 = 0x00;   LLWU_PE4 = 0x00; Since the LLWU pin sources work as GPIO interrupts, the propper ports in the MCU must be configured. Following code shows howthese pins are configured in the MCU.   /* PORTA_PCR18: ISF=0,MUX=1 */   PORTA_PCR18 = (uint32_t)((PORTA_PCR18 & (uint32_t)~(uint32_t)(                                                                 PORT_PCR_ISF_MASK |                                                                   PORT_PCR_MUX(0x06)                                                                     )) | (uint32_t)(                                                                                     PORT_PCR_MUX(0x01)                                                                                       ));   PORTA_PCR19 = (uint32_t)((PORTA_PCR19 & (uint32_t)~(uint32_t)(                                                                 PORT_PCR_ISF_MASK |                                                                   PORT_PCR_MUX(0x06)                                                                     )) | (uint32_t)(                                                                                     PORT_PCR_MUX(0x01)                                                                                       )); Once the pins have been defined, it is neccesary to configure them as Keyboard inputs for the Power Lib. Go to "PWRLib.h" and find the next define: #define  gPWRLib_LLWU_KeyboardFlagMask_c (gPWRLib_LLWU_WakeupPin_PTA18_c | gPWRLib_LLWU_WakeupPin_PTA19_c ) In this define you must place the pins that were configured previously as wakeup sources. Using Low Power in the Project When you define "cPWR_UsePowerDownMode"  in app_preinclude.h, it automatically creates a task in "ApplMain.c" called "App_Idle_Task". When executed by the OS scheduler, this task verifies if the device can go to sleep. This statement is always false unless the next function is called. PWR_AllowDeviceToSleep(); This function indicates the program that the device can enter in low power and will execute the neccesary code to enter in the power mode configured at that time. Note: Before you allow the device to sleep, disable all uneccessary modules and turn off all leds. When the device is ready to enter in low power (all the application layers allows it and the device is in an iddle state) function PWR_EnterLowPower() must be called. This function will enter the MCU into the selected low power mode. On the HID example this is done into the iddle task as shown below. #if (cPWR_UsePowerDownMode) static void App_Idle(void) {     PWRLib_WakeupReason_t wakeupReason;         if( PWR_CheckIfDeviceCanGoToSleep() )     {         /* Enter Low Power */         wakeupReason = PWR_EnterLowPower(); #if gFSCI_IncludeLpmCommands_c         /* Send Wake Up indication to FSCI */         FSCI_SendWakeUpIndication(); #endif #if gKeyBoardSupported_d              /* Woke up on Keyboard Press */         if(wakeupReason.Bits.FromKeyBoard)         {             KBD_SwitchPressedOnWakeUp();             PWR_DisallowDeviceToSleep();         } #endif                  if(wakeupReason.Bits.DeepSleepTimeout)         {           Led1On();           for(;;)           {}         }     } } #endif /* cPWR_UsePowerDownMode */ PWR_CheckIfDeviceCanGoToSleep() function checks that all the application layers are agree on entering in low power mode (checking that PWR_DisallowDeviceToSleep() function hasn't been called). If everything is ok, function PWR_EnterLowPower() enters the device in low power and waits for a wakeup event.
記事全体を表示
As know, FSK and OOK are the modulation types that can be configured in the radio by setting the bits 4-3 from the RegDataModul register, as shown in below picture taken from Reference Manual:                                                          A common inquire you could have is: what modulation should I use? Let's first understand how these modulations work. FSK: Frequency Shift Keying is a modulation type that uses two frequencies, for 0 and 1. In a spectrum analyzer we can see a spectrum similar to the next picture, where the frequency for 0's is separated from the central frequency with FDev, and same case for the frequency for the 1's: OOK: On Off Keying is a modulation type that represents a logic 1 with the presence of the carrier frequency and a logic 0 with the absence of it. In a spectrum analyzer we can see a spectrum similar to the next picture, where the central frequency represents a logic 1. We can not see a logic 0 in the spectrum due to it's represented as the absence of power. Then what modulation should I use? FSK is most commonly used because is more spectral efficient so has better sensitivity. In the other hand, OOK modulation is commonly used in applications where the frequency accuracy can not be guaranteed. It also helps in conserving battery power due to the power absence for the logic 0's. Regards, Luis Burgos.
記事全体を表示
This document describes the implementation of the Connected Home Gateway for the Internet of Things (IoT) and its controller implemented in a Smart device (tablet) running Android OS. The gateway is intended to serve as a communication bridge between WiFi/Ethernet and ZigBee Protocol, making every ZigBee-enabled device accessible and controllable from any smart device with Wi-Fi capabilities such as a smart phone or tablet. This will remove the need of having a ZigBee transceiver in every mobile device attempting to control the house appliances. In general, users will be able to: Remote control of Home Appliances using ZigBee protocol Any WiFi-enabled device could control the appliances without a ZigBee transceiver Achieve bi-directional communication between users and appliances Real system implementation would require a powerful MCU to manage all WiFi/Ethernet communication and a second MCU to manage all ZigBee communications. The Kinetis K60 and KW24 were selected among the different options available.
記事全体を表示
This video shows how to load the Open SDA software from PE micro to the TWR-KW2x in order to debug applications using USB port and without needing external JTAG debuggers. Required downloads: TWR-KW2x Board Support Package:Kinetis KW2x Tower System Modules|Freescale PE Micro - Open SDA: P&E Microcomputer Systems
記事全体を表示
This document and the attached files are maintained up to date in collaboration with Dragos Musoiu. This document is a supplement for USB MSC device bootloader revision for FRDM-KL25Z (IAR) written by Kai Liu and describes the bootloader support for USB-KW24D512. How to use 1) Connect the USB-KW24D512 to the PC USB port; 2) Download the attached file ‘USB_KW24D512_MSD_Bootloader.bin’ to the flash memory of the MKW24D512 SiP following the next steps: Connect a J-Link programmer to the PC USB port (other than the one used for the USB-KW24D512 dongle); Navigate to your J-Link driver folder using a command console and type ‘jlink.exe’ followed by enter; After the apparition of the J-Link prompter, type ‘unlock kinetis’ followed by enter; Wait for the unlock command confirmation and after, type ‘device mkw24d512xxx5’ followed by enter; After the J-Link prompter appears type ‘loadbin USB_KW24D512_MSD_Bootloader.bin 0’ followed by enter; (Be sure you copied the ‘USB_KW24D512_MSD_Bootloader.bin’ file in the same directory with jlink.exe otherwise, type the command specifying the full path of the binary file); After the flashing process successfully finished type ‘exit’ followed by enter. 3) Reset or reconnect the USB-KW24D512; 4) The OS will prompt MSD device connecting and then BOOTLOADER drive will appear. The bootloader software was tested on Microsoft Windows 10, Microsoft Windows 8.1, Microsoft Windows 7, Ubuntu 14.04 and MAC operating systems. 5) Copy and paste any user application .SREC or .bin file into BOOTLOADER drive; 6) If a valid .SREC or .bin file was given, the board restarts and starts to run the user application. Please refer to the Notes section in order to create valid .SREC or .bin files. Note:            The bootloader has conditional jump to user application. The condition is the state of the SW1 button (PTC4). If the button is pressed (PTC4 grounded) during reset, the bootloader sequence will start, installing BOOTLOADER drive, as described before. Else if the button is released during reset, the SP and PC will be updated from address 0xC000. This means, the user application has to use a linker file which forces the application start address to 0xC000. If a valid SP and PC value is found at address 0xC000, the user application is launched. The bootloader application is located in the flash memory of the MKW24D512 SiP, from address 0x0000 to 0xBFFF, so the user application should not put any code in this memory region. Avoid using .SREC or .bin files having program bytes or fill patterns in the bootloader section. Attached files: USB_KW24D512_MSD_Bootloader.bin – bootloader binary file for USB-KW24D512; Pflash_512KB_0xC000.icf – IAR linker file for user application development; 802.15.4SnifferOnUSB.bin – user application demo binary file for KW24D512-USB. Be aware that the file ‘802.15.4SnifferOnUSB.srec’ is linked according to the above memory restrictions and is working only with the bootloader presented in this document.
記事全体を表示
This document describes how to add additional cluster to the Router application in the JN-AN-1217 ZigBee 3.0 Base Device Application Note. The Router application's main endpoint contains Basic, Groups, Identify and OnOff server. The steps below describe how to add two clusters to Router: Temperature Measurement server and OnOff client. Note that these changes only go as far as making the new clusters added and discoverable, no functionality has been added to these clusters.  Common/Source/app.zpscfg The first step is to update the ZigBee PRO Stack Configuration file to add the new clusters (OnOff Client, Temperature Measurement Server) to the Router application endpoint. The HA profile already contains few clusters but Temperature Measurement cluster was added:   The OnOff client was already present in Router endpoint but the Temperature Measurement cluster was then added into Router application endpoint:   Router/Build/Makefile For cluster belonging to General domain, the cluster code is automatically build and linked but for other domains, the compiling and linking needs to be enabled. As Temperature Measurement belongs to Measurement and Sensing domain, enable the cluster code in Makefile: Router/Source/zcl_options.h This file is used to set the options used by the ZCL. Enable Clusters The cluster functionality for the router endpoint was enabled:   Enable any optional Attributes and Commands for the clusters  Add the cluster creation and initialization into ZigBee Base device definitions The cluster functionality for some of the clusters is already present on ZigBee Base Device. For Temperature Measurement cluster the functionality was added into ZigBee Base Device. <Path to JN-SW-4x70 SDK>/ Components/ZCL/Devices/ZHA/Generic/Include/base_device.h The first step was including the Temperature Measurement header files into base device header file as shown below:   The second step was adding cluster instance into base device Instance as shown below: The next step was to define the cluster into the base device structure as below: <Path to JN-SW-4x70 SDK>/ Components/ZCL/Devices/ZHA/Generic/Include/base_device.c The cluster create function for Temperature Measurement cluster for server was called in ZigBee base device registration function:   Router/Source/app_zcl_task.c Temperature Measurement Server Cluster Data Initialization - APP_vZCL_DeviceSpecific_Init() The default attribute values for the Temperature Measurement clusters are initialized:
記事全体を表示