Wireless Connectivity Knowledge Base

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

Wireless Connectivity Knowledge Base

Discussions

Sort by:
Generality on the Oscillation Margin Outline It is a margin to the oscillation stop and the most important item in the oscillation circuit. This margin is indicated by ratio based on the resistance of crystal, and it shows how amplification oscillation capability the circuit has. The oscillation circuit can theoretically operate if the oscillation margin is 1 or more. However, if oscillation margin is close to 1, the risk of operation failure will increase on module due to a too long oscillation start up time and so on. Such problems will be able to be solved by a larger oscillation margin. It is recommended to keep 3 times or more as oscillation margin during the startup of the oscillation. Factor of 10 is commonly requested for Automotive at startup and 5 for IoT market. However, some providers accept to have 3 times as oscillation margin for steady state. Here below is an oscillation example to explain better the phenomenon: At start up, the configuration is set internally by the hardware in order to be sure to start the oscillation, the load capacitor is 0pF. After this time, it is the steady state and the load capacitor from the internal capabank is taken into account.     If load capacitor is not set correctly with the right oscillator gain, the oscillation will not be maintained after the start up.   The oscillator gain value will also depend on the resisting path on the crystal track.  A good way to evaluate it is to add a resistor on the crystal path and try to launch the oscillation. In the SDK, the gain and the load capacitor can set directly in the application code.   Calculation The oscillation margin is able to be calculated as follows: The oscillation margin calculation is based on the motional resistor Rm by formula below :               Example: for the EVK board’s 32kHz crystal (NX2012SE) ESR   80000,0 ohm Rm1   79978,2 ohm Lm1    3900 H Cm1   6,00E-15 F C0      1,70E-12 F CL      1,25E-08 F fr        32901,2 Hz fosc    32771 Hz Series Resistor Rsmax      7,50E+05 Ohm Oscillation Margin   10,3   Measurement Requirements for measurement PCB Crystal unit (with equivalent circuit constants data) Resistors (SMD) Measurement equipment (Oscilloscope, Frequency counter or others capable to observe oscillation) Add a resistor to the resonator in serial and check if the oscillation circuit works or not. If the oscillation is confirmed by 2), change the resistor to larger. If there is no oscillation, change the resistor to smaller. Find out the maximum resistor (=Rs_max) which is the resistor just before the oscillation stop. Measure the oscillating frequency with Rs_max. Calculate the oscillation margin based on the Rs_max.   Notes The Oscillation margin is affected not only by crystal characteristics but also parts that compose the oscillation circuit (MCU, capacitor and resistor). Therefore, it is recommended to check the oscillation margin after the MCU functionality is checked on your module. The series resistor is only for the evaluation. Please do not use this resistor in actual usage. It is recommended to check the functionality of your module also. It is possible that the module does not work correctly due to a frequency shift on oscillation circuit and so on. Jig and socket could be used in measurement, but stray of them will give influence for oscillation margin.   KW45/K32W1 product oscillation margin overview 32MHz crystal NXP recommends to use the quartz NDK NX1612SA (EXS00A-CS14160) or NDK NX2016SA (EXS00A-CS14161) to be compliant with the +/-50ppm required in Bluetooth LE. Using the current SDK, NXP guarantees an oscillation margin of 10 for startup commonly used by Automotive customers and 3 for steady state. Higher oscillation margin can be reached by using higher ISEL and CDAC parameters with some drawback respectively on the power consumption and the clock accuracy. ( the load capacitance bank (CDAC) and the oscillator amplifier current (ISEL)) NDK recommended / target values for oscillation margin is informed case by case. On general basis requested oscillation margin has to be between recommended value and 3 times this value. "NDK quartz provider (FR) explains this oscillation margin specification is only mandatory at the start-up phase, not at the steady state. Starting the oscillation is the phase that needs more energy. That's why the gain of the oscillator gain is at the maximum value which means not optimal consumption. When the oscillation stability is reached, the gain could be reduced to save power. The oscillation will not be affected.  Keep in mind a quartz oscillates by mechanical effect. So, when the oscillation is starting you need the highest energy to emulate it. By its own inertial, you need less energy to maintain the mechanical oscillation. NDK provides a good picture of this. Starting up a crystal into oscillation is like a train what you would like to start moving. At the beginning the train is stopped and you need a lot of energy to start running. When the train is running at its nominal speed, you need less effort to maintain that movement and a very big effort to stop it completely."   Example: for the oscillation margin 10 (Series Resistor Rsmax = 560W) The CDAC/ISEL area where the oscillation starts and propagates in the internal blocks is defined (‘oscill’) in the table below.     32kHz crystal NXP recommends to use the quartz NDK NX2012SE (EXS00A-MU01517) or NDK NX2012SA (EXS00A-MU00801) to be compliant with the +/-500ppm required in Bluetooth LE. using the current SDK, the oscillation margin with this quartz is 10 with some limitation on the Crystal load capacitance selection (Cap_Sel) and the Oscillator coarse gain amplifier (ESR_Range) values, with some drawback respectively on the power consumption and the clock accuracy. For an oscillation margin at 10 for instance, the Capacitor value from the databank (CapSel) is limited (green area) as shown in the graph below: Example:  for an oscillation margin at 6.4, if the load cap is set at 14pF and the ESR_Range to 3, the 32kHz frequency accuracy will be around 91ppm. From this point, the oscillation margin can be enlarged to 10.3 by decreasing the load cap to 10pF but the accuracy will be degraded (183ppm). For an Oscillation margin at 10, the graph below is showing the ESR_Range versus the load cap. The possible load cap variation range (in green) is larger when the ESR_Range increases:   Example: at oscillation margin 10.3, the clock accuracy can be improved from 213ppm to 183ppm by setting the ESR_range 2 to an ESR_Range 3 but the current consumption will be increased to 169.5nA. An other important point is that for a given ESR_Range value, getting higher the load cap is much more increasing the current than in the example above.   Remark: Under a high oscillation margin condition, the crystal voltage will be smaller.   Other possible ways to improve the oscillation margin exist: - Use external capacitor instead of internal capacitor banks. Oscillation margin goes up to 10. - Use the internal 32kFRO is supported for BLE (target:+/-500ppm)
View full article
The High Power board design files can be found on the JN5189 product webpage, in the JN-RD-6054-JN5189 Design Files. More precisely, the reference manual and the design files are attached to this article (OM15072-2_MOD_EXT_AMP_QFN40_PCB2467-2.0.zip and JN-RM-2078-JN5189-Module-Development_1V4.pdf) Some guidance is available here. The RF performances are presented in the attached test report (powerpoint file). The FCC/IC Certificates or Declarations of conformity are in the article "Certificates/Declarations of conformity (nxp community)".  
View full article
Please, find the important link to build a PCB using a KW38 and all concerning the radio performances, low power and radio certification (CE/FCC/IC). Your first task before to send any inquiry to NXP support is to fill the KW38 Design In CHECK LIST available in this ticket.   KW38 product NXP web page: KW39/38/37 32-bit Bluetooth 5.0 Long-Range MCUs|NXP | NXP Semiconductors   FRDM-KW38 getting started NXP web page Getting Started with the FRDM-KW38 | NXP Semiconductors   HW: FRDM-KW38 User Guide: FRDM-KW38 Freedom Development Board User’s Guide (nxp.com.cn) Hardware design consideration: Hardware Design Considerations for MKW39A/38A/37A/38Z/37Z Bluetooth LE Devices (nxp.com) Minimum BoM: KW37_38_39 Minimum BoM Presentation.pdf - NXP Community DCDC management guide : MKW4xZ/3xZ/3xA/2xZ DC-DC Power Management (nxp.com)          Migration guide: KW36 to KW38: Migration Guide from MKW36A512xxx4 to MKW38A512xxx4 (nxp.com)          Design-In check list: attached excel file         Configuration for Unused Pins/GPIOs on Kinetis Radio: RF report: https://www.nxp.com.cn/docs/en/application-note/AN12517.pdf Annex: MIIT (China) sharpened Homologation on FRDM-KW38 &... - NXP Community          Radio co-existance: FRDM-KW38 Co-existence with RF System Evaluation Report for Bluetooth® Low Energy Application (nxp.com) Low Power Consumption: https://www.nxp.com/docs/en/application-note/AN12459.pdf Distance performances: KW37_38_39_Bluetooth LE Range Performance.pdf - NXP Community Antenna: https://www.nxp.com/docs/en/application-note/AN2731.pdf          Generic FSK Link Layer Quick Start: Connectivity test SW user guide in attached pdf file          Binary file attached: Connectivity test frdmkw38.bin          Return loss (S11) measurement: attached file          Loadpull: attached file Low Power:          Low power estimator tool link: https://community.nxp.com/t5/Connectivity-Support-QN-JN-KW/BLE-power-profile-calculator-v0p3-xlsx/ta-p/1107083 SW tools:          IoT Tool box          Connectivity test tool for connectivity products KW39/38/37 32-bit Bluetooth 5.0 Long-Range MCUs|NXP | NXP Semiconductors          DTM: How to use the HCI_bb on Kinetis family products a... - NXP Community https://community.nxp.com/t5/Wireless-Connectivity-Knowledge/BLE-HCI-Application-to-set-transmitter-receiver-test-commands/ta-p/1126093 Certification:          Zip attached file and the community link: KW39 KW38 KW37 Radio certification documents - NXP Community
View full article
KW39_38_37 radio certification information 
View full article
Introduction Over The Air Programming (OTAP) is a Bluetooth LE custom NXP's service that provides a solution to upgrade the software running in the microcontroller. This document guides to load a new software image in a KW38 device through (Over The Air Programming) OTAP Bluetooth LE service. Software Requirements MCUXpresso IDE or IAR Embedded Workbench IDE. FRDM-KW38 SDK. IoT Toolbox App, available for Android and iOS. You can also download the APK of the IoT Toolbox App from this post: IoT Toolbox for Android  Hardware Requirements FRDM-KW38 board. A smartphone with IoT Toolbox App. KW38 Flash Memory Used by the OTAP Client Software During the Update Process By default, the 512KB KW38 flash memory is partitioned into: One 256KB Program Flash array (P-Flash) divided into 2KB sectors with a flash address range from 0x0000_0000 to 0x0003_FFFF. One 256KB FlexNVM array divided into 2KB sectors with address range from 0x1000_0000 to 0x1003_FFFF. Alias memory with address range from 0x0004_0000 to 0x0007_FFFF. Writes or reads at the Alias memory modifies or returns the FlexNVM content, respectively. In other words, Alias memory is another way to refer to FlexNVM memory using different addresses. The following statements simplify how does the OTAP service work:   The OTAP application consists of two independent parts, OTAP bootloader, and OTAP client. The OTAP bootloader verifies if there is a new image available in the OTAP client to reprogram the device. The OTAP client software, on the other hand, provides the Bluetooth LE custom service needed to communicate the OTAP client device (device to be reprogrammed) with the OTAP server device (device that contains the image to reprogram the OTAP client device). Therefore, to prepare the software for the first time, the OTAP client device needs to be programmed twice, first with the OTAP bootloader, and then with the OTAP client software. The mechanism created to have two different software coexisting in the same device is storing each one in different memory regions. This is achieved by indicating to the linker file different memory regions on each individual software. For the KW38 device, the OTAP bootloader has reserved an 8KB slot from 0x0000_0000 to 0x0000_1FFF, thus the rest of the memory is reserved, among other things, by the OTAP client software.     When generating the new image file for the OTAP client device, we need to specify to the linker file that the code will be placed with an offset of 8KB (as the OTAP client software does), since these address range must be preserved to do not overwrite the OTAP bootloader. The new application should also contain the bootloader flags at the corresponding address to work properly (later we will return to this point).     While OTAP client and OTAP server devices are connected, and the download is in progress, the OTAP server device sends the image packets (known as chunks) to the OTAP client device via Bluetooth LE. The OTAP client device can store these chunks, in the external SPI flash (which is already populated on the FRDM-KW38) or in the on-chip FlexNVM region. The destination for these chunks is selectable in the OTAP client software (This post will give the instructions to modify the destination).     When the transfer of the image has finished, and all chunks were sent from the OTAP server device to the OTAP client device, the OTAP client software writes information such as the source of the software update (either external flash or FlexNVM) in a portion of memory known as bootloader flags. Then the OTAP client performs a software reset on the MCU to execute the OTAP bootloader code. Then, the OTAP bootloader code reads the bootloader flags to get the information needed to reprogram the device with the new application. See the following flow diagram which explains the flow of both applications.   Because the new application was built with an offset of 8KB, the OTAP bootloader programs the device starting from the 0x0000_2000 address, so, in consequence, the OTAP client application is overwritten by the new image. Then, the OTAP bootloader moves the flow of the application to start the execution of the new code.     In practice, the boundary between the OTAP client software and the software update when FlexNVM storage is enabled described in statement 3 is not placed exactly in the boundary of the P-Flash and FlexNVM memory regions, moreover, these values might change depending on your linker settings. To know where is located the boundary, you should inspect the effective memory addressing in your project.        Configuring and Programming OTAP Client Software in IAR Embedded Workbench IDE As mentioned in the last section, to complete the software for OTAP implementation, there are required two software programmed in your FRDM-KW38, OTAP bootloader and OTAP client. This section guides you to program and configure the settings to choose between external or internal storage using the IAR Embedded Workbench IDE. 1- The first step is to program the OTAP bootloader in your KW38. Unzip your SDK and then locate the OTAP bootloader software in the following path: <KW38_SDK>\boards\frdmkw38\wireless_examples\framework\bootloader_otap\bm\iar\bootloader_otap.eww 2- Program the OTAP bootloader project on your board by clicking on the "Download and Debug" icon (Ctrl + D) . Once the KW38 was programmed and the debug session begun, abort the session (Ctrl + Caps Lock + D)  to stop the MCU safely. 3- At this point, you have programmed the OTAP bootloader in your KW38. The next is to program and configure the OTAP client software. Locate the OTAP client software at the following path: Freertos project version: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\otac_att\freertos\iar\otap_client_att_freertos.eww Baremetal project version: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\otac_att\bm\iar\otap_client_att_bm.eww 4- Then, configure the OTAP client to select external or internal storage. To select the external storage, follow the next steps (this is the default configuration in the SDK project): 4.1- Locate the "app_preinclude.h" header file in the source folder of your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_AT45DB041E_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_AT45DB041E_c 4.2- Open the project options window (Alt + F7). Go to Linker->Config window and set "gUseInternalStorageLink_d=0".   To select the internal storage, follow the next steps: 4.1- Locate the "app_preinclude.h" header file in the source folder of your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_InternalFlash_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_InternalFlash_c 4.2- Open the project options window (Alt + F7). Go to Linker->Config window and set "gUseInternalStorageLink_d=1".   5- Once you have configured the storage settings, save the changes in the project. Then program the software on your board by clicking on the "Download and Debug" icon (Ctrl + D)  . Once the KW38 was programmed and the debug session began, abort the session (Ctrl + Caps Lock + D)  to stop the MCU safely. Creating an SREC Image to Update the Software in OTAP Client in IAR Embedded Workbench IDE This section shows how to create an image compatible with OTAP to reprogram the KW38 OTAP Client using as a starting point, our wireless examples with IAR Embedded Workbench IDE. 1- Select any example from your SDK package in the Bluetooth folder and open it using the IAR IDE. Bluetooth examples are located in the following path: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth  In this example, we will use the glucose sensor project: <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\glucose_s\freertos\iar\glucose_sensor_freertos.eww 2- Open the project options window in IAR (Alt + F7). In Linker->Config window, edit the options to include the "gUseBootloaderLink_d=1" flag and update the "gEraseNVMLink_d=0" flag. When the gUseBootlaoderLink_d flag is true, it indicates to the linker file that the image must be addressed after the first flash sector, to do not overwrite the OTAP Bootloader software (as we stated previously). On the other hand, the gEraseNVMLink_d symbol is used to fill with a 0xFF pattern the unused NVM flash memory region. Disabling this flag, our software image will not contain this pattern, in consequence, the image reduces its total size and it improves the speed of the OTAP download and memory usage. 3- Go to "Output Converter" window. Deselect the "Override default" checkbox, then expand the "Output format" combo box and select "Motorola S-records" format. Click the "OK" button to finish. 4- Build the project. 5- Locate the S-Record file (.srec) in the following path, and save it to a known location on your smartphone. <KW38_SDK>\boards\frdmkw38\wireless_examples\bluetooth\glucose_s\freertos\iar\debug\glucose_sensor_freertos.srec Configuring and Programming OTAP Client Software in MCUXpresso IDE As mentioned in a previous section, to complete the software for OTAP implementation, there are required two software programmed in your FRDM-KW38, OTAP bootloader and OTAP client. This section guides you to program and configure the settings to choose between external or internal storage using the MCUXpresso IDE. 1- Open MCUXpresso IDE. Click on "Import SDK example(s)" in the "Quickstart Panel". 2- Select the FRDM-KW38 icon and click "Next >". 3- Import the OTAP bootloader project. It is located in "wireless_examples -> framework -> bootloader_otap -> bm -> bootloader_otap". Click on the "Finish" button. 4- Program the OTAP bootloader project on your board by clicking on the "Debug" icon  . Once the KW38 was programmed and the debug session begun, abort the session  (Ctrl + F2) to stop the MCU safely. 5- Repeat steps 1 to 3 to import the OTAP client software on MCUXpresso IDE. It is located at "wireless_examples -> bluetooth -> otac_att -> freertos -> otap_client_att_freertos" for freertos version, or "wireless_examples -> bluetooth -> otac_att -> bm -> otap_client_bm_freertos" if you prefer baremetal instead. 6- Then, configure the OTAP client to select external or internal storage. To select the external storage, follow the next steps (this is the default configuration in the SDK project): 6.1- Locate the "app_preinclude.h" file under the source folder in your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_AT45DB041E_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_AT45DB041E_c 6.2- Navigate to "Project -> Properties -> C/C++ Build -> MCU settings -> Memory details". Edit the Flash fields as shown in the figure below, and leave intact the RAM. To select the internal storage, follow the next steps: 6.1- Locate the "app_preinclude.h" file under the source folder in your workspace. Search the "gEepromType_d" define and set its value to "gEepromDevice_InternalFlash_c". /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_InternalFlash_c 6.2- Navigate to "Project -> Properties -> C/C++ Build -> MCU settings -> Memory details". Edit the Flash fields as shown in the figure below, and leave intact the RAM. 7- Once you have configured the storage settings, save the changes in the project. Then program the software on your board by clicking on the "Debug" icon  . Once the KW38 was programmed and the debug session begun, abort the session  (Ctrl + F2) to stop the MCU safely. Creating an SREC Image to Update the Software in OTAP Client in MCUXpresso IDE This section shows how to create an image compatible with OTAP to reprogram the KW38 OTAP Client using as a starting point, our wireless examples with MCUXpresso IDE. 1- Import any example from your SDK package in the Bluetooth folder as explained previously. Bluetooth examples are located in "wireless_examples -> bluetooth" folder in the SDK Import Wizard. This example will make use of the glucose sensor project in "wireless_examples -> bluetooth -> glucose_s -> freertos -> glucose_sensor_freertos". See the picture below. 2- Navigate to "Project -> Properties -> C/C++ Build -> MCU settings -> Memory details". Edit the Flash fields as shown in the figure below, and leave intact the RAM. The last fields indicate to the linker file that the image must be addressed after the first flash sector, to do not overwrite the OTAP bootloader software, as we stated in the introduction of this post. 3- Unzip your KW38 SDK package. Drag and drop the "main_text_section.ldt" linker script from the following path to the "linkscripts" folder on your workspace. The result must be similar as shown in the following figure. <KW38_SDK>\middleware\wireless\framework\Common\devices\MKW38A4\mcux\linkscript_bootloader\main_text_section.ldt 4- Open the "end_text.ldt" linker script file located in the linkscripts folder in MCUXpresso IDE. Locate the section shown in the following figure and remove "FILL" and "BYTE" statements. BYTE and FILL lines are used to fill with a 0xFF pattern the unused NVM flash memory region. Removing this code, our software image will not contain this pattern, in consequence, the image reduces its total size and it improves the speed of the OTAP download and memory usage. 5- Open the "app_preinclude.h" file, and define "gEepromType_d" as internal storage. This is a dummy definition needed to place the bootloader flags in the proper address, so this will not affect the storage method chosen before when you programmed the OTAP client and the OTAP bootloader software in your MCU. /* Specifies the type of EEPROM available on the target board */ #define gEepromType_d gEepromDevice_InternalFlash_c 6-  Include in your project, the "OtaSupport" folder and its files in the "framework" folder of your project. Include as well the "External" folder and its files in the "framework -> Flash" folder of your project. "OtaSupport" and "External" folders can be found in your SDK. You can easily drag those folders from your SDK download path and drop it into your workspace in MCUXpresso to include them. "OtaSupport" and "External" folders are located at: OtaSupport <KW38_SDK>middleware\wireless\framework\OtaSupport External <KW38_SDK>middleware\wireless\framework\Flash\External The result must look like the following picture:  7- Go to "Project -> Properties -> C/C++ Build -> Settings -> Tool Settings -> MCU C Compiler -> Includes". Click on the icon next to "Include paths" (See the picture below). A new window will be displayed, then click on the "Workspace" button. 8- Deploy the directory of the project in the "Folder selection" window, and select "framework -> Flash -> External -> interface" and "framework -> OtaSupport -> interface" folders. Click the "OK" button to save the changes. 9- Ensure that "OtaSupport" and "External" folders were imported in the "Include paths" window. Then save the changes by clicking on the "Apply and Close" button. 10- Save and build the project by clicking this icon  . Then, deploy the "Binaries" icon in your project. Click the right mouse button on the ".axf" file and select the "Binary Utilities -> Create S-Record" option. The S-Record file generated will be saved in the Debug folder in your workspace with ".s19" extension. Save the S-Record file in a known location on your smartphone.    Testing the OTAP Client with IoT Toolbox App This section explains how to test the OTAP client software using the IoT Toolbox App. 1- Open the IoT Toolbox App on your smartphone. Select OTAP and click "SCAN" to start scanning for a suitable OTAP Client device.  2- Press the ADV button (SW2) on your FRDM-KW38 board to start advertising. 3- Once your smartphone has found the FRDM-KW38 board, it will be identified as "NXP_OTAA". Connect your smartphone with this device. Then a new window will be displayed on your smartphone.  4- Click the "Open" button and search for the SREC software update. 5- Click "Upload" to start the transfer. Wait while the download is completed. A confirmation message will be displayed after a successful update.  6- Wait a few seconds until the software update was programmed on your MCU. The new code will start automatically.   Please let me know any questions about this topic.
View full article
This document provides information on distance measurements depending of the Bluetooth LE data rate (1Mbps, 2Mbps, LR S=2 & LR S=8). The FRDM-KW38 boards are used to perform the measurements. Results are similar on KW37 and KW39.  
View full article
With the release of the Bluetooth LE core erratum 10734, two new Host test cases (SM/SLA/KDU/BI-01-C and SM/MAS/KDU/BI-01-C) were added to the Test Case Reference List (TCRL) and are active since 24-Jan-19. This has an impact on new product qualifications based on Component (Tested) QDIDs that used an older TCRL when the test cases for this erratum were not required. Products that rely on NXP HOST QDIDs have 2 options for covering the erratum 10734 in order to complete the qualification: NXP provides a new qualification/QDID that includes these 2 tests. This is scheduled for later this year for QN908x, KW35/36 and KW41/31 products. NXP provides the test evidence/logs for these 2 tests and the test house reviews them before completing the product qualification. Right now, option 2 can be followed using the test evidence/logs provided by NXP. Later in the year, option 1 can be followed with an updated QDID. To obtain the test evidence/logs, please submit a support request.
View full article
The FRDM-KW36 comes with the OpenSDA circuit which allows users to program and debug the evaluation board. There are different solutions to support such OpenSDA circuits: 1. The J-Link (SEGGER) firmware.  2. The CMSIS-DAP (mbed) firmware. The FRDM-KW36 comes pre-programmed with the CMSIS-DAP firmware. However, if you want to update the firmware version, you need to perform the next steps.  Press and hold the Reset button (SW1 push button in the board).  Unplug and plug the FRDM-KW36 again to the PC.  The board will be enumerated as "DAPLINKBOOT" device. Drag and drop the binary file to update the OpenSDA firmware.  If the J-Link version is programmed, the board will be enumerated as "FRDM-KW36J". On the other hand, if the CMSIS-DAP version is programmed, the board will be enumerated as "FRDM-KW36". The binary for the J-link version can be downloaded from the next link: SEGGER - The Embedded Experts - Downloads - J-Link / J-Trace  The binary for the CMSIS-DAP version can be found in the next link: OpenSDA Serial and Debug Adapter|NXP    Hope this helps... 
View full article
CMSIS, the ARM Cortex Microcontroller Software Interface Standard, can be used to distribute software components in standard package format. CMSIS compliant software components allow: • Easy reuse of example applications or template code • Combination of SW components from multiple vendors CMSIS packages available here: https://www.keil.arm.com/packs/ NXP WiFi package available here: https://www.keil.arm.com/packs/wifi-nxp/versions/   Getting NXP WiFi/BT software   Please find the minimal setup required to download the NXP WiFi/BT software CMSIS packs: First, get cpackget binary from the Open CMSIS Pack toolbox binaries Then, install the NXP WiFi and Bluetooth packages and their dependencies using below commands cpackget add NXP::WIFI@2.0.0 cpackget add NXP::WIRELESS_WPA_SUPPLICANT@2.0.0 cpackget add NXP::EDGEFAST_BT_BLE@2.0.0   Please note that the CMSIS software packs are installed in below directory: ~/.cache/arm/packs/NXP/   Building NXP WiFi/Bluetooth software   Using combined WiFi+Bluetooth application on i.MXRT1060-revC board, as an example.   Prerequisite Follow below steps to install all the required tools to get CMSIS packages and build them . <(curl https://aka.ms/vcpkg-init.sh -L) . ~/.vcpkg/vcpkg-init vcpkg new --application vcpkg add artifact arm:cmsis-toolbox vcpkg add artifact microsoft:cmake vcpkg add artifact microsoft:ninja vcpkg add artifact arm:arm-none-eabi-gcc vcpkg activate Refer to CMSIS toolbox installation documentation    Activate required tools . ~/.vcpkg/vcpkg-init vcpkg activate Install the NXP i.MXRT1060-REVC Bluetooth examples and their dependencies cpackget add NXP::MIMXRT1060-EVKC_EDGEFAST_BLUETOOTH_Examples@1.0.0 Workaround: current NXP SW is aligned with ARM::CMSIS@5.8.0, and does not support latest ARM::CMSIS@6.0.0, so we need to use older version with below commands cpackget rm ARM::CMSIS@6.0.0 cpackget add ARM::CMSIS@5.8.0 List the installed packages cpackget list Building combined WiFi+BT example application Copy example application to local directory and provide write permissions mkdir -p ~/test cp -r ~/.cache/arm/packs/NXP/MIMXRT1060-EVKC_EDGEFAST_BLUETOOTH_Examples/1.0.0/boards/evkcmimxrt1060/edgefast_bluetooth_examples/wifi_cli_over_ble_wu/ ~/test/ cd ~/test/wifi_cli_over_ble_wu/ && chmod -R u+w .   Build the application csolution convert wifi_cli_over_ble_wu.csolution.yml cbuild wifi_cli_over_ble_wu.flexspi_nor_debug+armgcc.cprj Convert elf to bin for flashing cd armgcc/flexspi_nor_debug arm-none-eabi-objcopy wifi_cli_over_ble_wu.elf -O binary wifi_cli_over_ble_wu.bin
View full article
This article explains how to implement a custom profile from both server and client side using the NXP BLE stack for the RT1060.   Generic Attribute Profile To fully understand the procedure of how to implement a custom profile in this platform, we must understand the BLE basics. The GATT (Generic Attribute Profile) will help us establish in detail the way server and client exchanges data over a BLE connection. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This means that if we want to have a successful connection and data transfer in our application, we must follow all the GATT procedures successfully. GATT roles: Server: This device will store the data to be transported or send and accepts the GATT requests, commands and confirmations from the client. Client: This device will access the data on the remote GATT server with operations such as read, write, notify or indicate. Figure 1. GATT Client-Server model   GATT database defines a type of hierarchy to organize attributes. These are named as Profile, Service, Characteristic and Descriptor. The structure is shown in Figure 2. The profile is a high level definition that determines the behavior of the application as a whole. For example, a Temperature Sensor profile. This profiles are defined by at least one service. The service defines a specific functionality for the device (e.g. battery service). The next level in the structure is the characteristic. The service is defined by one or more characteristics that hold individual measurements, control points or other kind of data. Finally we find descriptors. Characteristics have descriptors that defines how characteristics have to be accessed to read or write information. Figure 2. GATT database structure   Creating a New Profile With the GATT basics understood, we can start developing the code for our custom profile. In this case we will create a potentiometer custom profile. It will read the voltage drop of the potentiometer and send that value to the client every 5 seconds. Please note that in this document we will dismiss all the ADC initialization, the voltage value will be simulated. For time saving purposes, we will use the peripheral_ht and central_ht SDK examples structure to create this project. This means that the peripheral is going to be the server, the device that has the information. And the central will be the client, the device that gets the information. In case you don’t want to start this application from a SDK example, it is highly recommended to keep the same structure as in the examples, so if you would like to add your custom profile to an existing application, you have to prepare the project environment so all the new files where your service is declared is allocated in a specific path and avoid problems in the compiling process. For the case you want to add a new service to your project, it will be needed to create two folders called services and add our service files inside it. The first folder must be in the following route: ${ProjName}/edgefast/bluetooth/include/bluetooth. Inside this folder let´s create a new header file called pot.h. Note that if you are using the examples, you already have these folders so you only need to create the files. In this file we will declare the new UUID´s for our potentiometer service and the service characteristic. In this example we are declarin one profile, one service and one characteristic. To define a 128-bit UUID we are going to be using the macros available in the uuid.h file. The declarations will look like this: #define POTENTIOMETER_SERVICE_UUID 0xAA, 0x1C, 0x12, 0x5E, 0x40, 0xEE, 0xA1, 0xF1, 0xEE, 0xF4, 0x5E, 0xBA, 0x22, 0x33, 0xFF, 0x00 #define POTENTIOMETER_CHARACTERISTIC_UUID 0xAA, 0x1C, 0x12, 0x5E, 0x40, 0xEE, 0xA1, 0xF1, 0xEE, 0xF4, 0x5E, 0xBA, 0x22, 0x33, 0xFF, 0x01 #define POTENTIOMETER_SERVICE BT_UUID_DECLARE_128(POTENTIOMETER_SERVICE_UUID) #define POTENTIOMETER_CHARACTERISTIC BT_UUID_DECLARE_128(POTENTIOMETER_CHARACTERISTIC_UUID)   In this case we are declaring a service with the 128-bit service UUID and a characteristic with its 128-bit characteristic UUID. These macros are helping us to declare a struct bt_uuid according to a specific UUID. The other service folder must be allocated in the following route: ${ProjName}/edgefast/bluetooth/source. Inside this folder we have to create a new source file called pot.c (for simplicity we will use the same #include as in hts.c). There are important configurations and declarations we need to have in this file like the read function callback and the service declaration. It will look something like this: static uint8_t pot_level = 0x01U; /* Read function */ static ssize_t read_plvl(struct bt_conn *conn, const struct bt_gatt_attr *attr, void *buf, uint16_t len, uint16_t offset) { uint8_t lvl = pot_level; pot_level ++; /* Voltage level simulation */ return bt_gatt_attr_read(conn, attr, buf, len, offset, &lvl, sizeof(lvl)); } /* Potentiometer Service Declaration */ BT_GATT_SERVICE_DEFINE(pot, /* Name of the service */ BT_GATT_PRIMARY_SERVICE(POTENTIOMETER_SERVICE), /* Primary sevice UUID */ BT_GATT_CHARACTERISTIC(POTENTIOMETER_CHARACTERISTIC, BT_GATT_CHRC_READ | BT_GATT_CHRC_NOTIFY, BT_GATT_PERM_READ, read_plvl, NULL, NULL), /* Potentiometer characteristic */ BT_GATT_CCC(NULL, BT_GATT_PERM_READ | BT_GATT_PERM_WRITE), /* Client Characteristic Configuration Descriptor */ );   As you can see we have this variable called pot_level. This variable is the one that has the “sensed” voltage drop of the potentiometer. In this case it is a simulated value. Every time a device requests for the voltage value, pot_level­ is increased by 1. We are also defining the potentiometer service with the macro BT_GATT_SERVICE_DEFINE. The name of our service is “pot” and we are defining the properties, permissions and the read callback for our service. We have finished with these two files and there is no need to modify them again. These files are used for both server and client. Finally we need to include the new folder´s to the project path. Once again, note that if you are using the examples, this step is not needed. To do this we have to open the project properties, and go to Settings of the C/C++ Build option. In the MCU C Compiler, we have to select the Includes folder and add the previous two paths. Figure 3. Path including We should be able the compile our service files without problem. Let’s start the server code.   Server: We already have out service declared and now we have to create two new files that are going to handle the connections. We will be basing this part in the peripheral_ht SDK example. The new files should be allocated in the following route: ${ProjName}/source. These files are potentiometer.c and potentiometer.h. In the header file we will declare our potentiometer task, that is going to be our main task: void potentiometer_task(void *pvParameters);   In the source file we will need to include the pot.h and potentiometer.h files and declare some new information. Use peripheral_ht.c as a base. We have to create and define the advertising and response packets, the connection callbacks and functions related to the connection. We are going to start declaring the connection variable: static struct bt_conn *default_conn;   The advertising packet will have the following structure: static const struct bt_data ad[] = { BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)), BT_DATA_BYTES(BT_DATA_UUID128_SOME, POTENTIOMETER_SERVICE_UUID), };   We are creating an advertising packet that is general discoverable and Bluetooth basic rate/enhanced data rate is not supported, we are also including the potentiometer service UUID. The response packet will have the following structure: #define DEVICE_NAME "pot" #define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1) static const struct bt_data sd[] = { BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN), };   The response packet only has the device name, which in this case is pot. static void connected(struct bt_conn *conn, uint8_t error) { char addr[BT_ADDR_LE_STR_LEN]; struct bt_conn_info info; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (error) { PRINTF("Failed to connect to %s (err %u)\n\r", addr, error); } else { error = bt_conn_get_info(conn, &info); /* Getting connection info */ if(error) { PRINTF("Failed to get info\n\r"); return; } default_conn = conn; PRINTF("Connected to: %s\n\r", addr); } } static void disconnected(struct bt_conn *conn, uint8_t reason) { PRINTF("Disconnected (reason 0x%02x/n", reason); if(default_conn) { bt_conn_unref(default_conn); default_conn = NULL; } } static struct bt_conn_cb conn_callbacks = { .connected = connected, .disconnected = disconnected, };   Let’s keep up with the code. The connected function is going to run when a device is successfully connected to our server, and the disconnected function is going to restore the connection to NULL every time a device gets disconnected. static void bt_ready(int error) { char addr_s[BT_ADDR_LE_STR_LEN]; bt_addr_le_t addr = {0}; size_t count = 1; if (error) { PRINTF("Bluetooth init failed (error %d)\n", error); return; } PRINTF("Bluetooth initialized\n\r"); bt_conn_cb_register(&conn_callbacks); /*Start advertising*/ error = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), sd, ARRAY_SIZE(sd)); if (error) { PRINTF("Advertising failed to start (error %d)\n", error); return; } bt_id_get(&addr, &count); bt_addr_le_to_str(&addr, addr_s, sizeof(addr_s)); PRINTF("Advertising as %s\n\r", addr_s); } void potentiometer_task(void *pvParameters) { int error, result; PRINTF("BLE POTENITOMETER [Server] Custom Profile Running...\n\r"); error = bt_enable(bt_ready); if(error) { PRINTF("Bluetooth init failed (error %d)\n\r", error); return; } while(1) { } }   In the main task, we are going to initialize the BLE components, and then bt_ready is going to run. If the BLE initialization was correct, the advertising will start using the previous advertising and response packets. We will use xTaskCreate to create our new potentiometer task in the main file. Notice that this is the only task created in the main file. The server is done, we can get connected to it and start to receive the potentiometer voltage. But as we want two boards connected working in each role, we will also need to modify the code for the client. In the app_config.h file there should be the following macro defined. #define CONFIG_BT_PERIPHERAL 1​   Client: To create the Client part, we will be basing on the central_ht SDK example. We need to create a new file to handle the connections and initializations like we did before in the server. This file is going to have some similar functions to potentiometer.c. I will be using the same name for simplicity purposes. We need to import the potentiometer service by adding the the pot.c and pot.h files we did on previous steps. First thing to do is create the new variables. static struct bt_conn *default_conn; static struct bt_uuid_128 uuid = BT_UUID_INIT_128(0); static struct bt_gatt_discover_params discover_params; static struct bt_gatt_read_params read_params; static uint8_t connection_success; static uint8_t data_received;   Using central_h.c as reference, we need to modify some functions as it follows: static uint8_t read_func(struct bt_conn *conn, uint8_t err, struct bt_gatt_read_params *params, const void *data, uint16_t length) { if ((data != NULL) && (err == 0)) { data_received = *(uint8_t*)data; PRINTF("Read successful - Pot voltage level: %d\n\r", data_received); } else { PRINTF("Read Failed\n\r"); } return BT_GATT_ITER_STOP; } static int bt_get_pot_lvl(void) { return bt_gatt_read(default_conn, &read_params); } static uint8_t discover_func(struct bt_conn *conn, const struct bt_gatt_attr *attr, struct bt_gatt_discover_params *params) { int32_t err; if (!attr) { PRINTF("Discover complete, No attribute found \n\r"); (void)memset(params, 0, sizeof(*params)); return BT_GATT_ITER_STOP; } if (bt_uuid_cmp(discover_params.uuid, POTENTIOMETER_SERVICE) == 0) { /* Potentiometer service discovered */ /* Next, Potentiometer characteristic */ PRINTF("POT service UUID found: 0x"); for(int i = 0; i<sizeof(BT_UUID_128(POTENTIOMETER_SERVICE)->val) ; i += sizeof(uint16_t)) { PRINTF("%X", uuid.val[i]); PRINTF("%X", uuid.val[i + 1]); } PRINTF("\n\r"); memcpy(&uuid, POTENTIOMETER_CHARACTERISTIC, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.start_handle = attr->handle + 1; discover_params.type = BT_GATT_DISCOVER_CHARACTERISTIC; err = bt_gatt_discover(conn, &discover_params); if (err) { PRINTF("Discover failed (err %d)\n\r", err); } } else if(bt_uuid_cmp(discover_params.uuid, POTENTIOMETER_CHARACTERISTIC) == 0) { PRINTF("POT characteristic UUID found: 0x"); for(int i = 0; i<sizeof(BT_UUID_128(POTENTIOMETER_CHARACTERISTIC)->val) ; i += sizeof(uint16_t)) { PRINTF("%X", uuid.val[i]); PRINTF("%X", uuid.val[i + 1]); } PRINTF("\n\n\r"); /* Read Potentiometer */ read_params.func = read_func; read_params.handle_count = 0; /* Selects the UUID characteristic handle */ read_params.by_uuid.start_handle = 0x0001; read_params.by_uuid.end_handle = 0xffff; read_params.by_uuid.uuid = &uuid.uuid; /* Potentiometer characteristic */ err = bt_gatt_read(conn, &read_params); if(err) { PRINTF("Read failed (err %d)\n\r", err); } else { connection_success = 1; } return BT_GATT_ITER_STOP; } return BT_GATT_ITER_STOP; }   The read_func function is going to be the callback for the read parameters. The bt_get_pot_level function is going to use the read parameters to read the potentiometer value. The discover_func function is going to find every advertising device in the advertising channel. In this function we are going to force the connection to the potentiometer service, so if there is one device advertising with the potentiometer service UUID, we will verify if it has the characteristic we are interested in. In this case the potentiometer charactersic, and if this device also has this characteristic, we are going to read the data. static void connected(struct bt_conn *conn, uint8_t conn_err) { char addr[BT_ADDR_LE_STR_LEN]; int32_t err; bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr)); if (conn_err) { PRINTF("Failed to connect to %s (err %u)\n\r", addr, conn_err); bt_conn_unref(default_conn); default_conn = NULL; /* Restart scanning */ scan_start(); return; } PRINTF("Connected to peer: %s\n\r", addr); if (conn == default_conn) { memcpy(&uuid, POTENTIOMETER_SERVICE, sizeof(uuid)); discover_params.uuid = &uuid.uuid; discover_params.func = discover_func; discover_params.start_handle = 0x0001; discover_params.end_handle = 0xffff; discover_params.type = BT_GATT_DISCOVER_PRIMARY; /* Start service discovery */ err = bt_gatt_discover(default_conn, &discover_params); if (err) { PRINTF("Discover failed(err %d)\n\r", err); } else { PRINTF("Starting service discovery\n\r"); } } } ​   In the device_scanned function we are going to create a connection with the server, so we need to compare the UUID we are scanning and check if there is a device with the potentiometer service UUID. static bool device_scanned(struct bt_data *data, void *user_data) { bt_addr_le_t *addr = user_data; struct bt_uuid_128 uuid_temp; int err; int i; char dev[BT_ADDR_LE_STR_LEN]; bool continueParse = true; /* return true to continue parsing or false to stop parsing */ switch (data->type) { case BT_DATA_UUID16_SOME: break; case BT_DATA_UUID16_ALL: break; case BT_DATA_UUID128_SOME: { if (data->data_len % sizeof(uint16_t) != 0U) { PRINTF("AD malformed\n\r"); return true; } uuid_temp.uuid.type = BT_UUID_TYPE_128; for(i = 0; i < data->data_len ; i += sizeof(uint32_t)) { uuid_temp.val[i] = data->data[i]; uuid_temp.val[i + 1] = data->data[i + 1]; uuid_temp.val[i + 2] = data->data[i + 2]; uuid_temp.val[i + 3] = data->data[i + 3]; } /* Search for the Potentiometer Service in the advertising data */ if ((bt_uuid_cmp(&uuid_temp.uuid, POTENTIOMETER_SERVICE) == 0)) { /* found the Potentiometer service - stop scanning */ err = bt_le_scan_stop(); if (err) { PRINTF("Stop LE scan failed (err %d)\n", err); break; } bt_addr_le_to_str(addr, dev, sizeof(dev)); PRINTF("Found device: %s\n\r", dev); /* Send connection request */ err = bt_conn_le_create(addr, BT_CONN_LE_CREATE_CONN, BT_LE_CONN_PARAM_DEFAULT, &default_conn); if (err) { PRINTF("Create connection failed (err %d)\n", err); scan_start(); } continueParse = false; break; } break; } /*CASE UUDI128_SOME*/ default: { break; } } return continueParse; }   The device_found stays very similar to the example, we are just deleting the PRINTF’s functions because we don’t want to see every device found, we are just interested in our server. static void device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { /* We're only interested in connectable events */ if (type == BT_GAP_ADV_TYPE_ADV_IND || type == BT_GAP_ADV_TYPE_ADV_DIRECT_IND) { bt_data_parse(ad, device_scanned, (void *)addr); } } ​   The scan_start and disconnected stays the same. static int scan_start(void) { struct bt_le_scan_param scan_param = { .type = BT_LE_SCAN_TYPE_PASSIVE, .options = BT_LE_SCAN_OPT_NONE, .interval = BT_GAP_SCAN_FAST_INTERVAL, .window = BT_GAP_SCAN_FAST_WINDOW, }; return bt_le_scan_start(&scan_param, device_found); } static void disconnected(struct bt_conn *conn, uint8_t reason) { PRINTF("Disconnected reason 0x%02x\n\r", reason); int32_t err; connection_success = 0; if (default_conn != conn) { return; } bt_conn_unref(default_conn); default_conn = NULL; /* Restart scanning */ err = scan_start(); if (err) { PRINTF("Scanning failed to start (err %d)\n\r", err); } else { PRINTF("Scanning started\n\r"); } }   The bt_ready is almost the same. static void bt_ready(int error) { if (error) { PRINTF("Bluetooth init failed (error %d)\n\r", error); return; } PRINTF("Bluetooth initialized\n\r"); bt_conn_cb_register(&conn_callbacks); /*Scan Starting*/ error = scan_start(); if(error) { PRINTF("Scanning failed to start (error %d)\n\r", error); return; } PRINTF("Scanning started\n\r"); }   The last thing we are going to modify is the potentiometer task. We are going to read the potentiometer value every 5 seconds. void potentiometer_task(void *pvParameters) { int error, result; PRINTF("BLE POTENITOMETER [Client] Custom Profile Running...\n\r"); error = bt_enable(bt_ready); if(error) { PRINTF("Bluetooth init failed (error %d)\n\r", error); return; } while(1) { vTaskDelay(pdMS_TO_TICKS(5000)); if(connection_success) { error = bt_get_pot_lvl(); } } }   Finally, we need to add some macros to enable some scanning and discover functions, please confirm you do have them defined in the preprocessor or another file like app_config.h : #define CONFIG_BT_OBSERVER 1 #define CONFIG_BT_CENTRAL 1 #define CONFIG_BT_GATT_CLIENT 1   Please take in mind that if there are other BT macros defined in the app_config.h file that weren’t mentioned in this article, the example may not run as expected. Additional modifications might be needed to make it work.   Testing To test this application we are going to use the following: 2 x RT1060 EVK (Client and Server) AW-CM358-uSD (88W8987) AW-AM457-uSD (IW416)   Take in mind that to run BT and BLE applications there might be some connections or reworking needed in your board and wireless module. For more information take a look to the Hardware Rework Guide for EdgeFast BT PAL document. It is important to take in mind the version of EVK that we will be using since there might be some differences in the supported modules. In this case, the test is with the A revision of the RT1060 EVK.   Figure 4.  Server and client application running   Figure 5. Terminal output of the server (IW416)   Figure 6. Terminal output of the client (88W8987)
View full article
The QN9090 is a Bluetooth Low Energy device that achieves ultra-low-power consumption and integrates an Arm ® Cortex ® -M4 CPU with a comprehensive mix of analog and digital peripherals. If the developer is working with the Development platform for QN9090 wireless MCUs for the first time, it is recommended to follow the QN9090-DK Development kit Getting Started (this guide can be found in QN9090DK Documentation section). This Quick Start document provides an overview about the QN9090 DK and its software tools and lists the steps to install the hardware and the software. For this document, Temperature Sensor and Temperature Collector examples will be used to demonstrate the implementation of a custom profile (both examples can be found in the SDK). This article will explain how to add the Humidity Profile and how to modify the code to get the Humidity Sensor and Collector working.   Introduction   Generic Attribute Profile (GATT) GATT defines the way that profile and user data are exchanged between devices over a BLE connection. GATT deals with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly, making it a key section of the BLE specification since every single item of data relevant to applications and users must be formatted, packed and sent according to the rules. There are two GATT roles that define the devices exchanging data: GATT Server This device contains a GATT Database and stores the data transported over the Attribute Protocol (ATT). The Server accepts ATT requests, commands and confirmations sent by the Client; and it can be configured to send data on its own through notifications and indications. GATT Client This is the “active” device that accesses data on the remote GATT Server via read, write, notify, or indicate operations. Notify and indicate operations are enabled by the client but initiated by the server, providing a way to push data to the client. Notifications are unacknowledged, while indications are acknowledged. Notifications are therefore faster, but less reliable. GATT Database establishes a hierarchy to organize attributes and is a collection of Services and Characteristics exposing meaningful data. Profiles are high level definitions that define how Services can be used to enable an application; Services are collections of Characteristics. Descriptors define attributes that describe a characteristic value.   Server (Sensor)   The Temperature Sensor project will be used as base to create our Humidity Custom Profile Server (Sensor). BLE SIG profiles Some Profiles or Services are already defined in the specification, and we can verify this in the Bluetooth SIG profiles document. Also, we need to check in the ble_sig_defines.h files (${workspace_loc:/${ProjName}/bluetooth/host/interface}) if this is already declared in the code. In this case, the Service is not declared, but the Characteristic of the humidity is declared in the specification. Then, we need to check if the Characteristic is already included in ble_sig_defines.h. Since the characteristic is not included, we define it as shown: /*! Humidity Characteristic UUID */ #define gBleSig_Humidity_d                   0x2A6FU GATT Database The Humidity Sensor will act as GATT Server since it will be the device containing all the information for the GATT Client. Temperature Sensor demo already implements the Battery Service and Device Information, so we only have to change the Temperature Service to Humidity Service.   In order to create the demo, we need to define a Service that must be the same as in the GATT Client, this is declared in the gatt_uuid128.h. If the new service is not the same, Client and Server will not be able to communicate each other. All macros, functions or structures in the SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uui128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, 0x00, 0xfa, 0x10, 0x10) Units All the Services and Characteristics are declared in gatt_db.h. Descriptor 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 for Humidity Characteristic is Percentage, defined in the Bluetooth SIG profiles document as 0x27AD. Descriptor 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) Humidity service and interface Create a folder named “humidity” in path ${workspace_loc:/${ProjName}/bluetooth/profiles}. In the same path you can find the “temperature” folder; copy the temperature_service.c file and paste it inside the “humidity” folder with another name (humidity_service.c). After this, go back to the “temperature” folder and copy the temperature_interface.h file; paste it inside the “humidity” folder and rename it (humidity_interface.h). You will need to include the path of the created folder. Go to Project properties > C/C++ Build > Settings > Tool Settings > MCU C Compiler > Includes: Humidity Interface The humidity_interface.h file should include the following code, where the Service structure contains the Service handle and the initialization value: /*! Humidity Service - Configuration */ typedef struct humsConfig_tag {        uint16_t serviceHandle;        int16_t initialHumidity; } humsConfig_t; /*! Humidity Client - Configuration */ typedef struct humcConfig_tag {        uint16_t hService;        uint16_t hHumidity;        uint16_t hHumCccd;        uint16_t hHumDesc;        gattDbCharPresFormat_t humFormat; } humcConfig_t; Humidity service At minimum, humidity_service.c file must contain the following code: /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId; The Service stores the device identification for the connected client. This value is changed on subscription and non-subscription events. Initialization Initialization of the Service is made by calling the start procedure. This function is usually called when the application is initialized. In this case, this is done in the BleApp_Config() function. bleResult_t Hums_Start(humsConfig_t *pServiceConfig) {     mHums_SubscribedClientId = gInvalidDeviceId_c;     /* Set the initial value of the humidity characteristic */     return Hums_RecordHumidityMeasurement(pServiceConfig->serviceHandle,                                             pServiceConfig->initialHumidity); } Stop & Unsubscribe On stop function, the unsubscribe function is called. bleResult_t Hums_Stop(humsConfig_t *pServiceConfig) {     /* Stop functionality by unsubscribing */     return Hums_Unsubscribe(); } bleResult_t Hums_Unsubscribe(void) {     /* Unsubscribe by invalidating the client ID */     mHums_SubscribedClientId = gInvalidDeviceId_c;     return gBleSuccess_c; } Subscribe The subscribe function will be used in the main file to subscribe the GATT client to the Humidity Service. bleResult_t Hums_Subscribe(deviceId_t clientDeviceId) {     /* Subscribe by saving the client ID */     mHums_SubscribedClientId = clientDeviceId;     return gBleSuccess_c; } Record Humidity Depending on the complexity of the Service, the API will implement additional functions. For the Humidity Sensor will only have one Characteristic. The measurement will be saved 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)        {              /* Update characteristic value */              result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t *)&humidity);              if (result == gBleSuccess_c)              {                     /* Notify the humidity value */                     Hts_SendHumidityMeasurementNotification(handle);              }        }        return result; } Remember to add/update the prototype for Initialization, Subscribe, Unsubscribe, Stop and Record Humidity Measurement functions in humidity_interface.h. Send notification After saving the measurement on the GATT Database by using the GattDb_WriteAttribute function, we can send the notification. To send this notification, first we have to get the CCCD and check if the notification is active after that; if it is active, then we 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);        } } Remember to add or modify the prototype for Send Humidity Measurement Notification function.   Main file There are some modifications that need to be done in the Sensor main file: Add humidity_interface.h in main file /* Profile / Services */ #include "humidity_interface.h" Declare humidity service There are some modifications that have to be done in order to use the new Humidity Profile in the Sensor example. First, we need to declare the Humidity Service: static humsConfig_t humsServiceConfig = {(uint16_t)service_humidity, 0};   Rename BleApp_SendTemperature -> BleApp_SendHumidity static void BleApp_SendHumidity(void); After this, we need to add or modify the following functions and events: Modify BleApp_Start /* Device is connected, send humidity value */        BleApp_SendHumidity();   Ble_AppConfig Start Humidity Service and modify the Serial_Print line. /* Start services */ humsServiceConfig.initialHumidity = 0; (void)Hums_Start(&humsServiceConfig); (void)Serial_Print(gAppSerMgrIf, "\n\rHumidity sensor -> Press switch to start advertising.\n\r", gAllowToBlock_d);   BleApp_ConnectionCallback events - Event: gConnEvtConnected_c (void)Hums_Subscribe(peerDeviceId);   - Event: gConnEvtDisconnected_c (void)Hums_Unsubscribe();   Notify value in BleApp_GattServerCallback function /* Notify the humidity value when CCCD is written */ BleApp_SendHumidity(); Add the Hums_RecordHumidityMeasurement function and modify the initial value update in BleApp_SendHumidity function /* Update with initial humidity */ (void)Hums_RecordHumidityMeasurement((uint16_t)service_humidity,                                            (int16_t)(BOARD_GetTemperature())); Note: in this example, the Record Humidity uses the BOARD_GetTemperature to allow the developer to use the example without any external sensor and to be able to see a change in the collector, but in this section, there should be a GetHumidity function.   app_config.c file There are some modifications that need to be done inside app_config.c file: Modify Scanning and Advertising Data {     .length = NumberOfElements(uuid_service_humidity) + 1,     .adType = gAdComplete128bitServiceList_c,     .aData = (uint8_t *)uuid_service_humidity }   *Optional* Modify name {     .adType = gAdShortenedLocalName_c,     .length = 9,     .aData = (uint8_t*)"NXP_HUM" }   Modify Service Security Requirements {     .requirements = {         .securityModeLevel = gSecurityMode_1_Level_3_c,         .authorization = FALSE,         .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d     },     .serviceHandle = (uint16_t)service_humidity }   Client (Collector)   We will use the Temperature Collector project as base to create our Humidity Custom Profile Client (Collector). BLE SIG profiles As mentioned in the Server section, we need to verify if the Profile or Service is already defined in the specification. For this, we can take a look at the Bluetooth SIG profiles document and check in the ble_sig_defines.h file (${workspace_loc:/${ProjName}/bluetooth/host/interface}) if this is already declared in the code. In our case, the Service is not declared, but the Characteristic of the Humidity is declared in the specification. Then, we need to check if the Characteristic is already included in ble_sig_defines.h. Since the Characteristic is not included, we need to define it as shown: /*! Humidity Characteristic UUID */ #define gBleSig_Humidity_d                    0x2A6FU GATT Database The Humidity Collector is going to have the GATT client; this is the device that will receive all new information from the GATT Server. The demo provided in this article works in the same way as the Temperature Collector. When the Collector enables the notifications from the Sensor, received notifications will be printed in the seral terminal. In order to create the demo, we need to define or develop a Service that must be the same as in the GATT Server, this is declared in the gatt_uuid128.h file. If the new Service is no the same, Client and Server will not be able to communicate each other. All macros, functions or structures in the SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uui128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, 0x00, 0xfa, 0x10, 0x10) Includes After that, copy the humidity profile folder from the Sensor project and paste it into the Collector project inside ${workspace_loc:/${ProjName}/bluetooth/profiles}. Also, include the path of the new folder.   Main file In the Collector main file, we need to do some modifications to use the Humidity Profile Include humidity_interface.h /* Profile / Services */ #include "humidity_interface.h"   Modify the Custom Info of the Peer device humcConfig_t     humsClientConfig;   Modify BleApp_StoreServiceHandles function static void BleApp_StoreServiceHandles {     APP_DBG_LOG("");     uint8_t i,j;     if ((pService->uuidType == gBleUuidType128_c) &&              FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))     {         /* Found Humidity Service */        mPeerInformation.customInfo.humsClientConfig.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_Humidity_d))             {                 /* Found Humidity Char */             mPeerInformation.customInfo.humsClientConfig.hHumidity = 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 Humidity Char Presentation Format Descriptor */                             case gBleSig_CharPresFormatDescriptor_d:                             {                                 mPeerInformation.customInfo.humsClientConfig.hHumDesc = pService->aCharacteristics[i].aDescriptors[j].handle;                                 break;                             }                             /* Found Humidity Char CCCD */                             case gBleSig_CCCD_d:                             {                                 mPeerInformation.customInfo.humsClientConfig.hHumCccd = pService->aCharacteristics[i].aDescriptors[j].handle;                                 break;                             }                             default:                                 ; /* No action required */                                 break;                         }                     }                 }             }         }     } }   Modify BleApp_StoreDescValues function if (pDesc->handle == mPeerInformation.customInfo.humsClientConfig.hHumDesc) {        /* Store Humidity format*/        FLib_MemCpy(&mPeerInformation.customInfo.humsClientConfig.humFormat,                     pDesc->paValue,                     pDesc->valueLength); }   Implement BleApp_PrintHumidity function static void BleApp_PrintHumidity (     uint16_t humidity ) {     APP_DBG_LOG("");     shell_write("Humidity: ");     shell_writeDec((uint32_t)humidity);     /* Add '%' for Percentage - UUID 0x27AD.        www.bluetooth.com/specifications/assigned-numbers/units */     if (mPeerInformation.customInfo.humsClientConfig.humFormat.unitUuid16 == 0x27ADU)     {         shell_write(" %\r\n");     }     else     {         shell_write("\r\n");     } }   Modify BleApp_GattNotificationCallback function if (characteristicValueHandle == mPeerInformation.customInfo.humsClientConfig.hHumidity) { BleApp_PrintHumidity(Utils_ExtractTwoByteValue(aValue)); }   Modify CheckScanEvent function foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);   Some events inside BleApp_StateMachineHandler need to be modified: BleApp_StateMachineHandler - Event: mAppIdle_c if (mPeerInformation.customInfo.humsClientConfig.hHumidity != gGattDbInvalidHandle_d)   - Event: mAppServiceDisc_c if (mPeerInformation.customInfo.humsClientConfig.hHumDesc != 0U)  mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumDesc;   - Event: mAppReadDescriptor_c if (mPeerInformation.customInfo.humsClientConfig.hHumCccd != 0U)   Modify BleApp_ConfigureNotifications function mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumCccd;   Demonstration   In order to print the relevant data in console, it may be necessary to disable Power Down mode in app_preinclude.h file. This file can be found inside source folder. For this, cPWR_UsePowerDownMode and cPWR_FullPowerDownMode should be set to 0. Now, after connection, every time that you press the User Interface Button on QN9090 Humidity Sensor is going to send the value to QN9090 Humidity Collector. Humidity Sensor   Humidity Collector  
View full article
This guide explains how to configure Wi-Fi as Access Point using the i.MX8M Plus EVK (8MP) as the AP device and the i.MX8M Mini EVK (8MM) as the connected device.
View full article
The document is for 88w9098 users who is running lower version of linux kernel. just a reference for them. Driver version:      PCIE-WLAN-UART-BT-9098-U16-X86-17.68.1.p81-17.26.1.p81-MXM5X17277_V0V1-MGPL   NXP global CAS connectivity team Weidong Sun 12-29-2021
View full article
The document discusses how to enable MAYA_160(IW416) bluetooth on i.MX8MM UART2. 1. Hardware connections 2. how to change device tree 3. compiling mass market driver and getting firmware 4. starting bluetooth and setting bandrate to be 3Mbps More detailed information, see attachment, please!   NXP global CAS connectivity team weidong sun 12-29-2021
View full article
The border router device provides connectivity of the nodes in the Thread network with the possibility to connect to the networks as the www. Requirements Hardware K32W/JN5189 DK6 Board Udoo Neo Ethernet Cable Software MCUXpresso IDE v11.4.1 o newer. SDK 2.6.4. https://mcuxpresso.nxp.com/en/dashboard DK6 Production Flash Programmer Tool udoo_neo_os_nxp.img Docker Image Software Set up 1. Flash udoo_neo_os_nxp.img on an SD card using a tool. You could use any tool to flash the image, make sure that the SD card is correctly formatted. 2. Flash the ot-rcp.bin file on the USB Dongle(K32W/JN5189),  included in the SDK. \K32W061DK6\middleware\wireless\openthread\openthread\output\k32w061\bin DK6Programmer.exe -V5 -s COM2 -p ot-rcp.bin Running OpenThread BorderRouter You have connected your Udoo Neo board to an Ethernet cable, just open a new terminal to be sure that you have a connection. You could type the ping 8.8.8.8 command. If you do not have the IPV4, you could access connection your board to your computer and use the USB IP. After that, you could open a browser and enter to the Udoo Neo page using the USB IP. You could use the different address for creating a SSH connection.   Install Docker Copy the Docker image and Bash scripts to the Udoo Board; Install docker; curl -sSl https://get.docker.com | sh; The command will take some time   Verify the Docker images was successfully loaded Launch a Docker container   In this case, the UDOO NEO Extended doesn't have an Ethernet port, so, there is a USB converter to Ethernet. The OpenThread Example requires an IPV6 address sudo ./run_br_container.sh; Note: You have to have Ethernet Connection because the OpenThread requires IPV6. Be sure that the file has the execute permissions. The image below shows the process of the container. You cannot use this terminal, as this is a running Docker instance. It will output logs from the wpantund while it’s running.   Open a new terminal and look at for the container ID     After that, open a browser and search the IPV4 of your UDOO Neo, and you will find an OpenThread web page.     On the left side, select the option form, and a new page will be displayed for the network creation. Then you can ask for the wpanctl status, it will show all the Thread information, the address, the channel of the network, etc. sudo wpanctl status sudo wpanctl getprop Thread:OnMeshPrefixes Node A In the same UDOO terminal, start the border router internal commissioner and allow that a Thread node with the preshared key could join in this network. sudo wpanctl commissioner start; sudo wpanctl commissioner joiner-add “*” 120 J01NME; Node B Flash another JN5189/K32W using the REED example and type the next command for enabling and join to a Thread Network. \K32W061DK6\boards\k32w061dk6\wireless_examples\openthread\reed ifconfig up joiner start J01NME After the joining process is complete, type the next command to attach to the border router. thread start Look at the image below, you will notice the Node B Commands.   Ping the external internet 64:ff9b::808:808 to be sure that you have access to the internet.   For a better reference please look at the OpenThread Demo Applications User Guide included in your SDK documentation. "\K32W061DK6\docs\wireless\OpenThread" 11 Chapter Running Border Router Application Scenarios   Regards, Mario    
View full article
简介: 当 OTAP 客户端(接收软件更新的设备,通常为 Bluetooth LE 外围设备)从 OTAP 服务器 (发送软件更新的设备,通常为 Bluetooth LE Central)请求软件更新时,您可能希望保留一 些数据,例如绑定信息,系统振荡器的匹配值或您的应用程序的 FlexNVM 非易失数据。 本 文档指导您在执行 OTAP 更新时, 如何保留您感兴趣的闪存数据内容。 本文档适用于熟悉 OTAP 定制 Bluetooth LE 服务的开发人员,有关更多基础信息,您可以阅读以下文章: 使用 OTAP 客户端软件对 KW36 设备进行重新编程。 OTAP 标头和子元素 OTAP 协议为软件更新实现了一种格式,该格式由标题和定义数量的子元素组成。 OTAP 标 头描述了有关软件更新的一般信息,并且其定义的格式如下图所示。 有关标题字段的更多 信息,请转至 SDK 中的<SDK_2.2.X_FRDM-KW36_Download_Path> \ docs \ wireless \ Bluetooth 中的《 Bluetooth Low Energy Application Developer's Guide》文档的 11.4.1 Bluetooth Low Energy OTAP 标头一章。   每个子元素都包含用于特定目的的信息。 您可以为您的应用程序实现专有字段(有关子元 素字段的更多信息, 请转至 SDK 中的<SDK_2.2.X_FRDM-KW36_Download_Path> \ docs \ wireless \ Bluetooth 中的《 Bluetooth Low Energy Application Developer's Guide》文档的 11.4.1 Bluetooth Low Energy OTAP 标头一章。 OTAP 包含以下子元素: 镜像文件子元素 值字段长度(字节) 描述 升级镜像 变化 该子元素包含实际的二进制可执行镜像,该镜像将被复制到 OTAP 客户端设备的闪存中。 该子元素的最 大大小取决于目标硬件。 扇区位图 32 该子元素包含目标设备闪存的扇区位图,该位图告诉引导加载程序哪些扇区应被覆盖,哪些扇区保持完 整。 该字段的格式是每个字节的最低有效位在前,最低有效字节和位代表闪存的最低存储部分。 镜像文件CRC 2 是在镜像文件的所有元素(此字段本身除外)上计算的 16 位 CRC。 该元素必须是通过空中发送的镜像文件中的最后一个子元素。   OTAP 扇区位图子元素 KW36 闪存分为: 一个 256 KB 程序闪存( P-Flash)阵列, 最小单元为 2 KB 扇区,闪存地址范围为 0x0000_0000 至 0x0003_FFFF。 一个 256 KB FlexNVM 阵列, 最小单元为 2 KB 扇区,闪存地址范围为 0x1000_0000 至 0x1003_FFFF, 同时它也会被映射到地址范围为 0x0004_0000 至 0x0007_FFFF 的空间。 位图子元素的长度为 256 位,就 KW36 闪存而言,每个位代表 2KB 扇区,覆盖从 0x0- 0x0007_FFFF 的地址范围(P-Flash 到 FlexNVM 映射地址范围),其中 1 表示该扇区应 被擦 除, 0 表示应保留该扇区。 OTAP 引导加载程序使用位图字段来获取在使用软件更新对 KW36 进行编程之前应擦除的地址范围,因此必须在发送软件更新之前对其进行配置,以使包含您 的数据的内存的地址范围保持不变。仅擦除将被软件更新覆盖的地址范围。 例如:假设开发人员想要保留 0x7D800-0x7FFFF 之间的地址范围和 0x0-0x1FFF 之间的地址 范围,并且必须擦除剩余的存储器。 0x7D800-0x7FFFF 之间的地址范围对应于前 5 个闪存 扇区, 0x0-0x1FFF 之间的地址范围是最低的 4 个扇区。 因此,这意味着应将 256 和 252 之间的位(256、 255、 254、 253 和 252)以及 4 和 1 之间 的位(4、 3、 2 和 1)设置为 0,这样本示例的 OTAP 位图为 : 0x07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 使用 NXP 测试工具配置 OTAP 位图以保护地址范围 在恩智浦网站上下载并安装用于连接产品的测试工具   在 PC 上打开 NXP Test Tool 12 软件。 转到“ OTA 更新-> OTAP 蓝牙 LE”,然后单击“浏 览...”按钮加载用于软件更新的映像文件(NXP 测试工具仅接受.bin 和.srec 文件)。 您 可以配置 OTAP 位图,选择“覆盖扇区位图”复选框,并通过新的位图值更改默认值。 配 置位图后,选择“保存...”。   然后,将显示一个窗口,用于选择保存.bleota 文件的目的地,保存文件可以自行取名。 您可以将此文件与 Android 和 iOS 的 IoT Toolbox App 一起使用,以使用 OTAP 更新软 件。 这个新的.bleota 文件包含位图,该位图告诉 OTAP 引导加载程序哪些扇区将被擦 除,哪些扇区将被保留。    
View full article
URL : https://community.nxp.com/docs/DOC-343990 版本:3 最后更新:09-14-2020 更新:EdgarLomeli 介绍 本文档介绍了如何通过无线编程引导加载程序将新的软件镜像加载到KW41 设备中。此外, 还将详细说明如何设置客户端软件以更改镜像文件的存储方式。 软件要求 1. IAR 嵌入式集成开发环境或MCUXpresso IDE 2. 下载两个软件包,SDK FRDM-KW41Z 和SDK USB-KW41Z。 硬件要求 1. FRDM-KW41Z 板 更新过程中的OTAP 内存管理 KW41 具有512KB 程序闪存,其闪存地址范围为0x0000_0000 至0x0007_FFFF。 1. OTAP 应用程序将闪存分为两个独立的部分,即OTAP 引导加载程序(Bootloader)和 OTAP 客户端。OTAP Bootloader 会验证OTAP 客户端上是否有可用的新镜像文件要对 设备进行重新编程。OTAP 客户端软件提供了将OTAP 客户端设备与包含新镜像文件 的OTAP 服务器进行通信所需的Bluetooth LE 自定义服务(OTAP 服务器设备可以是连 接到安装有测试工具的PC 或安装有IoT 工具箱应用的智能手机的另一个FRDM-KW41Z 板)。因此,需要对OTAP 客户端设备进行两次编程,首先编程OTAP Bootloader,然后 编程支持OTAP 客户端的Bluetooth LE 应用程序。为使两个不同的软件共存于同一设备 而使用的方法是将每个软件存储在不同的存储区域中。此功能由链接器文件实现。在 KW41 设备中,引导加载程序已从0x0000_0000 到0x0003_FFF 保留了16 KB 的内存区 域,因此OTAP Client 演示程序保留了其余的内存空间。 2. 要为客户端设备创建新的镜像文件,开发人员需要在链接文件中指定将以16 KB 的偏移 量放置代码,因为必须把最前面的地址空间预留给OTAP Bootloader。 3. 在连接状态下,OTAP 服务器通过蓝牙LE 将镜像数据包(称为块)发送到OTAP 客户 端设备。OTAP 客户端设备可以首先将这些块存储在外部SPI 闪存或片上闪存中。在 OTAP 客户端软件中可以选择代码存储的目的地。 4. 当连接完成,并将所有块都从OTAP 服务器发送到OTAP 客户端设备后,OTAP 客户端 软件会将信息,比如镜像更新的来源(外部闪存或内部闪存)写入称为Bootloader 标 志的内存部分中并复位MCU 以执行OTAP Bootloader 代码。OTAP 引导加载程序 (Bootloader)会读取引导加载程序(Bootloader)标志以获取对设备进行编程所需的信 息,并触发编程以使用新应用程序对MCU 进行重新编程。由于新应用程序的偏移地 址为16 KB,因此OTAP Bootloader 从0x0000_4000 地址开始对设备进行编程,并且 OTAP 客户端应用程序将被新镜像文件所覆盖,因此,通过该方法对设备重新编程后, 将无法二次以同样的方法对设备再次编程。最后,OTAP 引导加载程序(Bootloader) 会触发命令以自动开始执行新代码。 使用IAR 嵌入式开发工具准备软件以测试KW41Z 设备的OTAP 客户端 ⚫ 加载OTAP Bootloader 到FRDM-KW41Z 上。可以通过以下路径从SDK FRDM-KW41Z 中包含的项目中编程OTAP Bootloader 软件,也可以从以下路径中拖放已编译好的二进 制文件。 ⚫ OTAP Bootloader 项目: <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\framework\bootloader_otap\bm\iar\bootloader_otap_bm.eww OTAP Bootloader 已编译好的二进制文件: <SDK_2.2.0_FRDM-KW41Z_download_path>\tools\wireless\binaries\bootloader_otap_frdmkw41z.bin ⚫ 打开位于以下路径的SDK FRDM-KW41Z 中包含的OTAP Client 项目。 <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\otap_client_att\freertos\iar\otap_client_att_freertos.eww ⚫ 自定义OTAP 客户端软件以选择存储方式。在工作区的源文件夹中找到 app_preinclude.h 头文件。 1. 要选择外部闪存存储方式,请将“gEepromType_d”定义为 “gEepromDevice_AT45DB041E_c” 2. 要选择内部闪存存储方式,请将“gEepromType_d”定义为 “gEepromDevice_InternalFlash_c” ⚫ 配置链接标志。打开项目选项窗口(Alt + F7)。在“Linker->Config”窗口中,找到 “Configuration file symbol definitions”窗格。 1. 要选择外部闪存存储方式,请删除“gUseInternalStorageLink_d = 1”链接标志 2. 要选择内部闪存存储方式,请添加“gUseInternalStorageLink_d = 1”链接标志 ⚫ 加载OTAP 客户端软件到FRDM-KW41Z 板上(Ctrl + D).停止调试会话(Ctrl + Shift + D). 项目默认的链接器配置会把OTAP 客户端应用程序存储到相应的内存偏移位置上。 使用MCUXpresso IDE准备软件以测试KW41Z 设备的OTAP 客户端 ⚫ 加载OTAP Bootloader 到FRDM-KW41Z 上。可以通过以下路径从SDK FRDM-KW41Z 中包含的项目中编程OTAP Bootloader 软件,也可以从以下路径中拖放已编译好的二进 制文件。 OTAP Bootloader项目: wireless_examples->framework->bootloader_otap->bm OTAP Bootloader 已编译好的二进制文件 <SDK_2.2.0_FRDM-KW41Z_download_path>\tools\wireless\binaries\bootloader_otap_frdmkw41z.bin • 单击"Quickstart Panel"视窗中的"Import SDK examples(s)"选项 • 双击frdmkw41z 图标 • 打开位于下列路径中包含在SDK FRDM-KW41Z 中的OTAP 客户端项目 wireless_examples->bluetooth->otap_client_att->freertos • 自定义OTAP 客户端软件以选择存储方式。在工作区的源文件夹中找到 app_preinclude.h 头文件。 1. 要选择外部闪存存储方式,请将“gEepromType_d”定义为 “gEepromDevice_AT45DB041E_c” 2. 要选择内部闪存存储方式,请将“gEepromType_d”定义为 “gEepromDevice_InternalFlash_c” • 配置链接文件 1. 若选择外部闪存存储方式,从此时起无需对项目中做任何修改,可跳过此步骤。 2. 若选择内部闪存存储方式,搜索位于下列路径中SDK USB-KW41Z 中的链接文件, 替换OTAP 客户端项目中源文件夹中的默认链接文件。你可以从SDK USB-KW41Z 复制(Ctrl+C ) 链接文件,并直接粘贴(Ctrl + V)在工作区中。这将显示一条警告消息,选择”Overwrite "。 SDK USB-KW41Z 上的链接文件: <SDK_2.2.0_USB-KW41Z_download_path>\boards\usbkw41z_kw41z\wireless_examples\bluetooth\otap_client_att\freertos\MKW41Z512xxx4_connectivity.ld • 保存项目中的更改。在“Quickstart Panel”中选择“Debug”。一旦项目已经加载到 设备上,请停止调试会话。 在IAR 嵌入式工作台中为FRDM-KW41Z OTAP 客户端创建S 记录镜像文件 • 从SDK FRDM-KW41Z 中打开要使用OTAP Bootloader 进行编程的一个无线连接的 项目。本示例是一个使用葡萄糖传感器的项目,该项目位于以下路径。 <SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\glucose_sensor\freertos\iar\glucose_sensor_freertos.eww • 打开项目选项窗口(Alt + F7)。在“Linker->Config”窗口中,在“Configuration file symbol definitions”文本框中添加以下链接标志。 gUseBootloaderLink_d=1 • 转到“Output Converter”窗口。取消选择“Override default”复选框,展开“Output format”组合框,然后选择Motorola S-records 格式,然后单击“确定”按钮。 • 重编译项目。 • 在以下路径中搜索S-Record 文件(.srec)<SDK_2.2.0_FRDM-KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\glucose_sensor\freertos\iar\debug 在MCUXpresso IDE 中为FRDM-KW41Z OTAP 客户端创建S-Record 镜像文件 • 从MCUXpresso IDE 中打开要使用OTAP Bootloader 进行编程的一个无线连接的项 目。本示例是一个使用葡萄糖传感器的项目,该项目位于以下路径。 wireless_examples->bluetooth->glucose_sensor->freertos • 搜索位于以下路径的SDK FRDM-KW41Z 中的链接文件,并替换Glucose Sensor 项 目中源文件夹中的默认链接文件。你可以从SDK FRDM-KW41Z 复制(Ctrl + C) 链接文件,然后直接粘贴(Ctrl + V)到工作区中。这将显示一条警告消息,请选择“Overwrite”。 SDK FRDM-KW41Z 上的链接文件: <SDK_2.2.0_FRDM- KW41Z_download_path>\boards\frdmkw41z\wireless_examples\bluetooth\otap_client_att\freertos\MKW41Z512xxx4_connectivity.ld • 打开新的“MKW41Z512xxx4_connectivity.ld”链接文件。找到下图的段位置,并删除 “FILL”和“BYTE”语句。 • 编译项目。 在工作区中找到“Binaries”图标。在“.axf”文件上单击鼠标右键。选择“Binary Utilities/Create S-Record”选项。S-Record 文件将保存在工作区中带有“.s19”扩展名的 “Debug”文件夹中。 使用IoT Toolbox App 测试OTAP 客户端演示 1. 将通过上一节中的步骤创建的S-Record 文件保存在智能手机中的已知位置。 2. 打开IoT Toolbox App,然后选择OTAP 演示。按“SCAN”开始扫描合适的广告客户。 3. 按下FRDM-KW41Z 板上的“SW4”按钮开始广告。 4. 与找到的设备建立连接。 5. 按“Open”并搜索S-Record 文件 6. 按“Upload”开始传输。 7. 传输完成后,请等待几秒钟,直到引导加载程序(bootloader)完成对新镜像文件 的编程。新的应用程序将自动启动。 标签:KW KW41Z | 31Z | 21Z frdm-kw41
View full article
从 MKW36Z512VHT4 到 MKW36A512VFT4 的软件移植指南 URL:https://community.nxp.com/docs/DOC-345487 由 Edgar Eduardo Lomeli Gonzalez 于 2020-09-14 创建的文档 引言 这篇文章将指导您如何从 MKW36Z512VHT4 移植到 MKW36A512VFT4 MCU。本示例将使用 “信标(beacon)” SDK 示例程序。 SDK 的下载和安装 1- 前往 MCUXpresso 网页:MCUXpresso 网页 2- 使用您的注册帐户登录。 3- 搜索“ KW36A”设备。单击建议的处理器型号,然后单击“Build MCUXpresso SDK”。 4- 点击后将显示另一页面。在“Toolchain / IDE”框中选择“All toolchains”,并提供名称以标 识软件包。然后点击“Download SDK”。   5- 接受许可协议。等待几分钟直到系统将软件包放入您的配置文件中。 单击“下载 SDK 存 档”(Download SDK Archive),下载 SDK,如下图所示。   6- 如果使用了 MCUXpresso IDE,请在“ Installed SDK’s”视图中拖放 KW36A SDK 压缩文件 夹来安装软件包。 至此,您已经下载并安装了 KW36A 芯片的 SDK 软件包。 MCUXpresso IDE 中的软件迁移 1- 在 MCUXpresso 工作区上导入“信标(beacon)”示例。单击“Import SDK examples(s)…” 选项,将出现一个新窗口。然后选择“ MKW36Z512xxx4”,单击 FRDM-KW36 图像。点击 “Next >”按钮。   2- 搜索信标例程并选择您的项目版本(裸机的 bm 或带 freertos 操作系统)。 3- 转到 Project/Properties。展开 C / C ++ Build / MCU 设置,然后选择 MKW36A512xxx4 MCU。单击“Apply and Close”按钮以保存配置。 4- 将 MKW36Z 文件夹重命名为 MKW36A,单击鼠标右键并选择“重命名”。这些是以下内容: framework/DCDC/Interface -> MKW36Z framework/DCDC/Source -> MKW36Z framework/LowPower/Interface -> MKW36Z framework/LowPower/Source -> MKW36Z framework/XCVR -> MKW36Z4 5- 在 MCUXpresso IDE 中打开“Project/Properties”窗口。 转到 C / C ++ Build / Settings,然 后在 Tool Settings 窗口中选择 MCU C Compiler / Includes 文件夹。在创建之前,根据 MKW35 文件夹,编辑与 MKW36 MCU 相关的所有路径。结果类似如下所示: ../framework/LowPower/Interface/MKW36A ../framework/LowPower/Source/MKW36A ../framework/DCDC/Interface/MKW36A ../framework/XCVR/MKW36A4  6- 在工具设置中选择 MCU Assembler/General 文件夹。 编辑与 MKW36 MCU 相关的路径。 结果类似如下所示: ../framework/LowPower/Interface/MKW36A ../framework/LowPower/Source/MKW36A ../framework/DCDC/Interface/MKW36A ../framework/XCVR/MKW36A4 7- 转到 Project/Properties。展开 MCU CCompiler/Preprocessor 窗口。编辑 “ CPU_MKW36Z512VHT4”和“ CPU_MKW36Z512VHT4_cm0plus”符号,分别将其重命名为 “ CPU_MKW36A512VFT4”和“ CPU_MKW36A512VFT4_cm0plus”。保存更改。 8- 转到工作区。删除位于 CMSIS 文件夹中的“ fsl_device_registers,MKW36Z4, MKW36Z4_features,system_MKW36Z4.h 和 system_MKW36Z4.c”文件。然后解压缩 MKW35Z SDK 软件包并在以下路径中搜索“ fsl_device_registers,MKW36A4,MKW36A4_features, system_MKW36A4.h 和 system_MKW36A4.c”文件到该文件夹中: <SDK_folder_root>/devices/MKW36A4/fsl_device_registers.h <SDK_folder_root>/devices/MKW36A4/MKW36A4.h <SDK_folder_root>/devices/MKW36A4/MKW36A4_features.h <SDK_folder_root>/devices/MKW36A4/system_MKW36A4.h <SDK_folder_root>/devices/MKW36A4/system_MKW36A4.c 9- 通过位于路径<SDK_folder_root> /devices/MKW36A4/mcuxpresso/startup_mkw36a4.c 中的“ startup_mkw36a4.c”覆盖“ startup_mkw36z4.c”(位于启动文件夹中)。 您只需拖放 启动文件夹,然后删除较旧的文件夹即可。 10- 在 CMSIS 文件夹中打开“ fsl_device_registers.h”文件。在以下代码(文件的第 18 行)中 添加“ defined(CPU_MKW36A512VFT4)”: 11- 在 bluetooth->host->config 文件夹中打开“ ble_config.h”文件。在以下代码中添加 “ defined(CPU_MKW36A512VFT4)”(文件的第 146 行): 12- 在 source-> common 文件夹中打开“ ble_controller_task.c”文件。在以下代码(文件的 第 272 行)中添加“ defined(CPU_MKW36A512VFT4)”: 13-生成项目。 至此,该项目已经在 MCUXpresso IDE 环境中移植完成。 IAR Embedded Workbench IDE 中的软件移植 1- 打开位于以下路径的信标项目: 2- 在工作区中选择项目,然后按 Alt + F7 打开项目选项。 3- 在 General Options/Target”窗口中,单击器件名称旁边的图标,再选择合适的器件 NXP / KinetisKW / KW3x / NXP MKW36A512xxx4,然后单击“确定”按钮。 4- 在以下路径中创建一个名为 MKW36A 的新文件夹: <SDK_root>/middleware/wireless/framework_5.4.6/DCDC/Interface <SDK_root>/middleware/wireless/framework_5.4.6/DCDC/Source <SDK_root>/middleware/wireless/framework_5.4.6/LowPower/Interface <SDK_root>/middleware/wireless/framework_5.4.6/LowPower/Source <SDK_root>/middleware/wireless/framework_5.4.6/XCVR   5- 复制位于上述路径的 MKW36Z 文件夹内的所有文件,然后粘贴到 MKW36A 文件夹中。   6- .在工作区中选择信标项目,然后按 Alt + F7 打开项目选项窗口。 在“ C/C++ Compiler/Preprocessor”窗口中,将所有路径里的 MKW36Z 文件夹重命名为 MKW36A 文件 夹。在已定义的符号文本框中,将 CPU_MKW36Z512VHT4 宏重命名为 CPU_MKW36A512VFT4。结果如下图所示:单击确定按钮。 7- 展开启动文件夹,选择所有文件,单击鼠标右键,然后选择“Remove”选项。在文件夹上 单击鼠标右键,然后选择““Add/Add files”。添加位于以下路径的 startup_MKW36A4.s: <SDK_root>/devices/MKW36A4/iar/startup_MKW36A4.s 另外,将 system_MKW36A4.c 和 system_MKW36A4.h 添加到启动文件夹中。 这两个文件都 位于如下的路径中: 8- 在 bluetooth->host->config 文件夹中打开“ ble_config.h”文件。在以下代码中添加 “ defined(CPU_MKW36A512VFT4)”: 9- 在 source-> common 文件夹中打开“ ble_controller_task.c”文件。在以下代码中添加 “ defined(CPU_MKW36A512VFT4)”: 10-生成项目。 至此,该项目已经在 IAR Embedded Workbench IDE 环境中移植完成。          
View full article
Symptoms In the KW36 SDK, there is an API bleResult_t Controller_SetTxPowerLevel(uint8_t level, txChannelType_t channel) to set the Tx power, but the unit of param[in] level is not dBm. But how do we set a Tx power in dBm? Diagnosis By going through the source code, we found that two conversions are required between the actual dBm and the set value of the API. One is PA_POWER to Transmit Output Power conversion table:     Other is Level to PA_POWER  conversion table: .tx_power[0] = 0x0001, .tx_power[1] = 0x0002, .tx_power[2] = 0x0004, .tx_power[3] = 0x0006, .tx_power[4] = 0x0008, .tx_power[5] = 0x000a, .tx_power[6] = 0x000c, .tx_power[7] = 0x000e, .tx_power[8] = 0x0010, .tx_power[9] = 0x0012, .tx_power[10] = 0x0014, .tx_power[11] = 0x0016, .tx_power[12] = 0x0018, .tx_power[13] = 0x001a, .tx_power[14] = 0x001c, .tx_power[15] = 0x001e, .tx_power[16] = 0x0020, .tx_power[17] = 0x0022, .tx_power[18] = 0x0024, .tx_power[19] = 0x0026, .tx_power[20] = 0x0028, .tx_power[21] = 0x002a, .tx_power[22] = 0x002c, .tx_power[23] = 0x002e, .tx_power[24] = 0x0030, .tx_power[25] = 0x0032, .tx_power[26] = 0x0034, .tx_power[27] = 0x0036, .tx_power[28] = 0x0038, .tx_power[29] = 0x003a, .tx_power[30] = 0x003c, .tx_power[31] = 0x003e, The input parameter 'level' of the API is the subscript of this array. The array value is PA_POWER of first conversion table, then we can find the final Tx power. From another perspective, the parameter 'level' is the index of the first table.   Solution The following demonstrates a conversion process.  
View full article
The radio certification has been performed on JN5189, QN9090 and K32W products. The certificates or declaration of conformity are available in attached files.   And click here to know more on the best way to build a PCB the first time right with K32W061, QN9090 or JN5189 ! 
View full article