Wireless Connectivity Knowledge Base

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

Wireless Connectivity Knowledge Base

Discussions

Sort by:
Bluetooth® Low Energy (or BLE) is a wireless technology that allows the exchange of information between a device that contains data (Server) and a device that requests that data (Client). Servers are usually small battery powered devices connected to sensors or actuators to gather data or perform some actions while clients are usually devices that use that information in a system or for display to a user (most common client devices are the Smartphones). When creating a custom BLE profile, we need to consider that it will need to be implemented on both Server and Client. Server will include the database of all the information that can be accessed or modified while the Client will require drivers to access and handle the data provided by the server. This post explains how to implement a custom profile in the server side using the NXP BLE stack. As example, a custom Potentiometer reporter is implemented on a MKW40Z160. Generic Attribute Profile Before implementing a custom profile, we need to be familiarized with the way BLE exchanges information. The Generic Attribute Profile (GATT) establishes how to exchange all profile and user data over a BLE connection. All standard BLE profiles are based on GATT and must comply with it to operate correctly. GATT defines two communication roles: Server and Client. The GATT Server stores the data to be transported and accepts GATT requests, commands and confirmations from the client. The GATT Client accesses data on the remote GATT server via read, write, notify or indicate operations. Figure 1 GATT Client-Server GATT data is exposed using attributes that are organized to describe the information accessible in a GATT server. These are Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that determine the behavior of the application as a whole (i.e. Heart Rate Monitor, or Temperature Sensor). Profiles are integrated by one or more Services that define individual functionalities (i.e. a Heart Rate Monitor requires a Heart Rate Sensor and a Battery Measurement Unit). Services are integrated by one or more characteristics that hold individual measurements, control points or other data for a service (i.e. Heart Rate Sensor might have a characteristic for Heart Rate and other for Sensor Location). Finally Descriptors define how characteristics must be accessed. Figure 2 GATT database structure Adding a New Service to the GATT Database The GATT database in a server only includes attributes that describe services, characteristics and descriptors. Profiles are implied since they are a set of predefined services. In the NXP Connectivity Software, macros are used to define each of the attributes present in the database in an easier way. Each service and characteristic in a GATT database has a Universally Unique Identifier (UUID). These UUID are assigned by Bluetooth Org on adopted services and characteristics. When working with custom profiles, a proprietary UUID must be assigned. In the NXP connectivity Software, custom UUIDs are defined in the file gatt_uuid128.h. Each new UUID must be defined using the macro UUID128 (name, bytes) where name is an identifier that will help us to reference the UUID later in the code. Byte is a sequence of 16-bytes (128-bits) which are the custom UUID. Following is an example of the definition of the Potentiometer service and the Potentiometer Relative Value characteristic associated to it. /* Potentiometer Service */ UUID128(uuid_service_potentiometer, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x04, 0x56, 0xFF, 0x02) /* Potentiometer Characteristic */ UUID128(uuid_characteristic_potentiometer_relative_value, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x04, 0x57, 0xFF, 0x02) ‍‍‍‍‍‍‍‍‍‍‍ Once proper UUIDs have been stablished, the new service must be added to the GATT database. It is defined in the file gatt_db.h. Simple macros are used to include each of the attributes in the proper order. Following code shows the implementation of the potentiometer service in gatt_db file. PRIMARY_SERVICE_UUID128(service_potentiometer, uuid_service_potentiometer)     CHARACTERISTIC_UUID128(char_potentiometer_relative_value, uuid_characteristic_potentiometer_relative_value, (gGattCharPropRead_c | gGattCharPropNotify_c))         VALUE_UUID128(value_potentiometer_relative_value, uuid_characteristic_potentiometer_relative_value, (gPermissionFlagReadable_c ), 1, 0x00)         CCCD(cccd_potentiometer)         DESCRIPTOR(cpfd_potentiometer, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, gCpfdUnsigned8BitInteger, 0x00,                    0xAD/*Unit precentage UUID in Little Endian (Lower byte)*/,                    0x27/*Unit precentage UUID in Little Endian (Higher byte)*/,                    0x01, 0x00, 0x00) ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ PRIMARY_SERVICE_UUID128 (service_name, service_uuid) defines a new service in the GATT database with a custom 128-bit UUID. It requires two parameters; service_name is the name of this service in the code and it is used later during the program implementation. Service_uuid is the identifier for the service UUID previously defined in gatt_uuid128.h. CHARACTERISTIC_UUID128 (characteristic_name, characteristic_uuid, flags) defines a new characteristic inside the previously defined service with a custom 128-bit UUID. It requires three parameters; characteristic_name is the name of the characteristic in the code, characteristic_uuid is the identifier for the characteristic UUID previously defined in gatt_uuid128.h. Finally, flags is a concatenation of all the characteristic properties (read, write, notify, etc.). VALUE_UUID128 (value_name, characteristic_uuid, permission_flags, number_of_bytes, initial_values…) defines the value in the database of the previously defined characteristic. Value_name is an identifier used later in the code to read or modify the characteristic value. Characteristic_uuid is the same UUID identifier for the previously defined characteristic. Permission_flags determine how the value can be accessed (read, write or both). Number of bytes define the size of the value followed by the initial value of each of those bytes. CCCD (cccd_name) defines a new Client Characteristic Configuration Descriptor for the previously defined characteristic. Cccd_name is the name of the CCCD for use later in the code. This value is optional depending on the characteristic flags. DESCRIPTOR (descriptor_name, descriptor_format, permissions, size, descriptor_bytes…) defines a descriptor for the previously defined characteristic. Descriptor_name defines the name for this descriptor. Descriptor_format determines the type of descriptor. Permissions stablishes how the descriptor is accessed. Finally the size and descriptor bytes are added. All the macros used to fill the GATT database are properly described in the BLEADG (included in the NXP Connectivity Software documentation) under chapter 7 “Creating a GATT Database”. Implementing Drivers for New Service Once the new service has been defined in gatt_db.h, drivers are required to handle the service and properly respond to client requests. To do this, two new files need to be created per every service added to the application; (service name)_service.c and (service name)_interface.h. The service.c file will include all the functions required to handle the service data, and the interface.h file will include all the definitions used by the application to refer to the recently created service. It is recommended to take an existing file for reference. Interface header file shall include the following. Service configuration structure that includes a 16-bit variable for Service Handle and a variable per each characteristic value in the service. /*! Potentiometer Service - Configuration */ typedef struct psConfig_tag {     uint16_t    serviceHandle;                 /*!<Service handle */     uint8_t     potentiometerValue;            /*!<Input report field */ } psConfig_t; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Function declarations for the start service and stop service functions. These are required to initialize/deinitialize a service. bleResult_t Ps_Start(psConfig_t *pServiceConfig); bleResult_t Ps_Stop(psConfig_t *pServiceConfig); ‍‍‍‍‍‍ Function declarations for subscribe and unsubscribe functions required to subscribe/unsubscribe a specific client to a service. bleResult_t Ps_Subscribe(deviceId_t clientDeviceId); bleResult_t Ps_Unsubscribe(); ‍‍‍‍‍‍ Depending on your application, functions to read, write, update a specific characteristic or a set of them. bleResult_t Ps_RecordPotentiometerMeasurement (uint16_t serviceHandle, uint8_t newPotentiometerValue);‍‍ Service source file shall include the following. A deviceId_t variable to store the ID for the subscribed client. /*! Potentiometer Service - Subscribed Client*/ static deviceId_t mPs_SubscribedClientId; ‍‍‍‍‍‍ Function definitions for the Start, Stop, Subscribe and Unsubscribe functions. The Start function may include code to set an initial value to the service characteristic values. bleResult_t Ps_Start (psConfig_t *pServiceConfig) {        /* Clear subscibed clien ID (if any) */     mPs_SubscribedClientId = gInvalidDeviceId_c;         /* Set the initial value defined in pServiceConfig to the characteristic values */     return Ps_RecordPotentiometerMeasurement (pServiceConfig->serviceHandle,                                              pServiceConfig->potentiometerValue); } bleResult_t Ps_Stop (psConfig_t *pServiceConfig) {   /* Unsubscribe current client */     return Ps_Unsubscribe(); } bleResult_t Ps_Subscribe(deviceId_t deviceId) {    /* Subscribe a new client to this service */     mPs_SubscribedClientId = deviceId;     return gBleSuccess_c; } bleResult_t Ps_Unsubscribe() {    /* Clear current subscribed client ID */     mPs_SubscribedClientId = gInvalidDeviceId_c;     return gBleSuccess_c; } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Definition of the service specific functions. It is, the functions used to write, read or notify characteristic values. Our example only implements two; a public function to update a characteristic value in the GATT database, and a local function to issue a notification with the recently updated value to the client. bleResult_t Ps_RecordPotentiometerMeasurement (uint16_t serviceHandle, uint8_t newPotentiometerValue) {     uint16_t  handle;     bleResult_t result;     /* Get handle of Potentiometer characteristic */     result = GattDb_FindCharValueHandleInService(serviceHandle,         gBleUuidType128_c, (bleUuid_t*)&potentiometerCharacteristicUuid128, &handle);     if (result != gBleSuccess_c)         return result;     /* Update characteristic value */     result = GattDb_WriteAttribute(handle, sizeof(uint8_t), (uint8_t*)&newPotentiometerValue);     if (result != gBleSuccess_c)         return result;     Ps_SendPotentiometerMeasurementNotification(handle);     return gBleSuccess_c; } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Previous function first obtains the handle value of the characteristic value we want to modify. Handle values are like an index used by the application to access attributes in the database. The UUID for the Potentiometer Relative Value is used to obtain the proper handle by calling GattDb_FindCharValueHandleInService function. Once handle has been obtained, is used in the GattDb_WriteAttribute function to write the new value into the GATT database and it can be accessed by the client. Finally our second function is called to issue a notification. static void Ps_SendPotentiometerMeasurementNotification (   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         (mPs_SubscribedClientId, hCccd, &isNotificationActive) &&         TRUE == isNotificationActive)     {         GattServer_SendNotification(mPs_SubscribedClientId, handle);     } } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ SendPotentiometerMeasurementNotification sends a notification to the client. It first obtain the handle value of the CCCD we defined in the GATT database for this characteristic. Then, it checks that the CCCD has been written by the client for notifications. If it has, then it sends the notification so the client can perform a read to the characteristic value. All the functions used to access the GATT database and use the GATT server are better explained in the BLEADG document under chapters 6 and 7. Also instructions on how to create a custom profile are included in chapter 8. BLEADG is part of the NXP Connectivity Software documentation. Integrating a New Service to an Existing BLE Project So far a new service has been created in the database and functions to handle it have been defined. Now this new project must be integrated so it can be managed by the NXP Connectivity Stack. Folder structure of an NXP Connectivity Software project is divided in five different modules. App includes all the application files. Bluetooth contains files related with BLE communications. Framework contains auxiliary software used by the stack for the handling of memory, low power etcetera. KSDK contains the Kinetis SDK drivers for low level modules (ADC, GPIO…) and RTOS include files associated with the operating system. Figure 3 Folder structure Service files must be added to the project under the Bluetooth folder, inside the profiles sub-folder. A new folder must be created for the service.c file and the interface.h file must be added under the interface sub-folder. Figure 4 Service files included Once the files are included in the project, the service must be initialized in the stack. File app.c is the main application file for the NXP BLE stack. It calls all the BLE initializations and application callbacks. The service_interface.h file must be included in this file. Figure 5 Interface header inclusion Then in the local variables definition, a new service configuration variable must be defined for the new service. The type of this variable is the one defined in the service interface file and must be initialized with the service name (defined in gattdb.h) and the initial values for all the characteristic values. Figure 6 Service configuration struct The service now must be initialized. It is performed inside the BleApp_Config function by calling the Start function for the recently added service. static void BleApp_Config() {      /* Read public address from controller */     Gap_ReadPublicDeviceAddress();     /* Register for callbacks*/     App_RegisterGattServerCallback(BleApp_GattServerCallback);       .    .    .    mAdvState.advOn = FALSE;     /* Start services */     Lcs_Start(&lcsServiceConfig);     Dis_Start(&disServiceConfig);     Irs_Start(&irsServiceConfig);     Bcs_Start(&bcsServiceConfig);     Ps_Start(&psServiceConfig); ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Finally, subscribe and unsubscribe functions must be added to the proper host callback. In the BleApp_ConnectionCallback function the subscribe function must be called after the gConnEvtConnected_c (device connected) case, and the unsubscribe function must be called after the gConnEvtDisconnected_c (device disconnected) case. static void BleApp_ConnectionCallback (deviceId_t peerDeviceId, gapConnectionEvent_t* pConnectionEvent) {     switch (pConnectionEvent->eventType)     {         case gConnEvtConnected_c:         {         .         .         .             /* Subscribe client*/             mPeerDeviceId = peerDeviceId;             Lcs_Subscribe(peerDeviceId);             Irs_Subscribe(peerDeviceId);             Bcs_Subscribe(peerDeviceId);             Cts_Subscribe(peerDeviceId);             Ps_Subscribe(peerDeviceId);             Acs_Subscribe(peerDeviceId);             Cps_Subscribe(peerDeviceId);             Rcs_Subscribe(peerDeviceId);         .         .         .         case gConnEvtDisconnected_c:         {         /* UI */           Led1Off();                     /* Unsubscribe client */           mPeerDeviceId = gInvalidDeviceId_c;           Lcs_Unsubscribe();           Irs_Unsubscribe();           Bcs_Unsubscribe();           Cts_Unsubscribe();           Ps_Unsubscribe();           Acs_Unsubscribe();           Cps_Unsubscribe();           Rcs_Unsubscribe(); ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ After this, services can be accessed by a client application. Handling Notifications and Write Requests Once the new service has been initialized, it is possible for the client to access GATT database attributes and issue commands (read, write, notify…). Nevertheless, when an attribute is written or a CCCD is set to start notifications, program must be aware of these requests to handle them if required. Handling Notifications When a characteristic has been configured as notifiable, the client expects to receive messages from it every time in a while depending on the pre-configured parameters. To indicate this, the client writes the specific CCCD for the characteristic indicating that notifications must start/stop being sent. When this occurs, BleApp_GattServerCallback is executed in the main program. All the application CCCDs must be monitored when the gEvtCharacteristicCccdWritten_c event is set. This event indicates that a CCCD has been written. A conditional structure must be programmed to determine which CCCD was modified and act accordingly. static void BleApp_GattServerCallback (deviceId_t deviceId, gattServerEvent_t* pServerEvent) {     switch (pServerEvent->eventType)     {       case gEvtCharacteristicCccdWritten_c:         {             /*             Attribute CCCD write handler: Create a case for your registered attribute and             execute callback action accordingly             */             switch(pServerEvent->eventData.charCccdWrittenEvent.handle)             {             case cccd_input_report:{               //Determine if the timer must be started or stopped               if (pServerEvent->eventData.charCccdWrittenEvent.newCccd){                 // CCCD set, start timer                 TMR_StartTimer(tsiTimerId, gTmrIntervalTimer_c, gTsiUpdateTime_c ,BleApp_TsiSensorTimer, NULL); #if gAllowUartDebug                 Serial_Print(debugUartId, "Input Report notifications enabled \n\r", gNoBlock_d); #endif               }               else{                 // CCCD cleared, stop timer                 TMR_StopTimer(tsiTimerId); #if gAllowUartDebug                 Serial_Print(debugUartId, "Input Report notifications disabled \n\r", gNoBlock_d); #endif               }             }               break;                           case cccd_potentiometer:{               //Determine if the timer must be started or stopped               if (pServerEvent->eventData.charCccdWrittenEvent.newCccd){                 // CCCD set, start timer                 TMR_StartTimer(potTimerId, gTmrIntervalTimer_c, gPotentiometerUpdateTime_c ,BleApp_PotentiometerTimer, NULL); #if gAllowUartDebug                 Serial_Print(debugUartId, "Potentiometer notifications enabled \n\r", gNoBlock_d); #endif               }               else{                 // CCCD cleared, stop timer                 TMR_StopTimer(potTimerId); #if gAllowUartDebug                 Serial_Print(debugUartId, "Potentiometer notifications disabled \n\r", gNoBlock_d); #endif               }             }               break; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ In this example, when the gEvtCharacteristicCccdWritten_c is set a switch-case selector is executed to determine the written CCCD. This is done by reading the pServerEvent structure in the eventData.charCccdWrittenEvent.handle field. The obtained handle must be compared with the name of the CCCD defined in gatt_db.h for each notifiable characteristic. Figure 7 CCCD name Once the correct CCCD has been detected, the program must determine if it was set or clear. This is done by reading the pServerEvent structure in the eventData.charCccdWrittenEvent.newCccd and executing an action accordingly. In the example code, a timer is started or stopped. Once this timer reaches its modulo value, a new notification is sent using the Ps_RecordPotentiometerMeasurement function previously defined in the service files (see Implementing Drivers for New Service). Handling Write Requests Write request callbacks are not automatically generated like the notification ones. They must be registered during the application initialization. Something to take into account is when this feature is enabled, the written value is not automatically stored in the GATT database. Developers must implement code to do this and perform other application actions if needed.To do this, the GattServer_RegisterHandlesForWriteNotifications function must be called including the handles of all the characteristics that are wanted to generate a callback when written. * Configure writtable attributes that require a callback action */     uint16_t notifiableHandleArray[] = {value_led_control, value_buzzer, value_accelerometer_scale, value_controller_command, value_controller_configuration};     uint8_t notifiableHandleCount = sizeof(notifiableHandleArray)/2;     bleResult_t initializationResult = GattServer_RegisterHandlesForWriteNotifications(notifiableHandleCount, (uint16_t*)&notifiableHandleArray[0]); ‍‍‍‍‍‍‍‍‍ In this example, an array with all the writable characteristics was created. The function that register callbacks requires the quantity of characteristic handles to be registered and the pointer to an array with all the handles. After a client has connected, the gEvtAttributeWritten_c will be executed inside the function BleApp_GattServerCallback every time one of the configured characteristics has been written. Variable pServerEvent->eventData.attributeWrittenEvent.handle must be read to determine the handle of the written characteristic and perform an action accordingly. Depending on the user application, the GATT database must be updated with the new value. To do this, function GattDb_WriteAttribute must be executed. It is recommended to create a function inside the service.c file that updates the attribute in database. case gEvtAttributeWritten_c:         {             /*             Attribute write handler: Create a case for your registered attribute and             execute callback action accordingly             */             switch(pServerEvent->eventData.attributeWrittenEvent.handle){               case value_led_control:{                 bleResult_t result;                                 //Get written value                 uint8_t* pAttWrittenValue = pServerEvent->eventData.attributeWrittenEvent.aValue;                                 //Create a new instance of the LED configurator structure                 lcsConfig_t lcs_LedConfigurator = {                   .serviceHandle = service_led_control,                   .ledControl.ledNumber = (uint8_t)*pAttWrittenValue,                   .ledControl.ledCommand = (uint8_t)*(pAttWrittenValue + sizeof(uint8_t)),                 };                                 //Call LED update function                 result = Lcs_SetNewLedValue(&lcs_LedConfigurator);                                 //Send response to client                 BleApp_SendAttWriteResponse(&deviceId, pServerEvent, &result);                               }               break; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ After all the required actions have been executed, server must send a response to the client. To do this, function GattServer_SendAttributeWrittenStatus is called including the handle and the error code for the client (OK or any other error status). static void BleApp_SendAttWriteResponse (deviceId_t* pDeviceId, gattServerEvent_t* pGattServerEvent, bleResult_t* pResult){   attErrorCode_t attErrorCode;     // Determine response to send (OK or Error)   if(*pResult == gBleSuccess_c)     attErrorCode = gAttErrCodeNoError_c;   else{     attErrorCode = (attErrorCode_t)(*pResult & 0x00FF);   }   // Send response to client    GattServer_SendAttributeWrittenStatus(*pDeviceId, pGattServerEvent->eventData.attributeWrittenEvent.handle, attErrorCode); } ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ More information on how to handle writable characteristics can be found in the BLEADG Chapter 5 (Included in the NXP Connectivity Software documentation). References Bluetooth® Low Energy Application Developer’s Guide (BLEADG)– Included in the NXP Connectivity Software Documentation FRDM-KW40Z Demo Application - Link
View full article
Bluetooth Low Energy is a standard for Low Power Wireless Networks introduced in the Bluetooth specification 4.0. Its target application domains include medical, sports & fitness, home automation and others. The adoption and development rates of this technology are growing fast helped by the wide availability of hardware support in most modern mobile phones and mobile operating systems. The purpose of this application note is to show how the Freescale FRDM-KW40Z can board with BLE Controller software can be used with the hcitool from the Linux Bluetooth stack over the HCI interface. 1. Introduction The Bluetooth specification has a very well defined interface between the Controller and the Host called the HCI (Host Controller Interface). This interface is defined for and can be used with various transport layers including an asynchronous serial transport layer. A typical scenario of Bluetooth Low Energy hardware use is a development board which has a BLE Controller accessible via serial transport HCI connected to a device on which the BLE Host runs. The device which runs the BLE Host can be any type of embedded device or a PC. PCs running a Linux type OS can use the hcitool from the Linux Bluetooth Stack to interact with a BLE Controller via the HCI interface. The particular use case of  FRDM-KW40Z board with a serial transport HCI interface running over USB CDC and connected to a PC running the Linux Bluetooth stack is shown in the diagram below and will be detailed din the following sections. Figure 1FRDM-KW40Z (BLE Controller) connected to Linux PC (Bluetooth Host Stack) via HCI Serial Transport 2. Loading the HCI Application onto the FRDM-KW40Z First load the hci_app on the FRDM-KW40Z board. The hci_app aplication can be found in the <ConnectivitySwInstallationPath>\ConnSw\examples\bluetooth\hci_app folder. 3. Connecting the FRDM-KW40Z to the Computer via a Serial Port After the app is downloaded to the board plug the board into a free USB port of your Linux computer. The following instructions, commands and their output is typical to a Debian based Linux OS. After the board is plugged in run the following command to list the serial ports available. >> dmesg | grep tty [ 0.000000] console [tty0] enabled [ 2374.118201] cdc_acm 1-2:1.1: ttyACM0: USB ACM device In our example the FRDM-KW40Z board serial port is ttyACM0. To test the connection some HCI commands can be sent in hex format from any terminal application to the serial HCI on the FRDM-KW40Z board. In the figure below an HCI_Read_BD_ADDR command and its corresponding Command Complete Event are shown as they were sent and received in hexadecimal format from the moserial serial terminal GUI application. Figure 2: HCI command and response event in hexadecimal format (HCI UART Transport) 4. Connecting the HCI Serial Interface to the Bluetooth Stack To connect the Linux Bluetooth stack to a serial HCI interface the hciattach command must be run as shown below. >> hciattach /dev/ttyACM0 any 115200 noflow nosleep Device setup complete If the the HCI serial interface is successfully attached to the Bluetooth stack then the "Device setup complete" message is shown. The any parameter specifies a generic Bluetooth device. The 115200 parameter is the UART baudrate. The noflow parameter diasables serial flow control. The nosleep parameter disables hardware specific power managment. Run the hciconfig command with no parameters to check the HCI interface id of the newly attached HCI serial device. >> hciconfig hci1:    Type: BR/EDR  Bus: UART     BD Address: 00:04:9F:00:00:15  ACL MTU: 27:4 SCO MTU: 0:0     UP RUNNING     RX bytes:205 acl:0 sco:0 events:14 errors:0     TX bytes:112 acl:0 sco:0 commands:14 errors:0 hci0:    Type: BR/EDR  Bus: USB     BD Address: 90:00:4E:A4:70:97  ACL MTU: 310:10  SCO MTU: 64:8     UP RUNNING     RX bytes:595 acl:0 sco:0 events:37 errors:0     TX bytes:2564 acl:0 sco:0 commands:36 errors:0 In this example the FRDM-KW40Z is assigned the hci1 interface as can be seen from the bus type (Type: BR/EDR  Bus: UART). The hci0 interface is the example shown corresponds to the on-board Bluetooth module from the machine. On some systems the interface might need to be manually started by using the hciconfig interfaceId up command. hciconfig hci1 up 5. Configuring the Bluetooth Device and Listing its Capabilities The hciconfig command offers the possibility of configuring the device and listing the device capabilities. To find all commands supported by the hciconfig tool type the following command. >> hciconfig –h ...display supported commands... Each individual hciconfig command must be addressed to the correct HCI interface as reported above. In our example we use the hci1 interface. Some hciconfig commands require root privileges and must be run with sudo (the "Operation not permitted(1)" error will be returned if a command needs to be run with root privileges). Some useful hci config commands: >> hciconfig hci1 version    -> lists hci device verison information >> hciconfig hci1 revision    -> lists hci device revision information >> hciconfig hci1 features    -> lists the features supported by the device >> hciconfig hci1 commands    -> lists the hci commands supported by the device >> sudo hciconfig hci1 lestates    -> lists the BLE states supported by the device >> sudo hciconfig hci1 lerandaddr 11:22:33:44:55:66    -> set a random address on the device >> sudo hciconfig hci1 leadv 3    -> enable LE advertising of the specified type >> sudo hciconfig hci1 noleadv    -> disable LE advertising Now the newly connected board with a serial HCI is attached to a HCI interface of the Bluetooth stack and is ready to use. 6.    Controlling the Bluetooth Device using the hcitool The hcitool can be used to send HCI commands to the Bluetooth device. A command is available which lists all available hcitool actions. >> hcitool -h ...display supported commands... To target a specific HCI interface use the -i hciX option for an hcitool command. We will use -i hci1 in our examples. The hcitool supports commands for common BLE HCI operations some of which are shown below and also supports sending generic HCI commands using a dedicated option which uses hexadecimal numbers for the OGF (Command Group), OCF (Command Code) and the parameters. The 6 bit OGF and the 10 bit OCF compose the 16 bit HCI Command Opcode. The command parameters are specific to each command. 6.1.  Listing Devices Available to the hcitool An hcitool command can list all available device interfaces. >> hcitool dev Devices: hci1    00:04:9F:00:00:15 hci0    90:00:4E:A4:70:97 The device we are working with is connected to the hci1 interface as seen from the output of the hciconfig command used above. 6.2.  Scanning for Advertising LE Devices The hcitool can be used to perform a LE Device scan. This command requires root privileges. Press Ctrl+C to stop the scan at any time. >> sudo hcitool -i hci1 lescan LE Scan ... 00:04:9F:00:00:13 (FSL_OTAC) ^C A list of addresses and device names will be shown if advertised (<<Shortened Local Name>> or <<Complete Local Name>> as define din the specification). 6.3.  Obtaining Remote LE Device Information Using the hcitool To obtain information about a remote LE device a special hcitool command can be used. The hcitool leinfo command creates a connection, extracts information from the remote device and then disconnects. The remote device information is shown at the command prompt. >> sudo hcitool -i hci1 leinfo 00:04:9F:00:00:13 Requesting information ...        Handle: 32 (0x0020)        LMP Version: 4.1 (0x7) LMP Subversion: 0x113        Manufacturer: Freescale Semiconductor, Inc. (511)        Features: 0x1f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 In this example information about a device previously discovered using the hcitool lescan command is shown. 6.4.  Connecting and Disconnecting from a Remote LE Device Connecting to a remote LE device is done using the hcitool lecc command. >> sudo hcitool -i hci1 lecc 00:04:9F:00:00:13 Connection handle 32 As before a previously discovered device address is used. If the connection is successful then the Connection Handle is returned and in our case the Connection Handle is 32. The hcitool con command shows active connections information: address, connection handle, role, etc. >> hcitool con Connections: < LE 00:04:9F:00:00:13 handle 32 state 1 lm MASTER To end a LE connection the hcitool ledc command can be used. It must be provided with the Connection Handle to be terminated, and optionally the reason. The device handle obtained after the connection and shown in the connected devices list is used. >> hcitool –I hci1 ledc 32 >> Listing the connections after all connections are terminated will show an empty connection list. >> hcitool con Connections: >> 6.5.  Sending Arbitrary HCI Commands To send arbitrary HCI commands to a device using the Command CopCode (OGF and OCF) the hcitool cmd command can be used. As an example the HCI_Read_BD_ADDR command is used which has the 0x1009 OpCode (OGF=0x04, OCF=0x009) and no parameters. It is the same command shown in the direct serial port to HCI communication example above. hcitool -i hci0 cmd 0x04 0x0009 < HCI Command: ogf 0x04, ocf 0x0009, plen 0 > HCI Event: 0x0e plen 10   01 09 10 00 15 00 00 9F 04 00 The OpCode OGF (0x04) and OCF (0x009) and no parameters are passed to the hcitool cmd command all in hexadecimal format. The parameters length (plen) is 0 for the command. The response is a Command Complete event (0x03) with the parameters length (plen) 10. The parameters are 01 09 10 00 15 00 00 9F 04 00: 01 is the Num_HCI_Command_Packets parameter 09 10 is the Command OpCode for which this Command Complete Event is returned (in little endian format) 00 is the status – Success in this case 15 00 00 9F 04 00 is the BD_ADDR of the device as listed by the hcitool dev command
View full article
This article will describe in detailed steps how to generate, build and test a Bluetooth low energy Heart Rate Sensor project on the FRDM-KW41Z evaluation board by using the Bluetooth Developer Studio (BDS) and the NXP Kinetis BDS Plug-in. Getting Started To use this plug-in and test its output, the following programs are required:  - Bluetooth Developer Studio v1.1.306 or newer: Bluetooth Developer Studio & Plugins | Bluetooth Technology Website   - NXP Semiconductors Kinetis Plug-in v1.0.0: Link  - Kinetis SDK 2.0 with support for MKW41Z and Bluetooth Stack version 1.2.2: Link  - Kinetis SDK 2.0 add-on for BDS (found in the same package as the plug-in)  - Kinetis BLE Toolbox Android or iOS mobile application To enable the NXP Kinetis BDS Plug-in in the Bluetooth Developer Studio, follow please the installation details in the readme.txt document included in the downloaded plug-in archive. Creating the project with BDS Create a new project by clicking FILE-> NEW PROJECT. Add project location, name and namespace as detailed below: Drag and drop an adopted Heart Rate Profile from the right hand side list. Your device should import the following services:   Next step will be to configure the GAP layer. Click on the GAP button. First tab will be the Advertising Data. Enter desired values and check which AD types you want to include in the advertising packets. A bar below will show you how much bytes your data uses. Make sure you do not use more than the 32 bytes available. Next step is to configure the GAP properties. Make sure you check at least one advertising channel and a reasonable advertising interval range, as presented below:     Click TOOLS->GENERATE CODE. Select Server as GATT side to be generated and NXP Semiconductors Kinetis v1.0.0 as the plug-in. BDS will prompt you to enter a location for the exported files. After generating the files, another window with the results log will appear. If no error messages appear, the generation is successful. Check the “Open output location when finished” box and hit the “Finish” button. A folder with the following content will open: Using the generated code Copy the contents inside the following folder:  "<SDK 2.0 installation folder>\middleware\wireless\bluetooth_1.2.2\examples\bds_template_app". To generate the “bds_template_app” embedded project and test it, follow the instructions detailed in the Bluetooth Quick Start Guide document from the SDK. Seeing the application in action Before compiling the application add the following code snippet in app.c inside BleApp_HandleKeys:         case gKBD_EventPressPB2_c:         {             mUserData.cRrIntervals = 0;             mUserData.expendedEnergy = 100;             Hrs_RecordHeartRateMeasurement(service_heart_rate, 120, &mUserData);             break;         } This will allow the board to send heart rate data of 120 bpm while in a connection and when pressing button SW3 on the FRDM-KW41Z board. The value can be seen when using Kinetis BLE Toolbox, as shown below:
View full article
HCI Application is a Host Controller Interface application which provides a serial communication to interface with the KW40/KW41 BLE radio part. It enables the user to have a way to control the radio through serial commands. In this section will be discussed how user could send serial commands to the KW40/KW41 device. “HCI app” file is given to test the BLE functionality. User needs to open the COM port with the configuration 115200 8N1N. Then, it is needed to send commands in Hex format, user can make use of Docklight application. Once HCI application is downloaded to the board, next steps need to be followed:         Open the COM port.       Send the next command in Hex format “01 03 0C 00”. It is to perform a Reset to the radio.       Send the next command in Hex format “01 1E 20 03 26 20 00”. It is to set the radio in Transmit test mode. The number 26 specifies the number of the channel in which user wants to see the signal(valid range is from 0x00 to 0x27, this means from BLE Channel 0 to BLE Channel 39). Number 00 specifies the type of the signal that will be sent, in this case, it is a PBRS9 format. (valid range are from 0x00 to 0x07). Refer to the next table to know the meanings of each type of signal.  Finally, 20 is the number that specifies the length that will be sent in the packet or the payload, in this case, it is configured to 20 (32 bytes), VALID RANGE is from 0x00 to 0x25.       In order to set the radio in Receiver Test Mode. The next command in hex format need to be used "01 1D 20 01 04", this command means that radio would be listening in channel 04. Hence, values "01 1D 20 01" is the command to set the radio in Rx mode, the last value "04' defines the channel in which device is going to listen. As an additional example, if channel 06 is desired, command "01 1D 20 01 06" should be used.     If there is a need to change the output power of the radio. The NXP connectivity software provides the Controller_SetTxPowerLevel() which is called inside of the Controller_TaskInit(). Controller_SetTxPowerLevel() function make use of the following defines to determine the default power output in the application:   mAdvertisingDefaultTxPower_c and mConnectionDefaultTxPower_c. The value range for both is from 0 to 31. The range might be different for each device, so, it needs to be corroborated. This range is applicable only for KW41Z device. For example, for KW40Z, range is from 0 to 15.     The defines are defined in the file ble_controller_task_config.h. Finally, HCI applications can be found in the connectivity software package of your desired device. If the KW40Z is the device under test (DUT), the HCI application is called "hci_app", it can be found in the next path: "<insllation_path>\KW40Z_Connectivity_Software_1.0.1\ConnSw\examples\bluetooth\hci_app"   If the KW41Z is the device under test (DUT), the HCI application is called "hci_black_box", it can be found in the next path: "<insllation_path>\MKW41Z_ConnSw_1.0.2\boards\frdmkw41z\wireless_examples\bluetooth\hci_black_box"
View full article
This document describes how to add additional cluster to the Router application in the JN-AN-1217 ZigBee 3.0 Base Device Application Note. The Router application's main endpoint contains Basic, Groups, Identify and OnOff server. The steps below describe how to add two clusters to Router: Temperature Measurement server and OnOff client. Note that these changes only go as far as making the new clusters added and discoverable, no functionality has been added to these clusters.  Common/Source/app.zpscfg The first step is to update the ZigBee PRO Stack Configuration file to add the new clusters (OnOff Client, Temperature Measurement Server) to the Router application endpoint. The HA profile already contains few clusters but Temperature Measurement cluster was added:   The OnOff client was already present in Router endpoint but the Temperature Measurement cluster was then added into Router application endpoint:   Router/Build/Makefile For cluster belonging to General domain, the cluster code is automatically build and linked but for other domains, the compiling and linking needs to be enabled. As Temperature Measurement belongs to Measurement and Sensing domain, enable the cluster code in Makefile: Router/Source/zcl_options.h This file is used to set the options used by the ZCL. Enable Clusters The cluster functionality for the router endpoint was enabled:   Enable any optional Attributes and Commands for the clusters  Add the cluster creation and initialization into ZigBee Base device definitions The cluster functionality for some of the clusters is already present on ZigBee Base Device. For Temperature Measurement cluster the functionality was added into ZigBee Base Device. <Path to JN-SW-4x70 SDK>/ Components/ZCL/Devices/ZHA/Generic/Include/base_device.h The first step was including the Temperature Measurement header files into base device header file as shown below:   The second step was adding cluster instance into base device Instance as shown below: The next step was to define the cluster into the base device structure as below: <Path to JN-SW-4x70 SDK>/ Components/ZCL/Devices/ZHA/Generic/Include/base_device.c The cluster create function for Temperature Measurement cluster for server was called in ZigBee base device registration function:   Router/Source/app_zcl_task.c Temperature Measurement Server Cluster Data Initialization - APP_vZCL_DeviceSpecific_Init() The default attribute values for the Temperature Measurement clusters are initialized:
View full article
General summary MCUBOOT, fsci_bootloader and otap_bootloader are 3 different bootloader applications that can be used depending on the use case. The MCU Flashloader is a separate implementation but it's also mentioned to avoid misunderstanding.   MCUBOOT The MCU bootloader provides support for multiple communication protocols (UART, SPI, I2C, CAN) and multiple applications to interface with it. Summary: - It's a configurable flash programming utility that operates over a serial connection on several Kinetis MCUs. - Host-side command line (blhost) and GUI tools are available to communicate with the bootloader.  -  By default, application starts at address 0xa000. - MCU Bootloader|NXP website - MCU Bootloader Reference Manual - MCU Bootloader Demo Application User's Guide   fsci_bootloader Framework Serial Connectivity Interface (FSCI) is an NXP propietary protocol that allows interfacing the Kinetis protocol stack with a host system or PC tool using a serial communication interface. The FSCI bootloader enables the FSCI module to communicate with the PC and transfer the image using the FSCI protocol. Summary: - It relies on the FSCI protocol to transfer the binary from a PC connected via UART, using a python and C applications. - To enter into bootloader mode (in FRDM-KW41Z), hold SW1 (Reset) and press SW4, then release SW1 first and SW4 second. Please refer to demo user's guide to get the specific steps for your platform. - By default, application starts at 0x4000. - FSCI Bootloader Manual   otap_bootloader The Connectivity SDK contains Over-the-Air firmware upgrade examples. The OTAP bootloader loads an image obtained from wireless communication, the OTAP bootloader only enters after an image was successfully transferred to the client device (internal or external flash). Summary: - It's used by over the air programmed devices. - The bootloader mode only enters if a flag is set after reset triggered by a successful reception of an image over the air. - By default, application starts at 0x4000. - Kinetis Thread Stack Over-the-Air (OTA) Firmware Update User’s Guide   mcu_flashloader The MCU flashloader is a specific implementation of the MCU bootloader. For the flashloader implementation, the MCU bootloader command interface is packaged as an executable that is loaded from flash and executed from RAM. This configuration allows the user application to be placed at the beginning of the on-chip flash where it is automatically launched upon boot from flash. Using the MCU flashloader to program a user application to the beginning of the flash makes this implementation of the bootloader a one-time programming aid. The MCU flashloader doesn't allow to jump to a different section after a timeout or button press like the other bootloaders, it's main purpose is to flash an application without the need of an external debugger, mainly used for factory programming. Summary: - It is pre-programmed into many Kinetis flash devices during manufacturing and enables flash programming without the need for a debugger. - After the user application is programmed into flash memory, the Kinetis flashloader is no longer available. - Documentation: Getting Started with the MCU Flashloader   You can select from the MCU Bootloader, FSCI_Bootloader and OTAP Bootloader, depending on your needs. JC
View full article
The purpose of this document is to communicate known issues with the FRDM-KW41Z development platform.  This document applies to all revisions of the FRDM-KW41Z development platform.  However, items are divided among their respective revisions and each item may or may not apply to all revisions.  Revision A The known issues, which may cause confusion for new customers, for revision A are as follows: 1) Incorrect default jumper configuration Issue:  Jumper, J24, shunt connector does not shunt pins 1 and 2, as noted in the schematic notes.   Impact:  Customers will not, by default, be able to put the OpenSDA circuit into bootloader mode.   Workaround:  There is currently only one workaround for this issue. Move shunt connector on jumper, J24, to shunt pins 1 and 2.   2) Default OpenSDA application may lose serial data Issue:  In certain situations, the serial to USB bridge portion of the default OpenSDA application may not correctly forward serial data. This problem typically only occurs after a POR of a development platform.   Impact: Customers may experience data loss when using the serial to USB converter functionality in their application.  Workaround:  There is currently one workaround for this issue.   Update to the latest JLink OpenSDA firmware.  To update to this firmware, consult sections 2.1 and 2.2 of the OpenSDA User Guide (found here:  http://cache.freescale.com/files/32bit/doc/user_guide/OPENSDAUG.pdf ).  The latest JLink OpenSDA firmware can be found here:  SEGGER - The Embedded Experts - Downloads - J-Link / J-Trace .  (Note:  Be sure to select the correct development platform.)                                                             3) Unable to measure correct IDD current when operating in buck mode and P3V3_BRD is disconnected Issue:  When configured for buck mode operation and J8 does not have a shunt connector, it is expected that P3V3_BRD will not be powered and thus, board peripherals will not be powered (thermistor, I2C line pull-ups, SPI Flash, Accelerometer, etc,).  However it should be noted that in this configuration, P3V3_BRD will be back-powered through resistor R90.  R90 is a 180kOhm resistor that connects directly to the MCU reset pin.  This R90 also connects to V_TGTMCU which is directly connected to P3V3_BRD through shorting trace SH500.  The internal pull-up on the reset pin will, in this case, power P3V3_BRD.      Impact:  Customers will not be able to isolate the MCU IDD current from the board peripherals when measuring current in the buck mode configuration.  This is a problem mostly when attempting to achieve datasheet IDD current numbers for low power modes in buck mode.   Workaround:  There are currently three (3) workarounds for this issue. Remove resistor R90. Cut shorting trace SH500. Customers should exercise caution when using this workaround.  After cutting this short trace, the OpenSDA interface buffers would no longer be powered.  Therefore, OpenSDA programming and serial communication will not be possible even when J8 shorting jumper is placed.   Disable the reset pin in the FOPT field then configure the pin, PTA2, for GPIO output functionality driven low.  Customers should exercise caution when implementing this option.  The pin, PTA2, could be used as a GPIO in the end application in this configuration, but you would not want to drive PTA2 high while SW1 was directly connected to PTA2 through pins 2 and 3 of jumper J24.  In this situation, you potentially short VDD and VSS inadvertently by pressing SW1.  If using this workaround, it is recommended to ensure the shorting jumper of J24 is either removed or connected to pins 1 and 2.    4) Incorrect routing of SWD clock for stand-alone debugger configuration Issue:  The signal SWD_CLK_TGTMCU  is incorrectly routed to pin 1 of connector J12 instead of pin 4 of the SWD connector, J9.     Impact:  With this routing, when the OpenSDA circuit is configured as a stand-alone debugger for debugging other targets (i.e., when J12's shorting trace is cut), the OpenSDA SWD clock will not be able to be present on pin 4 of connector J9. Therefore, the FRDM-KW41Z cannot act as a stand-alone debugger to facilitate debugging other systems.   Workaround:  There is currently only one workaround for this issue.  The workaround is a hardware workaround that requires a cutting tool (such as a modeler's knife), soldering iron, solder, and a spare wire.  To implement the workaround, follow these instructions.   Cut trace J12.                                                                                                                                                                            Cut the trace next to pin 2 and 4 of J9 that connects J9, pin 4 to J12, pin 2. Once this is done, be sure to use a multimeter and ensure there is no electrical connection between J12, pin 2, and J9, pin 4.                                                                                                          Solder one end of a spare wire to J9, pin 4, and the other end of the spare wire to J12, pin 1.  This should be done on the bottom of the board.  
View full article
Overview Bluetooth Low Energy offers the ability to broadcast data in format of non-connectable advertising packets while not being in a connection. This GAP Advertisement is widely known as a beacon and is used in today’s IoT applications in different forms. This article will present the current beacon format in our demo application from the KW40Z software package and how to create the most popular beacon formats on the market. The advertising packet format and payload are declared in the gAppAdvertisingData structure from app_config.c. This structure points to an array of AD elements, advScanStruct: static const gapAdStructure_t advScanStruct[] = {   {     .length = NumberOfElements(adData0) + 1,     .adType = gAdFlags_c,     .aData = (void *)adData0   },    {     .length = NumberOfElements(adData1) + 1,     .adType = gAdManufacturerSpecificData_c,     .aData = (void *)adData1   } }; Due to the fact that all beacons use the advertising flags structure and that the advertising PDU is 31 bytes in length (Bluetooth Low Energy v4.1), the maximum payload length is 28 bytes, including length and type for the AD elements. The AD Flags element is declared as it follows: static const uint8_t adData0[1] =  { (gapAdTypeFlags_t)(gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c) }; The demo application uses a hash function to generate a random UUID for the KW40Z default beacon. This is done in BleApp_Init: void BleApp_Init(void) {     sha1Context_t ctx;         /* Initialize sha buffer with values from SIM_UID */     FLib_MemCopy32Unaligned(&ctx.buffer[0], SIM_UIDL);     FLib_MemCopy32Unaligned(&ctx.buffer[4], SIM_UIDML);     FLib_MemCopy32Unaligned(&ctx.buffer[8], SIM_UIDMH);     FLib_MemCopy32Unaligned(&ctx.buffer[12], 0);          SHA1_Hash(&ctx, ctx.buffer, 16);         /* Updated UUID value from advertising data with the hashed value */     FLib_MemCpy(&gAppAdvertisingData.aAdStructures[1].aData[3], ctx.hash, 16); } When implementing a constant beacon payload, please bear in mind to disable this code section. KW40Z Default Beacon The KW40Z software implements a proprietary beacon with the maximum ADV payload and uses the following Manufacturer Specific Advertising Data structure of 26 bytes. This is the default implementation of the beacon demo example from the KW40Z Connectivity Software package. static uint8_t adData1[26] = {     /* Company Identifier*/     0xFF, 0x01     /* Beacon Identifier */     0xBC,     /* UUID */                  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,                                   /* A */                     0x00, 0x00,     /* B */                     0x00, 0x00,     /* C */                     0x00, 0x00,     /* RSSI at 1m */            0x1E}; iBeacon iBeacon is a protocol designed by Apple. It uses a 20 byte payload that consists of the following identifying information [1] : To advertise an iBeacon packet, the user needs to change the second AD element, adData1, like below: static uint8_t adData1[25] = {                                0x4C, 0x00,                                   0x02, 0x15,         /* UUID */             0xD9, 0xB9, 0xEC, 0x1F, 0x39, 0x25, 0x43, 0xD0, 0x80, 0xA9, 0x1E, 0x39, 0xD4, 0xCE, 0xA9, 0x5C,         /* Major Version */    0x00, 0x01         /* Minor Version */    0x00, 0x0A,                                0xC5}; AltBeacon AltBeacon is an open specification designed for proximity beacon advertisements [2]. It also uses a Manufacturer Specific Advertising Data structure: To advertise an AltBeacon packet, the user needs to change the second AD element, like below: static uint8_t adData1[26] = {     /* MFG ID*/         0xFF, 0x01,     /* Beacon Code */   0xBE, 0xAC,     /* Beacon ID */     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04,     /* Ref RSSI*/       0xC5,     /* MFG RSVD*/       0x00}; Eddystone™ Eddystone™ is an open Bluetooth® Smart beacon format from Google [3]. It offers three data type packets: Eddystone™-UID Eddystone™-URL Eddystone™-TLM Eddystone™ uses two advertising structures: Complete List of 16-bit Service UUIDs structure, which contains the Eddystone Service UUID (0xFEAA). Service Data structure, which also contains the Eddystone™ Service UUID (0xFEAA). Thus, advScanStruct will now have 3 elements: static const gapAdStructure_t advScanStruct[] = {   {     .length = NumberOfElements(adData0) + 1,     .adType = gAdFlags_c,     .aData = (void *)adData0   },    {     .length = NumberOfElements(adData1) + 1,     .adType = gAdComplete16bitServiceList_c,     .aData = (void *)adData1   },   {     .length = NumberOfElements(adData2) + 1,     .adType = gAdServiceData16bit_c,     .aData = (void *)adData2   } }; The complete List of 16-bit Service UUIDs element will look like: static const uint8_t adData1[2] =  { 0xAA, 0xFE }; Eddystone™-UID Eddystone™-UID broadcasts a unique 16-bit Beacon ID to identify a particular device in a group. The Service Data block has the following structure: To implement this, the user needs to add a third AD element, as follows: static uint8_t adData2[22] = {     /* ID */ 0xAA, 0xFE,     /* Frame Type */    0x00,     /* Ranging Data */  0xEE,     /* Namespace */     0x8B, 0x0C, 0xA7, 0x50, 0x09, 0x54, 0x77, 0xCB, 0x3E, 0x77,     /* Instance */      0x00, 0x00, 0x00, 0x00, 0x00, 0x01,     /* RFU */           0x00, 0x00}; Eddystone™-URL Eddystone™-URL broadcasts a compressed URL. The Service Data block has the following structure: In this example, we will implement a beacon which will advertise NXP’s webpage, http://www.nxp.com. To implement this, the user needs to add a third AD element, as follows: static const uint8_t adData2[9] = {     /* ID */ 0xAA, 0xFE,     /* Frame Type */    0x10,     /* TX Power */      0xEE,     /* URL scheme */    0x00,     /* Encode URL */    'n', 'x, 'p', 0x07}; Eddystone™-TLM Eddystone™-TLM broadcasts telemetry data about the beacon device operation. The Service Data block has the following structure: To implement this, the user needs to add a third AD element, as follows: static uint8_t adData2[16] = {     /* ID */ 0xAA, 0xFE,     /* Frame Type */    0x20,     /* TLM Version */   0x00,     /* VBATT */        0x00, 0x00,     /* TEMP */         0x00, 0x00,     /* ADV_CNT */      0x00, 0x00, 0x00, 0x00,     /* SEC_CNT */      0x00, 0x00, 0x00, 0x00};
View full article
I was investigating about how to create a current profile and I found interesting information I would like to share with the community. So, I decided to create an example to accomplish this task using BLE stack included in the MKW40Z Connectivity Software package. The demo to create is an Humidity Collector which make use of the Humidity custom profile and is based on the Temperature Collector demonstration application. The first thing to know is that the Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules.                                      GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations. 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. Figure 1. GATT Client-Server      GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors 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 KW40Z Connectivity Software package. Figure 2. GATT database      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 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      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 structures in BLE stack of KW40Z Connectivity Software have a common template. 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)      During the scanning process is when the client is going to connect with the Server. Hence, function CheckScanEvent can help us to ensure that peer device or server device support the specified service, in this case, it will be the humidity service we just created in the previous step. Then, CheckScanEvent needs to check which device is on advertising mode and with MatchDataInAdvElementList to verify if it is the same uuid_service_humidity, if the service is not in the list, client is not going to connect. CheckScanEvent function should look as shown next: static bool_t CheckScanEvent(gapScannedDevice_t* pData) { uint8_t index = 0; uint8_t name[10]; uint8_t nameLength; bool_t foundMatch = FALSE; while (index < pData->dataLength) {         gapAdStructure_t adElement;                 adElement.length = pData->data[index];         adElement.adType = (gapAdType_t)pData->data[index + 1];         adElement.aData = &pData->data[index + 2];          /* Search for Humidity Custom Service */         if ((adElement.adType == gAdIncomplete128bitServiceList_c) ||           (adElement.adType == gAdComplete128bitServiceList_c))         {             foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);         }                 if ((adElement.adType == gAdShortenedLocalName_c) ||           (adElement.adType == gAdCompleteLocalName_c))         {             nameLength = MIN(adElement.length, 10);             FLib_MemCpy(name, adElement.aData, nameLength);         }                 /* Move on to the next AD elemnt type */         index += adElement.length + sizeof(uint8_t); } if (foundMatch) {         /* UI */         shell_write("\r\nFound device: \r\n");         shell_writeN((char*)name, nameLength-1);         SHELL_NEWLINE();         shell_writeHex(pData->aAddress, 6); } return foundMatch; } The humidity_interface.h file should define the client structure and the server structure. For this demo, we only need the client structure, however, both are defined for reference. The Client Structure has all the data of the Humidity Service, in this case is a Service, characteristic, descriptor and CCCD handle and the format of the value. /*! Humidity Client - Configuration */ typedef struct humcConfig_tag { uint16_t    hService; uint16_t    hHumidity; uint16_t    hHumCccd; uint16_t    hHumDesc; gattDbCharPresFormat_t  humFormat; } humcConfig_t; The next configuration structure is for the Server; in this case we don’t need it. /*! Humidity Service - Configuration */ typedef struct humsConfig_tag { uint16_t    serviceHandle; int16_t     initialHumidity;        } humsConfig_t;     Now that the Client Structure is declared, go to the app.c and modify some functions. There are functions that help to store all the data of the humidity service. In our case they are 3 functions for the service, characteristic and descriptor. You have to be sure that the service that you create and the characteristics of humidity are in the functions. The Handle of each data is stored in the structure of the client. The three functions that need to be modify are the next: BleApp_StoreServiceHandles() stores handles for the specified service and characteristic. static void BleApp_StoreServiceHandles (     gattService_t   *pService ) {     uint8_t i;           if ((pService->uuidType == gBleUuidType128_c) &&         FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))     {         /* Found Humidity Service */         mPeerInformation.customInfo.humClientConfig.hService = pService->startHandle;                 for (i = 0; i < pService->cNumCharacteristics; i++)         {             if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&                 (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d))             {                 /* Found Humidity Char */                 mPeerInformation.customInfo.humClientConfig.hHumidity = pService->aCharacteristics[i].value.handle;             }         }     } } BleApp_StoreCharHandles() handles the descriptors. static void BleApp_StoreCharHandles (     gattCharacteristic_t   *pChar ) {     uint8_t i;         if ((pChar->value.uuidType == gBleUuidType16_c) &&         (pChar->value.uuid.uuid16 == gBleSig_Humidity_d))     {            for (i = 0; i < pChar->cNumDescriptors; i++)         {             if (pChar->aDescriptors[i].uuidType == gBleUuidType16_c)             {                 switch (pChar->aDescriptors[i].uuid.uuid16)                 {                     case gBleSig_CharPresFormatDescriptor_d:                     {                         mPeerInformation.customInfo.humClientConfig.hHumDesc = pChar->aDescriptors[i].handle;                         break;                     }                     case gBleSig_CCCD_d:                     {                         mPeerInformation.customInfo.humClientConfig.hHumCccd = pChar->aDescriptors[i].handle;                         break;                     }                     default:                         break;                 }             }         }     } } BleApp_StoreDescValues() stores the format of the value. static void BleApp_StoreDescValues (     gattAttribute_t     *pDesc ) {     if (pDesc->handle == mPeerInformation.customInfo.humClientConfig.hHumDesc)     {         /* Store Humidity format*/         FLib_MemCpy(&mPeerInformation.customInfo.humClientConfig.humFormat,                     pDesc->paValue,                     pDesc->valueLength);     }   }      After we store all the data of the Humidity Service, we need to check the notification callback. Every time the Client receives a notification with the BleApp_GattNotificationCallback(),  call the BleApp_PrintHumidity() function and check the Format Value; in this case is 0x27AD  that mean percentage and also have to be the same on the GATT server. static void BleApp_GattNotificationCallback (     deviceId_t serverDeviceId,     uint16_t characteristicValueHandle,     uint8_t* aValue,     uint16_t valueLength ) { /*Compare if the characteristics handle Server is the same of the GATT Server*/     if (characteristicValueHandle == mPeerInformation.customInfo.humClientConfig.hHumidity)     {            BleApp_PrintTemperature(*(uint16_t*)aValue);     }  } BleApp_PrintHumidity() print the value of the Humidity, but first check if the format value is the same. static void BleApp_PrintHumidity (     uint16_t humidity ) {     shell_write("Humidity: ");     shell_writeDec(humidity);      /*If the format value is the same, print the value*/     if (mPeerInformation.customInfo.humClientConfig.humFormat.unitUuid16 == 0x27AD)     {         shell_write(" %\r\n");     }     else     {         shell_write("\r\n");     } } Step to include the file to the demo. 1. Create a clone of the Temperature_Collector with the name of Humidity_Collector 2. Unzip the Humidity_Collector.zip file attached to this post. 3. Save the humidity folder in the fallowing path: <kw40zConnSoft_install_dir>\ConnSw\bluetooth\profiles . 4. Replaces the common folder in the next path: <kw40zConnSoft_install_dir>\ConnSw\examples\bluetooth\humidity_sensor\common . Once you already save the folders in the corresponding path you must to indicate in the demo where they are and drag the file in the humidity folder to the workspace. For test the demo fallow the next steps: Compile the project and run. Press SW1 for the advertising/scanning mode, and wait to connect it. Once the connection finish, press the SW1 of the Humidity Sensor board to get and print the data. Enjoy the demo! NOTE: This demo works with the Humidity Sensor demo. This means that you need one board programmed with the Humidity Sensor application and a second board with the Humidity Collector explained in this post. Figure 3. Example of the Humidity Collector using the Humidity Sensor.
View full article
The KW40Z connectivity software stack has several demo application available, and one of them is the OTAP client. This application allows the user to reprogram the device in a wireless fashion. This can be done by both using another device with an OTAP server application, or with the Kinetis BLE Toolbox mobile application, using the OTAP tool. To create a binary file for the KW40Z, follow these next steps: Using IAR Embedded Workbench, open the application you want to send through OTAP. Right click the main project, and open the Options... menu.                                                                                                                                              In the options menu, go to the Output Converter submenu. In the Output Converter submenu, check the "Generate additional output" box, and choose Motorola as the Output format.                                                                                                                                                                            In the options menu, go to the Linker submenu. Now, in the Config tab, replace the symbols in the Configuration file symbol definitions box with these: gUseNVMLink_d=1 gUseBootloaderLink_d=1 gUseInternalStorageLink_d=0 __ram_vector_table__=1                                                                                                                                                                                              In the Linker submenu, go to the Input tab. In the Keep symbols box, add the symbol 'bootloader' (without the quotes). In the Input tab, in the Raw binary image box, in the File option, add the following path: $PROJ_DIR$\..\..\..\..\..\..\..\framework\Bootloader\Bin\BootloaderOTAP_KW40Z4.bin In the Raw binary image box, add the following options to the Symbol, Section and Align boxes: Symbol: bootloader Section: .bootloader Align: 4                                                                                                                                                                                                                         Press OK. Compile the project. The output file (*.srec) should be in the main project folder, inside the debug folder.                                                      You can now use this binary file to reprogram your device with OTAP.
View full article
I got a question related to best practices to configure a GPIO if the pin is not used. To make it short, the recommendation is to leave the GPIO floating on the PCB and leave the GPIO in its "Default" state as shown in the Signal Multiplexing table in the Reference Manual. The Default state is either “Disabled” or an analog function.   Some Kinetis devices have analog only pins (PGAx/ADCx) while most have GPIO pins with analog functions (PTx/ADCx) or digital GPIO pins   Unused pins, whether analog only or GPIO, should be left floating. Analog only pins do not have input buffers that will cause shoot-through currents when the input floats. GPIO pins with analog functions default to analog functions, which disables the digital input buffer – no shoot-through current.   The digital GPIO pins default to "Disabled", which disables the input buffers - no shoot-through currents with floating inputs.   Finally, unused pins shall not be tied to VDD or VSS. Hence, when designing your board and there are some unused pins, leave them floating on the PCB and then make sure that the software leaves the GPIO in its Default state in the MUX register. 
View full article
Bluetooth Low Energy, through the Generic Attribute Profile (GATT), supports various ways to send and receive data between clients and servers. Data can be transmitted through indications, notifications, write requests and read requests. Data can also be transmitted through the Generic Access Profile (GAP) by using broadcasts. Here however, I'll focus on write and read requests. Write and read requests are made by a client to a server, to ask for data (read request) or to send data (write request). In these cases, the client first makes the request, and the server then responds, by either acknowledging the write request (and thus, writing the data) or by sending back the value requested by the client. To be able to make write and read requests, we must first understand how BLE handles the data it transmits. To transmit data back and forth between devices, BLE uses the GATT protocol. The GATT protocol handles data using a GATT database. A GATT database implements profiles, and each profile is made from a collection of services. These services each contain one or more characteristics. A BLE characteristic is made of attributes. These attributes constitute the data itself, and the handle to reference, access or modify said data. To have a characteristic that is able to be both written and read, it must be first created. This is done precisely in the GATT database file ( gatt_db.h 😞 /* gatt_db.h */ /* Custom service*/ PRIMARY_SERVICE_UUID128(service_custom, uuid_custom_service)     /* Custom characteristic with read and write properties */     CHARACTERISTIC_UUID128(char_custom, uuid_custom_char, (gGattCharPropRead_c | gGattCharPropWrite_c))         /* Custom length attribute with read and write permissions*/         VALUE_UUID128_VARLEN(value_custom, uuid_custom_char, (gPermissionFlagReadable_c | gPermissionFlagWritable_c), 50, 1, 0x00) The custom UUIDs are defined in the gatt_uuid128.h file: /* gatt_uuid128.h */ /* Custom 128 bit UUIDs*/ UUID128(uuid_custom_service, 0xE0, 0x1C, 0x4B, 0x5E, 0x1E, 0xEB, 0xA1, 0x5C, 0xEE, 0xF4, 0x5E, 0xBA, 0x00, 0x01, 0xFF, 0x01) UUID128(uuid_custom_char, 0xA1, 0xB2, 0xC3, 0xD4, 0xE5, 0xF6, 0x17, 0x28, 0x39, 0x4A, 0x5B, 0x6C, 0x7D, 0x8E, 0x9F, 0x00) With this custom characteristic, we can write and read a value of up to 50 bytes (as defined by the variable length value declared in the gatt_db.h file, see code above). Remember that you also need to implement the interface and functions for the service. For further information and guidance in how to make a custom profile, please refer to the BLE application developer's guide (BLEDAG.pdf, located in <KW40Z_connSw_install_dir>\ConnSw\doc\BLEADG.pdf. Once a connection has been made, and you've got two (or more) devices connected, read and write requests can be made. I'll first cover how to make a write and read request from the client side, then from the server side. Client To make a write request to a server, you'll need to have the handle for the characteristic you want to modify. This handle should be stored once the characteristic discovery is done. Obviously, you also need the data that is going to be written. The following function needs a pointer to the data and the size of the data. It also uses the handle to tell the server what characteristic is going to be written: static void SendWriteReq(uint8_t* data, uint8_t dataSize) {       gattCharacteristic_t characteristic;     characteristic.value.handle = charHandle;     // Previously stored characteristic handle     GattClient_WriteCharacteristicValue( mPeerInformation.deviceId, &characteristic,                                          dataSize, data, FALSE,                                          FALSE, FALSE, NULL); } uint8_t wdata[15] = {"Hello world!\r"}; uint8_t size = sizeof(wdata); SendWriteReq(wdata, size); The data is send with the GattClient_WriteCharacteristicValue() API. This function has various configurable parameters to establish how to send the data. The function's parameters are described with detail on the application developer's guide, but basically, you can determine whether you need or not a response for the server, whether the data is signed or not, etc. Whenever a client makes a read or write request to the server, there is a callback procedure triggered,  to which the program then goes. This callback function has to be registered though. You can register the client callback function using the App_RegisterGattClientProcedureCallback() API: App_RegisterGattClientProcedureCallback(gattClientProcedureCallback); void gattClientProcedureCallback ( deviceId_t deviceId,                                    gattProcedureType_t procedureType,                                    gattProcedureResult_t procedureResult,                                    bleResult_t error ) {   switch (procedureType)   {        /* ... */        case gGattProcWriteCharacteristicValue_c:             if (gGattProcSuccess_c == procedureResult)             {                  /* Continue */             }             else             {                  /* Handle error */             }             break;        /* ... */   } } Reading an attribute is somewhat similar to writing an attribute, you still need the handle for the characteristic, and a buffer in which to store the read value: #define size 17 static void SendReadReq(uint8_t* data, uint8_t dataSize) {     /* Memory has to be allocated for the characteristic because the        GattClient_ReadCharacteristicValue() API runs in a different task, so        it has a different stack. If memory were not allocated, the pointer to        the characteristic would point to junk. */     characteristic = MEM_BufferAlloc(sizeof(gattCharacteristic_t));     data = MEM_BufferAlloc(dataSize);         characteristic->value.handle = charHandle;     characteristic->value.paValue = data;     bleResult_t result = GattClient_ReadCharacteristicValue(mPeerInformation.deviceId, characteristic, dataSize); } uint8_t rdata[size];         SendReadReq(rdata, size); As mentioned before, a callback procedure is triggered whenever there is a write or read request. This is the same client callback procedure used for the write request, but the event generates a different procedure type: void gattClientProcedureCallback ( deviceId_t deviceId,                                    gattProcedureType_t procedureType,                                    gattProcedureResult_t procedureResult,                                    bleResult_t error ) {   switch (procedureType)   {        /* ... */        case gGattProcReadCharacteristicValue_c:             if (gGattProcSuccess_c == procedureResult)             {                  /* Read value length */                  PRINT(characteristic.value.valueLength);                  /* Read data */                  for (uint16_t j = 0; j < characteristic.value.valueLength; j++)                  {                       PRINT(characteristic.value.paValue[j]);                  }             }             else             {               /* Handle error */             }             break;       /* ... */   } } There are some other methods to read an attribute. For further information, refer to the application developer's guide chapter 5, section 5.1.4 Reading and Writing Characteristics. Server Naturally, every time there is a request to either read or write by a client, there must be a response from the server. Similar to the callback procedure from the client, with the server there is also a callback procedure triggered when the client makes a request. This callback function will handle both the write and read requests, but the procedure type changes. This function should also be registered using the  App_RegisterGattServerCallback() API. When there is a read request from a client, the server responds with the read status: App_RegisterGattServerCallback( gattServerProcedureCallback ); void gattServerProcedureCallback ( deviceId_t deviceId,                                    gattServerEvent_t* pServerEvent ) {     switch (pServerEvent->eventType)     {         /* ... */         case gEvtAttributeRead_c:             GattServer_SendAttributeReadStatus(deviceId, value_custom, gAttErrCodeNoError_c);                             break;         /* ... */     } } When there is a write request however, the server should write the received data in the corresponding attribute in the GATT database. To do this, the function GattDb_WriteAttribute() can be used: void gattServerProcedureCallback ( deviceId_t deviceId,                                    gattServerEvent_t* pServerEvent ) {     switch (pServerEvent->eventType)     {         /* ... */         case gEvtAttributeWritten_c:             if (pServerEvent->eventData.attributeWrittenEvent.handle == value_custom)             {                 GattDb_WriteAttribute( pServerEvent->eventData.attributeWrittenEvent.handle,                                        pServerEvent->eventData.attributeWrittenEvent.cValueLength,                                        pServerEvent->eventData.attributeWrittenEvent.aValue );                              GattServer_SendAttributeWrittenStatus(deviceId, value_custom, gAttErrCodeNoError_c);             }             break;         /* ... */     } } If you do not register the server callback function, the attribute can still be written in the GATT database (it is actually done automatically), however, if you want something else to happen when you receive a request (turning on a LED, for example), you will need the server callback procedure.
View full article
Wireless communication systems require several different components or parts to achieve reliable systems. Components like the antenna, radio and XTAL are all key elements in wireless communication. Here however, the XTAL will be discussed. In the Kinetis W series, for example, the XTAL used for wireless operation is usually the oscillator also used as a core clock. Now, while this external oscillator is connected to the MCU, it is also connected to an internal programmable capacitor bank. What is the purpose of these capacitor banks? To allow frequency trimming. And why would you want to trim the frequency provided by this oscillator? Well, to properly adjust the central frequency to where it should be operating. This option exists because not every design is going to be the same: not the same PCB, not the same components, not the same manufacturing process. Thus, having the option to adjust the frequency provided by the external oscillator allows to any possible device to operate under the same conditions is essential. Let’s say your design is using a 32 MHz external oscillator, but because of the conditions of your whole design, the operating frequency ends up being slightly different. Now, if this design transmits over the air through 802.15.4, there could be some consequences to this slight shift in frequency. This capture shows a transmission made without being centered in the desired channel. This signal should be centered exactly on 2405 MHz, as specified by IEEE 802.15.4 channel 11. As you may see, in this case the frequency is actually centered on 2405.0259 MHz. Trimming these capacitors to change the frequency obtained from the oscillator can help to adjust error. In this case, the frequency was adjusted so that it was centered in the central frequency of the desired channel, to prevent any possible mistakes while transmitting to other devices. Once the XTAL is trimmed, the signal is effectively centered on 802.15.4 channel 11's frequency, 2405 MHz. Both transmit and receive are affected by incorrect frequency trim. Receiver performance is degraded when either (or both) of the transmitting or receiving stations have a frequency offset. And if both transmitting and receiving stations have frequency offsets in opposite directions the result is the receiver experiences the sum of the frequency offsets. Now, when trimming the frequency of a design, there are two possibilities: That the board layout design, board manufacturing and component selection have repeatable values of resistance, capacitance and inductance, resulting in a stable XTAL trim – The components and manufacturing process of the board are reliable enough, allowing you to characterize the XTAL trim during the system development and then use it every board during production. That the design and component selection do not result in a stable XTAL trim – If there is considerable variation between different boards of the same design or components used in the board manufacturing, you would need to implement a XTAL trim procedure during the production process, and somehow program that trim value into the device's NVM. For evaluation purposes, a manual adjustment could be done to a single device, modifying the corresponding XTAL trim register, and then including said adjustment in the evaluation application. The two posts linked explain how to modify and use the SMAC Connectivity Test demo to find the proper XTAL trim for KW40Z and KW41Z.
View full article
For this example, the BLE stack VERSION was configure to create a Custom Profile with the KW40Z. The Custom to create is the Humidity Sensor and is based on the Temperature Sensor. The First thing to know is that the Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules. GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations.    Figure 1. GATT Client-Server       GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors are defined attributes that describe a characteristic value. To define a GATT Database several macros are provided by the GATT_DB API. Figure 2. GATT database      To know if the Profile or service is already defined on the specification, you have to look for on Bluetooth SIG profiles and check on the ble_sig_define module if is already declared on the code. In our case the Service is not declared(because is a Custom Profile) but the characteristic of the humidity it is on the specification but not on ble_sig_define. /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d                      0x2A6F The Humidity Sensor is going to have the GATT Server, because is going to be the device that has all the information for the GATT Client. The Application works like the Temperature Sensor, every time that you press the SW1 on USB is going to send the value. On the Temperature Sensor demo have the Battery Service and Device Information, so you only have to change the Temperature Service to Humidity Service. Figure 3. GATT database of Humidity Sensor      First thing to do is define the Humidity Server that has 16 bytes. To define a new Server or a Characteristic is in gatt_uuid128.h which is located in the application folder. All macros, function or structure in SDK have a common template which helps the application to act accordingly. /* Humidity */ UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)      All the Service and Characteristics is declared in gattdb.h. Descriptors are declared after the Characteristic Value declaration but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units of the Humidity Characteristic is on Percentage that is 0x27AD. Client Characteristic Configuration Descriptor(CCCD) is a descriptor where clients write some of the bits to activate Server notifications and/or indications PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity) CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c)) VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25) DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00) CCCD(cccd_humidity)      After that, create a folder humidity in the next path C:\....\KW40Z_BLE_Software_1.1.2\ConnSw\bluetooth\profiles. Found the temperature folder, copy the temperature_service and paste inside of the humidity folder with another name (humidity_service) Then go back and look for the interface folder, copy temperature_interface and change the name (humidity_interface) in the same path.      On the humidity_interface file should have the following code. The Service structure has the service handle, and the initialization value. /*! Humidity Service - Configuration */ typedef struct humsConfig_tag {     uint16_t serviceHandle;     int16_t initialHumidity;        } humsConfig_t; The next configuration structure is for the Client; in this case we don’t need it. /*! Humidity Client - Configuration */ typedef struct humcConfig_tag {     uint16_t    hService;     uint16_t    hHumidity;     uint16_t    hHumCccd;     uint16_t    hHumDesc;     gattDbCharPresFormat_t  humFormat; } humcConfig_t;      At minimum on humidity_service file, should have the following code. The service stores the device identification for the connected client. This value is changed on subscription and non-subscription events. /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId;      The initialization of the service is made by calling the start procedure. This function is usually called when the application is initialized. In this case is on the BleApp_Config(). On stop function, the unsubscribe function is called. bleResult_t Hums_Start (humsConfig_t *pServiceConfig) {        mHums_SubscribedClientId = gInvalidDeviceId_c;         return Hums_RecordHumidityMeasurement (pServiceConfig->serviceHandle, pServiceConfig->initialHumidity); } bleResult_t Hums_Stop (humsConfig_t *pServiceConfig) {     return Hums_Unsubscribe(); }      Depending on the complexity of the service, the API will implement additional functions. For the Humidity Sensor only have a one characteristic. The measurement will be saving on the GATT database and send the notification to the client. This function will need the service handle and the new value as input parameters. bleResult_t Hums_RecordHumidityMeasurement (uint16_t serviceHandle, int16_t humidity) {     uint16_t handle;     bleResult_t result;     bleUuid_t uuid = Uuid16(gBleSig_Humidity_d);         /* Get handle of Humidity characteristic */     result = GattDb_FindCharValueHandleInService(serviceHandle,         gBleUuidType16_c, &uuid, &handle);     if (result != gBleSuccess_c)         return result;     /* Update characteristic value */     result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t*)&humidity);     if (result != gBleSuccess_c)         return result; Hts_SendHumidityMeasurementNotification(handle);     return gBleSuccess_c; }      After save the measurement on the GATT database with GattDb_WriteAttribute function we send the notification. To send the notification, first have to get the CCCD and after check if the notification is active, if is active send the notification. static void Hts_SendHumidityMeasurementNotification (   uint16_t handle ) {     uint16_t hCccd;     bool_t isNotificationActive;     /* Get handle of CCCD */     if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd) != gBleSuccess_c)         return;     if (gBleSuccess_c == Gap_CheckNotificationStatus         (mHums_SubscribedClientId, hCccd, &isNotificationActive) &&         TRUE == isNotificationActive)     {           GattServer_SendNotification(mHums_SubscribedClientId, handle);     } }      Steps to include the files into the demo. 1. Create a clone of the Temperature_Sensor with the name of Humidity_Sensor 2. Unzip the Humidity_Sensor folder. 3. In the fallowing path <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profiles\interface save the humidity_interface file. 4. In the <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profiles save the humidity folder 5. In the next directory <kw40zConnSoft_intall_dir>\ConnSw\examples\bluetooth\humidity_sensor\common replaces with the common folder.           Steps to include the paths into the demo using IAR Embedded Workbench​ Once you already save the folders in the corresponding path you must to indicate in the demo where are they. 1. Drag the files into the corresponding folder. The principal menu is going to see like this. Figure 4. Principal Menu 2. Then click Option Figure 5. Option 3. Click on the C/C++ Compiler and then on the Preprocessor     Figure 6. Preposcessor Window 4. After that click on  "..." button to edit the include directories and then click to add a new path.      Add the <kw40zConnSoft_intall_dir>\ConnSw\bluetooth\profile\humidity path. Figure 7. Add a path Finally compile and enjoy the demo! NOTE: If you want to probe the demo using another board you must to run the humidity_collector demo too. Figure 8. Example of the Humidity Sensor using the Humidity Collector demo.
View full article
This document and the attached files are maintained up to date in collaboration with Dragos Musoiu. This document is a supplement for USB MSC device bootloader revision for FRDM-KL25Z (IAR) written by Kai Liu and describes the bootloader support for USB-KW24D512. How to use 1) Connect the USB-KW24D512 to the PC USB port; 2) Download the attached file ‘USB_KW24D512_MSD_Bootloader.bin’ to the flash memory of the MKW24D512 SiP following the next steps: Connect a J-Link programmer to the PC USB port (other than the one used for the USB-KW24D512 dongle); Navigate to your J-Link driver folder using a command console and type ‘jlink.exe’ followed by enter; After the apparition of the J-Link prompter, type ‘unlock kinetis’ followed by enter; Wait for the unlock command confirmation and after, type ‘device mkw24d512xxx5’ followed by enter; After the J-Link prompter appears type ‘loadbin USB_KW24D512_MSD_Bootloader.bin 0’ followed by enter; (Be sure you copied the ‘USB_KW24D512_MSD_Bootloader.bin’ file in the same directory with jlink.exe otherwise, type the command specifying the full path of the binary file); After the flashing process successfully finished type ‘exit’ followed by enter. 3) Reset or reconnect the USB-KW24D512; 4) The OS will prompt MSD device connecting and then BOOTLOADER drive will appear. The bootloader software was tested on Microsoft Windows 10, Microsoft Windows 8.1, Microsoft Windows 7, Ubuntu 14.04 and MAC operating systems. 5) Copy and paste any user application .SREC or .bin file into BOOTLOADER drive; 6) If a valid .SREC or .bin file was given, the board restarts and starts to run the user application. Please refer to the Notes section in order to create valid .SREC or .bin files. Note:            The bootloader has conditional jump to user application. The condition is the state of the SW1 button (PTC4). If the button is pressed (PTC4 grounded) during reset, the bootloader sequence will start, installing BOOTLOADER drive, as described before. Else if the button is released during reset, the SP and PC will be updated from address 0xC000. This means, the user application has to use a linker file which forces the application start address to 0xC000. If a valid SP and PC value is found at address 0xC000, the user application is launched. The bootloader application is located in the flash memory of the MKW24D512 SiP, from address 0x0000 to 0xBFFF, so the user application should not put any code in this memory region. Avoid using .SREC or .bin files having program bytes or fill patterns in the bootloader section. Attached files: USB_KW24D512_MSD_Bootloader.bin – bootloader binary file for USB-KW24D512; Pflash_512KB_0xC000.icf – IAR linker file for user application development; 802.15.4SnifferOnUSB.bin – user application demo binary file for KW24D512-USB. Be aware that the file ‘802.15.4SnifferOnUSB.srec’ is linked according to the above memory restrictions and is working only with the bootloader presented in this document.
View full article
I want to share with you the information that I found about Indication and notification. I hope this information help you to understand more about these topics. Indication and notifications are commands that could be send through the attribute(ATT) protocol. So, there are two roles defined at the ATT layer: Client devices access remote resources over a BLE link using the GATT protocol. Usually, the master is also the client but this is not required or mandatory. Server devices have the GATT database, access control methods, and provide resources to the remote client. Usually, the slave is also the server. BLE standard define two ways to transfer data for the server to the client: notification and indication. Maximum data payload size defined by the specification in each message is 20 bytes. Notifications and indications are initiated by the Server but enabled by the Client. Notification don't need acknowledged, so they are faster. Hence, server does not know if the message reach to the client. Indication need acknowledged to communicated. The client sent a confirmation message back to the server, this way server knows that message reached the client. One interesting thing defined by the ATT protocol is that a Server can't send two consecutive indications if the confirmation was not received. In other words, you have to wait for the confirmation of each indication in order to send the next indication. Figure 1. Indication/Notification Nevertheless, server are not able to send indications or notifications at the beginning of the communication. First, client must enable notifications and indications permissions on the server side, so, the server is allowed to send indications or notifications. This procedure involves the client to write the Client Characteristic Configuration Descriptor (CCCD) of the characteristic that will be notified/indicated. In other words, the client may request a notification for a particular characteristic from the server. Once the client enabled the notifications for such characteristic in the server, server can send the value to the client whenever it becomes available. For example, thinking in a heart rate sensor application connecting to Heart Rate smartphone application. Heart Rate Service can notify its Heart Rate Measurement Characteristic.  In this case, the sensor is the server while the smartphone is the client. Once devices are connected, smartphone application must set the notifications permissions of the Heart Rate Measurement Characteristic through its CCCD. Then, when smartphone application(client) set the CCCD withe notifications enabled, Heart Rate Sensor (server) is able to send notifications whenever a heart rate measurement is available. This same procedure is needed if the characteristic has indication properties.  At the end, the client is the one that allow the server to indicate or notify a characteristic. Finally, it is worth to comment that unlike notification, the indication is more reliable, but slower, because the server sends the data but the client must to confirm when data is received.
View full article
High level description to enable a Linux + KW41Z Border Router. Similar to how it’s shown for the K64 solution in the Kinetis Thread Stack Application Development Guide.   Configure the OpenWrt router to assign the IPv6 ULA prefix 2001:2002:2003::/48. On the LAN network, the router distributes addresses from range 2001:2002:2003::/60 Plug an Ethernet cable between the OpenWrt router and the Linux box. Before creating the Thread network, the Linux box has a global address on its eth interface from range 2001:2002:2003::/60. After creating the Thread network, the BR configures on its Serial TAP interface an address from range 2001:2002:2003::/60. On its 6LoWPAN interface, the BR configures an address from range 2001:2002:2003:c::/64. This is achieved with DHCPv6 prefix delegation - the router is requested to assign a new prefix space to be used by the Thread network. The forth segment in the IPv6 range might be 2, 4, 8 or c, depending of the number of DHCP-PD requests made to the router. After 4 attempts, the router will not lease any other prefixes for some time. In order to force that, you'd require to restart the odhcpd deamon in the OpenWrt router with the following command: /etc/init.d/odhcpd restart . Join the router eligible device, which configures an address in 2001:2002:2003::1/60. We then ping the "Internet" (the LAN interface on the OpenWrt router) and it works. “threadtap0” interface must be bridged with an uplink interface connected to an OpenWrt DHCPv6-PD enabled router; it will act identically as the K64F solution.   Setup Linux PC (Ubuntu) OpenWrt AP/Router with DHCPv6-PD support (OpenWrt version used in this guide: OpenWrt Chaos Calmer 15.05.1) For reference, hardware used on this guide: TP-Link Model TL-WR741ND 150Mbps Wireless N Router OpenWRT firmware supports multiple hardware available at https://openwrt.org/ 1 FRDM-KW41Z (Host Controlled Device, connected to Linux) 1 FRDM-KW41Z (Router Eligible Device or any joiner device) Thread version 1.1.1.20 (from SDK builder at mcuxpresso.nxp.com)   Host Controlled Device firmware, make sure the following macros are enabled: THR_SERIAL_TUN_ROUTER                       /source/config.h     -> Enables TAP interface by default (not TUN) THR_SERIAL_TUN_ENABLE_ND_HOST     /app/common/app_serial_tun.h   OpenWRT router Configure IPv6 ULA-Prefix:   Linux Copy HSDK folder Create 'threadtap0' TAP interface: …/host_sdk/hsdk/demo#   sudo bash make_tap.sh Use "Thread_Shell" or modify “Thread_KW_Tun” demo to enable the SERIAL_TAP macro …/host_sdk/hsdk/demo#   nano Thread_KW_Tun.c #define SERIAL_TAP 0   modify to:  #define SERIAL_TAP  1        Note: For demo purposes, the "Thread_Shell" demo is recommended, it already uses TAP by default and allows input commands. If this is not required and only the TAP bridge is to be used, use the Thread_KW_Tun demo. Bridge the interfaces; assuming eno1 is the interface connected directly to OpenWrt: # brctl addbr br0 # brctl addif br0 eno1 # brctl addif br0 threadtap0 # ifconfig br0 up Note: (Optional) Addresses on the bridged interfaces are lost and need to be reconfigured on the actual bridge. In this example, after bridging eno1 (interface to OpenWrt router), you’d have to run #dhclient br0 to get an IPv4 address on br0 for SSH to the router and/or #dhclient -6 br0 to get an IPv6 address to the br0 interface. There's a note here https://wiki.archlinux.org/index.php/Network_bridge#With_bridge-utils  about this.   Build C demos …/host_sdk/hsdk/demo#   make Run Thread_Shell or Thread_KW_Tun demo. …/host_sdk/hsdk/demo#   sudo ./bin/Thread_Shell /dev/ttyACM0 threadtap0 25 or …/host_sdk/hsdk/demo#   sudo ./bin/Thread_KW_Tun /dev/ttyACM0 threadtap0         Note: Try to run the demo without parameters to get some help on the input parameters   ifconfig Thread_Shell demo Thread_KW_Tun demo Joiner FRDM-KW41Z (shell) Join the Thread network Verify IP addresses Ping Eth LAN interface on OpenWrt router to verify “Internet” connectivity  Regards, JC
View full article
Bluetooth® Low-Energy (BLE) RF PHY tests can be done by using the Direct Test Mode (DTM).  This document will help as a guide to perform the test using a device from the KW family.     Direct Test Mode Direct Test Mode (DTM) is used to control the Device Under Test (DUT) and provides a report with the results from the tests performed by the Tester.   There are two ways to perform those tests:   HCI Through a 2-wire UART interface   The packet format from the DTM is different from the HCI commands.   For further information of the commands and this type of tests, please refer to the Bluetooth Core Specifications, Vol 6, Part F: Direct Test Mode   Software This guide will use the KW41Z as example, but the same changes must be applicable for the rest of the devices Download and install the software SDK of the device to use by following the getting started in the device page. In this case the SDK of the KW41Z will be downloaded from the MCUXpresso Builder. Setup for DTM using HCI Import the hci_black_box example to the IDE according to the getting started of the device.   Download and open the latest version of the Test Tool available in the page of the device under Lab & Test Software in the Software and Tools Tab. Open the Command console of the board, please be sure that you have the correct baud rate set for the example (Default: 115200) Select one of the available commands to either start or finish tests    Setup for DTM using DTM pins You can choose from any example available while making sure that the pins chosen for DTM  are not occupied or used. Import the beacon example to the IDE according to the getting started of the device.   The DTM pins behave as a UART interface; in order to enable them in our KW devices there is the need to follow the next steps Look at the Reference manual of the device and locate the pins that support the DTM_TX and the DTM_RX. In this case, we will select the PTB1 and PTB2.  Set the ALT_MUX of the pin in the code to work as DTM   PORT_SetPinMux(PORTB, PIN1_IDX, kPORT_MuxAlt2);            /* PORTB1 (pin 17) is configured as DTM_RX */   PORT_SetPinMux(PORTB, PIN2_IDX, kPORT_MuxAlt3);            /* PORTB2 (pin 18) is configured as DTM_TX */‍‍‍‍‍‍‍‍‍‍ Configure the baud rate of the DTM pins, this can be achieved by writing to the DTM_2WIRE_CONFIG register. This register is not available in the header file by default, so there is the need to create a pointer to such address. To verify this data, you can check the chapter 45.2.3.1.4 Test and Debug Registers Descriptions for the Bluetooth Link Layer of the reference manual. #define DTM_2WIRE_CONFIG                0x580 #define BTLE_RF_DTM_2WIRE_CONFIG        (*(volatile uint16_t *) (BTLE_RF_BASE+DTM_2WIRE_CONFIG)) BTLE_RF_DTM_2WIRE_CONFIG = 0x0042;  /*Configure DTM pins baud rate of 115200*/‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
View full article
The attached PDF file contains two A3 format "posters". The first one summarize the contents of the SMP Pairing Request and SMP Pairing Response packets (BLE 4.2). It shows how are the sub-fields of these packets set and what do they represent. The second one contains a diagram which summarizes how the pairing method and it's properties are determined during the SMP Pairing procedure for both BLE Legacy Pairing (BLE4.0 and BLE 4.1) and BLE Secure Connections Pairing with ECDH (BLE 4.2). Some of the tables in the diagram are taken from the BLE Specification. If you find any errors or have any suggestions of improvement please leave a comment or send me a message. Preview:
View full article
What you need: USB-KW40Z boards (at least 3 recommended) Kinetis KW40Z Connectivity Software Kinetis Protocol Analyzer Adapter Wireshark Consult the USB-KW40Z getting started guide for an in depth tutorial on how to program the boards with the sniffer software and how to install and use the Kinetis Protocol Analyzer Adapter and Wireshark. For best performance at least 3 boards are needed to continuously monitor all 3 BLE advertising channels: 37, 38 and 39. If you have more then it’s even better. Having less than 3 sniffer boards will lead to the BLE sniffer setup missing some advertising packets and connection events. If only 1 or 2 boards are present they will have to jump between the 3 advertising channels. After the initial setup is complete make sure the boards are plugged into USB ports and then start the Kinetis Protocol Analyzer Adapter software. Immediately after the application is started it will start looking for the sniffers: After the sniffers are detected the application window should look like the screenshot below. There should be a separate row shown for each sniffer board which is plugged in (3 in the example below – COM32, COM34, and COM33). Set each sniffer on a different advertising channel and (37, 38 and 39) and if you’re looking to sniff a specific device enable the Address Filter checkbox and enter the device’s address in the adjacent field as shown in the screenshot below. Use the same device address for all sniffer devices. Press the “shark fin” button in the upper right of the window to start Wireshark. After Wireshark starts select the PCAP IF shown in the Kinetis Protocol Analyzer Adapter window and start capturing packets. Local Area Connection 2 is the PCAP IF in the example. Wireshark will start showing the captured packets and the sniffers will catch Connection Request packets sent to the target device on any of the advertising channels. Useful tip: You can use the btle.advertising_header.length != 0 or btle.data_header.length != 0 filter in Wireshark to filter out empty BLE packets.
View full article