Wireless Connectivity Knowledge Base

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

Wireless Connectivity Knowledge Base

Discussions

Sort by:
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
Please find here all the information needed to build your own PCB based on K32W061/041(AM/A), QN9090/9030(T) or JN5189/5188(T). Your first task before to send any inquiry to NXP support is to fill the K32W Design In CHECK LIST available in this ticket.   K32W061 Manufacturing package  Find here all the product pages, most of the HW documents are in the corresponding platforms web pages: K32W061/041 (AM/A) QN9090/9030(T) JN5189/5188(T)   The K32W EVK getting started webpage: IOT_ZTB-DK006 Get started page (nxp.com) IoT_ZTB getting started manual (nxp.com)   HW: HW design consideration : JN-RM-2078-JN5189-Module-Development_1V4.pdf (see attached file) JN-RM-2079-QN9090-Module-Development_1V0.pdf (see attached file) JN-RM-2080-K32W-Module-Development_1V0.pdf (see attached file)   Radio: RF report:  JN5189: https://www.nxp.com/docs/en/application-note/AN12154.pdf (nxp.com) QN9090: https://www.nxp.com/docs/en/nxp/application-notes/AN12610.pdf (nxp.com) K32W: https://www.nxp.com/docs/en/application-note/AN12798.pdf (nxp.com) Antenna: https://www.nxp.com/docs/en/application-note/AN2731.pdf (nxp.com)   Low Power Consumption:  JN5189: https://www.nxp.com/docs/en/application-note/AN12898.pdf (nxp.com) QN9090: https://www.nxp.com/docs/en/application-note/AN12902.pdf (nxp.com) K32W: https://www.nxp.com/docs/en/application-note/AN12846.pdf (nxp.com) A power calculator tool is available here: https://community.nxp.com/t5/Connectivity-Support-QN-JN-KW/QN9090-Bluetooth-LE-Power-Profile-Calculator-Tool/ta-p/1209602 SW tools: Customer Module Evaluation Tool  (nxp.com) Bluetooth Low Energy Certification Tool (nxp.com) K32W041/K32W061/QN9090(T)/QN9030(T) Bluetooth Low Energy Certification Tool User's Guide (nxp.com)     Certification: Certificates/Declarations of conformity (nxp community)  
View full article
In the process of practical application, customers often need the combination of ble + NFC. At present, our IOT-DK006 is the only development board with NFC module. But the NFC example is not perfect. So we porting the library of NFC reader- PN7150, to support KW series microcomputer so that KW series can handle the demand of ble + NFC function. Now I will introduce you how to port the NFC lib to KW. 1 PN7150 Introduction PN7150 is the high-performance version of PN7120, the plug’n play NFC solution for easy integration into any OS environment, reducing Bill of Material (BOM) size and cost. PN71xx controllers are ideal for home-automation applications such as gateways and work seamlessly with NFC connected tags. 2 Tools hardware:FRDM-KW36,PN7150 , some wire software:mcuxpresso11.3 package:NXP-NCI MCUXpresso example Project This package contains the nfc library and example that we need. We will refer the ‘NXPNCI-K64F_example’ firstly. Sdk version: 2.2.8, Example: frdmkw36_rtos_examples_freertos_i2c  3 Steps Hardware part:We need connect the PN7150 to KW36 like the picture. Although we can connect the PN7150 to board through the ardunio connector, the pin’s voltage is not enough to drive the PN7150. So we need a wire connected to U1 to get 3.3V.   PN7150 FRDM-KW36 VBAT/PVDD 3.3V VANT 5V GND GND IRQ PTA16 VEN PTC15 SCL PTB0,I2C0 SDA PTB1,I2C0 Software part:We should add the nfc library and directory into our project. You can check the following picture to know what file is necessary. If you want to know how to add directory into our project, you can refer this link. The red line shows what file we need. Please notice that when we add file path into the mcuxpresso configuration, we also need add the path into ‘Path and Symbols’ .   We need add some macro into ‘Preprocessor’.   We copy the NXPNCI-K64F_example’s main file content into our ‘freertos_i2c.c’. Next, we need modify the file pin_mux.c, tml.c and board.h   In file board.h,add the following macro. Don't forget to enable the pin clock. /* NXPNCI NFC related declaration */ #define BOARD_NXPNCI_I2C_INSTANCE I2C0 #define BOARD_NXPNCI_I2C_BAUDRATE (100000) #define BOARD_NXPNCI_I2C_ADDR       (0x28) #define BOARD_NXPNCI_IRQ_PORTIRQn PORTA_IRQn #define BOARD_NXPNCI_IRQ_GPIO     (GPIOA) #define BOARD_NXPNCI_IRQ_PORT     (PORTA) #define BOARD_NXPNCI_IRQ_PIN      (16U) #define BOARD_NXPNCI_VEN_GPIO     (GPIOC) #define BOARD_NXPNCI_VEN_PORT     (PORTC) #define NXPNCI_VEN_PIN            (5U)     In file pin_mux.c, add head file ‘board.h’. Add the following code in function ’ BOARD_InitPins’. The step is to configure the VEN, IRQ and I2C0. This example contains the I2C1’s code, you can comment them.     /* Initialize NXPNCI GPIO pins below */   /* IRQ and VEN PIN_MUX Configuration */   PORT_SetPinMux(BOARD_NXPNCI_IRQ_PORT, BOARD_NXPNCI_IRQ_PIN, kPORT_MuxAsGpio);   PORT_SetPinMux(BOARD_NXPNCI_VEN_PORT, NXPNCI_VEN_PIN, kPORT_MuxAsGpio);   /* IRQ interrupt Configuration */   NVIC_SetPriority(BOARD_NXPNCI_IRQ_PORTIRQn, 6);   EnableIRQ(BOARD_NXPNCI_IRQ_PORTIRQn);   PORT_SetPinInterruptConfig(BOARD_NXPNCI_IRQ_PORT, BOARD_NXPNCI_IRQ_PIN, kPORT_InterruptRisingEdge);   Finally, in file tml.c, modify PORTC_IRQHandler as PORTA_IRQHandler We finished all steps. 4 Results We use ntag to test the reading and writing operation.   When the tag is closed to the PN7150, we will get the following message.   The text recording is ‘VER=03’. Next, we will modify the text recording We need add the new macro to preprocessor.   We can modify the variable NDEF_MESSAGE in function task_nfc_reader to modify the text recording.   Then we download the program again. We will see the original text ‘VER=03’ and the text has been modified. Then we read the tag again. We will see the new text.   If we want to send the larger text, what should we do? We need modify the macro ‘ADD’. When only 4 characters are sent, ‘ADD’ is 0. And every additional character is added, the ‘ADD’ will add. We modify the tag as ‘Ver=03’, and we have two more characters. So ‘ADD’ needs to be defined as 2   It firstly shows the text ‘Test’. Then it will show the new text ‘Ver=03’. Other tags’ reading and writing operation can be enabled by defining some macro.      
View full article
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.
View full article
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 AN12459 Power Consumption Analysis - FRDM-KW38 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) 10 different deep sleep modes Different Tx output power (0dBm, +3.5dBm or +5dBm) Data rate (1Mbps, 2Mbps, 500kbps, 125kbps) 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 9 typical batteries.
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
This document describes a simple process for enabling the user controls the radio through serial commands. Hardware requirements: • FRDM-KW41Z/QN902x board or a board programmed with HCI black box application. Software requirements: • Test Tool 12 application. It can be downloaded from the NXP web page. • HCI Black Box binary.   Running Demo 1. Load the board with hci_black_box example. 2. Open the Test Tool 12 software 3. Set up the correct Serial Configuration. If there were no changes in the application the default configuration will correspond to the one showed in the following figure. 4. Double click on the active device that you want to test, this will open the COM port in the command console. 5. Set the command set to the BLE_HCI.xml. This file has a list of the HCI commands that the user can send to the device, some of the commands have some options to be configured if necessary or some data to be filled. 6. To make easier the use of frequent commands, there is the option to add a shortcut to the command and the chosen behavior will be added to the panel. 7. Once you add the shortcut or choose the command or your preference, just double click over it and the tool will send the command to the device. In this case, we will send a reset on the board, this command does not receive any extra parameters, data or need any extra configuration.   8. If successful there will be a response or acknowledge of the behavior that will be shown in the right panel. Hope it helps. Regards, Mario
View full article
The homologation requirements in China (MIIT [2002]353) obviously are planned (end of December 2022) to be sharpened (MIIT publication from 2021-01-27: “Notice on Matters Related to Radio Management in the 2400MHz, 5100MHz and 5800MHz Bands”).   A modification register is need on the KW38 and KW36 to pass the new Chinese  requirement with acceptable margin: PA_RAMP_SEL value must be set to 0x02h (2us) instead of 0x01h (1us default value) Modification SW: XCVR_TX_DIG_PA_CTRL_PA_RAMP_SEL(2) in the nxp_xcvr_common_config.c All the details are in the attached file.   Note: This SW modification is for China country only.
View full article
This example of custom profile uses the Temperature Sensor and Temperature Collector examples as a base, so it can be easily modified. Both examples are in the SDK, so this document explains 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) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules. GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations. 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. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors defined attributes that describe a characteristic value.    To define a GATT Database several macros are provided by the GATT_DB API in the Freescale BLE Stack, which is part KW38 SDK. Server (Sensor)  First, we need to use the Temperature Sensor project as a base, to create our Humidity Custom Profile Server (Sensor). BLE SIG profiles To know if the Profile or service is already defined in the specification, you have to look for in Bluetooth SIG profiles 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 next:   /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d 0x2A6F   GATT Database The Humidity Sensor is going to have the GATT Server, because is going to be the device that has all the information for the GATT Client. On the Temperature Sensor demo have the Battery Service and Device Information, so you only have to change the Temperature Service to Humidity Service    In order to create the demo we need to define or develop a service that has to be the same as in the GATT Client, this is declared in the gatt_uuid128.h.If the new service is not the same, they will never be able to communicate each other. All macros, function or structure in SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uuid128.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)   All the Service and Characteristics is declared in gattdb.h. Descriptors are declared after the Characteristic Value declaration but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units of the Humidity Characteristic is on Percentage that is 0x27AD. Client Characteristic Configuration Descriptor (CCCD) is a descriptor where clients write some of the bits to activate Server notifications and/or indications.   PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity) CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c)) VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25) DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00) CCCD(cccd_humidity)   After that, create a folder humidity in the next path ${workspace_loc:/${ProjName}/bluetooth/profiles. Found the temperature folder, copy the temperature_service.c and paste inside of the humidity folder with another name (humidity_service.c). Then go back and look for the interface folder, copy temperature_interface.h and change the name (humidity_interface.h) in the same path. You need to include the path of the created folder. Project properties>C/C+ Build>Settings>Tool Settings>MCU C Compiler>Includes: Humidity Interface The humidity_interface.h file should have the following code. The Service structure has the service handle, and the initialization value.   /*! Humidity Service - Configuration */ typedef struct humsConfig_tag { uint16_t serviceHandle; int16_t initialHumidity; } humsConfig_t; /*! 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 on humidity_service.c file, should have the following code. The service stores the device identification for the connected client. This value is changed on subscription and non-subscription events.   /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId;   The initialization of the service is made by calling the start procedure. This function is usually called when the application is initialized. In this case is on the BleApp_Config().   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); }   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; }   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; }   Depending on the complexity of the service, the API will implement additional functions. For the Humidity Sensor only have a one characteristic. The measurement will be saving on the GATT database and send the notification to the client. This function will need the service handle and the new value as input parameters.   bleResult_t Hums_RecordHumidityMeasurement(uint16_t serviceHandle, int16_t humidity) { uint16_t handle; bleResult_t result; bleUuid_t uuid = Uuid16(gBleSig_Humidity_d); /* Get handle of Humidity characteristic */ result = GattDb_FindCharValueHandleInService(serviceHandle, gBleUuidType16_c, &uuid, &handle); if (result != gBleSuccess_c) return result; /* Update characteristic value */ result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t*) &humidity); if (result != gBleSuccess_c) return result; Hts_SendHumidityMeasurementNotification(handle); return gBleSuccess_c; }   After save the measurement on the GATT database with GattDb_WriteAttribute function we send the notification. To send the notification, first have to get the CCCD and after check if the notification is active, if is active send the notification.   static void Hts_SendHumidityMeasurementNotification ( uint16_t handle ) { uint16_t hCccd; bool_t isNotificationActive; /* Get handle of CCCD */ if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd) != gBleSuccess_c) return; if (gBleSuccess_c == Gap_CheckNotificationStatus (mHums_SubscribedClientId, hCccd, &isNotificationActive) && TRUE == isNotificationActive) { GattServer_SendNotification(mHums_SubscribedClientId, handle); } }   Humidity Sensor Main file There are some modifications that have to be done, to use the new Humidity profile in our sensor example. First, we need to declare the humidity service:   static humsConfig_t humsServiceConfig = {(uint16_t)service_humidity, 0};   Then, we need to add or modify the following functions: BleApp_Start You need to modify this line:   /* Device is connected, send humidity value */ BleApp_SendHumidity();   BleApp_Config You need to start the Humidity Service, and to modify the PrintString line:   humsServiceConfig.initialHumidity = 0; (void)Hums_Start(&humsServiceConfig);     AppPrintString("\r\nHumidity sensor -> Press switch to start advertising.\r\n");   BleApp_ConnectionCallback There are some modifications required in two Connection Events. gConnEvtConnected_c   (void)Hums_Subscribe(peerDeviceId); gConnEvtDisconnected_c   gConnEvtDisconnected_c   (void)Hums_Unsubscribe();   BleApp_GattServerCallback   /* Notify the humidity value when CCCD is written */ BleApp_SendHumidity()   BleApp_SendHumidity And, we need to add this function:   static void BleApp_SendHumidity(void) { (void)TMR_StopTimer(appTimerId); /* Update with initial humidity */ (void)Hums_RecordHumidityMeasurement((uint16_t)service_humidity, (int16_t)(BOARD_GetTemperature())); #if defined(cPWR_UsePowerDownMode) && (cPWR_UsePowerDownMode) /* Start Sleep After Data timer */ (void)TMR_StartLowPowerTimer(appTimerId, gTmrLowPowerSecondTimer_c, TmrSeconds(gGoToSleepAfterDataTime_c), DisconnectTimerCallback, NULL); #endif }   In this example, the Record Humidity uses the BOARD_GetTemperature, to use the example without any external sensor and to be able to see a change in the collector, but, in this section would be a GetHumidity function. Client (Collector)  First, we need to use the Temperature Collector project as a base, to create our Humidity Custom Profile Client (Collector). BLE SIG profiles The same applies for the Client. To know if the Profile or service is already defined in the specification, you have to look for in Bluetooth SIG profiles 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 next:   /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d 0x2A6F   GATT Database The Humidity Collector is going to have the GATT client; this is the device that will receive all information from  the GATT server. Demo provided in this post works like the Temperature Collector. When the Collector enables the notifications from the sensor, received notifications will be printed in the serial terminal. In order to create the demo we need to define or develop a service that has to be the same as in the GATT Server, this is declared in the gatt_uuid128.h.If the new service is not the same, they will never be able to communicate each other. All macros, function or structure in SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uuid128.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)   After that, copy the humidity profile folder from the Sensor project, to the Collector project ${workspace_loc:/${ProjName}/bluetooth/profiles. And also for this project, include the path of the new folder. Project properties>C/C+ Build>Settings>Tool Settings>MCU C Compiler>Includes: Humidity Collector Main file In the Collector source file, we need to do also some modifications, to use the Humidity Profile. First, we need to modify the Custom Information of the Peer device:   humcConfig_t humsClientConfig;   BleApp_StoreServiceHandles   static void BleApp_StoreServiceHandles ( gattService_t *pService ) { 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 Humudity 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; } } } } } } }   BleApp_StoreDescValues   if (pDesc->handle == mPeerInformation.customInfo.humsClientConfig.hHumDesc) { /* Store Humidity format*/ FLib_MemCpy(&mPeerInformation.customInfo.humsClientConfig.humFormat, pDesc->paValue, pDesc->valueLength); }   BleApp_PrintHumidity   /*www.bluetooth.com/specifications/assigned-numbers/units */ if (mPeerInformation.customInfo.humsClientConfig.humFormat.unitUuid16 == 0x27ADU) { AppPrintString(" %\r\n"); } else { AppPrintString("\r\n"); }   BleApp_GattNotificationCallback   if (characteristicValueHandle == mPeerInformation.customInfo.humsClientConfig.hHumidity) { BleApp_PrintHumidity(Utils_ExtractTwoByteValue(aValue)); }    CheckScanEvent   foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);   BleApp_StateMachineHandler mAppIdle_c   if (mPeerInformation.customInfo.humsClientConfig.hHumidity != gGattDbInvalidHandle_d)   mAppServiceDisc_c   if (mPeerInformation.customInfo.humsClientConfig.hHumDesc != 0U) mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumDesc;   mAppReadDescriptor_c   if (mPeerInformation.customInfo.humsClientConfig.hHumCccd != 0U)   BleApp_ConfigureNotifications   mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumCccd;   Demonstration Now, after connection, every time that you press the SW3 on KW38 Humidity Sensor is going to send the value to KW38 Humidity Collector.  
View full article
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).
View full article
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.
View full article
Introduction   This post explains how to create a BLE GATT database using FSCI commands sent to the BLE Server device. Additionally, this document explains how to set up the fields of each FSCI command used to create the BLE GATT database for the BLE Server.   Main FSCI commands to create the BLE GATT DB in the BLE Server device   The following, are the main commands to create, write and read the GATT DB from the BLE Server perspective. The purpose of this post is to serve as a reference and summary of the most important commands. The full list of commands FSCI commands can be found in the Framework Serial Connectivity Interface (FSCI) for Bluetooth Low Energy Host Stack documentation within your SDK package. GATT-InitRequest This command is used to initialize the GATT database at runtime, and it must be sent before any other command to declare a database in your BLE Server device. GATTServer-RegisterCallback.Request This command installs an application callback for the GATT Server module, enabling the device to respond to the FSCI request from the CPU application through an FSCI indication. GATTDBDynamic-AddPrimaryServiceDeclaration.Request It adds a primary service to the database. It has 3 parameters that should be configured, the desired handle, the UUID type (16 bits, 32 bits, 128 bits), and the UUID value. Usually, the desired handle should be set to zero and the stack will assign the handle of the primary service automatically.   If the GATT application callback was installed through the GATTServer-RegisterCallback.Request command, the GATT Server responds to the GATTDBDynamic-AddPrimaryServiceDeclaration.Request command with a GATTDBDynamic-AddPrimaryServiceDeclaration.Indication that contains the handle assigned to the primary service. The following example shows how to prepare this command to define the battery service in the database. GATTDBDynamic-AddCharacteristicDeclarationAndValue.Request It adds a characteristic and its value to the database. It has 7 parameters that should be configured, the UUID type (16 bits, 32 bits, 128 bits), the UUID value, characteristic properties, the maximum length of the value (only for variable-length values), the initial length of the value, the initial value of the characteristic and value access permissions. The characteristic declared using this command, belongs to the last primary service declared in the database. For values with a fixed length, the maximum length parameter should be set to 0, and the length is obtained from the initial length of the value parameter.   If the GATT application callback was installed, the response of this command is indicated by the GATTDBDynamic-AddCharacteristicDeclarationAndValue.Indication command. The following example shows how to prepare this command to define the battery level characteristic in the database with a fixed length of 1 byte and an initial value of 90%. GATTDBDynamic-AddCharacteristicDescriptor.Request It adds a characteristic descriptor to the database. It has 5 parameters that should be configured, the UUID type (16 bits, 32 bits, 128 bits), UUID value, length of the descriptor value, descriptor’s value, and descriptor access permissions. The descriptor declared using this command, belongs to the last characteristic declared in the database.   If the GATT application callback was installed, the response of this command is indicated by the GATTDBDynamic-AddCharacteristicDescriptor.Indication command. The following example shows how to prepare this command to add the characteristic presentation format descriptor of the battery level characteristic in the database.   GATTDBDynamic-AddCccd.Request It adds a CCDD into the database. This command does not have parameters. The CCCD declared using this command, belongs to the last characteristic declared in the database. The response of this command is indicated by GATTDBDynamic-AddCccd.Indication.   GATTDB-FindServiceHandle.Request This command is used to find the handle of a service previously declared in the database. It has 3 parameters that should be configured, the handle to start the search (should be 1 on the first call), the UUID type of the service to find (16 bits, 32 bits, 128 bits), and the UUID value of the service that you are searching.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindServiceHandle.Indication command, which contains the handle of the found service. The following example shows how to prepare this command to find the handle of the battery service declared in the previous examples. Notice that the result of the search corresponds to the handle returned by the GATTDBDynamic-AddPrimaryServiceDeclaration.Indication as expected.   GATTDB-FindCharValueHandleInService It finds the characteristic´s handle of a given service previously declared in the database. It has 3 parameters that should be configured, the handle of the service that contains the characteristic, the UUID type of the characteristic to find (16 bits, 32 bits, 128 bits), and the UUID value of the characteristic that you are searching for.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindCharValueHandleInService.Indication command, which contains the handle of the found characteristic’s value. The following example shows how to prepare this command to find the handle of the battery level value. Notice that the result of the search corresponds to the handle returned by the GATTDBDynamic-AddCharacteristicDeclarationAndValue.Indication plus one, because the AddCharacteristicDeclarationAndValueIndication command returns the handle of the characteristic and, on the other hand, FindCharValueHandleInService returns the handle of the characteristic’s value. GATTDB-FindDescriptorHandleForcharValueHandle.Request It finds the descriptor´s handle of a given characteristic previously declared in the database. It has 3 parameters that should be configured, the handle of the characteristic’s value that contains the descriptor, the UUID type of the descriptor to find (16 bits, 32 bits, 128 bits), and the UUID value of the descriptor that you are searching.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindDescriptorHandleForCharValueHandle.Indication command, which contains the handle of the found descriptor. The following example shows how to prepare this command to find the handle of the characteristic presentation format descriptor. The result corresponds to the handle returned by the GATTDBDynamic-AddCharacteristicDescriptor.Indication   GATTDB-FindCccdHandleForCharValueHandle.Request It finds the CCCD’s handle of a given characteristic previously declared in the database. It has only one parameter, the handle of the characteristic’s value that contains the CCCD.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindCccdHandleForCharValueHandle.Indication command, which contains the handle of the found CCCD. The following example shows how to prepare this command to find the handle of CCCD. The result corresponds to the handle returned by the GATTDBDynamic-AddCccd.Indication.   GATTDB-WriteAttribute.Request It writes the value of a given attribute from the application level. It has 3 parameters that should be configured, the handle of the attribute that you want to write, the length of the value in bytes, and the new value.   In the following example, we will modify the battery level characteristic’s value from 90% to 80%.   GATTDB-ReadAttribute.Request   It reads the value of a given attribute from the application level. It has 2 parameters that should be configured, the handle of the attribute that you want to read, and the maximum bytes that you want to read. The GATT application callback must be installed, since the response of this command indicated by the GATTDB-ReadAttribute.Indication command contains the value read from the database. In the following example, we will read the battery level characteristic’s value, the result is 80%.      
View full article
Introduction This document is a quick start guide to load a new software image in a KW36 device through FSCI (Freescale Serial Communication Interface) bootloader software. Also, it contains all the steps needed to install the software required in a Windows host to handle the FSCI communication protocol. Software Requirements IAR Embedded Workbench IDE or MCUXpresso IDE. FRDM-KW36 SDK. Hardware Requirements FRDM-KW36 board. Downloading the SDK When downloading the SDK, select your specific IDE or simply choose all toolchains as shown below. In the option "Add software component", ensure to select all middleware components as depicted below. Installing FSCI Host in Windows OS The host software for the Windows OS was designed to work in a Python environment. The following steps are to download and install the software needed to use FSCI in a Windows OS. Visit the Python web site and download the latest Python 2.7.x MSI installer package for Windows OS. Open the MSI installer package. When customizing the installation options, check "Add python.exe to Path" as shown below Complete the rest of the steps for the Python installation process. Unzip the FRDM-KW36 SDK. Depending on your Python environment architecture, copy the HSDK.dll from <SDK_root>\tools\wireless\host_sdk\sdk-python\lib\<x86_or_x64> to <Python_directory>\DLLs (default in C:\Python27\DLLs). Download and install Visual C++ Redistributable Packages for Microsoft Visual Studio 2013 depending on the Windows architecture (vcredist_x86.exe or vcredist_x64.exe) from the Microsoft web site. Download and install the Microsoft Visual C++ Compiler for Python 2.7 from the following web site. To run Python scripts from the Command Prompt of Windows, we must create a system variable named PYTHONPATH. Search “System” in the Windows browser. Go to Advanced system settings -> Environment Variables… -> System variables. Click on the “New…” button and create the PYTHONPATH variable with the following value: <SDK_root>\tools\wireless\host_sdk\hsdk-python\src. Programming the FSCI bootloader on FRDM-KW36 board Attach the FRDM-KW36 board to your PC. Drag and drop the “bootloader_fsci_frdmkw36.bin” from the previously unzipped SDK file, you can find this file in: <SDK_root>\tools\wireless\binaries to your board. Like a common USB device. Creating a binary image to reprogram the device   IAR Embedded Workbench Open the connectivity project that you want to program through the FSCI bootloader from your SDK. This example will make use of the heart rate sensor project, located at the following path: <SDK_root>\boards\frdmkw36\wireless_examples\bluetooth\hrs\freertos\iar\hrs_freertos.eww. Open the project options window (Alt+F7). In Linker -> Config window, edit the “Configuration file symbol definitions” add the “gUseBootloaderLink_d=1” linker flag as shown below. Go to the “Output Converter” window and ensure that the output file is in binary format (.bin), otherwise, deselect the “Override default” checkbox, expand the “Output format” combo box and select “Raw binary. Click the OK button. Rebuild the project. The binary will be saved at: <SDK_root>\boards\frdmkw36\wireless_examples\bluetooth\hrs\freertos\iar\debug   MCUXpresso IDE Import your FRDM-KW36 SDK to MCUXpresso. Drag and drop your SDK on the "installed SDK's" toolbar. (In this step, it is not necessary to unzip the package). Open any connectivity project that you want to program through the FSCI bootloader from your SDK. This example will make use of the heart rate sensor project. Go to Project -> Properties, a new window will appear. Then, open the C/C++ Build -> Settings -> Linker -> Miscellaneous. Press the icon below, a new window will be deployed. Add “--defsym=gUseBootloaderLink_d=1”. Click on “Apply and Close”. Build the project. Deploy the “Binaries” icon in the workspace. Click the right mouse button on the “.axf” file. Select “Binary Utilities -> Create binary” option. The binary file will be saved at “Debug” folder in the workspace with “.bin” extension. Reprogramming an FRDM-KW36 board using the FSCI bootloader The following steps are to test the FSCI bootloader in a Windows OS. Search "Command Prompt" in the Windows browser. Run the "fsci_bootloader.py" Python script. Type the “python.exe” path in the console (default C:\Python27\python.exe). Drag and drop the “fsci_bootloader.py” from: <SDK_root>\tools\wireless\host_sdk\hsdk-python\src\com\nxp\wireless_connectivity\test\bootloader on the command prompt screen. Search the COM Port of your FRDM-KW36 board and type in the console. You can find it typing ‘Device manager’ from windows home and then search it in Ports (COM & LPT) toolbar. As you can see in this example the port may change depending on each case. Search the binary image file (created in the last section). Drag and drop on the screen. Press “Enter” to start the firmware update trough FSCI bootloader. Automatically the KW36 device will trigger to run the new software. To see all your process running, you can download the ‘IoT Toolbox’ from the app store to your smartphone and connect your device with the board to verify the random data that the heart rate sensor example generates.
View full article
Introduction When a software update is requested by an OTAP Client (a device that receives a software update, commonly Bluetooth LE Peripheral) from the OTAP Server (a device that sends a software update, commonly Bluetooth LE Central), you may want to preserve some data previously acquired, such as bonding information, trimming values for the system oscillators, or probably NVM data for your application. This document guides you in performing OTAP updates preserving the flash data content of your interest. This document is intended for developers familiarized with OTAP custom Bluetooth LE service, for more information, you can take a look at the following post: Reprogramming a KW36 device using the OTAP Client Software.   OTAP Header and Sub-elements OTAP Protocol implements a format for the software update that is composed of a header and a defined number of sub-elements. The OTAP Header describes general information about the software update and it has a defined format shown in the following figure. For more information about the header fields, you can go to 11.4.1 Bluetooth Low Energy OTAP header chapter of the Bluetooth Low Energy Application Developer's Guide document included in the SDK at <SDK_2.2.X_FRDM-KW36_Download_Path>\docs\wireless\Bluetooth                              Each Sub-element contains information for a specific purpose. You could implement your proprietary fields for your application (For more information about sub-element fields, you can go to 11.4.1 Bluetooth Low Energy OTAP header chapter of the Bluetooth Low Energy Application Developer's Guide document included in the SDK at <SDK_2.2.X_FRDM-KW36_Download_Path>\docs\wireless\Bluetooth). OTAP includes the following sub-elements: Image File Sub-element Value Field Lenght (bytes) Description Upgrade Image  Variable This sub-element contains the actual binary executable image which is copied into the flash memory of the OTAP Client device. The maximum size of this sub-element depends on the target hardware. Sector Bitmap 32 This sub-element contains a sector bitmap of the flash memory of the target device which tells the bootloader which sectors should be overwritten and which leave intact. The format of this field is the least-significant bit first for each byte with the least significant bytes and bits standing for the lowest memory sections of the flash.  Image File CRC 2 This is a 16-bit CRC calculated over all elements of the image file except this field itself. This element must be the last sub-element in an image file sent over the air.   OTAP Sector Bitmap Sub-element Field The KW36 Flash is partitioned into: One 256 KB Program Flash (P-Flash) array divided into 2 KB sectors with a flash address range from 0x0000_0000 to 0x0003_FFFF. One 256 KB FlexNVM array divided in 2 KB sectors, flash address ranges from 0x1000_0000 to 0x1003_FFFF with an Alias memory with address range 0x0004_0000 to 0x0007_FFFF. The Bitmap sub-element is 256 bits of length, in terms of the KW36 flash, each bit represents a 2KB sector covering the address range from 0x0 - 0x0007_FFFF (P-Flash to FlexNVM Alias address range), where 1 means that such sector should be erased and 0 means that such sector should be preserved. The Bitmap field is used by the OTAP Bootloader to obtain the address range which should be erased before programming the KW36 with the software update, so it must be configured before sending a software update to leave intact the address range of memory that contain data of your interest and erase only the address range that will be overwritten by the software update.        For example: Suppose that a developer wants to preserve the address range between 0x7D800 - 0x7FFFF and the address range between 0x0 - 0x1FFF, and the left memory must be erased. The address range between 0x7D800 - 0x7FFFF corresponds to the 5 top flash sectors and the address range between 0x0 - 0x1FFF is the lowest 4 sectors. So, it means that bits between 256 and 252 (256, 255, 254, 253 and 252) and bits between 4 and 1 (4,3,2 and 1) should be set to 0, that way OTAP Bitmap for this example is: 0x07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0   Configuring OTAP Bitmap to Protect an Address Range with NXP Test Tool Download and install Test Tool for Connectivity products in NXP's web site Open NXP Test Tool 12 software on your PC. Go to "OTA Updates -> OTAP Bluetooth LE" Then load your image file for the software update clicking on the "Browse..." button (NXP Test Tool only accepts .bin and .srec files). You can configure the OTAP Bitmap selecting the "Override sector bitmap" checkbox and changing the default value by your new bitmap value. Once you have configured the bitmap, select "Save...".   Then, a window will be displayed to select the destination to save the .bleota file. Provide a name to identify this file. You can use this file with IoT Toolbox App for Android and iOS to update the software using OTAP. This new .bleota file contains the bitmap that tells to the OTAP Bootloader which sectors will be erased and which sectors will be preserved.          
View full article
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.
View full article
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.
View full article
Introduction This post guides you on migrating from MKW36Z512VHT4 to MKW36A512VFT4 MCUs. This example will make use of the "beacon" SDK example. SDK Download and Install 1- Go to MCUXpresso web page: MCUXpresso Web Page 2- Log in with your registered account. 3- Search for the "KW36A" device. Then click on the suggested processor and click on "Build MCUXpresso SDK"       4- The next page will be displayed. Select “All toolchains” in the “Toolchain / IDE” box and provide a name to identify the package. Then click on "Download SDK".     5- Accept the license agreement. Wait a few minutes until the system gets the package into your profile. Download the SDK clicking on "Download SDK Archive" as depicted in the following figure.     6- If MCUXpresso IDE is used, drag and drop the KW36A SDK zip folder in “Installed SDK’s” perspective to install the package.     At this point, you have downloaded and installed the SDK package for the KW36A device.   Software Migration in MCUXpresso IDE 1- Import the "beacon" example on the MCUXpresso workspace. Click on “Import SDK examples(s)…” option, a new window will appear. Then select "MKW36Z512xxx4" and click on the FRDM-KW36 image. Click on the "Next >" button.     2- Search beacon and select your project version (bm or freertos).     3- Go to Project/Properties. Expand C/C++ Build/MCU settings and select MKW36A512xxx4 MCU. Click Apply and Close button to save the configuration.     4- Rename MKW36Z folders as MKW36A, clicking the right mouse button and selecting "Rename". These are the following:   framework/DCDC/Interface -> MKW36Z framework/DCDC/Source -> MKW36Z framework/LowPower/Interface -> MKW36Z framework/LowPower/Source -> MKW36Z framework/XCVR -> MKW36Z4     5- Open the Project/Properties window in MCUXpresso IDE. Go to C/C++ Build/Settings and select MCU C Compiler/Includes folder in the Tool Settings window. Edit all paths related to MKW36 MCU, in according to MKW35 folders before created. The results must look similar as shown below:   ../framework/LowPower/Interface/MKW36A ../framework/LowPower/Source/MKW36A ../framework/DCDC/Interface/MKW36A ../framework/XCVR/MKW36A4     6- Select MCU Assembler/General folder in Tool Settings. Edit the paths related to MKW36 MCU. The results must look similar as shown below:   ../framework/LowPower/Interface/MKW36A ../framework/LowPower/Source/MKW36A ../framework/DCDC/Interface/MKW36A ../framework/XCVR/MKW36A4     7- Go to Project/Properties. Expand MCU C Compiler/Preprocessor window. Edit "CPU_MKW36Z512VHT4" and "CPU_MKW36Z512VHT4_cm0plus" symbols, rename it as "CPU_MKW36A512VFT4" and "CPU_MKW36A512VFT4_cm0plus" respectively. Save the changes.     8- Go to the workspace. Delete “fsl_device_registers, MKW36Z4, MKW36Z4_features, system_MKW36Z4.h and system_MKW36Z4.c” files located at CMSIS folder. Then, unzip the MKW35Z SDK package and search for “fsl_device_registers, MKW36A4, MKW36A4_features, system_MKW36A4.h and system_MKW36A4.c” files into this folder at the following paths:   <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- Overwirte the “startup_mkw36z4.c” (located inthe startup folder) by the "startup_mkw36a4.c" located in the following path <SDK_folder_root>/devices/MKW36A4/mcuxpresso/startup_mkw36a4.c. You can simply drag and drop on the startup folder, and remove the older one.     10- Open "fsl_device_registers.h" file in CMSIS folder. Add"defined(CPU_MKW36A512VFT4)" in the following code (line 18 of the file):   /* * Include the cpu specific register header files. * * The CPU macro should be declared in the project or makefile. */ #if (defined(CPU_MKW36A512VFP4) || defined(CPU_MKW36A512VFT4) || defined(CPU_MKW36A512VHT4) || defined(CPU_MKW36A512VFT4))‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   11- Open "ble_config.h" file in bluetooth->host->config folder. Add "defined(CPU_MKW36A512VFT4)" in the following code (line 146 of the file):   /* The maximum number of BLE connection supported by platform */ #if defined(CPU_QN9080C) #define MAX_PLATFORM_SUPPORTED_CONNECTIONS 16 #elif (defined(CPU_MKW36Z512VFP4) || defined(CPU_MKW36Z512VHT4) || defined(CPU_MKW36A512VFP4) || defined(CPU_MKW36A512VHT4) || defined(CPU_MKW36A512VFT4) || \ defined(CPU_MKW35Z512VHT4) || defined(CPU_MKW35A512VFP4) || \ defined(CPU_K32W032S1M2CAx_cm0plus) || defined(CPU_K32W032S1M2VPJ_cm0plus) || \ defined(CPU_K32W032S1M2CAx_cm4) || defined(CPU_K32W032S1M2VPJ_cm4) || \ defined(CPU_MKW38A512VFT4) || defined (CPU_MKW38Z512VFT4) || defined(CPU_MKW39A512VFT4) || \ defined(CPU_MKW37A512VFT4) || defined(CPU_MKW37Z512VFT4))‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   12- Open "ble_controller_task.c" file in source->common folder. Add "defined(CPU_MKW36A512VFT4)" in the following code (line 272 of the file):    #elif (defined(CPU_MKW35A512VFP4) || defined(CPU_MKW35Z512VHT4) || defined(CPU_MKW36A512VFP4) || defined(CPU_MKW36A512VFT4) ||\ defined(CPU_MKW36A512VHT4) || defined(CPU_MKW36Z512VFP4) || defined(CPU_MKW36Z512VHT4)) /* Select BLE protocol on RADIO0_IRQ */ XCVR_MISC->XCVR_CTRL = (uint32_t)((XCVR_MISC->XCVR_CTRL & (uint32_t)~(uint32_t)( XCVR_CTRL_XCVR_CTRL_RADIO0_IRQ_SEL_MASK )) | (uint32_t)( (0UL << XCVR_CTRL_XCVR_CTRL_RADIO0_IRQ_SEL_SHIFT) ));‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   13-Build the project.   At this point, the project is already migrated.   Software Migration in IAR Embedded Workbench IDE 1- Open the beacon project located in the following path: 2- Select the project in the workspace and press Alt + F7 to open project options.   3- In the General Options/Target window click the icon next to the device name and select the appropriate device NXP/KinetisKW/KW3x/NXP MKW36A512xxx4, then click the OK button.   4- Create a new folder with the name MKW36A at following paths: <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- Copy all files inside MKW36Z folders located at the above paths and paste in MKW36A folders.     6- Select the beacon project in the workspace and press Alt+F7 to open project options window. In C/C++ Compiler/Preprocessor window, rename the paths related to MKW36Z folders to MKW36A folders. Rename the CPU_MKW36Z512VHT4 macro as CPU_MKW36A512VFT4 in the defined symbols text box. The results must look similar as shown below: Click the OK button. $PROJ_DIR$/middleware/wireless/framework_5.4.2/LowPower/Interface/MKW36A $PROJ_DIR$/../../../../../../../devices/MKW36A4/drivers $PROJ_DIR$/../../../../../../../middleware/wireless/framework_5.4.2/DCDC/Interface/MKW36A $PROJ_DIR$/../../../../../../../middleware/wireless/framework_5.4.2/XCVR/MKW36A4 $PROJ_DIR$/../../../../../../../devices/MKW36A4 $PROJ_DIR$/../../../../../../../devices/MKW36A4/utilities     7- Expand the startup folder, select all files, click the right mouse button and select the “Remove” option. Click the right mouse button on the folder and select “Add/Add files”. Add the startup_MKW36A4.s located at this path: <SDK_root>/devices/MKW36A4/iar/startup_MKW36A4.s Also, add system_MKW36A4.c and system_MKW36A4.h into the startup folder. Both files are located at the next path: <SDK_root>/devices/MKW36A4   8- Open "ble_config.h" file in bluetooth->host->config folder. Add "defined(CPU_MKW36A512VFT4)" in the following code: /* The maximum number of BLE connection supported by platform */ #if defined(CPU_QN9080C) #define MAX_PLATFORM_SUPPORTED_CONNECTIONS 16 #elif (defined(CPU_MKW36Z512VFP4) || defined(CPU_MKW36Z512VHT4) || defined(CPU_MKW36A512VFP4) || defined(CPU_MKW36A512VHT4) || defined(CPU_MKW36A512VFT4) || \ defined(CPU_MKW35Z512VHT4) || defined(CPU_MKW35A512VFP4) || \ defined(CPU_K32W032S1M2CAx_cm0plus) || defined(CPU_K32W032S1M2VPJ_cm0plus) || \ defined(CPU_K32W032S1M2CAx_cm4) || defined(CPU_K32W032S1M2VPJ_cm4) || \ defined(CPU_MKW38A512VFT4) || defined (CPU_MKW38Z512VFT4) || defined(CPU_MKW39A512VFT4) || \ defined(CPU_MKW37A512VFT4) || defined(CPU_MKW37Z512VFT4))‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   9- Open "ble_controller_task.c" file in source->common folder. Add "defined(CPU_MKW36A512VFT4)" in the following code: #elif (defined(CPU_MKW35A512VFP4) || defined(CPU_MKW35Z512VHT4) || defined(CPU_MKW36A512VFP4) || defined(CPU_MKW36A512VFT4) ||\ defined(CPU_MKW36A512VHT4) || defined(CPU_MKW36Z512VFP4) || defined(CPU_MKW36Z512VHT4)) /* Select BLE protocol on RADIO0_IRQ */ XCVR_MISC->XCVR_CTRL = (uint32_t)((XCVR_MISC->XCVR_CTRL & (uint32_t)~(uint32_t)( XCVR_CTRL_XCVR_CTRL_RADIO0_IRQ_SEL_MASK )) | (uint32_t)( (0UL << XCVR_CTRL_XCVR_CTRL_RADIO0_IRQ_SEL_SHIFT) ));‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   10-Build the project.   At this point, the project is already migrated.
View full article
Introduction HCI Application is a Host Controller Interface application which provides a serial communication to interface with the KW40/KW41/KW35/KW36/QN9080 BLE radio part. It enables the user to have a way to control the radio through serial commands. The format of the HCI Command Packet it’s composed of the following parts:     Each command is assigned a 2 byte Opcode which it’s divided into two fields, called the OpCode Group Field (OGF) and OpCode Command Field (OCF). The OGF uses the upper 6 bits of the Opcode, while the OCF corresponds to the remaining 10 bits. The OGF of 0x3F is reserved for vendor-specific debug commands. The organization of the opcodes allows additional information to be inferred without fully decoding the entire Opcode. For further information regarding this topic, please check the BLUETOOTH SPECIFICATION Version 5.0 | Vol 2, Part E, 5.4 EXCHANGE OF HCI-SPECIFIC INFORMATION.   Adding HCI Custom Commands Example This document will guide you through the implementation of custom HCI commands in the KW36. For this example, we will include the following set of custom commands: 01 50 FC 00 – This command is to send a continuous unmodulated wave using a defined channel and output power (default: frequency 2.402GHz and PA_POWER register set to 0x3E).  01 4F FC 00 – This command is to stop the continuous unmodulated wave and configure the radio in Bluetooth LE mode again. This way you can continue sending adopted HCI commands. 01 00 FC 00 – Set the Channel 0 Freq 2402 MHz 01 01 FC 00 – Set the Channel 19 Freq 2440 MHz 01 02 FC 00 – Set the Channel 39 Freq 2480 MHz 01 10 FC 00 – Set the PA_POWER 1 01 11 FC 00 – Set the PA_POWER 32 01 12 FC 00 – Set the PA_POWER 62 The changes described in the following sections were based on the HCI Black Box SDK example (it is located at wireless_examples -> bluetooth -> hci_bb)   Changes in hci_transport.h The "hci_transport.h" file is located at bluetooth->hci_transport->interface folder. Include the following macros in ''Public constants and macros" #define gHciCustomCommandOpcodeUpper (0xFC50) #define gHciCustomCommandOpcodeLower (0xFC00) #define gHciInCustomVendorCommandsRange(x) (((x) <= gHciCustomCommandOpcodeUpper) && \ ((x) >= gHciCustomCommandOpcodeLower))‍‍‍‍‍‍‍‍ Declare a function to install the custom command as follows: void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler);‍   Changes in hcit_serial_interface.c The "hci_transport.h" file is located at bluetooth->hci_transport->source folder. Add the following in "Private memory declarations" static hciTransportInterface_t mCustomTransportInterface = NULL;‍ Modify the Hcit_SendMessage function as follows: static inline void Hcit_SendMessage(void) { uint16_t opcode = 0; /* verify if this is an event packet */ if(mHcitData.pktHeader.packetTypeMarker == gHciEventPacket_c) { /* verify if this is a command complete event */ if(mHcitData.pPacket->raw[0] == gHciCommandCompleteEvent_c) { /* extract the first opcode to verify if it is a custom command */ opcode = mHcitData.pPacket->raw[3] | (mHcitData.pPacket->raw[4] << 8); } } /* verify if command packet */ else if(mHcitData.pktHeader.packetTypeMarker == gHciCommandPacket_c) { /* extract opcode */ opcode = mHcitData.pPacket->raw[0] | (mHcitData.pPacket->raw[1] << 8); } if(gHciInCustomVendorCommandsRange(opcode)) { if(mCustomTransportInterface) { mCustomTransportInterface( mHcitData.pktHeader.packetTypeMarker, mHcitData.pPacket, mHcitData.bytesReceived); } } else { /* Send the message to HCI */ (void)mTransportInterface(mHcitData.pktHeader.packetTypeMarker, mHcitData.pPacket, mHcitData.bytesReceived); } mHcitData.pPacket = NULL; mPacketDetectStep = mDetectMarker_c; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Develop the function to install the custom command as follows:   void Hcit_InstallCustomCommandHandler(hciTransportInterface_t mCustomInterfaceHandler) { OSA_InterruptDisable(); mCustomTransportInterface = mCustomInterfaceHandler; OSA_InterruptEnable(); }‍‍‍‍‍‍   Changes in hci_black_box.c This is the main application file, and it is located at source folder. Include the following files to support our HCI custom commands #include "hci_transport.h" #include "fsl_xcvr.h"‍‍ Define the following macros which represent the opcode for each custom command #define CUSTOM_HCI_CW_ON (0xFC50) #define CUSTOM_HCI_CW_OFF (0xFC4F) #define CUSTOM_HCI_CW_SET_CHN_0 (0xFC00) /*Channel 0 Freq 2402 MHz*/ #define CUSTOM_HCI_CW_SET_CHN_19 (0xFC01) /*Channel 19 Freq 2440 MHz*/ #define CUSTOM_HCI_CW_SET_CHN_39 (0xFC02) /*Channel 39 Freq 2480 MHz*/ #define CUSTOM_HCI_CW_SET_PA_PWR_1 (0xFC10) /*PA_POWER 1 */ #define CUSTOM_HCI_CW_SET_PA_PWR_32 (0xFC11) /*PA_POWER 32 */ #define CUSTOM_HCI_CW_SET_PA_PWR_62 (0xFC12) /*PA_POWER 62 */ #define CUSTOM_HCI_CW_EVENT_SIZE (0x04) #define CUSTOM_HCI_EVENT_SUCCESS (0x00) #define CUSTOM_HCI_EVENT_FAIL (0x01)‍‍‍‍‍‍‍‍‍‍‍ Add the following application variables static uint16_t channelCC = 2402; static uint8_t powerCC = 0x3E; uint8_t eventPacket[6] = {gHciCommandCompleteEvent_c, CUSTOM_HCI_CW_EVENT_SIZE, 1, 0, 0, 0 };‍‍‍‍‍‍ Declare the handler for our custom commands bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize);‍ Find the "main_task" function, and register the handler for the custom commands through "Hcit_InstallCustomCommandHandler" function. You can include it just after BleApp_Init(); /* Initialize peripheral drivers specific to the application */ BleApp_Init(); /* Register the callback for the custom commands */ Hcit_InstallCustomCommandHandler((hciTransportInterface_t)&BleApp_CustomCommandsHandle); /* Create application event */ mAppEvent = OSA_EventCreate(TRUE); if( NULL == mAppEvent ) { panic(0,0,0,0); return; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Develop the handler of our custom commands as follows: bleResult_t BleApp_CustomCommandsHandle(hciPacketType_t packetType, void* pPacket, uint16_t packetSize) { uint16_t opcode = 0; if(gHciCommandPacket_c == packetType) { opcode = ((uint8_t*)pPacket)[0] | (((uint8_t*)pPacket)[1] << 8); switch(opcode) { /*@CC: Set Channel */ case CUSTOM_HCI_CW_SET_CHN_0: /*@CC: Set Channel 0 Freq 2402 MHz */ channelCC=2402; break; case CUSTOM_HCI_CW_SET_CHN_19: /*@CC: Channel 19 Freq 2440 MHz*/ channelCC=2440; break; case CUSTOM_HCI_CW_SET_CHN_39: /*@CC: Channel 39 Freq 2480 MHz */ channelCC=2480; break; /*@CC: Set PA_POWER */ case CUSTOM_HCI_CW_SET_PA_PWR_1: /*@CC: Set PA_POWER 1 */ powerCC=0x01; break; case CUSTOM_HCI_CW_SET_PA_PWR_32: /*@CC: Set PA_POWER 32 */ powerCC=0x20; break; case CUSTOM_HCI_CW_SET_PA_PWR_62: /*@CC: Set PA_POWER 62 */ powerCC=0x3E; break; /*@CC: Generate a Continuous Unmodulated Signal ON / OFF */ case CUSTOM_HCI_CW_ON: /*@CC: Generate a Continuous Unmodulated Signal when pressing SW3 */ XCVR_DftTxCW(channelCC, 6); XCVR_ForcePAPower(powerCC); break; case CUSTOM_HCI_CW_OFF: /*@CC: Turn OFF the transmitter */ XCVR_ForceTxWd(); /* Initialize the PHY as BLE */ XCVR_Init(BLE_MODE, DR_1MBPS); break; default: eventPacket[5] = CUSTOM_HCI_EVENT_FAIL; break; } eventPacket[3] = (uint8_t)opcode; eventPacket[4] = (uint8_t)(opcode >> 8); eventPacket[5] = CUSTOM_HCI_EVENT_SUCCESS; Hcit_SendPacket(gHciEventPacket_c, eventPacket, sizeof(eventPacket)); } else { return gBleUnexpectedError_c; } return gBleSuccess_c; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Testing Custom HCI Commands Using NXP Test Tool 12 To test HCI Black Box software, we need to install NXP Test Tool 12, from the NXP Semiconductors | Automotive, Security, IoT official web site. Once you have installed Test Tool, attach the FRDM-KW36 board to your PC and open the serial port enumerated in the start page clicking twice on the icon. Then, select "Raw Data" checkbox and type any of our custom commands, for instance, "01 01 FC 00" (Set the Channel 19 Freq 2440 MHz). Shift out the command clicking on the "Send Raw..." button. You will see the HCI Tx and Rx in the right upper corner of your screen
View full article
Introduction This document is to guide how to modify the OTAP Client software to the Low Power module. The starting point of this document is the OTAP Client example in the FRDM-KW36 SDK v2.2.2.   Deep Sleep Modes This section provides a base to understand how the developer should change between DSM1 (Deep Sleep Mode 1) and DSM3 (Deep Sleep Mode 3). The DSM6 does not need to be started by the developer, instead, the controller configures this mode automatically and returns to the latest mode after finished the radio activity.   DSM1 This low-power mode was designed to be used when the BLE stack is active, in other words when the LL is in advertising, scanning, or connection states. In this mode, the MCU enters LLS3 and BLE Link Layer enters deep sleep. The SoC wakes up from this mode by the on-board switches, by LPTMR timeout, or by BLE Link Layer wake-up interrupt (BLE_LL reference clock reaches wake up instance register) using LLWU module. The LPTMR timer is used to measure the time that the MCU spends in deep sleep to synchronize low-power timers at wakeup.   DSM3 This low-power mode was designed to be used when all stacks enabled for this platform are idle, in other words, when the LL stop advertising, scanning, or connection. In this mode, the MCU enters LLS3 and all enabled link layers remain idle. All RAM is retained. The SoC wakes up from this mode by the on-board switches, by DCDC power switch (when DCDC is in buck mode), or by LPTMR timeout using LLWU module. The LPTMR timer is also used to measure the time that MCU spends in deep sleep to synchronize low-power timers at wakeup.   DSM6 This low-power mode was developed to save some power while the radio is on. Its most common use case is with the radio in Rx waiting for a packet. Upon receiving the packet the radio wakes up the MCU. In this mode, the MCU enters STOP mode and the radio maintains its state. Any module capable of producing an interrupt can wake up the MCU, such as on-board switches, DCDC power switch (when DCDC is in buck mode), LPTMR timeout, Radio Interrupt, UART, and so on. The LPTMR timer is also used to measure the time that the MCU spends in deep sleep to synchronize low-power timers at wakeup.   For more information about DSM modes, you can inspect the “Connectivity Framework Reference Manual” chapter 3.15 Low-power library, it provides full information of Low Power modes and the usage on the NXP stack. It is available in your SDK at <FRDM-KW36 SDK root>\docs\wireless\Common.   Modifications on the Software In order to add low power on the OTAP Client (switching between DSM1, DSM3, and DSM6) two files must be modified: - app_preinclude.h - otap_client_att.c The following sections explain these changes.   app_preinclude.h This file is intended to contain the definitions that manage the behavior of the application. To include and enable the Low Power module you must add (or modify if the macro is already defined in this file) the following preprocessor directives.   1. Modify the AppPoolsDetails as following. /* Defines pools by block size and number of blocks. Must be aligned to 4 bytes.*/ #define AppPoolsDetails_c \ _block_size_ 32 _number_of_blocks_ 6 _eol_ \ _block_size_ 64 _number_of_blocks_ 4 _eol_ \ _block_size_ 88 _number_of_blocks_ 3 _eol_ \ _block_size_ 248 _number_of_blocks_ 2 _eol_ \ _block_size_ 312 _number_of_blocks_ 1 _eol_ \ _block_size_ 392 _number_of_blocks_ 1 _eol_‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 2. Set “cPWR_UsePowerDownMode” to 1 and keep the following directives in the “Framework Configuration” section as shown below. /* Check Low Power Timer */ #define cPWR_CheckLowPowerTimers 1 /* Enable/Disable Low Power Timer */ #define gTMR_EnableLowPowerTimers 1 /* Enable/Disable PowerDown functionality in PwrLib */ #define cPWR_UsePowerDownMode 1 /* Enable/Disable BLE Link Layer DSM */ #define cPWR_BLE_LL_Enable 1 /* Default Deep Sleep Mode*/ #define cPWR_DeepSleepMode 3 /* Enable/Disable MCU Sleep During BLE Events */ #define cMCU_SleepDuringBleEvents 1 /* Default deep sleep duration in ms */ #define cPWR_DeepSleepDurationMs 30000 /* Number of slots(625us) before the wake up instant before which the hardware needs to exit from deep sleep mode. */ #define cPWR_BLE_LL_OffsetToWakeupInstant 3 /* Enables / Disables the DCDC platform component */ #define gDCDC_Enabled_d 1 /* Default DCDC Mode used by the application */ #define APP_DCDC_MODE gDCDC_Mode_Buck_c /* Default DCDC Battery Level Monitor interval */ #define APP_DCDC_VBAT_MONITOR_INTERVAL 600000‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 3. Add the following directives in the “BLE Stack Configuration” section. Create the “Auto Configuration” section to disable LED support whenever Low Power is enabled. /*! ********************************************************************************* * BLE Stack Configuration ********************************************************************************** */ /* Time between the beginning of two consecutive advertising PDU's */ #define mcAdvertisingPacketInterval_c 0x02 /* 1.25 msec */ /* Offset to the first instant register. */ #define mcOffsetToFirstInstant_c 0x00 /* 625usec */ /*! ********************************************************************************* * Auto Configuration ********************************************************************************** */ /* Disable LEDs when enabling low power */ #if cPWR_UsePowerDownMode || gMWS_UseCoexistence_d #define gLEDSupported_d 0 #endif #if gMWS_UseCoexistence_d #undef gKBD_KeysCount_c #define gKBD_KeysCount_c 1 #endif‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 4. Modify the “Memory Pools Configuration” section as follows. /* Enable RNG seed storage in Flash */ #define gRngSeedStorageAddr_d ((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR + 1024) /* Enable XCVR calibration storage in Flash */ #define gPreserveXcvrDacTrimValue_d 1 #define gXcvrDacTrimValueSorageAddr_d ((uint32_t)FREESCALE_PROD_DATA_BASE_ADDR + 1040) /* Application Connection sleep mode */ #define gAppDeepSleepMode_c 1 /* Application RAM usage configuration */ #define cPWR_RamRetentionInVLLS 2 /* 32K */ /* Disable unused LowPower modes */ #define cPWR_EnableDeepSleepMode_1 1 #define cPWR_EnableDeepSleepMode_2 0 #define cPWR_EnableDeepSleepMode_3 1 #define cPWR_EnableDeepSleepMode_4 0 #define cPWR_EnableDeepSleepMode_5 0 #define cPWR_EnableDeepSleepMode_7 0 #define cPWR_EnableDeepSleepMode_8 0 /* Warm-boot sequence will use the default stack which is used by ISRs on FreeRTOS */ #define USE_WARMBOOT_SP 0‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   otap_client_att.c This is the main source file at the application level. Here are managed all the procedures that the device performs, before, during, and after to create a connection. This allows you to get the state of the device any instant and, hence, the dedicated low power APIs that rule the application must be implemented here, in the callbacks contained in this file, for an easier switching among the low power states.   1. Include “PWR_Configuration.h” header in “Include” section: #if (cPWR_UsePowerDownMode) #include "PWR_Interface.h" #include "PWR_Configuration.h" #endif‍‍‍‍‍‍‍‍‍‍‍‍ 2. Locate the “BleApp_Config” function. This function is executed once, after POR (Power on reset) during the device setup. Here you can change the deep sleep mode to DSM3 and allow the device to sleep using “PWR_ChangeDeepSleepMode” and “PWR_AllowDeviceToSleep” APIs. When the device has finished the initialization, it goes to sleep since all stacks are idle. See the following example. static void BleApp_Config(void) { #if defined(MULTICORE_APPLICATION_CORE) && (MULTICORE_APPLICATION_CORE == 1) if (GattDbDynamic_CreateDatabase() != gBleSuccess_c) { panic(0,0,0,0); return; } #endif /* MULTICORE_APPLICATION_CORE */ /* Common GAP configuration */ BleConnManager_GapCommonConfig(); /* Register stack callbacks */ (void)App_RegisterGattServerCallback (BleApp_GattServerCallback);‍‍‍‍‍‍‍‍‍‍‍‍‍ mAdvState.advOn = FALSE; /* Start services */ basServiceConfig.batteryLevel = BOARD_GetBatteryLevel(); (void)Bas_Start(&basServiceConfig); (void)Dis_Start(&disServiceConfig); if (OtapClient_Config() == FALSE) { /* An error occurred in configuring the OTAP Client */ panic(0,0,0,0); } /* Allocate application timer */ appTimerId = TMR_AllocateTimer(); mBatteryMeasurementTimerId = TMR_AllocateTimer(); #if (cPWR_UsePowerDownMode) #if MULTICORE_APPLICATION_CORE #if gErpcLowPowerApiServiceIncluded_c PWR_ChangeBlackBoxDeepSleepMode(cPWR_DeepSleepMode); PWR_AllowBlackBoxToSleep(); #endif PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode); PWR_AllowDeviceToSleep(); #else PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode); PWR_AllowDeviceToSleep(); #endif #endif }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 3. Locate the “BleApp_Start” function. This function is executed just after wake up by pressing the LLWU SW3 button. This action will trigger the advertising, so, you must change the deep sleep mode to DSM1 using “PWR_ChangeDeepSleepMode” API since the BLE stack is active. See the following example. void BleApp_Start(void) { Led1On(); if (mPeerDeviceId == gInvalidDeviceId_c) { /* Device is not connected and not advertising*/ if (!mAdvState.advOn) { #if gAppUseBonding_d if (gcBondedDevices > 0) { mAdvState.advType = whiteListAdvState_c; } else { #endif mAdvState.advType = advState_c; #if gAppUseBonding_d } #endif #if (cPWR_UsePowerDownMode) #if MULTICORE_APPLICATION_CORE #if gErpcLowPowerApiServiceIncluded_c PWR_ChangeBlackBoxDeepSleepMode(gAppDeepSleepMode_c); #endif #else PWR_ChangeDeepSleepMode(gAppDeepSleepMode_c); #endif #endif BleApp_Advertise(); } } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 4. Locate the “BleApp_AdvertisingCallback” function. This function is executed every time the advertising state changes. Change the deep sleep mode to DSM3 when “mAdvState.advOn” is false, in other words, when the device stops advertising. If you stop the advertising either using an application timer or a user button, KW36 will go to sleep until you start advertising again (pressing LLWU SW3 button), saving power when all stacks are idle. See the following example. static void BleApp_AdvertisingCallback (gapAdvertisingEvent_t* pAdvertisingEvent) { switch (pAdvertisingEvent->eventType) { case gAdvertisingStateChanged_c: { mAdvState.advOn = !mAdvState.advOn; if(mAdvState.advOn) { LED_StopFlashingAllLeds(); Led1Flashing(); } #if (cPWR_UsePowerDownMode) else { #if MULTICORE_APPLICATION_CORE #if gErpcLowPowerApiServiceIncluded_c PWR_ChangeBlackBoxDeepSleepMode(cPWR_DeepSleepMode); #endif #else PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode); #endif } #endif } break; case gAdvertisingCommandFailed_c: { Led2On(); panic(0,0,0,0); } break; default: ; /* For MISRA compliance */ break; } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ 5. Locate “BleApp_ConnectionCallback” function. It is executed every time the connection state changes. In “gConnEvtConnected_c” add the following code to change to DSM1, since the BLE stack is active. case gConnEvtConnected_c: { /* Advertising stops when connected */ mAdvState.advOn = FALSE; (void)TMR_StopTimer(appTimerId); /* Subscribe client*/ mPeerDeviceId = peerDeviceId; (void)Bas_Subscribe(&basServiceConfig, peerDeviceId); (void)OtapCS_Subscribe(peerDeviceId); OtapClient_HandleConnectionEvent (peerDeviceId); /* Start battery measurements */ (void)TMR_StartLowPowerTimer(mBatteryMeasurementTimerId, gTmrLowPowerIntervalMillisTimer_c, TmrSeconds(mBatteryLevelReportInterval_c), BatteryMeasurementTimerCallback, NULL); #if (cPWR_UsePowerDownMode) #if MULTICORE_APPLICATION_CORE #if gErpcLowPowerApiServiceIncluded_c PWR_ChangeBlackBoxDeepSleepMode(gAppDeepSleepMode_c); PWR_AllowBlackBoxToSleep(); #endif #else PWR_ChangeDeepSleepMode(gAppDeepSleepMode_c); PWR_AllowDeviceToSleep(); #endif #else /* UI */ LED_StopFlashingAllLeds(); Led1On(); #endif } break;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ In “gConnEvtDisconnected_c” add the following code to change to DSM3, since all stacks are idle. case gConnEvtDisconnected_c: { /* Unsubscribe client */ mPeerDeviceId = gInvalidDeviceId_c; (void)Bas_Unsubscribe(&basServiceConfig, peerDeviceId); (void)OtapCS_Unsubscribe(); /* UI */ LED_StopFlashingAllLeds(); Led1Flashing(); Led2Flashing(); Led3Flashing(); Led4Flashing();‍‍‍‍‍‍‍‍‍‍‍‍ OtapClient_HandleDisconnectionEvent (peerDeviceId); #if (cPWR_UsePowerDownMode) /* Go to sleep */ #if MULTICORE_APPLICATION_CORE #if gErpcLowPowerApiServiceIncluded_c PWR_ChangeBlackBoxDeepSleepMode(cPWR_DeepSleepMode); #endif #else PWR_ChangeDeepSleepMode(cPWR_DeepSleepMode); #endif #else /* Restart advertising*/ BleApp_Start(); #endif } break;‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Power Consumption Profile of OTAP Client This section explains the behavior of the power consumption profile along the time. We can differ when DSM1 or DSM3 are used depending on the device state. If the device needs to advertise or is in connection state, it will use DSM1 because this sleep mode can predict when the device needs to handle the communication with others and wake up automatically through the BLE Link Layer wakeup interrupt. On the other hand, when no actions are in progress, it will use DSM3 and the wake up depends entirely on the LLWU SW3 button in this example. On the other hand, the DSM6 puts the MCU in STOP mode during the transmission and reception in BLE events, it does not need to be started manually, instead, the controller configures this mode automatically and returns to DSM1 mode after finished the radio activity.   The APIs that change the deep sleep mode to DSM1 are: • BleApp_Start: It starts advertising. • BleApp_ConnectionCallback – gConnEvtConnected_d: It notifies when the MCU has been connected to a peer device.   The APIs that change the deep sleep mode to DSM3 are: • BleApp_Config: It takes part of the initialization procedure after POR. All tasks are idle, the device is waiting for the LLWU SW3 button to wake up and start advertising. • BleApp_AdvertisingCallback – mAdvState is off: The device has to stopped advertising, so the MCU is idle. • BleApp_ConnectionCallback – gConnEvtDisconnected_d: It notifies when the device has been disconnected, so the MCU is idle.   Please let us know any questions or comments regarding this topic.
View full article
Introduction This document provides guidance to load a new software image in a KW35 device through OTAP (Over The Air Programming) bootloader for KW35. This article also provides the steps needed to download and install the SDK used in the tutorial. Software Requirements IAR Embedded Workbench IDE or MCUXpresso IDE. SDK MKW36A512xxx4 RC4 or further. Hardware Requirements MKW35A512xxx4 device. KW35 Flash Memory Used for the OTAP Software Deployment The KW35 Flash is partitioned into: 2x256 KB Program Flash (P-Flash) array divided into 2 KB sectors with a flash address range from 0x0000_0000 to 0x0007_FFFF.     The statements to comprehend how the OTAP Client software and his features works are: The OTAP Client software is split into two parts, the OTAP bootloader and the OTAP client service. The OTAP bootloader verifies if there is a new image already available to reprogram the device. The OTAP client service software provides the Bluetooth LE custom services needed to communicate with the server that contains the new image file. Therefore, before to start the test, the device has been programmed twice, first with the OTAP bootloader then with the OTAP client service project. The mechanism used to have two different software in the same device is to store each one in different memory regions and this is implemented by the linker file. In the KW35 device, the bootloader application has reserved a 16KB slot of memory starting from the 0x0 address (0x0 to 0x3FFF) thus, the left memory of the first P-Flash memory bank is reserved, among other things, by the OTAP client service application.   To create a new image file for the client device, the developer needs to specify to the linker file that the code will be stored with an offset of 16KB since the first addresses are reserved for the bootloader. At connection event, the server sends all the chunks of code to the client via Bluetooth LE. The client stores the code at the second P-Flash memory bank but is not able to run yet.   When the broadcast has finished, and all chunks were sent, the OTAP bootloader detects this situation and triggers a command to reprogram the device with the new application. Due the new application was built with an offset of 16KB, the OTAP bootloader program the device starting from the 0x3FFF address and the OTAP client service application is overwritten by the new image. Then the OTAP bootloader triggers the new application, starting the execution of the code.   Software Development Kit download and install   Go to MCUXpresso web page. Log in with your registered account. Search for “MKW36A” device. Then click on the suggested processor and click on “Build MCUXpresso SDK” The next page is displayed. Select “All toolchains” in the “Toolchain / IDE” combo box and provide the name to identify the package. Click on “Add software component”, then deploy the combo box and click on “Select All” option. Save the changes. Click on “Download SDK” button and accept the license agreement. If MCUXpresso IDE is used, drag and drop the SDK zip folder in “Installed SDK’s” perspective to install the package.     Preparing the software to test the OTAP for KW35 device using IAR Embedded Workbench   This section provides the steps needed to test the OTAP software on the KW35. Program the OTAP bootloader on the KW35. 1.1 Open the OTAP_bootloader project located at the following path: <SDK_download_root>\boards\virtual-board-kw35\wireless_examples\framework\bootloader_otap\bm\iar\bootloader_otap_bm.eww     1.2 Flash the project (Ctrl + D). Stop the debug session (Ctrl + Shift + D). Program the OTAP client application on the KW35.         2.1 Open the OTAP client project located in the path below.          <SDK_download_root>\boards\frdmkw36\wireless_examples\bluetooth\otac_att\freertos\iar\otac_att_freertos.eww          2.2 Follow the steps 2 to 12 described in the “4.1. Changes Required in Project Options and Settings” section of the AN12252 “Migration Guide from               MKW36Z512xxx4 to MKW35Z512xxx4” application note.            2.3 Open the app_preinclude.h file under the source directory in the workspace. Find the “gEepromType_d” definition and update the value to                                 “gEepromDevice_InternalFlash_c” as shown below.   #define gEepromType_d gEepromDevice_InternalFlash_c‍‍‍‍‍            2.4 Save the MKW35Z512xxx4_connectivity.icf file located at:                <SDK_download_root>\middleware\wireless\framework_5.4.4\Common\devices\MKW35Z4\iar                               Into the folder of the OTAP Client ATT project:                <SDK_download_root>\boards\frdmkw36\wireless_examples\bluetooth\otac_att\freertos\iar            2.5 Open the project options window (Alt+F7). In Linker/Config window click the icon next to linker path and select the linker configuration file “MKW35Z512xxx4_connectivity.icf”. Set the "gUseInternalStorageLink_d” flag to 1.              2.6 Click the OK button in the project options window to save the new configuration.          2.7 Flash the project (Ctrl + D). Stop the debug session (Ctrl + Shift + D).    Preparing the software to test the OTAP for KW35 device using MCUXpresso IDE   This section provides the steps needed to test the OTAP software on the KW35. Program the OTAP bootloader on the KW35.          1.1 Open MCUXpresso IDE. Click on “Import SDK example(s)” option in the “Quickstart Panel” view.                        1.2 Click on virtual-board-kw35 SDK icon.          1.3 Deploy the wireless_examples\framework\bootloader_otap folders and select bm project. Click Finish button.                                                                           1.4 Select “Debug” option in the Quickstart Panel. Once the project is already loaded on the device, stop the debug session.      2. Program the OTAP client application on the KW35.          2.1 Open MCUXpresso IDE. Click on “Import SDK example(s)” option in the “Quickstart Panel” view.                          2.2 Click twice on the frdmkw36 icon.                                                                            2.3 Type “otac_att” in the examples textbox and select the freertos project at wireless_examples\bluetooth\otac_att\freertos. Finally, click on Finish button.              2.4 Follow the steps 5 to 17 described in the “5.1. Changes Required in Project Options and Settings” section of the AN12252 “Migration Guide from MKW36Z512xxx4 to MKW35Z512xxx4” application note.            2.5. Open the app_preinclude.h file under the source directory in the workspace. Find the “gEepromType_d” definition and update the value to                “gEepromDevice_InternalFlash_c” as shown below. #define gEepromType_d gEepromDevice_InternalFlash_c‍‍‍‍‍            2.6 Save the MKW35Z512xxx4_connectivity.ld file located at:                <SDK_download_root>\middleware\wireless\framework_5.4.4\Common\devices\MKW35Z4\gcc                Into the source folder in the workspace.              2.7 Open the Project/Properties window. Next, go to the MCU Linker/Managed Linker Script perspective and edit the Linker Script name to “MKW35Z512xxx4_connectivity.ld”.              2.8 Go to MCU Linker/Miscellaneous view. Press the icon below, a new window will be deployed. Add the following definition in the “Other options” box: --defsym=gUseInternalStorageLink_d=1.              2.9 Click the “Apply and Close” button in the project options window to save the new configuration.          2.10 Select “Debug” option in the Quickstart Panel. Once the project is already loaded on the device, stop the debug session.   Running OTAP demo with the IoT Toolbox App Save the S-Record file created with the steps in Appendix A or Appendix B in your smartphone at a known location. Open the IoT Toolbox App and select OTAP demo. Press “SCAN” to start scanning for a suitable advertiser. Perform a falling edge on the PTB18 in the KW35 to start advertising. Create a connection with the founded device. Press “Open” and search the S-Record file. Press “Upload” to start the transfer. Once the transfer is complete, wait a few seconds until the bootloader has finished programming the new image. The new application will start automatically.    Appendix A. Creating an S-Record image file for KW35 client using IAR Embedded Workbench Open the connectivity project that you want to program using the OTAP bootloader from your SDK. This example will make use of the glucose sensor project. <SDK_download_root>\boards\frdmkw36\wireless_examples\bluetooth\glucose_s\freertos\iar\glucose_s_freertos.eww Follow the steps 2 to 12 described in the “4.1. Changes Required in Project Options and Settings” section of the AN12252 “Migration Guide from              MKW36Z512xxx4 to MKW35Z512xxx4” application note. Save the MKW35Z512xxx4_connectivity.icf file located at: <SDK_download_root>\middleware\wireless\framework_5.4.4\Common\devices\MKW35Z4\iar                In the containing folder of your project. <SDK_download_root>\boards\frdmkw36\wireless_examples\bluetooth\glucose_s\freertos\iar Open the project options window (Alt+F7). In Linker/Config window click the icon next to linker path and select the linker configuration file MKW35Z512xxx4_connectivity.icf. Then, enable “gUseBootloaderLink_d” macro in the “Configuration file symbol definitions” textbox. Go to the “Output Converter” window. Deselect the “Override default" checkbox, expand the “Output format” combo box and select Motorola S-records format. Click OK button.                                                                                                                                           Rebuild the project. Search the S-Record file in the following path: <SDK_download_root>\boards\frdmkw36\wireless_examples\bluetooth\glucose_s\freertos\iar\debug   Appendix B. Creating an S-Record image file for KW35 client using MCUXpresso IDE Open the connectivity project that you want to program using the OTAP bootloader from MCUXpresso IDE This example will make use of the glucose sensor project Follow the steps 5 to 17 described in the “5.1. Changes Required in Project Options and Settings” section of the AN12252 “Migration Guide from MKW36Z512xxx4 to MKW35Z512xxx4” application note. Save the MKW35Z512xxx4_connectivity.ld file located at: <SDK_download_root>\middleware\wireless\framework_5.4.4\Common\devices\MKW35Z4\gcc Into the source folder in the workspace.                                                                                                                  Open the Project/Properties window. Next, go to the MCU Linker/Managed Linker Script perspective and edit the Linker Script name to “MKW35Z512xxx4_connectivity.ld”.                                                                                  Go to MCU Linker/Miscellaneous view. Press the icon below, a new window will be deployed. Add the following definition in the “Other options” box: --defsym=gUseBootloaderLink_d=1. Click the “Apply and Close” button.                              Build the project. Deploy the “Binaries” icon in the workspace. Click the right mouse button on the “.axf” file. Select “Binary Utilities/Create S-Record” option. The S-Record file will be saved at “Debug” folder in the workspace with “.s19” extension.  
View full article