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

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

Wireless Connectivity Knowledge Base

ディスカッション

ソート順:
Hello community, This time I bring to you a document which explains what are the ZigBee Test Client commands and how to use it. Before to read this guide, I widely recommend to take a look into the document Running a demo with BeeKit (802.15.4 MAC, SMAC and ZigBee BeeStack). This guide requires the BeeKit Wireless Connectivity Toolkit​ and the Test Tool for Connectivity Products applications.     I hope you find this guide useful. Enjoy this guide! Any feedback is welcome. Best regards, Earl Orlando Ramírez-Sánchez Technical Support Engineer NXP Semiconductors
記事全体を表示
What you need: USB-KW40Z boards (at least 3 recommended) Kinetis KW40Z Connectivity Software Kinetis Protocol Analyzer Adapter Wireshark Consult the USB-KW40Z getting started guide for an in depth tutorial on how to program the boards with the sniffer software and how to install and use the Kinetis Protocol Analyzer Adapter and Wireshark. For best performance at least 3 boards are needed to continuously monitor all 3 BLE advertising channels: 37, 38 and 39. If you have more then it’s even better. Having less than 3 sniffer boards will lead to the BLE sniffer setup missing some advertising packets and connection events. If only 1 or 2 boards are present they will have to jump between the 3 advertising channels. After the initial setup is complete make sure the boards are plugged into USB ports and then start the Kinetis Protocol Analyzer Adapter software. Immediately after the application is started it will start looking for the sniffers: After the sniffers are detected the application window should look like the screenshot below. There should be a separate row shown for each sniffer board which is plugged in (3 in the example below – COM32, COM34, and COM33). Set each sniffer on a different advertising channel and (37, 38 and 39) and if you’re looking to sniff a specific device enable the Address Filter checkbox and enter the device’s address in the adjacent field as shown in the screenshot below. Use the same device address for all sniffer devices. Press the “shark fin” button in the upper right of the window to start Wireshark. After Wireshark starts select the PCAP IF shown in the Kinetis Protocol Analyzer Adapter window and start capturing packets. Local Area Connection 2 is the PCAP IF in the example. Wireshark will start showing the captured packets and the sniffers will catch Connection Request packets sent to the target device on any of the advertising channels. Useful tip: You can use the btle.advertising_header.length != 0 or btle.data_header.length != 0 filter in Wireshark to filter out empty BLE packets.
記事全体を表示
MyWirelessAPP Demo Beacon(End device) code for RTS development
記事全体を表示
Hello everyone, Over The Air Programming (OTAP) NXP's custom Bluetooth LE service provides the developer a solution to upgrade the software that the MCU contains. It removes the need for cables and a physical link between the OTAP client (the device that is reprogrammed) and the OTAP server (the device that contains the software update). This post explains how to run the OTAP Client Software that comes within the FRDM-KW36 package: Reprogramming a KW36 device using the OTAP Client Software. As it is mentioned in the last post, the OTAP Client can reprogram the KW36 while it is running, with new software using Bluetooth LE. However, this implementation for most of the applications is not enough since once you have reprogrammed the new image, the KW36 can not be reprogramed a second time using this method. For these applications that require to be updated many times using Bluetooth LE during run-time, we have created the following application note, that comes with a functional example of how to implement the OTAP Client software, taking advantage of this service. You can download the software clicking on the link in blue and the documentation is in the link in green. Please visit the following link: DOCUMENTS and Application Notes for KW36 In the "DOCUMENTS" section, you can found more information of the KW36. In the "Application Note" section, you can found more software and documentation of interesting topics like this.        Best Regards.
記事全体を表示
Introduction This document describes the hardware considerations for the schematic and layout of the MKW36A512VFT4 device. This MCU is packaged into a 48-pin HVQFN - 7x7 mm, dissimilar to MKW36Z512VHT4 which comes packaged into a 48-pin LQFN - 7x7 mm (the last one takes part of FRDM-KW36).   Pin Layout  The MKW36A512VFT4 MCU is pin to pin compatible with the MKW36Z512VHT4 (FRDM-KW36) MCU, except for the DCDC pins. The following figure shows the distribution of the pins in the MKW36A512VFT4 MCU (left), compared with the MKW36Z512VHT4 (FRDM-KW36 MCU, right). Surely, this is the most important consideration for MKW36A512VFT4, since you can not simply move the FRDM-KW36 layout on your design. Minimum BOM The following figures show the minimum BOM necessary for each DCDC mode in KW36. For more information about DCDC modes and hardware guidelines, please visit: MKW4xZ/3xZ/3xA/2xZ DC-DC Power Management Bypass Mode   Buck Auto-Start Mode   Buck Manual-Start Mode     Layout Recommendations The footprint and layout are critical for RF performance, hence if the recommended design is followed exactly in the RF region of the PCB, sensitivity, output power, harmonic and spurious radiation, and range, you will succeed. For more information of layout recommendations, please visit Hardware Design Considerations for MKW35A/36A/35Z/36Z Bluetooth Low Energy Devices. The footprint recommended for the MKW36A512VFT4 is shown in the figure below. NXP prefers to use a top layer thickness of no less than 8-10 mils. The use of a correct substrate like the FR4 with a dielectric constant of 4.3 will assist you in achieving a good RF design. Other recommendations during EMC certification stages are: - Specific attention must be taken on 4 pins PTC1, 2, 3 & 4 if they are used on the application. - 4 decoupling capacitors of 3pF are mandatory on those pins and be positioned as close as possible. - Wires from those 4 pins must be underlayer. - NXP recommends putting the vias under the package in case the customer HW design rules allow it. Some recommendations for a good Vdd_RF supply layout are: - Vdd_RF1 and Vdd_RF2 lines must have the same length as possible, linked to pointA (‘Y’ connection). - 12pF decoupling capacitor from Vdd_RF wire must be connected to the Ground Antenna. The purpose is to get the path as short as possible from Vdd_RF1/Vdd_RF2 to the ground antenna. - 12pF decoupling capacitor from the Vdd_RF3 pin must be as close as possible. Return to ground must be as short as possible. So vias (2 in this below picture) must be placed near to the decoupling capacitor to get close connection to the ground layer. The recommended RF stage is shown in the following figure. The MKW36A512VFT4 has a single-ended RF output with a 2 components matching network composed of a shunt capacitor and a series inductor. Both elements transform the device impedance to 50 ohms. The value of these components may vary depending on your board layout. Avoid routing traces near or parallel to RF transmission lines or crystal signals. Maintain a continuous ground under an RF trace is critical to keep unaltered the characteristic impedance of the transmission line. Avoid routing on the ground layer that will result in disrupting the ground under RF traces. For more information about RF considerations please visit: Freescale IEEE 802.15.4 / ZigBee Package and Hardware Layout Considerations.
記事全体を表示
This document describes how to sniff ZigBee packets to identify messages and layers from the ZigBee stack using the MC1322x USB dongle and Wireshark protocol analyzer. --------------------------------------------------------------------------------------------------------- Pre-Requisites If not done yet, download & Install Wireshark protocol analyzer http://www.wireshark.org/download.html Download the Wireshark ZigBee Utility Zip file from Sourceforge http://sourceforge.net/projects/wiresharkzigbee/ Unzip the file in a known location -------------------------------------------------------------------------------------------------------- 1. Install MC1322x dongle Plug-in MC1322xUSB dongle and wait for Windows to install the driver. If the driver was not found, steer Windows manually to the directory         C:\Program Files\Freescale\Drivers If BeeKit is not installed, be aware of the following: The 1322x USB Dongle uses the FTDI serial to USB converter, Virtual COM Port (VCP) driver for Windows, available at www.ftdichip.com/ftdrivers.htm. The FTDI web site offers drivers for other platforms including Windows® (98 through Vista x64 and CE), MAC OS (8 through X) and Linux. Download the appropriate driver and follow the instructions to complete driver installation. 2. Check COM port Once installed, the MC1322xUSB dongle should be listed in the available COM ports in Widows device manager. Verify the board’s drivers were successfully installed and take note of the COM port assigned      3. Run the ZigBee Utility Open a command console and navigate to the directory where Wireshark Zigbee utility files were unzipped. c:\<path> Then start the .exe utility and set the serial port and ZigBee channel to monitor, for instance:     4. Setting Wireshark Start Wireshark and open Capture>Options Dialog Click on “Manage Interfaces” and add a new pipe with ‘\\.\pipe\wireshark’. Save it and start capture. 5. Start sniffing
記事全体を表示
In this document we will be seeing how to create a BLE demo application for an adopted BLE profile based on another demo application with a different profile. In this demo, the Pulse Oximeter Profile will be implemented.  The PLX (Pulse Oximeter) Profile was adopted by the Bluetooth SIG on 14th of July 2015. You can download the adopted profile and services specifications on https://www.bluetooth.org/en-us/specification/adopted-specifications. The files that will be modified in this post are, app.c,  app_config.c, app_preinclude.h, gatt_db.h, pulse_oximeter_service.c and pulse_oximeter_interface.h. A profile can have many services, the specification for the PLX profile defines which services need to be instantiated. The following table shows the Sensor Service Requirements. Service Sensor Pulse Oximeter Service Mandatory Device Information Service Mandatory Current Time Service Optional Bond Management Service Optional Battery Service Optional Table 1. Sensor Service Requirements For this demo we will instantiate the PLX service, the Device Information Service and the Battery Service. Each service has a source file and an interface file, the device information and battery services are already implemented, so we will only need to create the pulse_oximeter_interface.h file and the pulse_oximeter_service.c file. The PLX Service also has some requirements, these can be seen in the PLX service specification. The characteristic requirements for this service are shown in the table below. Characteristic Name Requirement Mandatory Properties Security Permissions PLX Spot-check Measurement C1 Indicate None PLX Continuous Measurement C1 Notify None PLX Features Mandatory Read None Record Access Control Point C2 Indicate, Write None Table 2. Pulse Oximeter Service Characteristics C1: Mandatory to support at least one of these characteristics. C2: Mandatory if measurement storage is supported for Spot-check measurements. For this demo, all the characteristics will be supported. Create a folder for the pulse oximeter service in  \ConnSw\bluetooth\profiles named pulse_oximeter and create the pulse_oximeter_service.c file. Next, go to the interface folder in \ConnSw\bluetooth\profiles and create the pulse_oximeter_interface.h file. At this point these files will be blank, but as we advance in the document we will be adding the service implementation and the interface macros and declarations. Clonate a BLE project with the cloner tool. For this demo the heart rate sensor project was clonated. You can choose an RTOS between bare metal or FreeRTOS. You will need to change some workspace configuration.  In the bluetooth->profiles->interface group, remove the interface file for the heart rate service and add the interface file that we just created. Rename the group named heart_rate in the bluetooth->profiles group to pulse_oximeter and remove the heart rate service source file and add the pulse_oximeter_service.c source file. These changes will be saved on the actual workspace, so if you change your RTOS you need to reconfigure your workspace. To change the device name that will be advertised you have to change the advertising structure located in app_config.h. /* Scanning and Advertising Data */ static const uint8_t adData0[1] = { (gapAdTypeFlags_t)(gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c) }; static const uint8_t adData1[2] = { UuidArray(gBleSig_PulseOximeterService_d)}; static const gapAdStructure_t advScanStruct[] = { { .length = NumberOfElements(adData0) + 1, .adType = gAdFlags_c, .aData = (void *)adData0 }, { .length = NumberOfElements(adData1) + 1, .adType = gAdIncomplete16bitServiceList_c, .aData = (void *)adData1 }, { .adType = gAdShortenedLocalName_c, .length = 8, .aData = "FSL_PLX" } }; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ We also need to change the address of the device so we do not have conflicts with another device with the same address. The definition for the address is located in app_preinclude.h and is called BD_ADDR. In the demo it was changed to: #define BD_ADDR 0xBE,0x00,0x00,0x9F,0x04,0x00 ‍‍‍ Add the definitions in ble_sig_defines.h located in Bluetooth->host->interface for the UUID’s of the PLX service and its characteristics. /*! Pulse Oximeter Service UUID */ #define gBleSig_PulseOximeterService_d 0x1822 /*! PLX Spot-Check Measurement Characteristic UUID */ #define gBleSig_PLXSpotCheckMeasurement_d 0x2A5E /*! PLX Continuous Measurement Characteristic UUID */ #define gBleSig_PLXContinuousMeasurement_d 0x2A5F /*! PLX Features Characteristic UUID */ #define gBleSig_PLXFeatures_d 0x2A60 ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ We need to create the GATT database for the pulse oximeter service. The requirements for the service can be found in the PLX Service specification. The database is created at compile time and is defined in the gatt_db.h.  Each characteristic can have certain properties such as read, write, notify, indicate, etc. We will modify the existing database according to our needs. The database for the pulse oximeter service should look something like this. PRIMARY_SERVICE(service_pulse_oximeter, gBleSig_PulseOximeterService_d) CHARACTERISTIC(char_plx_spotcheck_measurement, gBleSig_PLXSpotCheckMeasurement_d, (gGattCharPropIndicate_c)) VALUE_VARLEN(value_PLX_spotcheck_measurement, gBleSig_PLXSpotCheckMeasurement_d, (gPermissionNone_c), 19, 3, 0x00, 0x00, 0x00) CCCD(cccd_PLX_spotcheck_measurement) CHARACTERISTIC(char_plx_continuous_measurement, gBleSig_PLXContinuousMeasurement_d, (gGattCharPropNotify_c)) VALUE_VARLEN(value_PLX_continuous_measurement, gBleSig_PLXContinuousMeasurement_d, (gPermissionNone_c), 20, 3, 0x00, 0x00, 0x00) CCCD(cccd_PLX_continuous_measurement) CHARACTERISTIC(char_plx_features, gBleSig_PLXFeatures_d, (gGattCharPropRead_c)) VALUE_VARLEN(value_plx_features, gBleSig_PLXFeatures_d, (gPermissionFlagReadable_c), 7, 2, 0x00, 0x00) CHARACTERISTIC(char_RACP, gBleSig_RaCtrlPoint_d, (gGattCharPropIndicate_c | gGattCharPropWrite_c)) VALUE_VARLEN(value_RACP, gBleSig_RaCtrlPoint_d, (gPermissionFlagWritable_c), 4, 3, 0x00, 0x00, 0x00) CCCD(cccd_RACP) ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ For more information on how to create a GATT database you can check the BLE Application Developer’s Guide chapter 7. Now we need to make the interface file that contains all the macros and declarations of the structures needed by the PLX service. Enumerated types need to be created for each of the flags field or status field of every characteristic of the service. For example, the PLX Spot-check measurement field has a flags field, so we declare an enumerated type that will help us keep the program organized and well structured. The enum should look something like this: /*! Pulse Oximeter Service - PLX Spotcheck Measurement Flags */ typedef enum { gPlx_TimestampPresent_c = BIT0, /* C1 */ gPlx_SpotcheckMeasurementStatusPresent_c = BIT1, /* C2 */ gPlx_SpotcheckDeviceAndSensorStatusPresent_c = BIT2, /* C3 */ gPlx_SpotcheckPulseAmplitudeIndexPresent_c = BIT3, /* C4 */ gPlx_DeviceClockNotSet_c = BIT4 } plxSpotcheckMeasurementFlags_tag; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The characteristics that will be indicated or notified need to have a structure type that contains all the fields that need to be transmitted to the client. Some characteristics will not always notify or indicate the same fields, this varies depending on the flags field and the requirements for each field. In order to notify a characteristic we need to check the flags in the measurement structure to know which fields need to be transmitted. The structure for the PLX Spot-check measurement should look something like this: /*! Pulse Oximeter Service - Spotcheck Measurement */ typedef struct plxSpotcheckMeasurement_tag { ctsDateTime_t timestamp; /* C1 */ plxSpO2PR_t SpO2PRSpotcheck; /* M */ uint32_t deviceAndSensorStatus; /* C3 */ uint16_t measurementStatus; /* C2 */ ieee11073_16BitFloat_t pulseAmplitudeIndex; /* C4 */ uint8_t flags; /* M */ }plxSpotcheckMeasurement_t; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The service has a configuration structure that contains the service handle, the initial features of the PLX Features characteristic and a pointer to an allocated space in memory to store spot-check measurements. The interface will also declare some functions such as Start, Stop, Subscribe, Unsubscribe, Record Measurements and the control point handler. /*! Pulse Oximeter Service - Configuration */ typedef struct plxConfig_tag { uint16_t serviceHandle; plxFeatures_t plxFeatureFlags; plxUserData_t *pUserData; bool_t procInProgress; } plxConfig_t; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The service source file implements the service specific functionality. For example, in the PLX service, there are functions to record the different types of measurements, store a spot-check measurement in the database, execute a procedure for the RACP characteristic, validate a RACP procedure, etc. It implements the functions declared in the interface and some static functions that are needed to perform service specific tasks. To initialize the service you use the start function. This function initializes some characteristic values. In the PLX profile, the Features characteristic is initialized and a timer is allocated to indicate the spot-check measurements periodically when the Report Stored Records procedure is written to the RACP characteristic. The subscribe and unsubscribe functions are used to update the device identification when a device is connected to the server or disconnected. bleResult_t Plx_Start (plxConfig_t *pServiceConfig) { mReportTimerId = TMR_AllocateTimer(); return Plx_SetPLXFeatures(pServiceConfig->serviceHandle, pServiceConfig->plxFeatureFlags); } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ All of the services implementations follow a similar template, each service can have certain characteristics that need to implement its own custom functions. In the case of the PLX service, the Record Access Control Point characteristic will need many functions to provide the full functionality of this characteristic. It needs a control point handler, a function for each of the possible procedures, a function to validate the procedures, etc. When the application makes a measurement it must fill the corresponding structure and call a function that will write the attribute in the database with the correct fields and then send an indication or notification. This function is called RecordMeasurement and is similar between the majority of the services. It receives the measurement structure and depending on the flags of the measurement, it writes the attribute in the GATT database in the correct format. One way to update a characteristic is to create an array of the maximum length of the characteristic and check which fields need to be added and keep an index to know how many bytes will be written to the characteristic by using the function GattDb_WriteAttribute(handle, index, &charValue[0]). The following function shows an example of how a characteristic can be updated. In the demo the function contains more fields, but the logic is the same. static bleResult_t Plx_UpdatePLXContinuousMeasurementCharacteristic ( uint16_t handle, plxContinuousMeasurement_t *pMeasurement ) { uint8_t charValue[20]; uint8_t index = 0; /* Add flags */ charValue[0] = pMeasurement->flags; index++; /* Add SpO2PR-Normal */ FLib_MemCpy(&charValue[index], &pMeasurement->SpO2PRNormal, sizeof(plxSpO2PR_t)); index += sizeof(plxSpO2PR_t); /* Add SpO2PR-Fast */ if (pMeasurement->flags & gPlx_SpO2PRFastPresent_c) { FLib_MemCpy(&charValue[index], &pMeasurement->SpO2PRFast, sizeof(plxSpO2PR_t)); index += sizeof(plxSpO2PR_t); } return GattDb_WriteAttribute(handle, index, &charValue[0]); } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ The app.c handles the application specific functionality. In the PLX demo it handles the timer callback to make a PLX continuous measurement every second. It handles the key presses and makes a spot-check measurement each time the SW3 pushbutton is pressed. The GATT server callback receives an event when an attribute is written, and in our application the RACP characteristic is the only one that can be written by the client. When this event occurs, we call the Control Point Handler function. This function makes sure the indications are properly configured and check if another procedure is in progress. Then it calls the Send Procedure Response function, this function validates the procedure and calls the Execute Procedure function. This function will call one of the 4 possible procedures. It can call Report Stored Records, Report Number of Stored Records, Abort Operation or Delete Stored Records. When the project is running, the 4 LEDs will blink indicating an idle state. To start advertising, press the SW4 button and the LED1 will start flashing. When the device has connected to a client the LED1 will stop flashing and turn on. To disconnect the device, hold the SW4 button for some seconds. The device will return to an advertising state. In this demo, the spot-check measurement is made when the SW3 is pressed, and the continuous measurement is made every second. The spot-check measurement can be stored by the application if the Measurement Storage for spot-check measurements is supported (bit 2 of Supported Features Field in the PLX Features characteristic). The RACP characteristic lets the client control the database of the spot-check measurements, you can request the existing records, delete them, request the number of stored records or abort a procedure. To test the demo you can download and install a BLE Scanner application to your smartphone that supports BLE. Whit this app you should be able to discover the services in the sensor and interact with each characteristic. Depending on the app that you installed, it will parse known characteristics, but because the PLX profile is relatively new, these characteristics will not be parsed and the values will be displayed in a raw format. In Figure 1, the USB-KW40Z was used with the sniffer application to analyze the data exchange between the PLX sensor and the client. You can see how the sensor sends the measurements, and how the client interacts with the RACP characteristic. Figure 1. Sniffer log from USB-KW40Z
記事全体を表示
Introduction In some applications, is it necessary to keep updated the software running in many MCU's that take part in the system, fortunately, Over The Air Programming, it's a custom Bluetooth LE service developed to send "over the air" software updates for the KW MCU series. FRDM-KW36 SDK already provides the "otap_client" software, that can be used together with the "otap_bootloader" such as it is described in the following community post: Reprogramming a KW36 device using the OTAP Client Software to reprogram the KW36. This example can be modified to store code for another MCU and later send the software update to this device as depicted in the figure below. This post guides you on modifying the OTAP client software to support software updates for other MCU's. Preparing the OTAP client software The starting point of the following modifications is supposing that there is no need to perform over the air updates for the KW36 MCU, so the use of the "otap_bootloader" is obsolete and will be removed in this example. In other words, KW36 will be programmed only with the "otap_client" code. Open the MCUXpresso settings window (Project->Properties->"C/C++ Build->MCU settings") and configure the following fields. Save the changes. For external storage: For internal storage: Locate the "app_preinclude.h" file, and set the storage method, as follows: For external storage: #define gEepromType_d       gEepromDevice_AT45DB041E_c For internal storage: #define gEepromType_d        gEepromDevice_InternalFlash_c Locate the "main_text_section.ldt" linker script into the "linkscripts" folder, and delete it from the project.  Search in the project for "OTA_SetNewImageFlag();" and "ResetMCU();" functions in the "otap_client.c" file (source->common->otap_client->otap_client.c) and delete or comment. (For reference, there are 4 in total). Locate the following code in "OtaSupport.h" (framework->OtaSupport->Interface) and delete or comment. extern uint16_t gBootFlagsSectorBitNo;‍‍‍‍‍‍ void OTA_SetNewImageFlag(void);‍‍‍‍‍‍‍ Locate the following code in "OtaSupport.c" (framework->OtaSupport->Source) and delete or comment. extern uint32_t __BootFlags_Start__[]; #define gBootImageFlagsAddress_c ((uint32_t)__BootFlags_Start__)‍‍‍‍‍‍‍‍‍‍‍‍ #if !gEnableOTAServer_d || (gEnableOTAServer_d && gUpgradeImageOnCurrentDevice_d) /*! Variables used by the Bootloader */ #if defined(__IAR_SYSTEMS_ICC__) #pragma location = "BootloaderFlags" const bootInfo_t gBootFlags = #elif defined(__GNUC__) const bootInfo_t gBootFlags __attribute__ ((section(".BootloaderFlags"))) = #elif defined(__CC_ARM) volatile const bootInfo_t gBootFlags __attribute__ ((section(".BootloaderFlags"))) = #else #error "Compiler unknown!" #endif { {gBootFlagUnprogrammed_c}, {gBootValueForTRUE_c}, {0x00, 0x02}, {gBootFlagUnprogrammed_c}, #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1) {PLACEHOLDER_SBKEK}, {BOOT_MAGIC_WORD} #endif }; #endif /* !gEnableOTAServer_d || (gEnableOTAServer_d && gUpgradeImageOnCurrentDevice_d) */‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ uint16_t gBootFlagsSectorBitNo; gBootFlagsSectorBitNo = gBootImageFlagsAddress_c/(uint32_t)((uint8_t*)FSL_FEATURE_FLASH_PFLASH_BLOCK_SECTOR_SIZE);‍‍‍‍ gBootFlagsSectorBitNo = gBootImageFlagsAddress_c/(uint32_t)((uint8_t*)FSL_FEATURE_FLASH_PAGE_SIZE_BYTES);‍‍‍‍ void OTA_SetNewImageFlag(void) { #if (gEepromType_d != gEepromDevice_None_c) && (!gEnableOTAServer_d || (gEnableOTAServer_d && gUpgradeImageOnCurrentDevice_d)) /* OTA image successfully written into the non-volatile storage. Set the boot flag to trigger the Bootloader at the next CPU Reset. */ union{ uint32_t value; uint8_t aValue[FSL_FEATURE_FLASH_PFLASH_BLOCK_WRITE_UNIT_SIZE]; }bootFlag; #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1) uint8_t defaultSBKEK[SBKEK_SIZE] = {DEFAULT_DEMO_SBKEK}; #endif uint32_t status; if( mNewImageReady ) { NV_Init(); bootFlag.value = gBootValueForTRUE_c; status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.newBootImageAvailable, sizeof(bootFlag), bootFlag.aValue); if( (status == kStatus_FLASH_Success) && FLib_MemCmpToVal(gBootFlags.internalStorageAddr, 0xFF, sizeof(gBootFlags.internalStorageAddr)) ) { bootFlag.value = gEepromParams_StartOffset_c + gBootData_ImageLength_Offset_c; status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.internalStorageAddr, sizeof(bootFlag), bootFlag.aValue); } #if defined(CPU_K32W032S1M2VPJ_cm4) && (CPU_K32W032S1M2VPJ_cm4 == 1) if( status == kStatus_FLASH_Success ) { /* Write the default SBKEK for secured OTA */ status = NV_FlashProgramUnaligned((uint32_t)&gBootFlags.sbkek, SBKEK_SIZE, defaultSBKEK); } #endif if( status == kStatus_FLASH_Success ) { mNewImageReady = FALSE; } } #endif }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   At this point, the FRDM-KW36 can receive and store any image for any MCU and can request a further software update from the OTAP server device.    Adding API's to reprogram the "MCU X" on OTAP client software Once the software update has been downloaded from the OTAP Server into the OTAP Client, the developer should request the software update from the OTAP Client to the "MCU X" through a serial protocol such as UART, SPI, CAN, etc. You should develop the API's and the protocol according to the requirements for your system to send the software update to the "MCU X" (as well as the bootloader for the MCU X). The handling your protocol can be integrated into the OTAP client code replacing "ResetMCU()" (The same code removed in step 4) in the code by "APISendSoftwareUpdateToMCUX()" for instance, since at this point the image was successfully sent over the air and stored in the memory of the KW36. 
記事全体を表示
The image below shows the different types of devices in a Thread Network. Router Routers provide routing services to network devices. Routers also provide joining and security services for devices trying to join the network. Routers are not designed to sleep. Routers can downgrade their functionality and become REEDs (Router-eligible End Devices). A Router can become a Leader and start a Thread network. Border Router A Border Router is a type of Router that provides connectivity from the 802.15.4 network to adjacent networks on other physical layers (for example, Wi-Fi and Ethernet). Border Routers provide services for devices within the 802.15.4 network, including routing services for off-network operations. There may be one or more Border Routers in a Thread Network. The Border Router also serves as an interface point for the Commissioner when the Commissioner is on a non-Thread Network; it requires a Thread interface and may be combined in any device with other Thread roles except the Joiner. Leader A Router or Border Router can assume a Leader role for certain functions in the Thread Network. This Leader is required to make decisions within the network. For example, the Leader assigns Router addresses and allows new Router requests. The Leader role is elected and if the Leader fails, another Router or Border Router assumes the Leader role. It is this autonomous operation that ensures there is no single point of failure. Router-eligible End Device REEDs have the capability to become Routers but due to the network topology or conditions these devices are not acting as Routers. These devices do not generally forward messages or provide joining or security services for other devices in the Thread Network. The Thread Network manages REEDs becoming Routers if necessary without user interaction. Sleepy End Device Sleepy end devices are host devices. They communicate only through their Parent Router and cannot forward messages for other devices References: Thread Whitepapers available at http://threadgroup.org 
記事全体を表示
The MCU in the KW40/30Z has various available very low power modes. In these power modes, the chip goes to sleep to save power, and it is not usable during this time (it can however receive different kinds of interruptions that could wake it up). The very low power modes supported by the microcontroller are: The KW40Z connectivity software stack has 6 predetermined deep sleep modes. These deep sleep modes have different configurations for the microcontroller low power mode, the BLE Link Layer state and in which ways the device can be awaken. These predetermined DSM (Deep Sleep Modes) are: * VLLS0 if DCDC is bypassed. VLLS1 with either Buck or Boost. ** Available in Buck mode only. Having said that, if you want the lowest possible consumption by the MCU, while also being able to wake up your application automatically with a timer (achieved with VLSS1), there is no DSM available. You can, however, create your own Deep Sleep Mode with low power timers enabled. Please note that VLSS1 has the lowest possible consumption when using a DCDC converter. When in bypass mode, the lowest possible consumption is achieved with VLSS0. To create your Deep Sleep Mode, you should start with the function that will actually handle the board going into deep sleep. This should be done in the PWR.c file, along with the rest of the DSM handler functions. This function is quite similar to the ones already made for the other deep sleep modes. Link layer interruptions, timer settings and the low power mode for the MCU are handled here. /* PWR.c */ #if (cPWR_UsePowerDownMode) static void PWR_HandleDeepSleepMode_7(void) {   #if cPWR_BLE_LL_Enable   uint16_t bleEnabledInt; #endif   uint8_t clkMode;   uint32_t lptmrTicks;   uint32_t lptmrFreq;     PWRLib_MCU_WakeupReason.AllBits = 0;   #if cPWR_BLE_LL_Enable    if(RSIM_BRD_CONTROL_BLE_RF_OSC_REQ_STAT(RSIM)== 0) // BLL in DSM   {     return;   bleEnabledInt = PWRLib_BLL_GetIntEn();   PWRLib_BLL_ClearInterrupts(bleEnabledInt);      PWRLib_BLL_DisableInterrupts(bleEnabledInt); #endif     if(gpfPWR_LowPowerEnterCb != NULL)   {     gpfPWR_LowPowerEnterCb();   }     /* Put the device in deep sleep mode */ #if cPWR_DCDC_InBypass    PWRLib_MCU_Enter_VLLS0(); #else   PWRLib_MCU_Enter_VLLS1(); #endif     if(gpfPWR_LowPowerExitCb != NULL)   {     gpfPWR_LowPowerExitCb();   }   #if cPWR_BLE_LL_Enable    PWRLib_BLL_EnableInterrupts(bleEnabledInt);        #endif      PWRLib_LPTMR_ClockStop();   } #endif /* #if (cPWR_UsePowerDownMode) */ ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Remember to add this function to the deep sleep handler function array: /* PWR.c */ const pfHandleDeepSleepFunc_t maHandleDeepSleep[]={PWR_HandleDeepSleepMode_1,                                                     PWR_HandleDeepSleepMode_2,                                                     PWR_HandleDeepSleepMode_3,                                                     PWR_HandleDeepSleepMode_4,                                                     PWR_HandleDeepSleepMode_5,                                                     PWR_HandleDeepSleepMode_6,                                                     PWR_HandleDeepSleepMode_7                                                    }; ‍‍‍‍‍‍‍‍‍‍ This function should allow your device to go to sleep. It does the strictly necessary things before the device goes to sleep: disables link layer interruptions, gets the configuration for the low power timer and it starts the timer. Please note that when the board is in either Buck or Boost DCDC mode, only VLSS1 is supported. When the device is in bypass mode, VLSS0 can be chosen. Now that the deep sleep handler is done, there are some changes that have to be made to have a proper execution. In the PWR_Configuration.h file, for example, there is an error message when the parameter cPWR_DeepSleepMode is larger than 6 (the default DSM modes), but, since you have added a new deep sleep mode, this number should be changed to 7: #if (cPWR_DeepSleepMode > 7 )  // default: 6   #error "*** ERROR: Illegal value in cPWR_DeepSleepMode" #endif ‍‍‍ Other changes that have to be made are the Low Leakage Wake Up unit and the deep sleep mode configurations. To change the LLWU configuration, you should add a case for the new deep sleep mode in the PWRLib_ConfigLLWU() function: /* PWRLib.c */ void PWRLib_ConfigLLWU( uint8_t lpMode ) {   switch(lpMode)   {   case 1:     LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_BTLL_c | gPWRLib_LLWU_WakeupModuleEnable_LPTMR_c;   break;   case 2:     LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_BTLL_c;   break;   case 3:     LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_LPTMR_c | gPWRLib_LLWU_WakeupModuleEnable_DCDC_c;   break;   case 4:   case 5:     LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_DCDC_c;    break;   case 6:     LLWU_ME = 0;   break;   case 7: /* The new deep sleep mode can be awaken through a Low Power Timer timeout */     LLWU_ME = gPWRLib_LLWU_WakeupModuleEnable_LPTMR_c;   break;   } }  } #endif /* #if (cPWR_UsePowerDownMode) */ ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Once this case has been added, you should change the function that calls PWRLib_ConfigLLWU(), PWRChangeDeepSleepMode(): /* PWR.c */ bool_t PWR_ChangeDeepSleepMode (uint8_t dsMode) { #if (cPWR_UsePowerDownMode)   if(dsMode > 7) //Since you’ve added an extra DSM, this is now 7 (default: 6)   {      return FALSE;   }    PWRLib_SetDeepSleepMode(dsMode); PWRLib_ConfigLLWU(dsMode); #if (cPWR_BLE_LL_Enable)    PWRLib_BLL_ConfigDSM(dsMode);   PWRLib_ConfigRSIM(dsMode); #endif    return TRUE;   #else   return TRUE; #endif  /* #if (cPWR_UsePowerDownMode) */ } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Now, since you’ll be using a Low Power Timer, you should modify the maLPModeUseLPTMR[] constant in the PWRLib.c file, indicating that you will use a low power timer: /* PWRLib.c */ const uint8_t maLPModeUseLPTMR[]={0,1,1,1,0,0,1,1}; //We add the last 1. default: {0,1,1,1,0,0,1} ‍‍‍ You should add a case for your new low power mode in the PWRLib_ConfigRSIM(). Here you will handle the BLE link layer whilst the device is in low power mode. This function can be found in the PWRLib.c file: /* PWRLib.c */ void PWRLib_ConfigRSIM( uint8_t lpMode ) {   switch(lpMode)   {   case 1:   case 2:       RSIM_BWR_CONTROL_STOP_ACK_OVRD_EN(RSIM, 0);       RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK;     break;   case 3:   case 4:   case 5:       RSIM_CONTROL &= ~(RSIM_CONTROL_STOP_ACK_OVRD_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK);       RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK;     break;   case 6:       RSIM_CONTROL &= ~(RSIM_CONTROL_STOP_ACK_OVRD_EN_MASK  | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK);       RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK;     break;   case 7: //@PNN       RSIM_CONTROL &= ~(RSIM_CONTROL_STOP_ACK_OVRD_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_EN_MASK | RSIM_CONTROL_BLE_RF_OSC_REQ_INT_EN_MASK);       RSIM_CONTROL |= RSIM_CONTROL_BLE_RF_OSC_REQ_INT_MASK;     break;   } } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Your low power mode awaken by a low power timer should now be ready. To change the deep sleep mode and the time the device will be in deep sleep mode before it is awaken, use these functions in your application: PWR_ChangeDeepSleepMode(7);                                     /* Change deep sleep mode */ PWR_SetDeepSleepTimeInMs(YOUR_DEEP_SLEEP_TIME_IN_MS);           /* Time the device will spend on deep sleep mode */ PWR_AllowDeviceToSleep();                                      /* Allows the device to go to deep sleep mode */ PWR_DisallowDeviceToSleep();                                   /* Does not allows the device to go to deep sleep mode */ ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
記事全体を表示
Introduction The FRDM-KW36 includes an RSIM (Radio System Integration Module) module with an external 32 MHz crystal oscillator. This clock source reference is mainly intended to supply the Bluetooth LE Radio peripheral, but it can be used as the main clock source of the MCU as well. This oscillator includes a set of programmable capacitors to support crystals with different load capacitance needs. Changing the value of these capacitors can modify the frequency the oscillator provides, that way, the central frequency can be tuned to meet the wireless protocol standards. This configurable capacitance range is from C1: 5.7pF - C2: 7.1pF to C1: 22.6pF - C2: 28.2pF and it is configured through the BB_XTAL_TRIM field at the ANA_TRIM. The KW36 comes preprogrammed with a default load capacitance value. However, since there is variance in devices due to tolerances and parasite effects, the correct load capacitance should be checked by verifying that the optimal central frequency is attained.  You will need a spectrum analyzer to measure the central frequency. To find the most accurate value for the load capacitance, it is recommended to use the Connectivity Test demo application. Adjusting Frequency Example Program the KW36 Connectivity Test software on the device. This example can be found in wireless_examples -> genfsk -> conn_test folder from your SDK package. Baremetal and FreeRTOS versions are available. In case that FRDM-KW36 board is being used to perform the test, you should move the 10pF capacitor populated in C55 to C57, to direct the RF signal on the SMA connector. Connect the board to a serial terminal software. When you start the application, you will be greeted by the NXP logo screen:  Press the enter key to start the test. Then press "1" to select "Continuous tests": Finally, select "6" to start a continuous unmodulated RF test. At this point, you should be able to measure the signal in the spectrum analyzer. You can change the RF channel from 0 to 127 ("q" Ch+ and "w" Ch- keys), which represents the bandwidth from 2.360GHz to 2.487GHz, stepping of 1MHz between two consecutive channels. To demonstrate the trimming procedure, this document will make use of channel 42 (2.402GHz) which corresponds to the Bluetooth LE channel 37. In this case, with the default capacitance value, our oscillator is not exactly placed at the center of the 2.402GHz, instead, it is slightly deflected to 2.40200155 GHz, as depicted in the following figure: The capacitance can be adjusted with the "d" XtalTrim+ and "f" XtalTrim- keys. Increasing the capacitance bank means a lower frequency. In our case, we need to increase the capacitance to decrease the frequency. The nearest frequency of 2.402 GHz was 2.40199940 GHz  Once the appropriate XTAL trim value has been found, it can be programmed as default in any Bluetooth LE example, changing the mXtalTrimDefault constant located in the board.c file: static const uint8_t mXtalTrimDefault‍ = 0x36;‍‍‍
記事全体を表示
This document provides the calculation of the Bluetooth Low Power consumption linked to the setting of the Kinetis.   The Power Profile Calculator is build to provide the power consumption of your application. It's a mix between real measurements in voltage and temperature. The process is not taken into account which may create some variation.   DISCLAIMER: This excel workbook is provided as an estimation tool for NXP customers and is based on power profile measurements done on a set of randomly selected parts. A specific part may exhibit deviation from the nominal measurements used on this tool.   This document is the summary of all the information available in the AN12180 Power Consumption Analysis - FRDM-KW36 available in the NXP web page.   Several parameters could be fill-in: Buck or bypass mode (DCDC) Supply Voltage (2.4V to 3.6V) Temperature (-40°C to +105°C) Processor configuration (20MHz, 32MHz or 48MHz) 2 different deep sleep modes (LLS3 or VLLS2) Different Tx output power (0dBm, +3.5dBm or +5dBm) Possibility to set the Advertising interval, connection interval, scan interval and active scan windows duration Fix the Bluetooth Packet sizes in Advertising and Connection  Tx/Rx payload.   One optional information is to provide an idea of the duration life time on typical batteries.
記事全体を表示
Regarding to the "Reprogramming a KW36 device using the OTAP Client Software" and "Reprogramming a KW35 device using the OTAP Client Software" documents, there are some additional steps to debug the OTAP client software in the specific case when you use MCUXpresso together with a P&E micro debug probe. Just before to program the OTAP client project (the second software), the user must do the following: Open the "Debug Configurations" view clicking on the green bug as depicted below. Go to the "Debugger" perspective and search the "Advanced Options" button. Enable the "Preserve this range (Memory Range 0)" checkbox, and edit the textbox "From: 0" To: 1fff" for the KW36 device or "From: 0 To: 3fff" for the KW35 device. After to flash the device, disconnect and connect again. If everything it's OK, the RGB LED must blink (If you are using an FRDM board). Then, test the demo as described in the document.
記事全体を表示
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
記事全体を表示
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.
記事全体を表示
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.
記事全体を表示
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.
記事全体を表示
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).
記事全体を表示