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

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

Wireless Connectivity Knowledge Base

ディスカッション

ソート順:
The FRDM-KW36 comes with the OpenSDA circuit which allows users to program and debug the evaluation board. There are different solutions to support such OpenSDA circuits: 1. The J-Link (SEGGER) firmware.  2. The CMSIS-DAP (mbed) firmware. The FRDM-KW36 comes pre-programmed with the CMSIS-DAP firmware. However, if you want to update the firmware version, you need to perform the next steps.  Press and hold the Reset button (SW1 push button in the board).  Unplug and plug the FRDM-KW36 again to the PC.  The board will be enumerated as "DAPLINKBOOT" device. Drag and drop the binary file to update the OpenSDA firmware.  If the J-Link version is programmed, the board will be enumerated as "FRDM-KW36J". On the other hand, if the CMSIS-DAP version is programmed, the board will be enumerated as "FRDM-KW36". The binary for the J-link version can be downloaded from the next link: SEGGER - The Embedded Experts - Downloads - J-Link / J-Trace  The binary for the CMSIS-DAP version can be found in the next link: OpenSDA Serial and Debug Adapter|NXP    Hope this helps... 
記事全体を表示
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.
記事全体を表示
This document describes how to update and sniff Bluetooth LE wireless applications on the USB-KW41 Programming the USB-KW41 as sniffer   It was noticed that there are some issues trying to follow a Bluetooth LE connection, even if the sniffer catches the connection request. These issues have been fixed in the latest binary file which can be found in the Test Tool for Connectivity Products 12.8.0.0 or newest.   After the Test Tool Installation, you’ll find the sniffer binary file at the following path. C:\NXP\Test Tool 12.8.1.0\images\KW41_802.15.4_SnifferOnUSB.bin   Programming Process. 1. Connect the USB-KW41Z to your PC, and it will be enumerated as Mass Storage Device 2. Drag and drop the "KW41_802.15.4_SnifferOnUSB.bin" included in Test tool for Connectivity Products.    "C:\NXP\Test Tool 12.8.0.0\images\KW41_802.15.4_SnifferOnUSB.bin"   3. Unplug the device and hold the RESET button of the USB-KW41Z, plug to your PC and the K22 will enter in bootloader mode. 4. Drag and drop the "sniffer_usbkw41z_k22f_0x8000.bin" included in Test tool for Connectivity Products.    "C:\NXP\Test Tool 12.8.5.9\images\sniffer_usbkw41z_k22f_0x8000.bin"   5. Then, unplug and plug the USB-KW41Z to your PC.                                                                                                          Note: If the USB-KW41 is not enumerated as Mass Storage Device, please look at the next thread https://community.nxp.com/thread/444708   General Recommendations   Software Tools  Kinetis Protocol Analyzer Wireshark version (2.4.8) Hardware Tools 1 USB-KW41 (updated with KW41_802.15.4_SnifferOnUSB.bin from Test Tool 12.8 or later)   The Kinetis Protocol Analyzer provides the ability to monitor the Bluetooth LE Advertisement Channels. It listens to all the activity and follows the connection when capturing a Connection Request.   Bluetooth LE Peripheral device transmits packets on the 3 advertising channels one after the other, so the USB-KW41 will listen to the 3 channels one by one and could or not catch the connection request.   Common use case The USB-KW41 will follow the Bluetooth LE connection if the connection request happens on the same channel that It is listening. If is listening to a different channel when the connection request is sent, it won't be able to follow it.   A Simple recommendation is the Bluetooth LE Peripheral should be set up to send the adv packets only to one channel and the sniffer just capturing on the same channel.   Improvement Use 3 USB-KW41, each of them will be dedicated to one channel and will catch the connection request.   Configure Kinetis Protocol Analyzer and Wireshark Network Analyzer   Note: For better results, address filter can be activated. When you are capturing all the packets in the air, you will notice 3 adv packets. Each packet will show the adv channel that is getting the adv frame.       One of the three sniffers will capture the Connection Request. In this case, it happens on channel 38.       You will be able to follow the connection, see all the data exchange.   For a better reference, you can look at the USB-KW41 Getting Started     Hope it helps   Regards, Mario
記事全体を表示
The QN9090 is a Bluetooth Low Energy device that achieves ultra-low-power consumption and integrates an Arm ® Cortex ® -M4 CPU with a comprehensive mix of analog and digital peripherals. If the developer is working with the Development platform for QN9090 wireless MCUs for the first time, it is recommended to follow the QN9090-DK Development kit Getting Started (this guide can be found in QN9090DK Documentation section). This Quick Start document provides an overview about the QN9090 DK and its software tools and lists the steps to install the hardware and the software. For this document, Temperature Sensor and Temperature Collector examples will be used to demonstrate the implementation of a custom profile (both examples can be found in the SDK). This article will explain how to add the Humidity Profile and how to modify the code to get the Humidity Sensor and Collector working.   Introduction   Generic Attribute Profile (GATT) GATT defines the way that profile and user data are exchanged between devices over a BLE connection. GATT deals with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly, making it a key section of the BLE specification since every single item of data relevant to applications and users must be formatted, packed and sent according to the rules. There are two GATT roles that define the devices exchanging data: GATT Server This device contains a GATT Database and stores the data transported over the Attribute Protocol (ATT). The Server accepts ATT requests, commands and confirmations sent by the Client; and it can be configured to send data on its own through notifications and indications. GATT Client This is the “active” device that accesses data on the remote GATT Server via read, write, notify, or indicate operations. Notify and indicate operations are enabled by the client but initiated by the server, providing a way to push data to the client. Notifications are unacknowledged, while indications are acknowledged. Notifications are therefore faster, but less reliable. GATT Database establishes a hierarchy to organize attributes and is a collection of Services and Characteristics exposing meaningful data. Profiles are high level definitions that define how Services can be used to enable an application; Services are collections of Characteristics. Descriptors define attributes that describe a characteristic value.   Server (Sensor)   The Temperature Sensor project will be used as base to create our Humidity Custom Profile Server (Sensor). BLE SIG profiles Some Profiles or Services are already defined in the specification, and we can verify this in the Bluetooth SIG profiles document. Also, we need to check in the ble_sig_defines.h files (${workspace_loc:/${ProjName}/bluetooth/host/interface}) if this is already declared in the code. In this case, the Service is not declared, but the Characteristic of the humidity is declared in the specification. Then, we need to check if the Characteristic is already included in ble_sig_defines.h. Since the characteristic is not included, we define it as shown: /*! Humidity Characteristic UUID */ #define gBleSig_Humidity_d                   0x2A6FU GATT Database The Humidity Sensor will act as GATT Server since it will be the device containing all the information for the GATT Client. Temperature Sensor demo already implements the Battery Service and Device Information, so we only have to change the Temperature Service to Humidity Service.   In order to create the demo, we need to define a Service that must be the same as in the GATT Client, this is declared in the gatt_uuid128.h. If the new service is not the same, Client and Server will not be able to communicate each other. All macros, functions or structures in the SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uui128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, 0x00, 0xfa, 0x10, 0x10) Units All the Services and Characteristics are declared in gatt_db.h. Descriptor are declared after the Characteristic Value declaration, but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units for Humidity Characteristic is Percentage, defined in the Bluetooth SIG profiles document as 0x27AD. Descriptor Client Characteristic Configuration Descriptor (CCCD) is a descriptor where Clients write some of the bits to activate Server notifications and/or indications. PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity)        CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c))              VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25)              DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00)              CCCD(cccd_humidity) Humidity service and interface Create a folder named “humidity” in path ${workspace_loc:/${ProjName}/bluetooth/profiles}. In the same path you can find the “temperature” folder; copy the temperature_service.c file and paste it inside the “humidity” folder with another name (humidity_service.c). After this, go back to the “temperature” folder and copy the temperature_interface.h file; paste it inside the “humidity” folder and rename it (humidity_interface.h). You will need to include the path of the created folder. Go to Project properties > C/C++ Build > Settings > Tool Settings > MCU C Compiler > Includes: Humidity Interface The humidity_interface.h file should include the following code, where the Service structure contains the Service handle and the initialization value: /*! Humidity Service - Configuration */ typedef struct humsConfig_tag {        uint16_t serviceHandle;        int16_t initialHumidity; } humsConfig_t; /*! Humidity Client - Configuration */ typedef struct humcConfig_tag {        uint16_t hService;        uint16_t hHumidity;        uint16_t hHumCccd;        uint16_t hHumDesc;        gattDbCharPresFormat_t humFormat; } humcConfig_t; Humidity service At minimum, humidity_service.c file must contain the following code: /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId; The Service stores the device identification for the connected client. This value is changed on subscription and non-subscription events. Initialization Initialization of the Service is made by calling the start procedure. This function is usually called when the application is initialized. In this case, this is done in the BleApp_Config() function. bleResult_t Hums_Start(humsConfig_t *pServiceConfig) {     mHums_SubscribedClientId = gInvalidDeviceId_c;     /* Set the initial value of the humidity characteristic */     return Hums_RecordHumidityMeasurement(pServiceConfig->serviceHandle,                                             pServiceConfig->initialHumidity); } Stop & Unsubscribe On stop function, the unsubscribe function is called. bleResult_t Hums_Stop(humsConfig_t *pServiceConfig) {     /* Stop functionality by unsubscribing */     return Hums_Unsubscribe(); } bleResult_t Hums_Unsubscribe(void) {     /* Unsubscribe by invalidating the client ID */     mHums_SubscribedClientId = gInvalidDeviceId_c;     return gBleSuccess_c; } Subscribe The subscribe function will be used in the main file to subscribe the GATT client to the Humidity Service. bleResult_t Hums_Subscribe(deviceId_t clientDeviceId) {     /* Subscribe by saving the client ID */     mHums_SubscribedClientId = clientDeviceId;     return gBleSuccess_c; } Record Humidity Depending on the complexity of the Service, the API will implement additional functions. For the Humidity Sensor will only have one Characteristic. The measurement will be saved on the GATT Database and send the notification to the Client. This function will need the Service handle and the new value as input parameters. bleResult_t Hums_RecordHumidityMeasurement(uint16_t serviceHandle, int16_t humidity) {        uint16_t handle;        bleResult_t result;        bleUuid_t uuid = Uuid16(gBleSig_Humidity_d);        /* Get handle of Humidity characteristic */        result = GattDb_FindCharValueHandleInService(serviceHandle,                      gBleUuidType16_c, &uuid, &handle);        if (result == gBleSuccess_c)        {              /* Update characteristic value */              result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t *)&humidity);              if (result == gBleSuccess_c)              {                     /* Notify the humidity value */                     Hts_SendHumidityMeasurementNotification(handle);              }        }        return result; } Remember to add/update the prototype for Initialization, Subscribe, Unsubscribe, Stop and Record Humidity Measurement functions in humidity_interface.h. Send notification After saving the measurement on the GATT Database by using the GattDb_WriteAttribute function, we can send the notification. To send this notification, first we have to get the CCCD and check if the notification is active after that; if it is active, then we send the notification. static void Hts_SendHumidityMeasurementNotification (              uint16_t handle ) {        uint16_t hCccd;        bool_t isNotificationActive;        /* Get handle of CCCD */        if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd)                     != gBleSuccess_c)              return;        if (gBleSuccess_c == Gap_CheckNotificationStatus                     (mHums_SubscribedClientId, hCccd, &isNotificationActive) &&                     TRUE == isNotificationActive)        {              GattServer_SendNotification(mHums_SubscribedClientId, handle);        } } Remember to add or modify the prototype for Send Humidity Measurement Notification function.   Main file There are some modifications that need to be done in the Sensor main file: Add humidity_interface.h in main file /* Profile / Services */ #include "humidity_interface.h" Declare humidity service There are some modifications that have to be done in order to use the new Humidity Profile in the Sensor example. First, we need to declare the Humidity Service: static humsConfig_t humsServiceConfig = {(uint16_t)service_humidity, 0};   Rename BleApp_SendTemperature -> BleApp_SendHumidity static void BleApp_SendHumidity(void); After this, we need to add or modify the following functions and events: Modify BleApp_Start /* Device is connected, send humidity value */        BleApp_SendHumidity();   Ble_AppConfig Start Humidity Service and modify the Serial_Print line. /* Start services */ humsServiceConfig.initialHumidity = 0; (void)Hums_Start(&humsServiceConfig); (void)Serial_Print(gAppSerMgrIf, "\n\rHumidity sensor -> Press switch to start advertising.\n\r", gAllowToBlock_d);   BleApp_ConnectionCallback events - Event: gConnEvtConnected_c (void)Hums_Subscribe(peerDeviceId);   - Event: gConnEvtDisconnected_c (void)Hums_Unsubscribe();   Notify value in BleApp_GattServerCallback function /* Notify the humidity value when CCCD is written */ BleApp_SendHumidity(); Add the Hums_RecordHumidityMeasurement function and modify the initial value update in BleApp_SendHumidity function /* Update with initial humidity */ (void)Hums_RecordHumidityMeasurement((uint16_t)service_humidity,                                            (int16_t)(BOARD_GetTemperature())); Note: in this example, the Record Humidity uses the BOARD_GetTemperature to allow the developer to use the example without any external sensor and to be able to see a change in the collector, but in this section, there should be a GetHumidity function.   app_config.c file There are some modifications that need to be done inside app_config.c file: Modify Scanning and Advertising Data {     .length = NumberOfElements(uuid_service_humidity) + 1,     .adType = gAdComplete128bitServiceList_c,     .aData = (uint8_t *)uuid_service_humidity }   *Optional* Modify name {     .adType = gAdShortenedLocalName_c,     .length = 9,     .aData = (uint8_t*)"NXP_HUM" }   Modify Service Security Requirements {     .requirements = {         .securityModeLevel = gSecurityMode_1_Level_3_c,         .authorization = FALSE,         .minimumEncryptionKeySize = gDefaultEncryptionKeySize_d     },     .serviceHandle = (uint16_t)service_humidity }   Client (Collector)   We will use the Temperature Collector project as base to create our Humidity Custom Profile Client (Collector). BLE SIG profiles As mentioned in the Server section, we need to verify if the Profile or Service is already defined in the specification. For this, we can take a look at the Bluetooth SIG profiles document and check in the ble_sig_defines.h file (${workspace_loc:/${ProjName}/bluetooth/host/interface}) if this is already declared in the code. In our case, the Service is not declared, but the Characteristic of the Humidity is declared in the specification. Then, we need to check if the Characteristic is already included in ble_sig_defines.h. Since the Characteristic is not included, we need to define it as shown: /*! Humidity Characteristic UUID */ #define gBleSig_Humidity_d                    0x2A6FU GATT Database The Humidity Collector is going to have the GATT client; this is the device that will receive all new information from the GATT Server. The demo provided in this article works in the same way as the Temperature Collector. When the Collector enables the notifications from the Sensor, received notifications will be printed in the seral terminal. In order to create the demo, we need to define or develop a Service that must be the same as in the GATT Server, this is declared in the gatt_uuid128.h file. If the new Service is no the same, Client and Server will not be able to communicate each other. All macros, functions or structures in the SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uui128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x02, 0x00, 0xfa, 0x10, 0x10) Includes After that, copy the humidity profile folder from the Sensor project and paste it into the Collector project inside ${workspace_loc:/${ProjName}/bluetooth/profiles}. Also, include the path of the new folder.   Main file In the Collector main file, we need to do some modifications to use the Humidity Profile Include humidity_interface.h /* Profile / Services */ #include "humidity_interface.h"   Modify the Custom Info of the Peer device humcConfig_t     humsClientConfig;   Modify BleApp_StoreServiceHandles function static void BleApp_StoreServiceHandles {     APP_DBG_LOG("");     uint8_t i,j;     if ((pService->uuidType == gBleUuidType128_c) &&              FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))     {         /* Found Humidity Service */        mPeerInformation.customInfo.humsClientConfig.hService = pService->startHandle;         for (i = 0; i < pService->cNumCharacteristics; i++)         {             if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&                     (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d))             {                 /* Found Humidity Char */             mPeerInformation.customInfo.humsClientConfig.hHumidity = pService->aCharacteristics[i].value.handle;                 for (j = 0; j < pService->aCharacteristics[i].cNumDescriptors; j++)                 {                     if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType16_c)                     {                         switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16)                         {                             /* Found Humidity Char Presentation Format Descriptor */                             case gBleSig_CharPresFormatDescriptor_d:                             {                                 mPeerInformation.customInfo.humsClientConfig.hHumDesc = pService->aCharacteristics[i].aDescriptors[j].handle;                                 break;                             }                             /* Found Humidity Char CCCD */                             case gBleSig_CCCD_d:                             {                                 mPeerInformation.customInfo.humsClientConfig.hHumCccd = pService->aCharacteristics[i].aDescriptors[j].handle;                                 break;                             }                             default:                                 ; /* No action required */                                 break;                         }                     }                 }             }         }     } }   Modify BleApp_StoreDescValues function if (pDesc->handle == mPeerInformation.customInfo.humsClientConfig.hHumDesc) {        /* Store Humidity format*/        FLib_MemCpy(&mPeerInformation.customInfo.humsClientConfig.humFormat,                     pDesc->paValue,                     pDesc->valueLength); }   Implement BleApp_PrintHumidity function static void BleApp_PrintHumidity (     uint16_t humidity ) {     APP_DBG_LOG("");     shell_write("Humidity: ");     shell_writeDec((uint32_t)humidity);     /* Add '%' for Percentage - UUID 0x27AD.        www.bluetooth.com/specifications/assigned-numbers/units */     if (mPeerInformation.customInfo.humsClientConfig.humFormat.unitUuid16 == 0x27ADU)     {         shell_write(" %\r\n");     }     else     {         shell_write("\r\n");     } }   Modify BleApp_GattNotificationCallback function if (characteristicValueHandle == mPeerInformation.customInfo.humsClientConfig.hHumidity) { BleApp_PrintHumidity(Utils_ExtractTwoByteValue(aValue)); }   Modify CheckScanEvent function foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);   Some events inside BleApp_StateMachineHandler need to be modified: BleApp_StateMachineHandler - Event: mAppIdle_c if (mPeerInformation.customInfo.humsClientConfig.hHumidity != gGattDbInvalidHandle_d)   - Event: mAppServiceDisc_c if (mPeerInformation.customInfo.humsClientConfig.hHumDesc != 0U)  mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumDesc;   - Event: mAppReadDescriptor_c if (mPeerInformation.customInfo.humsClientConfig.hHumCccd != 0U)   Modify BleApp_ConfigureNotifications function mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumCccd;   Demonstration   In order to print the relevant data in console, it may be necessary to disable Power Down mode in app_preinclude.h file. This file can be found inside source folder. For this, cPWR_UsePowerDownMode and cPWR_FullPowerDownMode should be set to 0. Now, after connection, every time that you press the User Interface Button on QN9090 Humidity Sensor is going to send the value to QN9090 Humidity Collector. Humidity Sensor   Humidity Collector  
記事全体を表示
简介: 当 OTAP 客户端(接收软件更新的设备,通常为 Bluetooth LE 外围设备)从 OTAP 服务器 (发送软件更新的设备,通常为 Bluetooth LE Central)请求软件更新时,您可能希望保留一 些数据,例如绑定信息,系统振荡器的匹配值或您的应用程序的 FlexNVM 非易失数据。 本 文档指导您在执行 OTAP 更新时, 如何保留您感兴趣的闪存数据内容。 本文档适用于熟悉 OTAP 定制 Bluetooth LE 服务的开发人员,有关更多基础信息,您可以阅读以下文章: 使用 OTAP 客户端软件对 KW36 设备进行重新编程。 OTAP 标头和子元素 OTAP 协议为软件更新实现了一种格式,该格式由标题和定义数量的子元素组成。 OTAP 标 头描述了有关软件更新的一般信息,并且其定义的格式如下图所示。 有关标题字段的更多 信息,请转至 SDK 中的<SDK_2.2.X_FRDM-KW36_Download_Path> \ docs \ wireless \ Bluetooth 中的《 Bluetooth Low Energy Application Developer's Guide》文档的 11.4.1 Bluetooth Low Energy OTAP 标头一章。   每个子元素都包含用于特定目的的信息。 您可以为您的应用程序实现专有字段(有关子元 素字段的更多信息, 请转至 SDK 中的<SDK_2.2.X_FRDM-KW36_Download_Path> \ docs \ wireless \ Bluetooth 中的《 Bluetooth Low Energy Application Developer's Guide》文档的 11.4.1 Bluetooth Low Energy OTAP 标头一章。 OTAP 包含以下子元素: 镜像文件子元素 值字段长度(字节) 描述 升级镜像 变化 该子元素包含实际的二进制可执行镜像,该镜像将被复制到 OTAP 客户端设备的闪存中。 该子元素的最 大大小取决于目标硬件。 扇区位图 32 该子元素包含目标设备闪存的扇区位图,该位图告诉引导加载程序哪些扇区应被覆盖,哪些扇区保持完 整。 该字段的格式是每个字节的最低有效位在前,最低有效字节和位代表闪存的最低存储部分。 镜像文件CRC 2 是在镜像文件的所有元素(此字段本身除外)上计算的 16 位 CRC。 该元素必须是通过空中发送的镜像文件中的最后一个子元素。   OTAP 扇区位图子元素 KW36 闪存分为: 一个 256 KB 程序闪存( P-Flash)阵列, 最小单元为 2 KB 扇区,闪存地址范围为 0x0000_0000 至 0x0003_FFFF。 一个 256 KB FlexNVM 阵列, 最小单元为 2 KB 扇区,闪存地址范围为 0x1000_0000 至 0x1003_FFFF, 同时它也会被映射到地址范围为 0x0004_0000 至 0x0007_FFFF 的空间。 位图子元素的长度为 256 位,就 KW36 闪存而言,每个位代表 2KB 扇区,覆盖从 0x0- 0x0007_FFFF 的地址范围(P-Flash 到 FlexNVM 映射地址范围),其中 1 表示该扇区应 被擦 除, 0 表示应保留该扇区。 OTAP 引导加载程序使用位图字段来获取在使用软件更新对 KW36 进行编程之前应擦除的地址范围,因此必须在发送软件更新之前对其进行配置,以使包含您 的数据的内存的地址范围保持不变。仅擦除将被软件更新覆盖的地址范围。 例如:假设开发人员想要保留 0x7D800-0x7FFFF 之间的地址范围和 0x0-0x1FFF 之间的地址 范围,并且必须擦除剩余的存储器。 0x7D800-0x7FFFF 之间的地址范围对应于前 5 个闪存 扇区, 0x0-0x1FFF 之间的地址范围是最低的 4 个扇区。 因此,这意味着应将 256 和 252 之间的位(256、 255、 254、 253 和 252)以及 4 和 1 之间 的位(4、 3、 2 和 1)设置为 0,这样本示例的 OTAP 位图为 : 0x07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF0 使用 NXP 测试工具配置 OTAP 位图以保护地址范围 在恩智浦网站上下载并安装用于连接产品的测试工具   在 PC 上打开 NXP Test Tool 12 软件。 转到“ OTA 更新-> OTAP 蓝牙 LE”,然后单击“浏 览...”按钮加载用于软件更新的映像文件(NXP 测试工具仅接受.bin 和.srec 文件)。 您 可以配置 OTAP 位图,选择“覆盖扇区位图”复选框,并通过新的位图值更改默认值。 配 置位图后,选择“保存...”。   然后,将显示一个窗口,用于选择保存.bleota 文件的目的地,保存文件可以自行取名。 您可以将此文件与 Android 和 iOS 的 IoT Toolbox App 一起使用,以使用 OTAP 更新软 件。 这个新的.bleota 文件包含位图,该位图告诉 OTAP 引导加载程序哪些扇区将被擦 除,哪些扇区将被保留。    
記事全体を表示
The homologation requirements in China (MIIT [2002]353) obviously are planned (end of December 2022) to be sharpened (MIIT publication from 2021-01-27: “Notice on Matters Related to Radio Management in the 2400MHz, 5100MHz and 5800MHz Bands”).   A modification register is need on the KW38 and KW36 to pass the new Chinese  requirement with acceptable margin: PA_RAMP_SEL value must be set to 0x02h (2us) instead of 0x01h (1us default value) Modification SW: XCVR_TX_DIG_PA_CTRL_PA_RAMP_SEL(2) in the nxp_xcvr_common_config.c All the details are in the attached file.   Note: This SW modification is for China country only.
記事全体を表示
In the process of practical application, customers often need the combination of ble + NFC. At present, our IOT-DK006 is the only development board with NFC module. But the NFC example is not perfect. So we porting the library of NFC reader- PN7150, to support KW series microcomputer so that KW series can handle the demand of ble + NFC function. Now I will introduce you how to port the NFC lib to KW. 1 PN7150 Introduction PN7150 is the high-performance version of PN7120, the plug’n play NFC solution for easy integration into any OS environment, reducing Bill of Material (BOM) size and cost. PN71xx controllers are ideal for home-automation applications such as gateways and work seamlessly with NFC connected tags. 2 Tools hardware:FRDM-KW36,PN7150 , some wire software:mcuxpresso11.3 package:NXP-NCI MCUXpresso example Project This package contains the nfc library and example that we need. We will refer the ‘NXPNCI-K64F_example’ firstly. Sdk version: 2.2.8, Example: frdmkw36_rtos_examples_freertos_i2c  3 Steps Hardware part:We need connect the PN7150 to KW36 like the picture. Although we can connect the PN7150 to board through the ardunio connector, the pin’s voltage is not enough to drive the PN7150. So we need a wire connected to U1 to get 3.3V.   PN7150 FRDM-KW36 VBAT/PVDD 3.3V VANT 5V GND GND IRQ PTA16 VEN PTC15 SCL PTB0,I2C0 SDA PTB1,I2C0 Software part:We should add the nfc library and directory into our project. You can check the following picture to know what file is necessary. If you want to know how to add directory into our project, you can refer this link. The red line shows what file we need. Please notice that when we add file path into the mcuxpresso configuration, we also need add the path into ‘Path and Symbols’ .   We need add some macro into ‘Preprocessor’.   We copy the NXPNCI-K64F_example’s main file content into our ‘freertos_i2c.c’. Next, we need modify the file pin_mux.c, tml.c and board.h   In file board.h,add the following macro. Don't forget to enable the pin clock. /* NXPNCI NFC related declaration */ #define BOARD_NXPNCI_I2C_INSTANCE I2C0 #define BOARD_NXPNCI_I2C_BAUDRATE (100000) #define BOARD_NXPNCI_I2C_ADDR       (0x28) #define BOARD_NXPNCI_IRQ_PORTIRQn PORTA_IRQn #define BOARD_NXPNCI_IRQ_GPIO     (GPIOA) #define BOARD_NXPNCI_IRQ_PORT     (PORTA) #define BOARD_NXPNCI_IRQ_PIN      (16U) #define BOARD_NXPNCI_VEN_GPIO     (GPIOC) #define BOARD_NXPNCI_VEN_PORT     (PORTC) #define NXPNCI_VEN_PIN            (5U)     In file pin_mux.c, add head file ‘board.h’. Add the following code in function ’ BOARD_InitPins’. The step is to configure the VEN, IRQ and I2C0. This example contains the I2C1’s code, you can comment them.     /* Initialize NXPNCI GPIO pins below */   /* IRQ and VEN PIN_MUX Configuration */   PORT_SetPinMux(BOARD_NXPNCI_IRQ_PORT, BOARD_NXPNCI_IRQ_PIN, kPORT_MuxAsGpio);   PORT_SetPinMux(BOARD_NXPNCI_VEN_PORT, NXPNCI_VEN_PIN, kPORT_MuxAsGpio);   /* IRQ interrupt Configuration */   NVIC_SetPriority(BOARD_NXPNCI_IRQ_PORTIRQn, 6);   EnableIRQ(BOARD_NXPNCI_IRQ_PORTIRQn);   PORT_SetPinInterruptConfig(BOARD_NXPNCI_IRQ_PORT, BOARD_NXPNCI_IRQ_PIN, kPORT_InterruptRisingEdge);   Finally, in file tml.c, modify PORTC_IRQHandler as PORTA_IRQHandler We finished all steps. 4 Results We use ntag to test the reading and writing operation.   When the tag is closed to the PN7150, we will get the following message.   The text recording is ‘VER=03’. Next, we will modify the text recording We need add the new macro to preprocessor.   We can modify the variable NDEF_MESSAGE in function task_nfc_reader to modify the text recording.   Then we download the program again. We will see the original text ‘VER=03’ and the text has been modified. Then we read the tag again. We will see the new text.   If we want to send the larger text, what should we do? We need modify the macro ‘ADD’. When only 4 characters are sent, ‘ADD’ is 0. And every additional character is added, the ‘ADD’ will add. We modify the tag as ‘Ver=03’, and we have two more characters. So ‘ADD’ needs to be defined as 2   It firstly shows the text ‘Test’. Then it will show the new text ‘Ver=03’. Other tags’ reading and writing operation can be enabled by defining some macro.      
記事全体を表示
This example of custom profile uses the Temperature Sensor and Temperature Collector examples as a base, so it can be easily modified. Both examples are in the SDK, so this document explains how to add the Humidity profile, and how to modify the code to get the Humidity Sensor and Collector working. Introduction Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules. GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations. Notify and indicate operations are enabled by the client but initiated by the server, providing a way to push data to the client. Notifications are unacknowledged, while indications are acknowledged. Notifications are therefore faster, but less reliable.  GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors defined attributes that describe a characteristic value.    To define a GATT Database several macros are provided by the GATT_DB API in the Freescale BLE Stack, which is part KW38 SDK. Server (Sensor)  First, we need to use the Temperature Sensor project as a base, to create our Humidity Custom Profile Server (Sensor). BLE SIG profiles To know if the Profile or service is already defined in the specification, you have to look for in Bluetooth SIG profiles and check in the ble_sig_defines.h file (${workspace_loc:/${ProjName}/bluetooth/host/interface) if this is already declared in the code. In our case, the service is not declared, but the characteristic of the humidity is declared in the specification. Then, we need to check if the characteristic is already included in ble_sig_defines.h. Since, the characteristic is not included, we need to define it as shown next:   /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d 0x2A6F   GATT Database The Humidity Sensor is going to have the GATT Server, because is going to be the device that has all the information for the GATT Client. On the Temperature Sensor demo have the Battery Service and Device Information, so you only have to change the Temperature Service to Humidity Service    In order to create the demo we need to define or develop a service that has to be the same as in the GATT Client, this is declared in the gatt_uuid128.h.If the new service is not the same, they will never be able to communicate each other. All macros, function or structure in SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uuid128.h as shown next:    /* Humidity */ UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)   All the Service and Characteristics is declared in gattdb.h. Descriptors are declared after the Characteristic Value declaration but before the next Characteristic declaration. In this case the permission is the CharPresFormatDescriptor that have specific description by the standard. The Units of the Humidity Characteristic is on Percentage that is 0x27AD. Client Characteristic Configuration Descriptor (CCCD) is a descriptor where clients write some of the bits to activate Server notifications and/or indications.   PRIMARY_SERVICE_UUID128(service_humidity, uuid_service_humidity) CHARACTERISTIC(char_humidity, gBleSig_Humidity_d, (gGattCharPropNotify_c)) VALUE(value_humidity, gBleSig_Humidity_d, (gPermissionNone_c), 2, 0x00, 0x25) DESCRIPTOR(desc_humidity, gBleSig_CharPresFormatDescriptor_d, (gPermissionFlagReadable_c), 7, 0x0E, 0x00, 0xAD, 0x27, 0x00, 0x00, 0x00) CCCD(cccd_humidity)   After that, create a folder humidity in the next path ${workspace_loc:/${ProjName}/bluetooth/profiles. Found the temperature folder, copy the temperature_service.c and paste inside of the humidity folder with another name (humidity_service.c). Then go back and look for the interface folder, copy temperature_interface.h and change the name (humidity_interface.h) in the same path. You need to include the path of the created folder. Project properties>C/C+ Build>Settings>Tool Settings>MCU C Compiler>Includes: Humidity Interface The humidity_interface.h file should have the following code. The Service structure has the service handle, and the initialization value.   /*! Humidity Service - Configuration */ typedef struct humsConfig_tag { uint16_t serviceHandle; int16_t initialHumidity; } humsConfig_t; /*! Humidity Client - Configuration */ typedef struct humcConfig_tag { uint16_t hService; uint16_t hHumidity; uint16_t hHumCccd; uint16_t hHumDesc; gattDbCharPresFormat_t humFormat; } humcConfig_t;   Humidity Service At minimum on humidity_service.c file, should have the following code. The service stores the device identification for the connected client. This value is changed on subscription and non-subscription events.   /*! Humidity Service - Subscribed Client*/ static deviceId_t mHums_SubscribedClientId;   The initialization of the service is made by calling the start procedure. This function is usually called when the application is initialized. In this case is on the BleApp_Config().   bleResult_t Hums_Start(humsConfig_t *pServiceConfig) { mHums_SubscribedClientId = gInvalidDeviceId_c; /* Set the initial value of the humidity characteristic */ return Hums_RecordHumidityMeasurement(pServiceConfig->serviceHandle, pServiceConfig->initialHumidity); }   On stop function, the unsubscribe function is called.   bleResult_t Hums_Stop(humsConfig_t *pServiceConfig) { /* Stop functionality by unsubscribing */ return Hums_Unsubscribe(); } bleResult_t Hums_Unsubscribe(void) { /* Unsubscribe by invalidating the client ID */ mHums_SubscribedClientId = gInvalidDeviceId_c; return gBleSuccess_c; }   The subscribe function will be used in the main file, to subscribe the GATT client to the Humidity service.   bleResult_t Hums_Subscribe(deviceId_t clientDeviceId) { /* Subscribe by saving the client ID */ mHums_SubscribedClientId = clientDeviceId; return gBleSuccess_c; }   Depending on the complexity of the service, the API will implement additional functions. For the Humidity Sensor only have a one characteristic. The measurement will be saving on the GATT database and send the notification to the client. This function will need the service handle and the new value as input parameters.   bleResult_t Hums_RecordHumidityMeasurement(uint16_t serviceHandle, int16_t humidity) { uint16_t handle; bleResult_t result; bleUuid_t uuid = Uuid16(gBleSig_Humidity_d); /* Get handle of Humidity characteristic */ result = GattDb_FindCharValueHandleInService(serviceHandle, gBleUuidType16_c, &uuid, &handle); if (result != gBleSuccess_c) return result; /* Update characteristic value */ result = GattDb_WriteAttribute(handle, sizeof(uint16_t), (uint8_t*) &humidity); if (result != gBleSuccess_c) return result; Hts_SendHumidityMeasurementNotification(handle); return gBleSuccess_c; }   After save the measurement on the GATT database with GattDb_WriteAttribute function we send the notification. To send the notification, first have to get the CCCD and after check if the notification is active, if is active send the notification.   static void Hts_SendHumidityMeasurementNotification ( uint16_t handle ) { uint16_t hCccd; bool_t isNotificationActive; /* Get handle of CCCD */ if (GattDb_FindCccdHandleForCharValueHandle(handle, &hCccd) != gBleSuccess_c) return; if (gBleSuccess_c == Gap_CheckNotificationStatus (mHums_SubscribedClientId, hCccd, &isNotificationActive) && TRUE == isNotificationActive) { GattServer_SendNotification(mHums_SubscribedClientId, handle); } }   Humidity Sensor Main file There are some modifications that have to be done, to use the new Humidity profile in our sensor example. First, we need to declare the humidity service:   static humsConfig_t humsServiceConfig = {(uint16_t)service_humidity, 0};   Then, we need to add or modify the following functions: BleApp_Start You need to modify this line:   /* Device is connected, send humidity value */ BleApp_SendHumidity();   BleApp_Config You need to start the Humidity Service, and to modify the PrintString line:   humsServiceConfig.initialHumidity = 0; (void)Hums_Start(&humsServiceConfig);     AppPrintString("\r\nHumidity sensor -> Press switch to start advertising.\r\n");   BleApp_ConnectionCallback There are some modifications required in two Connection Events. gConnEvtConnected_c   (void)Hums_Subscribe(peerDeviceId); gConnEvtDisconnected_c   gConnEvtDisconnected_c   (void)Hums_Unsubscribe();   BleApp_GattServerCallback   /* Notify the humidity value when CCCD is written */ BleApp_SendHumidity()   BleApp_SendHumidity And, we need to add this function:   static void BleApp_SendHumidity(void) { (void)TMR_StopTimer(appTimerId); /* Update with initial humidity */ (void)Hums_RecordHumidityMeasurement((uint16_t)service_humidity, (int16_t)(BOARD_GetTemperature())); #if defined(cPWR_UsePowerDownMode) && (cPWR_UsePowerDownMode) /* Start Sleep After Data timer */ (void)TMR_StartLowPowerTimer(appTimerId, gTmrLowPowerSecondTimer_c, TmrSeconds(gGoToSleepAfterDataTime_c), DisconnectTimerCallback, NULL); #endif }   In this example, the Record Humidity uses the BOARD_GetTemperature, to use the example without any external sensor and to be able to see a change in the collector, but, in this section would be a GetHumidity function. Client (Collector)  First, we need to use the Temperature Collector project as a base, to create our Humidity Custom Profile Client (Collector). BLE SIG profiles The same applies for the Client. To know if the Profile or service is already defined in the specification, you have to look for in Bluetooth SIG profiles and check in the ble_sig_defines.h file (${workspace_loc:/${ProjName}/bluetooth/host/interface) if this is already declared in the code. In our case, the service is not declared, but the characteristic of the humidity is declared in the specification. Then, we need to check if the characteristic is already included in ble_sig_defines.h. Since, the characteristic is not included, we need to define it as shown next:   /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d 0x2A6F   GATT Database The Humidity Collector is going to have the GATT client; this is the device that will receive all information from  the GATT server. Demo provided in this post works like the Temperature Collector. When the Collector enables the notifications from the sensor, received notifications will be printed in the serial terminal. In order to create the demo we need to define or develop a service that has to be the same as in the GATT Server, this is declared in the gatt_uuid128.h.If the new service is not the same, they will never be able to communicate each other. All macros, function or structure in SDK have a common template which helps the application to act accordingly. Hence, we need to define this service in the gatt_uuid128.h as shown next:   /* Humidity */ UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)   After that, copy the humidity profile folder from the Sensor project, to the Collector project ${workspace_loc:/${ProjName}/bluetooth/profiles. And also for this project, include the path of the new folder. Project properties>C/C+ Build>Settings>Tool Settings>MCU C Compiler>Includes: Humidity Collector Main file In the Collector source file, we need to do also some modifications, to use the Humidity Profile. First, we need to modify the Custom Information of the Peer device:   humcConfig_t humsClientConfig;   BleApp_StoreServiceHandles   static void BleApp_StoreServiceHandles ( gattService_t *pService ) { uint8_t i,j; if ((pService->uuidType == gBleUuidType128_c) && FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16)) { /* Found Humidity Service */ mPeerInformation.customInfo.humsClientConfig.hService = pService->startHandle; for (i = 0; i < pService->cNumCharacteristics; i++) { if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) && (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d)) { /* Found Humudity Char */ mPeerInformation.customInfo.humsClientConfig.hHumidity = pService->aCharacteristics[i].value.handle; for (j = 0; j < pService->aCharacteristics[i].cNumDescriptors; j++) { if (pService->aCharacteristics[i].aDescriptors[j].uuidType == gBleUuidType16_c) { switch (pService->aCharacteristics[i].aDescriptors[j].uuid.uuid16) { /* Found Humidity Char Presentation Format Descriptor */ case gBleSig_CharPresFormatDescriptor_d: { mPeerInformation.customInfo.humsClientConfig.hHumDesc = pService->aCharacteristics[i].aDescriptors[j].handle; break; } /* Found Humidity Char CCCD */ case gBleSig_CCCD_d: { mPeerInformation.customInfo.humsClientConfig.hHumCccd = pService->aCharacteristics[i].aDescriptors[j].handle; break; } default: ; /* No action required */ break; } } } } } } }   BleApp_StoreDescValues   if (pDesc->handle == mPeerInformation.customInfo.humsClientConfig.hHumDesc) { /* Store Humidity format*/ FLib_MemCpy(&mPeerInformation.customInfo.humsClientConfig.humFormat, pDesc->paValue, pDesc->valueLength); }   BleApp_PrintHumidity   /*www.bluetooth.com/specifications/assigned-numbers/units */ if (mPeerInformation.customInfo.humsClientConfig.humFormat.unitUuid16 == 0x27ADU) { AppPrintString(" %\r\n"); } else { AppPrintString("\r\n"); }   BleApp_GattNotificationCallback   if (characteristicValueHandle == mPeerInformation.customInfo.humsClientConfig.hHumidity) { BleApp_PrintHumidity(Utils_ExtractTwoByteValue(aValue)); }    CheckScanEvent   foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);   BleApp_StateMachineHandler mAppIdle_c   if (mPeerInformation.customInfo.humsClientConfig.hHumidity != gGattDbInvalidHandle_d)   mAppServiceDisc_c   if (mPeerInformation.customInfo.humsClientConfig.hHumDesc != 0U) mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumDesc;   mAppReadDescriptor_c   if (mPeerInformation.customInfo.humsClientConfig.hHumCccd != 0U)   BleApp_ConfigureNotifications   mpCharProcBuffer->handle = mPeerInformation.customInfo.humsClientConfig.hHumCccd;   Demonstration Now, after connection, every time that you press the SW3 on KW38 Humidity Sensor is going to send the value to KW38 Humidity Collector.  
記事全体を表示
1 Introduction Two development boards transmit control information through ble. One development board connects to paj7620 and provides gesture information through IIC bus. The other development board uses ble and USB HID. Ble is used to receive data, and USB HID is used to simulate keyboard input and control ppt                  Figure  1 2 Preparation We need two development boards qn908x and gesture control device paj7620. We use IAR as development enviroment.The example we use is temperature_sensor, and temperature_ colloctor. The SDK version is 2.2.3   3 Code 3.1  temperature_sensor code We want to implement IIC to read gesture information from paj7620 and send data. The pins used by IIC are PA6 and PA7 Simply encapsulate the IIC reading and writing code in the code to create i2c_ operation.c and i2c_ operation.h. Realize IIC initialization and reading / writing register function in it                        Figure  2                        Figure  3   3.1.1 After having these functions, we begin to write gesture recognition code. First, we add two blank files paj7620.c and paj7620.h into our project.   Select bank register area                               Figure 4   Wake up paj7620 to read device state                    Figure 5   Initialize device                    Figure 6   Gesture test function                                   Figure 7   3.1.2 When you are ready to read the device information, You should initialize IIC and paj7620 in BleApp_Init function                                Figure 8 In principle, we need to create a custom service for the PAJ device, but we replace the temperature data as our gesture control data. If you want to create a custom service, refer to this link custom profile   3.1.3 Create a timer that sends gesture data regularly. In file temerature_sensor.c Define a timer,static tmrTimerID_t dataTimerId; Allocate a timer, dataTimerId = TMR_AllocateTimer(); Define the callback function of this timer                                           Figure 9 Start timer                                    Figure 10 Close the low power mode. #define cPWR_UsePowerDownMode 0 3.2 temperature_collector code The most important thing here is to port USB HID into our project. The USB  example we use is the USB keyboard and mouse. 3.2.1 Add the OSA and USB folder under the example to the project directory, and copy the file to the corresponding folder according to the file structure of the original example.                      Figure 11 3.2.2 Add header file directory after completion                                           Figure 12 At the same time, in this tab, add two macro definitions USB_STACK_FREERTOS_HEAP_SIZE=16384 USB_STACK_FREERTOS   3.2.3 Next, we need to modify the main function in usb example . Open composite.c file.                      Figure 13 It calls the APP_task. So this function also need to be modified.                                   Figure 14 3.2.4Find hid_mouse.c,Comment function USB_DeviceHidMouseAction Find hid_keyboard.h. Define the gesture information.                                  Figure 15 Find hid_keyboard.c. We need to modify the function USB_DeviceHidKeyboardAction as following figure.                                                  Figure 16   Among them, we also need to implement the following function. When the up hand gesture is detected, the previous ppt will be played. The down hand gesture will be the next PPT, the left hand gesture will exit PPT, and the forward hand gesture will play ppt                                                  Figure 17 It also refers to an external variable gesture_from_server. The variable definition is in file temperature_ collocation.c,.     3.2.5 After that, let's go to BleApp_Statemachinehandler function in temperature_colloctor.c. In case mApppRunning_c, we will call usb_main to initialize USB HID                                                  Figure 18 3.2.6 In BleApp_PrintTemperature, we will save the gesture data to gesture_from_server                                                         Figure 19 We finished the all steps.        
記事全体を表示
Introduction   This post explains how to create a BLE GATT database using FSCI commands sent to the BLE Server device. Additionally, this document explains how to set up the fields of each FSCI command used to create the BLE GATT database for the BLE Server.   Main FSCI commands to create the BLE GATT DB in the BLE Server device   The following, are the main commands to create, write and read the GATT DB from the BLE Server perspective. The purpose of this post is to serve as a reference and summary of the most important commands. The full list of commands FSCI commands can be found in the Framework Serial Connectivity Interface (FSCI) for Bluetooth Low Energy Host Stack documentation within your SDK package. GATT-InitRequest This command is used to initialize the GATT database at runtime, and it must be sent before any other command to declare a database in your BLE Server device. GATTServer-RegisterCallback.Request This command installs an application callback for the GATT Server module, enabling the device to respond to the FSCI request from the CPU application through an FSCI indication. GATTDBDynamic-AddPrimaryServiceDeclaration.Request It adds a primary service to the database. It has 3 parameters that should be configured, the desired handle, the UUID type (16 bits, 32 bits, 128 bits), and the UUID value. Usually, the desired handle should be set to zero and the stack will assign the handle of the primary service automatically.   If the GATT application callback was installed through the GATTServer-RegisterCallback.Request command, the GATT Server responds to the GATTDBDynamic-AddPrimaryServiceDeclaration.Request command with a GATTDBDynamic-AddPrimaryServiceDeclaration.Indication that contains the handle assigned to the primary service. The following example shows how to prepare this command to define the battery service in the database. GATTDBDynamic-AddCharacteristicDeclarationAndValue.Request It adds a characteristic and its value to the database. It has 7 parameters that should be configured, the UUID type (16 bits, 32 bits, 128 bits), the UUID value, characteristic properties, the maximum length of the value (only for variable-length values), the initial length of the value, the initial value of the characteristic and value access permissions. The characteristic declared using this command, belongs to the last primary service declared in the database. For values with a fixed length, the maximum length parameter should be set to 0, and the length is obtained from the initial length of the value parameter.   If the GATT application callback was installed, the response of this command is indicated by the GATTDBDynamic-AddCharacteristicDeclarationAndValue.Indication command. The following example shows how to prepare this command to define the battery level characteristic in the database with a fixed length of 1 byte and an initial value of 90%. GATTDBDynamic-AddCharacteristicDescriptor.Request It adds a characteristic descriptor to the database. It has 5 parameters that should be configured, the UUID type (16 bits, 32 bits, 128 bits), UUID value, length of the descriptor value, descriptor’s value, and descriptor access permissions. The descriptor declared using this command, belongs to the last characteristic declared in the database.   If the GATT application callback was installed, the response of this command is indicated by the GATTDBDynamic-AddCharacteristicDescriptor.Indication command. The following example shows how to prepare this command to add the characteristic presentation format descriptor of the battery level characteristic in the database.   GATTDBDynamic-AddCccd.Request It adds a CCDD into the database. This command does not have parameters. The CCCD declared using this command, belongs to the last characteristic declared in the database. The response of this command is indicated by GATTDBDynamic-AddCccd.Indication.   GATTDB-FindServiceHandle.Request This command is used to find the handle of a service previously declared in the database. It has 3 parameters that should be configured, the handle to start the search (should be 1 on the first call), the UUID type of the service to find (16 bits, 32 bits, 128 bits), and the UUID value of the service that you are searching.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindServiceHandle.Indication command, which contains the handle of the found service. The following example shows how to prepare this command to find the handle of the battery service declared in the previous examples. Notice that the result of the search corresponds to the handle returned by the GATTDBDynamic-AddPrimaryServiceDeclaration.Indication as expected.   GATTDB-FindCharValueHandleInService It finds the characteristic´s handle of a given service previously declared in the database. It has 3 parameters that should be configured, the handle of the service that contains the characteristic, the UUID type of the characteristic to find (16 bits, 32 bits, 128 bits), and the UUID value of the characteristic that you are searching for.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindCharValueHandleInService.Indication command, which contains the handle of the found characteristic’s value. The following example shows how to prepare this command to find the handle of the battery level value. Notice that the result of the search corresponds to the handle returned by the GATTDBDynamic-AddCharacteristicDeclarationAndValue.Indication plus one, because the AddCharacteristicDeclarationAndValueIndication command returns the handle of the characteristic and, on the other hand, FindCharValueHandleInService returns the handle of the characteristic’s value. GATTDB-FindDescriptorHandleForcharValueHandle.Request It finds the descriptor´s handle of a given characteristic previously declared in the database. It has 3 parameters that should be configured, the handle of the characteristic’s value that contains the descriptor, the UUID type of the descriptor to find (16 bits, 32 bits, 128 bits), and the UUID value of the descriptor that you are searching.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindDescriptorHandleForCharValueHandle.Indication command, which contains the handle of the found descriptor. The following example shows how to prepare this command to find the handle of the characteristic presentation format descriptor. The result corresponds to the handle returned by the GATTDBDynamic-AddCharacteristicDescriptor.Indication   GATTDB-FindCccdHandleForCharValueHandle.Request It finds the CCCD’s handle of a given characteristic previously declared in the database. It has only one parameter, the handle of the characteristic’s value that contains the CCCD.   If the GATT application callback was installed, the response of this command is indicated by the GATTDB-FindCccdHandleForCharValueHandle.Indication command, which contains the handle of the found CCCD. The following example shows how to prepare this command to find the handle of CCCD. The result corresponds to the handle returned by the GATTDBDynamic-AddCccd.Indication.   GATTDB-WriteAttribute.Request It writes the value of a given attribute from the application level. It has 3 parameters that should be configured, the handle of the attribute that you want to write, the length of the value in bytes, and the new value.   In the following example, we will modify the battery level characteristic’s value from 90% to 80%.   GATTDB-ReadAttribute.Request   It reads the value of a given attribute from the application level. It has 2 parameters that should be configured, the handle of the attribute that you want to read, and the maximum bytes that you want to read. The GATT application callback must be installed, since the response of this command indicated by the GATTDB-ReadAttribute.Indication command contains the value read from the database. In the following example, we will read the battery level characteristic’s value, the result is 80%.      
記事全体を表示
Overview The Bluetooth specification defines 4 Generic Access Profile (GAP) roles for devices operating over a Low Energy physical transport [1]: Peripheral Central Broadcaster Observer The Bluetooth Low Energy Host Stack implementation on the Kinetis KW40Z offers devices the possibility to change between any of the 4 roles at run time. This article will present the interaction with the Bluetooth Low Energy Host API needed to implement a GAP multiple role device. General Procedure instructions Running the GAP roles requires the application to go through the following 3 steps: Configuration - Stack configuration for the desired GAP role The application needs to configure the stack parameters, e.g. advertising parameters, advertising data, scan parameters, callbacks. Note that configuration of the advertising parameters or scanning response and advertising data can be done only once if the values don’t change at runtime. The configuration is always made in the Link Layer Standby state. Start - Running the role The application needs to start advertising, scanning or initiate connection. Stop - Return to Standby state When changing between roles, the Link layer must always go through the Link Layer Standby state. Running as a GAP Broadcaster or GAP Peripheral The GAP Broadcaster or Peripheral sends advertising events. Additionally, the GAP Peripheral will accept the establishment of a LE link. This is why the GAP Observer will only support the Non Connectable Advertising mode (gAdvNonConnectable_c). Both roles requires configuration of advertising data, advertising parameters. The configuration (gAppAdvertisingData, gAppScanRspData and gAdvParams) usually resides in app_config.c. The confirmation events for setting these parameters is received in BleApp_GenericCallback. The confirmation event for the changing state of advertising is received in BleApp_AdvertisingCallback. Configuration /* Setup Advertising and scanning data */ Gap_SetAdvertisingData(&gAppAdvertisingData, &gAppScanRspData); /* Setting only for GAP Broadcaster role */ gAdvParams. advertisingType = gAdvNonConnectable_c; /* Set advertising parameters*/ Gap_SetAdvertisingParameters(&gAdvParams); Start App_StartAdvertising(BleApp_AdvertisingCallback, BleApp_ConnectionCallback); Stop Gap_StopAdvertising(); Running as a GAP Observer The GAP Observer receives advertising events. Unlike the GAP Peripheral or Broadcaster, it does not need to set scanning parameters separately. It passes the configuration with the start procedure. The configuration (gAppScanParams) usually resides in app_config.c. The confirmation event for the changing state of scanning is received in BleApp_ScanningCallback. Configuration and Start App_StartScanning(&gAppScanParams, BleApp_ScanningCallback); Stop Gap_StopScanning (); Running as a GAP Central The GAP Central initiates the establishment of the LE link. Like the GAP Observer, it passes the configuration with the start procedure. The configuration (gConnReqParams) usually resides in app_config.c. The confirmation event for the changing state of link is received in BleApp_ConnectionCallback. Configuration and Start Gap_Connect(&gConnReqParams, BleApp_ConnectionCallback); Stop Gap_Disconnect(deviceId); Example An out-of-the box example for multiple role is attached. The application named blood_pressure_multi_role implements a Blood Pressure GATT client and server and can switch between the following GAP roles: Peripheral, Observer and Central. The contents of the archive needs to be copied to the following location: <Installer Path>\KW40Z_Connectivity_Software_1.0.1\ConnSw\examples\bluetooth\ The application can be found at: <Install Path specified>\KW40Z_Connectivity_Software_1.0.1\ConnSw\examples\bluetooth\blood_pressure_multi_role\frdmkw40z\bare_metal\build\iar\blood_pressure_multi_role.eww Running as GAP Peripheral Press SW4. LED1 will start flashing and the console will show that the Link Layer enters Advertising. If the Link Layer was in a previous state, it will go through Standby. static void BleApp_Advertise(void) {     /* Ensure Link Layer is in Standby */     BleApp_GoToStandby();         shell_write(" GAP Role: Peripheral\n\r");     mGapRole = gGapPeripheral_c;         /* Start GAP Peripheral */     App_StartAdvertising(BleApp_AdvertisingCallback, BleApp_ConnectionCallback); } Running as GAP Observer Press SW3. A chasing LED pattern will start and the console will show that the Link Layer enters Scanning. If the Link Layer was in a previous state, it will go through Standby. static void BleApp_Scan(void) {     /* Ensure Link Layer is in Standby */     BleApp_GoToStandby();         shell_write(" GAP Role: Observer\n\r");     mGapRole = gGapObserver_c;         /* Start GAP Observer */     App_StartScanning(&gAppScanParams, BleApp_ScanningCallback); } Running as GAP Central If the Link Layer is in scanning and finds a Blood Pressure Sensor, it will go through Standby and initiate connection. static void BleApp_Connect(void) {     /* Ensure Link Layer is in Standby */     BleApp_GoToStandby();         shell_write(" GAP Role: Central\n\r");     mGapRole = gGapCentral_c;         /* Start GAP Central */     Gap_Connect(&gConnReqParams, BleApp_ConnectionCallback); } Returning to Standby Pressing SW3 for more than 2 seconds, brings the Link Layer back in Standby. static void BleApp_GoToStandby(void) {     /* Check if connection is on */     if (mPeerInformation.deviceId != gInvalidDeviceId_c)     {         /* Stop GAP Central or Peripheral */         Gap_Disconnect(mPeerInformation.deviceId);     }     if (mAdvOn)     {         /* Stop GAP Peripheral or Bradcaster */         Gap_StopAdvertising();     }         if (mScanningOn)     {         /* Stop GAP Observer */         Gap_StopScanning();     } } References [1] BLUETOOTH SPECIFICATION Version 4.2 [Vol 3, Part C], 2.2 PROFILE ROLES
記事全体を表示
Thread is a secure, wireless, simplified IPv6-based mesh networking protocol developed by industry leading technology companies, including Freescale, for connecting devices to each other, to the internet and to the cloud. Before starting a Thread Network implementation, users should be familiar with some concepts and how they are related to Thread protocol. IPv6 Addressing Devices in the Thread stack support IPv6 addressing IPv6 addresses are 128-bit identifiers (IPv4 is only 32-bit) for interfaces and sets of interfaces.  Thread supports the following types of addresses: Unicast:  An identifier for a single interface.  A packet sent to a unicast address is delivered to the interface identified by that address. Multicast: An identifier for a set of interfaces (typically belonging to different nodes).  A packet sent to a multicast address is delivered to all interfaces identified by that address. NOTES There are no broadcast addresses in IPv6, their function being superseded by multicast addresses. Each device joining the Thread Network is also assigned a 16-bit short address as specified in IEEE 802.15.4. 6LoWPAN All Thread devices use 6LoWPAN 6LoWPAN stands for “IPv6 over Low Power Wireless Personal Networks”. 6LoWPAN is a set of standards defined by the Internet Engineering Task Force (IETF), which enables the efficient use of IPv6 over low-power, low-rate wireless networks on simple embedded devices through an adaptation layer and the optimization of related protocols. Its main goal is to send/receive IPv6 packets over 802.15.4 links. Next figure compares IP and 6LoWPAN protocol stacks: The following concepts would explain the transport layer. ICMP Thread devices support the ICMPv6 (Internet Control Message Protocol version 6) protocol and ICMPv6 error messages, as well as the echo request and echo reply messages. The Internet Control Message Protocol (ICMP) is an error reporting and diagnostic utility and is considered a required part of any IP implementation. ICMPs are used by routers, intermediary devices, or hosts to communicate updates or error information to other routers, intermediary devices, or hosts. For instance, ICMPv6 is used by IPv6 nodes to report errors encountered in processing packets, and to perform other internet-layer functions, such as diagnostics. ICMP differs from transport protocols such as TCP and UDP in that it is not typically used to exchange data between systems, nor is it regularly employed by end-user network applications.  The ICMPv6 messages have the following general format: The type field indicates the type of the message.  Its value determines the format of the remaining data. The code field depends on the message type.  It is used to create an additional level of message granularity. The checksum field is used to detect data corruption in the ICMPv6 message and parts of the IPv6 header. ICMPv6 messages are grouped into two classes: error messages and informational messages.  Error messages are identified as such by a zero in the high-order bit of their message Type field values.  Thus,   error messages have message types from 0 to 127; informational messages have message types from 128 to 255. UDP The Thread stack supports UDP for messaging between devices. This User Datagram Protocol  (UDP)  is defined  to  make available  a datagram   mode of  packet-switched   computer communication  in  the environment  of an  interconnected  set  of  computer  networks, assuming that the Internet  Protocol (IP) is used as the underlying protocol. With UDP, applications can send data messages to other hosts on an IP network without prior communications to set up special transmission channels or data paths. UDP is suitable for purposes where error checking and correction is either not necessary or is performed in the application, avoiding the overhead of such processing at the network interface level. The UDP format is as follows: Source Port is an optional field, when meaningful, it indicates the port of the sending  process,  and may be assumed  to be the port  to which a reply should be addressed  in the absence of any other information.  If not used, a value of zero is inserted. Destination Port has a meaning within the context of a particular internet destination address. Length is the length in octets of this user datagram including this header and the data.   (This means the minimum value of the length is eight.) Checksum is the 16-bit one's complement of the one's complement sum of a pseudo header of information from the IP header, the UDP header, and the data, padded  with zero octets at the end (if  necessary)  to  make  a multiple of two octets. References White papers available at http://threadgroup.org/ “6LoWPAN: The Wireless Embedded Internet” by Zach Shelby and Carsten Bromann RFC 4291, RFC 4944, RFC 4443 and RFC 768 from https://www.ietf.org
記事全体を表示
Many applications make use of 32 kHz clocks to keep tracking of real-time or to have a low power time reference for the system. Most of the systems might use a 32.768 kHz XTAL for this purpose. However, there might be some exceptions in which the application requires compensate the frequency of this clock due to temperature changes, aging, or just because the clock provides from a source which frequency is close to the ideal 32.768 kHz, but it presents some variations. QN908x devices require a 32 kHz clock source for some applications like running the BLE stack in low power. 32.768 kHz XTALs are more accurate so they are used to generate a 32 kHz source by compensating for the ppm difference. This provides us with tools to compensate for any external 32 kHz source by first obtaining the ppm difference from the ideal frequency. The solution consists in determining how off is the external clock input frequency from the ideal 32 kHz by making a comparison with a trusted clock in the system, typically the 32 MHz / 16 MHz XTAL. This process is executed in the background in an interrupt-based system so the application can initialize or run other processes in the meantime. Then, the results of the ppm calculation are reported to the main application to compensate for the changes and provide for a more accurate clock source. This example makes use of the following peripherals in the QN908x RTC Seconds Timer CTIMER DMA The RTC Seconds Timer uses the 32 kHz clock source as a reference. It contains an internal 32000 cycles counter that increases each 32 kHz clock period. On overflow, it rises the SEC_INT flag to indicate that one second has elapsed. The CTIMER makes use of the APB clock which derives from the 32 MHz / 16 MHz clock. This timer is used in free-running mode with a Prescaler value of 1 to count the number of APB pulses. The algorithm consists of counting the amount of APB pulses (trusted clock reference) elapsed by the time the RTC SEC_INT flag is set. Ideally, if both clocks are in the right frequency, the number of APB pulses must be equal to the reference clock frequency. For example, if the APB clock is 16 MHz, by the time the SEC_INT flag sets, the CTIMER counter must have a value of 16 x 10 6 counts. Assuming our reference clock is ideal, the difference between the CTIMER counter value and 16 x 10 6 can be used to obtain the ppm difference given the following formula. Where f 0 is the ideal APB frequency (16 MHz) and f 1 is the real measured frequency (CTIMER counter value). Since the pulses counted using the CTIMER correspond to the time it took to the RTC Seconds Timer to count one second, we can extrapolate the obtained ppm value as a difference in the 32 kHz clock source from the ideal 32 kHz. To prevent from any application or task servicing latency, the algorithm makes use of the DMA to automatically capture the CTIMER Counter value when the SEC_INT flag is set. The program flow is described in the diagram below. As a way of demonstrating this algorithm, two APIs were implemented to calculate the ppm value and apply the compensation to the system. Both APIs are included in the file fsl_osc_32k_cal .c and .h files. OSC_32K_CAL_GetPpm (osc_32k_cal_callback_t pCallbackFnc): Initializes the required timers and DMA and starts with the CTIMER capture. A callback is passed so it can be executed once the ppm calculation sequence completes. OSC_32_CAL_ApplyPpm (int32_t ppmMeasurement): Uses the previously calculated ppm passed as an input parameter to compensate the RTC and the BLE timer used during sleep mode. OSC_32K_CAL_GetPpm is called every time the ppm value of the 32 kHz source clock needs to be calculated. It takes around one second to complete (depending on how off the 32 kHz source clock is from the ideal frequency) and the application cannot enter into low power state during this time. The registered callback function is executed once the calculation is complete. The ppm calculation is performed into the DMA callback. It consists of obtaining the CTIMER counter difference and use it as f 1 in the formula shown before. The ppm values are calculated using floating point unit. /* Calculate PPMs */ ppmResult = (float)((float)1-((float)ApbClockFreq/(float)ApbCountDiff)); ppmResult *= (float)1048576;‍‍‍‍‍‍ Then OSC_32_CAL_ApplyPpm must be called using the ppm value obtained after calling OSC_32K_CAL_GetPpm. This API programs the necessary values in the RTCàCAL register and the BLE Sleep timer registers to compensate for the differences in the 32 kHz source clock. Finally, the user must account for all those other APIs that make use of the 32 kHz clock frequency and update the values accordingly. For the particular case of the NXP BLE Stack, there are two APIs that need to be updated to return the clock frequency after the calibration has been applied. uint32_t PWRLib_LPTMR_GetInputFrequency(void) { uint32_t result = 32000; int32_t ppm = 0; if ( RTC->CTRL & RTC_CTRL_CAL_EN_MASK) /* is calibration enabled ? */ { /* Get the current calibration value */ if (RTC->CAL & RTC_CAL_DIR_MASK) { /* Backward calibration */ ppm -= (int32_t) (RTC->CAL & RTC_CAL_PPM_MASK); } else { /* Forward calibration */ ppm += (int32_t) (RTC->CAL & RTC_CAL_PPM_MASK); } /* Obtain the uncalibrated clock frequency using the formula * fUncal = 32000 - (ppm*0.03125) where 0.03125 is the number * of Hz per PPM digit obtained from (768 Hz/0x6000 PPM) */ result -= (float) ppm * (float) 0.03125; } else { #if (defined(BOARD_XTAL1_CLK_HZ) && (BOARD_XTAL1_CLK_HZ == CLK_XTAL_32KHZ)) result = CLOCK_GetFreq(kCLOCK_32KClk); /* 32,768Khz crystal is used */ #else result = CLOCK_GetFreq(kCLOCK_32KClk); /* 32,000Khz internal RCO is used */ #endif } return result; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ uint32_t StackTimer_GetInputFrequency(void) { uint32_t prescaller = 0; uint32_t refClk = 0; uint32_t result = 0; #if FSL_FEATURE_SOC_FTM_COUNT refClk = BOARD_GetFtmClock(gStackTimerInstance_c); prescaller = mFtmConfig.prescale; result = refClk / (1 << prescaller); #elif FSL_FEATURE_RTC_HAS_FRC int32_t ppm = 0; (void)prescaller; /* unused variables */ (void)refClk; /* suppress warnings */ result = 32000; if ( RTC->CTRL & RTC_CTRL_CAL_EN_MASK) /* is calibration enabled ? */ { /* Get the current calibration value */ if (RTC->CAL & RTC_CAL_DIR_MASK) { /* Backward calibration */ ppm -= (int32_t) (RTC->CAL & RTC_CAL_PPM_MASK); } else { /* Forward calibration */ ppm += (int32_t) (RTC->CAL & RTC_CAL_PPM_MASK); } /* Obtain the uncalibrated clock frequency using the formula * fUncal = 32000 - (ppm*0.03125) where 0.03125 is the number * of Hz per PPM digit obtained from (768 Hz/0x6000 PPM) */ result -= (float) ppm * (float) 0.03125; } else { #if (defined(BOARD_XTAL1_CLK_HZ) && (BOARD_XTAL1_CLK_HZ == CLK_XTAL_32KHZ)) result = CLOCK_GetFreq(kCLOCK_32KClk); /* 32,768Khz crystal is used */ #else result = CLOCK_GetFreq(kCLOCK_32KClk); /* 32,000Khz internal RCO is used */ #endif } #elif FSL_FEATURE_SOC_CTIMER_COUNT refClk = BOARD_GetCtimerClock(mCtimerBase[gStackTimerInstance_c]); prescaller = mCtimerConfig[gStackTimerInstance_c].prescale; result = refClk / (prescaller + 1); #else refClk = BOARD_GetTpmClock(gStackTimerInstance_c); prescaller = mTpmConfig.prescale; result = refClk / (1 << prescaller); #endif return result; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
記事全体を表示
The connectivity software is an add-on of the Kinetis SDK, therefore the demos are referenced to a KSDK path variable named "KSDK_PATH" in IAR. The KSDK_PATH variable contains the path of the installation folder for the KSDK version in your PC. Taking as an example the MRB-KW01 SMAC Connectivity Software, we can realize that this variable is used to reference for libraries. In particular, this SMAC software for the MRB-KW01 works with KSDK 1.2, that is why you could have troubles if the variable is referenced to another KSDK version (for example KSDK 1.1). Follow the next steps to modify the KSDK_PATH variable in your computer: 1. Right click on "computer", then click "properties" 2. A Control Panel window will be opened. Click on "Advanced system settings" 3. A system Properties windows will be opened. Select the "Advanced" tab, then click "Environment Variables". 4. Select the KSDK_PATH variable and assure that it stores the correct path needed for your project. In case that you need to modify the variable, then click "Edit" 5. Finally click "Ok" to close all tabs and you will be able to run your connectivity software without problems. Best regards, Luis Burgos.
記事全体を表示
Hello All, I designed a ultra low low cost evaluation board (ULC-Zigbee) based in Kinetis wireless MCUs, take a look at the attached PDF for the brief description.  I was able to build three of them at ~$10USD each. The ULC-Zigbee is covered under the GNU General Public License. The required files to build the board are attached, it measures 30 x 50mm. My partner AngelC   wrote a sample code. The software basically communicates wirelessly the ULC-Zigbee board with a USB-KW24D512. An FXOS8700 is externally connected through the prototype board connector and the magnetic and acceleration values are then wirelessly transmitted to the USB stick, then the values can be printed in a HyperTerminal. The attached zip file contains the following files: File name Description ULC-Zigbee-EBV_V10.pdf Brief description of the ULC-Zigbee board MKW2x_Eagle_library.lbr  Required EAGLE CADSOFT LIBRARY ULC-Zigbee-EBV_V10.brd EAGLE v6.5 Board ULC-Zigbee-EBV_V10.sch EAGLE v6.5 Schematic ULC-Zigbee-EBV_V10_SCH.pdf ULC-Zigbee board schematic ULC-Zigbee-EBV_V10_BOM.xlsx Bill of materials ULC-Zigbee-EBV_V10_GERBER_FILES.zip Gerber files WirelessUART_MKW2x_v1.3_eCompass_TX_v1.zip ULC-Zigbee board sample software WirelessUART_MKW2x_v1.3_eCompass_RX_v1.zip USB-KW24D512 sample software     Hope it helps!   -Josh   Este documento fue generado desde la siguiente discusión:Ultra Low Cost Zigbee Evaluation Board
記事全体を表示
This post explains the implementation to operate the KW36 MCU on VLPR when the clocking mode is BLPE or BLPI. It's also included the explanation on how to configure clocks for BLPE and BLPI modes. For this example, the beacon demo from the wireless examples of the FRDM-KW36 is used. FRDM-KW36 SDK can be downloaded from MCUXpresso webpage. A recommended option to configure clock modes is "Config Tools" from MCUXpresso. Config Tools is embedded to MCUXpresso IDE, or you can download Config Tools from this LINK if you are using other supported IDE for this tool. MCUXpresso IDE is used in this example. Configure BLPE or BLPI clocking modes Select your proyect on MCUXpresso IDE, then open the clocks configuration window from Config Tools by clicking the arrow next to Config Tools icon from your MCUXpresso IDE, and then select "Open Clocks" as shown in Figure 1. Figure 1. Open Clocks from Config Tools using MCUXpresso IDE. A clocks diagram window will be opened. To configure the clock modes just select your option "BLPI" or "BLPE" on MCG Mode as shown in Figure 2. Clock will be automatically configured. Figure 2. MCG Mode selection. Now let's configure the appropiate clocks for Core clock and Bus clock to run in VLPR. Figure 3 taken from KW36 Reference Manual shows achievables frequencies when MCU is on VLPR.  Figure 3. VLPR clocks. Core clock should be 4MHz for BLPE and BLPI clocking modes, and Bus clock should be 1MHz for BLPE and 800kHz for BLPI.  Figure 4 shows clocks distribution for BLPE and Figure 5 for BLPI to operate with discussed frequencies. Figure 4. Clock distribution - VLPR and BLPE. Figure 5. Clock distribution - VLPR and BLPI. Press "Update Project" (Figure 6) to apply your new clock configuration to your firmware, then change perspective to "Develop" icon on right corner up to go to your project (See Figure 7). Compile your project to apply the changes. Figure 6. Update Project button. Figure 7. Develop button. At this point your project is ready to work with BLPE or BLPI clocks modes. Now, let's configure MCU to go to VLPR power mode. Configure VLPR mode VLPR mode can be configured using Config Tools too, but you may have an error trying to configure it when BLPE mode, this is because CLKDIV1 register cannot be written when the device is on VLPR mode. For this example, let's configure MCU into VLPR mode by firmware. Follow next steps to configure KW36 into VLPR power mode: 1. Configure RF Ref Oscillator to operate in VLPR mode. By default, the RF Ref Osc it's configured to operate into RUN mode. To change it to operate on VLPR mode just change the bits RF_OSC_EN from Radio System Control from 1 (RUN) to 7 (VLPR). Figure 8 taken from KW36 Reference Manual shows RF_OSC_EN value options from Radio System Control.    Figure 8. RF_OSC_EN bits from Radio System Control register. Go to clock_config.c file in your MCUXpresso project and search for "BOARD_RfOscInit" function. Change the code line as shown in Figure 9 to configure RF Ref Osc to work into VLPR mode. You may see a window asking if you want to make writable the read-only file, click Yes. Figure 9. Code line to configure RF Ref Osc to work into VLPR mode Be aware that code line shown in Figure 9 may change with updates done in clocks using Config Tools. Note 2. Configure DCDC in continuous mode. According to KW36 Reference Manual, the use of BLPE in VLPR mode is only feasible when the DCDC is configured for continuous mode. First, let's define gDCDC_Enabled_d flag to 1 on preprocesor. With this implementation, the use of DCDC_Init function will be enabled, and it's where we going to add the code line to enable continuous mode. Right click on your project, select Properties, go to Settings under C/C++ Build, then Preprocessor under MCU C Compiler (Figure 10).   Figure 10. MCUXpresso Preprocessor   Click on add button from Defined symbols, write gDCDC_Enabled_d=1 and click OK to finish (Figure 11).  Re-compile your project. Figure 11. MCUXpresso Defined symbols   Now let's set VLPR_VLPW_CONFIG_DCDC_HP bits to 1 from DCDC_REG0 register. Figure 12 was taken from KW36 Reference Manual. Figure 12. VLPR_VLPW_CONFIG_DCDC_HP values. Go to DCDC_Init  function and add the next code line to enable continuous mode on DCDC: DCDC->REG0 |= DCDC_REG0_VLPR_VLPW_CONFIG_DCDC_HP_MASK; Figure 13 shows the previous code line implemented in firmware project inside of DCDC_Init function. Figure 13. Continuous mode for DCDC enabled. 3. Configure MCU into VLPR mode To finish, let's write the code to configure MCU into VLPR power mode. Copy and paste next code just after doing implementation described on step 1 and 2: #if (defined(FSL_FEATURE_SMC_HAS_LPWUI) && FSL_FEATURE_SMC_HAS_LPWUI) SMC_SetPowerModeVlpr(SMC, false); #else SMC_SetPowerModeVlpr(SMC); #endif while (kSMC_PowerStateVlpr != SMC_GetPowerModeState(SMC)) { } It may be needed to add the SMC library: #include "fsl_smc.h" The code is configuring MCU into VLPR mode with bits RUNM from SMC_PMCTRL register (Figure 14) and then check if it was correctly configured by reading status bits PMSTAT from SMC_PMSTAT register (Figure 15) Figure 14. RUNM bits from SMC_PMCTRL register. Figure 15. PMSTAT bits from  SMC_PMSTAT register. KW36 is ready to operate and BLPE or BLPI clocking modes with VLPR power mode.
記事全体を表示
The KW41Z has support for an external 26 MHz or 32 MHz reference oscillator. This oscillator is used, among other things, as the clock for the RF operation. This means that the oscillator plays an important role in the RF operation and must be tuned properly to meet wireless protocol standards. The KW41Z has adjustable internal load capacitors to support crystals with different load capacitance needs. For proper oscillator function, it is important that these load capacitors be adjusted such that the oscillator frequency is as close to the center frequency of the connected crystal (either 26 MHz or 32 MHz in this case). The load capacitance is adjusted via the BB_XTAL_TRIM bit field in the ANA_TRIM register of the Radio block. The KW41Z comes preprogrammed with a default load capacitance value. However, since there is variance in devices due to device tolerances, the correct load capacitance should be verified by verifying that the optimal central frequency is attained.  You will need a spectrum analyzer to verify the central frequency. To find the most accurate value for the load capacitance, it is recommended to use the Connectivity Test demo application. This post is aimed at showing you just how to do that.   In this case, the Agilent Technologies N9020A MXA Signal Analyzer was used to measure, configured with the following parameters: FREQ (central frequency): 2405 MHz (test will be conducted on channel 11) SPAN (x-axis): 100 KHz AMPTD (amplitude, y-axis): 5 dBm To perform the test, program the KW41Z with the Connectivity Test application. The project, for both IAR and KDS, for this demo application can be found in the following folder: <KW41Z_connSw_1.0.2_install_dir>\boards\frdmkw41z\wireless_examples\smac\connectivity_test\FreeRTOS NOTE:  If you need help programming this application onto your board, consult your Getting Started material for the SMAC applications.  For the FRDM-KW41Z, it is located here. Once the device is programmed, make sure the device is connected to a terminal application in your PC. When you start the application, you're greeted by this screen: Press 'ENTER' to start the application. Press '1' to select the continuous tests mode. Press '4' to start a continuous unmodulated transmission. Once the test is running, you should be able to see the unmodulated signal in the spectrum analyzer. Press 'd' and 'f' to change the XTAL trim value, thus changing the central frequency. Now, considering the test in this example is being performed in 802.15.4 channel 11, the central frequency should be centered exactly in 2.405 GHz, but on this board, it is slightly above (2.4050259 GHz) by default. In order to fix this, the XTAL trim value was adjusted to a value that moves the frequency to where it should be centered. Once the adequate XTAL trim value is found, it can be programmed to be used by default. This other post explains how to do this process.
記事全体を表示
Commissioner Authentication server for new Thread devices and the authorizer for providing the network credentials they require to join the network. A device capable of being elected as a Commissioner is called a Commissioner Candidate. Devices without Thread interfaces may perform this role, but those that have them may combine this role with all other roles except the Joiner. This device may be, for example, a cell phone or a server in the cloud, and typically provides the interface by which a human administrator manages joining a new device to the Thread Network. Commissioner Candidate A device that is capable of becoming the Commissioner, and either intends or is currently petitioning the Leader to become the Commissioner, but has not yet been formally assigned the role of Commissioner. Commissioner Credential A human-scaled passphrase for use in authenticating that a device may petition to become the commissioner of the network. This credential can be thought of as the network administrator password for a Thread Network. The first device in a network, typically the initial Leader, MUST be out-of-band commissioned to inject the correct user generated Commissioning Credential into the Thread Network, or provide a known default Commissioning Credential to be changed later. Joiner A device to be added by a human administrator to a commissioned Thread Network. This role requires a Thread interface to perform and cannot be combined with another role in one device. The Joiner does not have network credentials. Joiner Router An existing Thread router or REED (Router-Eligible End Device) on the secure Thread Network that is one radio hop away from the Joiner. The Joiner Router requires a Thread interface to operate, and may be combined in any device with other roles except the Joiner role. Information extracted from the Thread Whitepapers available at threadgroup.org
記事全体を表示
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*/‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
記事全体を表示
Introduction This document describes the steps needed to enable System View tool emphasizing in connectivity software stack for the QN9080CDK MCU.   Software Requirements QN908XCDK SDK 2.2.0 SystemView Software J-Link Software and Documentation Pack     Hardware Requirements QN9080CDK Board with J-Link debug interface   Enabling SystemView in IAR Embedded Workbench IDE   1. Unzip your QN908XCDK SDK. Open your desired project from:<SDK_install_path>/boards/qn908xcdk/wireless_examples/<Choose_your_project>/freertos/iar/<Your_project.eww>   2. Select the project in the workspace, press the right mouse button and select “Add->Add Group...” option       3. Create a new group called “SEGGER”, click on the “OK” button. Repeat the step 1 and create other groups called “Config” and “FreeRTOS_SEGGER”.     The workspace will be updated as shown below       4. Create folders called “SEGGER”, “Config” and “FreeRTOS_SEGGER” in the Windows directory at the following path:     <QN9080_SDK_root>/boards/qn908xcdk/wireless_examples/bluetooth/<your_example>/freertos       5. Add the following files in the recently created folders (SEGGER, Config and FreeRTOS_SEGGER) on Windows directory (the default SysView installation path is C:\Program Files (x86)\SEGGER\SystemView_V252c):   For the SEGGER folder:        All files located at <SysView_installation_path>\Src\SEGGER   For the Config folder:       All files located at <SysView_installation_path>\Src\Config   For the FreeRTOS_SEGGER folder:       <SysView_installation_path>\Src\Sample\FreeRTOSV9\SEGGER_SYSVIEW_FreeRTOS.c       <SysView_installation_path>\Src\Sample\FreeRTOSV9\SEGGER_SYSVIEW_FreeRTOS.h       <SysView_installation_path>\Src\Sample\FreeRTOSV9\Config\SEGGER_SYSVIEW_Config_FreeRTOS.c     6. Go to the workspace and click the right mouse button on “SEGGER”, “Config” and “FreeRTOS_SEGGER” groups, then select “Add->Add Files...” option. Add the following files:   For the SEGGER group:         All files in <QN9080_SDK_root>/boards/qn908xcdk/wireless_examples/bluetooth/<your_example>/freertos/SEGGER folder    For the Config group:        All files in <QN9080_SDK_root>/boards/qn908xcdk/wireless_examples/bluetooth/<your_example>/freertos/Config folder   For the FreeRTOS_SEGGER group:        All files in <QN9080_SDK_root>/boards/qn908xcdk/wireless_examples/bluetooth/<your_example>/freertos/FreeRTOS_SEGGER folder   The workspace will be updated as shown in the picture below       7. Select the project in the workspace and press Alt + F7. Go to “C/C++ Compiler” window and select “Preprocessor”. Include in “Additional include directories” view the following paths:   $PROJ_DIR$ /../Config $PROJ_DIR$ /../FreeRTOS_SEGGER $PROJ_DIR$ /../SEGGER       8. Go to “Assembler”, click on “Preprocessor”. Include the last paths on “Additional include directories” view as shown below. Click the OK button.     9. Replace the following files in the workspace with the files attached in this post (IAR files.zip). Make sure that each new file is located on the same path as the respectively last one.   freertos/FreeRTOS.h freertos/task.h freertos/tasks.c freertos/portable/portasm.s freertos/portable/port.c freertos/portable/portmacro.h   10. Add #include "SEGGER_SYSVIEW_FreeRTOS.h" at the end of the FreeRTOSConfig.h file located at source/FreeRTOSConfig.h in the workspace.       11. Search the “SEGGER_SYSVIEW_Config_FreeRTOS.c” file at FreeRTOS_SEGGER folder in the workspace. Modify the SYSVIEW_RAM_BASE value to the lowest RAM address (default 0x20000000 in QN9080) and add an extern declaration to the SystemCoreClock variable: extern uint32_t SystemCoreClock;‍‍       12. Search the “fsl_os_abstraction_free_rtos.c” file at framework/OSAbstraction folder in the workspace. Add #include "SEGGER_SYSVIEW.h" at the top of the file. Search the main function and add the following call to function inside:   SEGGER_SYSVIEW_Conf(); SEGGER_SYSVIEW_Start();‍‍‍‍‍‍‍‍‍‍        13. Build and run your example. Run SystemView in your PC.     Enabling SystemView in MCUXpresso IDE 1. Install your QN908XCDK SDK in MCUXpresso IDE and import any freertos example from "wireless_examples" folder.  2. Select the project in the workspace, press the right mouse button and select "New->Source Folder" option     3. Create a new folder called “SEGGER”, click on the “Finish” button. Repeat the step 1 and create other folders called “Config” and “FreeRTOS_SEGGER”.     The workspace will be updated as shown below     4. Add the following files in the SEGGER, Config and FreeRTOS_SEGGER folders on the workspace dragging and dropping (the default SysView installation path is C:\Program Files (x86)\SEGGER\SystemView_V252c):   For the SEGGER folder:        All files located at <SysView_installation_path>\Src\SEGGER   For the Config folder:       All files located at <SysView_installation_path>\Src\Config   For the FreeRTOS_SEGGER folder:       <SysView_installation_path>\Src\Sample\FreeRTOSV9\SEGGER_SYSVIEW_FreeRTOS.c       <SysView_installation_path>\Src\Sample\FreeRTOSV9\SEGGER_SYSVIEW_FreeRTOS.h       <SysView_installation_path>\Src\Sample\FreeRTOSV9\Config\SEGGER_SYSVIEW_Config_FreeRTOS.c   When dragging and dropping, a new window will appear. Select "Copy files" in the button group and click "OK".       5. Select the project in the workspace, then go to "Project->Properties". The project properties window will be deployed.       6. Go to "C/C++ Build->Settings->Tool Settings->MCU C Compiler->Includes" view. Click on the "Green plus icon" in the "Include paths" view. A new window will appear, click on "Workspace..." button.       7. Select SEGGER, Config and FreeRTOS_SEGGER folders and click "OK", then click "Apply and Close" in the Project Properties window.   .   8. Replace the following files in the workspace with the files attached in this post (MCUXpresso files.zip).   freertos/FreeRTOS.h freertos/task.h freertos/tasks.c freertos/port.c freertos/portmacro.h   9. Add #include "SEGGER_SYSVIEW_FreeRTOS.h" at the end of the FreeRTOSConfig.h file located at source/FreeRTOSConfig.h in the workspace.     10. Search the “SEGGER_SYSVIEW_Config_FreeRTOS.c” file at FreeRTOS_SEGGER folder in the workspace. Modify the SYSVIEW_RAM_BASE value to the lowest RAM address (default 0x20000000 in QN9080) and add an extern declaration to the SystemCoreClock variable: extern uint32_t SystemCoreClock;‍‍   11. Search the “fsl_os_abstraction_free_rtos.c” file at framework/OSAbstraction/Source folder in the workspace. Add #include "SEGGER_SYSVIEW.h" at the top of the file. Search the main function and add the following call to function inside: SEGGER_SYSVIEW_Conf(); SEGGER_SYSVIEW_Start();‍‍‍‍‍‍‍‍‍‍‍‍   12. Build and run your example. Run SystemView in your PC.
記事全体を表示