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

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

Wireless Connectivity Knowledge Base

ディスカッション

ソート順:
One of the most difficult part of creating connected medical applications is, actually, keep it connected. Different protocols are available to transmit information from a medical device to a database or user interface. Sometimes integrating our application to the current communication protocols can be as difficult as developing the device itself. Freescale has launched its Bluetooth® Low Energy (BLE) chips, and with them, a complete software stack that integrates most of the available profiles for BLE oriented applications. Using this set, it becomes easy to integrate your current medical application to use BLE as communications method. Freescale Connectivity Software Examples The connectivity software includes examples to demonstrate BLE communications with a smartphone device. Using these examples as a base facilitates the integration with an existing application and reduces the required time it takes to have a fully connected application. This post uses as an example the Heart Rate Monitor demo to show how these applications can be customized. Modifying general device information The BLE services information reported by the device is stored in a file named “gatt_db.h”. This services information is what is shown on a smartphone when the device has connected. The Generic Access Profile service includes the device name reported when advertising. To change it just replace the device name between “” and update the character count. Detailed device information is accessed via the Device Information Service including the manufacturer name, model and serial number etcetera. This information can also be adjusted to the custom device requirements by modifying the string between “” and updating the character number. Adapting example code to report application data The connectivity software includes some predefined services that can be used to customize the server to report our application data. These predefined services already include structures with the information that needs to be reported to the client. On the application example file app.c some of these services are configured. For the heart rate service, a variable of type hrsConfig_t is created containing configuration information of the heart rate sensor such as the supported characteristics and sensor location. All of these characteristics are described in the heart rate service file heart_rate_interface.h /* Service Data*/ static basConfig_t      basServiceConfig = {service_battery, 0}; static disConfig_t      disServiceConfig = {service_device_info}; static hrsUserData_t    hrsUserData; static hrsConfig_t hrsServiceConfig = {service_heart_rate, TRUE, TRUE, TRUE, gHrs_BodySensorLocChest_c, &hrsUserData}; static uint16_t cpHandles[1] = { value_hr_ctrl_point }; /*! Heart Rate Service - Configuration */ typedef struct hrsConfig_tag {     uint16_t             serviceHandle;     bool_t               sensorContactSupported;     bool_t               sensorContactDetected;     bool_t               energyExpandedEnabled;     hrsBodySensorLoc_t   bodySensorLocation;     hrsUserData_t        *pUserData; } hrsConfig_t; This information is used to configure the server when the function BleApp_Config is called. /* Start services */ hrsServiceConfig.sensorContactDetected = mContactStatus; #if gHrs_EnableRRIntervalMeasurements_d    hrsServiceConfig.pUserData->pStoredRrIntervals = MEM_BufferAlloc(sizeof(uint16_t) * gHrs_NumOfRRIntervalsRecorded_c); #endif    Hrs_Start(&hrsServiceConfig); basServiceConfig.batteryLevel = BOARD_GetBatteryLevel(); Bas_Start(&basServiceConfig); /* Allocate application timers */ mAdvTimerId = TMR_AllocateTimer(); Once the server is configured, the application is stated by entering the device in advertising state in order to make it visible for clients. This is done by calling the function BleApp_Advertise that configures the server to start advertising. void BleApp_Start(void) { /* Device is not connected and not advertising*/ if (!mAdvState.advOn) { #if gBondingSupported_d if (mcBondedDevices > 0) { mAdvState.advType = fastWhiteListAdvState_c; } else { #endif mAdvState.advType = fastAdvState_c; #if gBondingSupported_d } #endif BleApp_Advertise(); } #if (cPWR_UsePowerDownMode)    PWR_ChangeDeepSleepMode(1); /* MCU=LLS3, LL=DSM, wakeup on GPIO/LL */ PWR_AllowDeviceToSleep(); #endif       } Once the server has been found and a connection has been stablished with the client, the configured services must be started. This is done by calling the “subscribe” function for each service. For heart rate sensor, the function Hrs_Suscribe must be called. This function is available from the heart_rate_interface files. /* Subscribe client*/ Bas_Subscribe(peerDeviceId);        Hrs_Subscribe(peerDeviceId); #if (!cPWR_UsePowerDownMode)  /* UI */            During connection, the application measurements can be reported to the client by using the “record measurement” functions included in the service interfaces. For the heart rate sensor this is the Hrs_RecordHeartRateMeasurement function. static void TimerMeasurementCallback(void * pParam) { uint16_t hr = BOARD_GetPotentiometerLevel(); hr = (hr * mHeartRateRange_c) >> 12; #if gHrs_EnableRRIntervalMeasurements_d    Hrs_RecordRRInterval(&hrsUserData, (hr & 0x0F)); Hrs_RecordRRInterval(&hrsUserData,(hr & 0xF0)); #endif if (mToggle16BitHeartRate) { Hrs_RecordHeartRateMeasurement(service_heart_rate, 0x0100 + (hr & 0xFF), &hrsUserData); } else { Hrs_RecordHeartRateMeasurement(service_heart_rate, mHeartRateLowerLimit_c + hr, &hrsUserData); } Hrs_AddExpendedEnergy(&hrsUserData, 100); #if (cPWR_UsePowerDownMode) PWR_SetDeepSleepTimeInMs(900); PWR_ChangeDeepSleepMode(6); PWR_AllowDeviceToSleep();    #endif } This updates the current measurement and sends a notification to the client indicating that a new measurement report is ready. Many profiles are implemented in the connectivity software to enable already developed medical applications with BLE connectivity. APIs are easy to use and can significantly reduce the development times.
記事全体を表示
This is some information of Bluetooth Low Energy about the White List. I hope this information help you to understand the White List. The device to connect is saved on the white list located in the LL block of the controller. This enumerates the remote devices that are allowed to communicate with the local device. Since device filtering occurs in the LL it can have a significant impact on power consumption by filtering (or ignoring) advertising packets, scan requests or connection requests from being sent to the higher layers for handling. The Withe List can restrict which device are allowed to connect to other device. If is not, is not going to connect.      Once the address was saved, the connection with that device is going to be an auto connection establishment procedure.This means that the Controller autonomously establishes a connection with the device address that matches the address stored in the While List. Figure 1. White List Procedure NOTE: For more details download the Specification of the Ble​
記事全体を表示
802.15.4 wireless sniffers like the USB-KW41Z are capable of capturing over-the-air traffic. The captured packets are passed to a network protocol decoder like Wireshark over a network interface tunnel built by the Kinetis Protocol Analyzer.   Hardware  One USB-KW41Z preloaded with sniffer firmware ( instructions found at www.nxp.com/usb-kw41z )  Software Download & Install Thread Wireshark from wireshark.org which is an open-source network protocol analyzer capable of debugging over the air communication between Thread devices. Kinetis Protocol Analyzer is a software that provides a bridge between the USB-KW41 and Wireshark.  Wireshark Configuration  Open Wireshark from the Program Files Click Edit and select Preferences  Click Protocols to expand a list of protocols Select IEEE 802.15.4, click the Decryption Keys Edit... button Create a new key entry by pressing the plus button, then set the following values and click OK       Decryption key = 00112233445566778899aabbccddeeff      Decryption key index = 1      Key hash = Thread hash Find CoAP and configure it with CoAP UDP port number = 5683 Click Thread and select Decode CoAP for Thread  with Thread sequence counter = 00000000 as shown below At the 6LoWPAN preferences, add the Context 0 value of fd00:0db8::/64 Click OK and close Wireshark Configure Kinetis Protocol Analyzer  Connect the USB-KW41Z to one of the USB ports on your computer Open the device manager and look for the device connected port Open the "Kinetis Protocol Analyzer Adapter" program Make sure, you have a USB-KW41Z connected to your PC when opening the program because the Kinetis Protocol Adapter will start looking for kinetis sniffer hardware. Once the USB-KW41Z is detected, the previously identify COM port will be displayed Select the desired IEEE 802.15.4 channel to scan in the Kinetis Protocol Analyzer window. This guide selects channel 12 as an example  Click on the Wireshark icon to open Wireshark Network Protocol Analyzer An error may appear while opening Wireshark, click OK and continue Wireshark Sniffing Wireshark Network Analyzer will be opened. On the "Capture" option of the main window, select the Local Area Connection that was created by the Kinetis Protocol Analyzer, in this example, Kinetis Protocol Analyzer created "Local Area Connection 2", then click "Start" button. USB-KW41Z will start to sniff and upcoming data will be displayed in the "Capture" window of the Wireshark Network Protocol Analyzer.
記事全体を表示
This project is for Kinets L MCU Brazil challenge.Actually we don´t know if the project was registered. The goal of this project is to make Bluetooth communication between an android and  Freescale Freedom development kit FRDM-KL25Z. We will show the FRDM-KL25Z accelerometer status and the internal temperature sensor on android app. The android app requires version 4.x or above. Bluetooth module is connected to UART1.The embeddec code was created on CodeWarrior and exported to Keil MDK ARM.   http://youtu.be/-waEkfIuZCw
記事全体を表示
This document describes how to add additional cluster to the router application in the AN12061-MKW41Z-AN-Zigbee-3-0-Base-Device Application Note.   The Router application's main endpoint contains Basic, Groups, Identify and OnOff server. The steps below describe how to add two clusters to Router: Temperature Measurement server and OnOff client. Note that these changes only go as far as making the new clusters added and discoverable, no functionality has been added to these clusters. Router/app_zcl_cfg.h The first step is to update the application ZCL Configuration file to add the new clusters (OnOff Client, Temperature Measurement Server) to the Router application endpoint. The HA profile already contains few clusters but Temperature Measurement cluster was added:   /* Profile 'HA' */ #define HA_ILLUMINANCEMEASUREMENT_CLUSTER_ID (0x0400) #define HA_DEFAULT_CLUSTER_ID                (0xffff) #define HA_OTA_CLUSTER_ID                    (0x0019) #define HA_TEMPMEASUREMENT_CLUSTER_ID        (0x0402) Router/app_zcl_globals.c The OnOff client was already present in Router endpoint but made discoverable and the Temperature Measurement cluster was added and made discoverable into Router application endpoint.The clusters are added to the Input cluster list (Server side) and output cluster list (Client side) and made discoverable using DiscFlag only for the cluster list for which it is enabled. So, assuming you need to add OnOff cluster client, you would need to use add the cluster id (0x0006 for OnOff) into input cluster list (Server side of cluster) and output cluster list (Client side of the cluster) and make it discoverable for output cluster list as it is a client cluster. For temperature measurement, you need to make it discoverable for input Cluster list as below: PRIVATE const uint16 s_au16Endpoint1InputClusterList[6] = { 0x0000, 0x0004, 0x0003, 0x0006, HA_TEMPMEASUREMENT_CLUSTER_ID , 0xffff, }; PRIVATE const PDUM_thAPdu s_ahEndpoint1InputClusterAPdus[6] = { apduZCL, apduZCL, apduZCL, apduZCL, apduZCL, apduZCL, }; PRIVATE uint8 s_au8Endpoint1InputClusterDiscFlags[1] = { 0x1f }; PRIVATE const uint16 s_au16Endpoint1OutputClusterList[5] = { 0x0000, 0x0004, 0x0003, 0x0006, HA_TEMPMEASUREMENT_CLUSTER_ID, }; PRIVATE uint8 s_au8Endpoint1OutputClusterDiscFlags[1] = { 0x08 }; Now update Simple Descriptor structure (see the declaration of zps_tsAplAfSimpleDescCont and ZPS_tsAplAfSimpleDescriptor structures to understand how to correctly fill the various parameters) to reflect the input cluster and output cluster list correctly as below : PUBLIC zps_tsAplAfSimpleDescCont s_asSimpleDescConts[2] = { {    {       0x0000,       0,       0,       0,       84,       84,       s_au16Endpoint0InputClusterList,       s_au16Endpoint0OutputClusterList,       s_au8Endpoint0InputClusterDiscFlags,       s_au8Endpoint0OutputClusterDiscFlags,    },    s_ahEndpoint0InputClusterAPdus,    1 }, {    {       0x0104,       0,       1,       1,       6,       5,       s_au16Endpoint1InputClusterList,       s_au16Endpoint1OutputClusterList,       s_au8Endpoint1InputClusterDiscFlags,       s_au8Endpoint1OutputClusterDiscFlags,    },    s_ahEndpoint1InputClusterAPdus,    1 }, }; Router/zcl_options.h This file is used to set the options used by the ZCL. Enable Clusters The cluster functionality for the router endpoint was enabled: /****************************************************************************/ /*                             Enable Cluster                               */ /*                                                                          */ /* Add the following #define's to your zcl_options.h file to enable         */ /* cluster and their client or server instances                             */ /****************************************************************************/ #define CLD_BASIC #define BASIC_SERVER #define CLD_IDENTIFY #define IDENTIFY_SERVER #define CLD_GROUPS #define GROUPS_SERVER #define CLD_ONOFF #define ONOFF_SERVER #define ONOFF_CLIENT #define CLD_TEMPERATURE_MEASUREMENT #define TEMPERATURE_MEASUREMENT_SERVER Enable any optional Attributes and Commands for the clusters /****************************************************************************/ /* Temperature Measurement Cluster - Optional Attributes */ /* */ /* Add the following #define's to your zcl_options.h file to add optional */ /* attributes to the time cluster. */ /****************************************************************************/ #define CLD_TEMPMEAS_ATTR_TOLERANCE /****************************************************************************/ /* Basic Cluster - Optional Commands */ /* */ /* Add the following #define's to your zcl_options.h file to add optional */ /* commands to the basic cluster. */ /****************************************************************************/ #define CLD_BAS_CMD_RESET_TO_FACTORY_DEFAULTS /****************************************************************************/ /* OnOff Cluster - Optional Commands */ /* */ /* Add the following #define's to your zcl_options.h file to add optional */ /* commands to the OnOff cluster. */ /****************************************************************************/ #define CLD_ONOFF_CMD_OFF_WITH_EFFECT  Add the cluster creation and initialization into ZigBee Base device definitions The cluster functionality for some of the clusters (like OnOff Client) is already present on ZigBee Base Device. For Temperature Measurement cluster the functionality was added into ZigBee Base Device. <SDK>/middleware/wireless/Zigbee_3_0_6.0.6/core/ZCL/Devices/ZHA/Generic/Include/base_device.h The first step was including the Temperature Measurement header files into base device header file as shown below:  #ifdef CLD_TEMPERATURE_MEASUREMENT #include "TemperatureMeasurement.h" #endif The second step was adding cluster instance (tsZHA_BaseDeviceClusterInstances) into base device Instance as shown below: /* Temperature Measurement Instance */ #if (defined CLD_TEMPERATURE_MEASUREMENT) && (defined TEMPERATURE_MEASUREMENT_SERVER) tsZCL_ClusterInstance sTemperatureMeasurementServer; #endif The next step was to define the cluster into the base device structure (tsZHA_BaseDevice) as below: #if (defined CLD_TEMPERATURE_MEASUREMENT) && (defined TEMPERATURE_MEASUREMENT_SERVER) tsCLD_TemperatureMeasurement sTemperatureMeasurementServerCluster; #endif <SDK>/middleware/wireless/Zigbee_3_0_6.0.6/core/ZCL/Devices/ZHA/Generic/Include/base_device.c The cluster create function for Temperature Measurement cluster for server was called in ZigBee base device registration function:   #if (defined CLD_TEMPERATURE_MEASUREMENT) && (defined TEMPERATURE_MEASUREMENT_SERVER)    /* Create an instance of a Temperature Measurement cluster as a server */    if(eCLD_TemperatureMeasurementCreateTemperatureMeasurement(&psDeviceInfo->sClusterInstance.sTemperatureMeasurementServer,                                                    TRUE,                                                    &sCLD_TemperatureMeasurement,                                                    &psDeviceInfo->sTemperatureMeasurementServerCluster,                                                    &au8TemperatureMeasurementAttributeControlBits[0]) != E_ZCL_SUCCESS)   {       return E_ZCL_FAIL;    } #endif Router/app_zcl_task.c Temperature Measurement Server Cluster Data Initialization - APP_vZCL_DeviceSpecific_Init() The default attribute values for the Temperature Measurement clusters are initialized: PRIVATE void APP_vZCL_DeviceSpecific_Init(void) {    sBaseDevice.sOnOffServerCluster.bOnOff = FALSE;    FLib_MemCpy(sBaseDevice.sBasicServerCluster.au8ManufacturerName, "NXP", CLD_BAS_MANUF_NAME_SIZE);    FLib_MemCpy(sBaseDevice.sBasicServerCluster.au8ModelIdentifier, "BDB-Router", CLD_BAS_MODEL_ID_SIZE);    FLib_MemCpy(sBaseDevice.sBasicServerCluster.au8DateCode, "20150212", CLD_BAS_DATE_SIZE);    FLib_MemCpy(sBaseDevice.sBasicServerCluster.au8SWBuildID, "1000-0001", CLD_BAS_SW_BUILD_SIZE);    sBaseDevice.sTemperatureMeasurementServerCluster.i16MeasuredValue = 0;    sBaseDevice.sTemperatureMeasurementServerCluster.i16MinMeasuredValue = 0;    sBaseDevice.sTemperatureMeasurementServerCluster.i16MaxMeasuredValue = 0; }
記事全体を表示
I was investigating about how to create a current profile and I found interesting information I would like to share with the community. So, I decided to create an example to accomplish this task using BLE stack included in the MKW40Z Connectivity Software package. The demo to create is an Humidity Collector which make use of the Humidity custom profile and is based on the Temperature Collector demonstration application. The first thing to know is that the Generic Attribute Profile (GATT) establishes in detail how to exchange all profile and user data over a BLE connection. GATT deals only with actual data transfer procedures and formats. All standard BLE profiles are based on GATT and must comply with it to operate correctly. This makes GATT a key section of the BLE specification, because every single item of data relevant to applications and users must be formatted, packed, and sent according to the rules.                                      GATT defines two roles: Server and Client. The GATT server stores the data transported over the Attribute Protocol (ATT) and accepts Attribute Protocol requests, commands and confirmations from the GATT client. The GATT client accesses data on the remote GATT server via read, write, notify, or indicate operations. Notify and indicate operations are enabled by the client but initiated by the server, providing a way to push data to the client. Notifications are unacknowledged, while indications are acknowledged. Notifications are therefore faster, but less reliable. Figure 1. GATT Client-Server      GATT Database establishes a hierarchy to organize attributes. These are the Profile, Service, Characteristic and Descriptor. Profiles are high level definitions that define how services can be used to enable an application and Services are collections of characteristics. Descriptors defined attributes that describe a characteristic value. To define a GATT Database several macros are provided by the GATT_DB API in the Freescale BLE Stack, which is part KW40Z Connectivity Software package. Figure 2. GATT database      To know if the Profile or service is already defined in the specification, you have to look for in Bluetooth SIG profiles and check in the ble_sig_defines.h file if this is already declared in the code. In our case, the service is not declared, but the characteristic of the humidity is declared in the specification. Then, we need to check if the characteristic is already included in ble_sig_defines.h. Since, the characteristic is not included, we need to define it as shown next: /*! Humidity Charactristic UUID */ #define gBleSig_Humidity_d                      0x2A6F      The Humidity Collector is going to have the GATT client; this is the device that will receive all information from  the GATT server. Demo provided in this post works like the Temperature Collector. When the Collector enables the notifications from the sensor, received notifications will be printed in the serial terminal. In order to create the demo we need to define or develop a service that has to be the same as in the GATT Server, this is declared in the gatt_uuid128.h.If the new service is not the same, they will never be able to communicate each other. All macros function or structures in BLE stack of KW40Z Connectivity Software have a common template. Hence, we need to define this service in the gatt_uuid128.h as shown next: /* Humidity */ UUID128(uuid_service_humidity, 0xfe ,0x34 ,0x9b ,0x5f ,0x80 ,0x00 ,0x00 ,0x80 ,0x00 ,0x10 ,0x00 ,0x02 ,0x00 ,0xfa ,0x10 ,0x10)      During the scanning process is when the client is going to connect with the Server. Hence, function CheckScanEvent can help us to ensure that peer device or server device support the specified service, in this case, it will be the humidity service we just created in the previous step. Then, CheckScanEvent needs to check which device is on advertising mode and with MatchDataInAdvElementList to verify if it is the same uuid_service_humidity, if the service is not in the list, client is not going to connect. CheckScanEvent function should look as shown next: static bool_t CheckScanEvent(gapScannedDevice_t* pData) { uint8_t index = 0; uint8_t name[10]; uint8_t nameLength; bool_t foundMatch = FALSE; while (index < pData->dataLength) {         gapAdStructure_t adElement;                 adElement.length = pData->data[index];         adElement.adType = (gapAdType_t)pData->data[index + 1];         adElement.aData = &pData->data[index + 2];          /* Search for Humidity Custom Service */         if ((adElement.adType == gAdIncomplete128bitServiceList_c) ||           (adElement.adType == gAdComplete128bitServiceList_c))         {             foundMatch = MatchDataInAdvElementList(&adElement, &uuid_service_humidity, 16);         }                 if ((adElement.adType == gAdShortenedLocalName_c) ||           (adElement.adType == gAdCompleteLocalName_c))         {             nameLength = MIN(adElement.length, 10);             FLib_MemCpy(name, adElement.aData, nameLength);         }                 /* Move on to the next AD elemnt type */         index += adElement.length + sizeof(uint8_t); } if (foundMatch) {         /* UI */         shell_write("\r\nFound device: \r\n");         shell_writeN((char*)name, nameLength-1);         SHELL_NEWLINE();         shell_writeHex(pData->aAddress, 6); } return foundMatch; } The humidity_interface.h file should define the client structure and the server structure. For this demo, we only need the client structure, however, both are defined for reference. The Client Structure has all the data of the Humidity Service, in this case is a Service, characteristic, descriptor and CCCD handle and the format of the value. /*! Humidity Client - Configuration */ typedef struct humcConfig_tag { uint16_t    hService; uint16_t    hHumidity; uint16_t    hHumCccd; uint16_t    hHumDesc; gattDbCharPresFormat_t  humFormat; } humcConfig_t; The next configuration structure is for the Server; in this case we don’t need it. /*! Humidity Service - Configuration */ typedef struct humsConfig_tag { uint16_t    serviceHandle; int16_t     initialHumidity;        } humsConfig_t;     Now that the Client Structure is declared, go to the app.c and modify some functions. There are functions that help to store all the data of the humidity service. In our case they are 3 functions for the service, characteristic and descriptor. You have to be sure that the service that you create and the characteristics of humidity are in the functions. The Handle of each data is stored in the structure of the client. The three functions that need to be modify are the next: BleApp_StoreServiceHandles() stores handles for the specified service and characteristic. static void BleApp_StoreServiceHandles (     gattService_t   *pService ) {     uint8_t i;           if ((pService->uuidType == gBleUuidType128_c) &&         FLib_MemCmp(pService->uuid.uuid128, uuid_service_humidity, 16))     {         /* Found Humidity Service */         mPeerInformation.customInfo.humClientConfig.hService = pService->startHandle;                 for (i = 0; i < pService->cNumCharacteristics; i++)         {             if ((pService->aCharacteristics[i].value.uuidType == gBleUuidType16_c) &&                 (pService->aCharacteristics[i].value.uuid.uuid16 == gBleSig_Humidity_d))             {                 /* Found Humidity Char */                 mPeerInformation.customInfo.humClientConfig.hHumidity = pService->aCharacteristics[i].value.handle;             }         }     } } BleApp_StoreCharHandles() handles the descriptors. static void BleApp_StoreCharHandles (     gattCharacteristic_t   *pChar ) {     uint8_t i;         if ((pChar->value.uuidType == gBleUuidType16_c) &&         (pChar->value.uuid.uuid16 == gBleSig_Humidity_d))     {            for (i = 0; i < pChar->cNumDescriptors; i++)         {             if (pChar->aDescriptors[i].uuidType == gBleUuidType16_c)             {                 switch (pChar->aDescriptors[i].uuid.uuid16)                 {                     case gBleSig_CharPresFormatDescriptor_d:                     {                         mPeerInformation.customInfo.humClientConfig.hHumDesc = pChar->aDescriptors[i].handle;                         break;                     }                     case gBleSig_CCCD_d:                     {                         mPeerInformation.customInfo.humClientConfig.hHumCccd = pChar->aDescriptors[i].handle;                         break;                     }                     default:                         break;                 }             }         }     } } BleApp_StoreDescValues() stores the format of the value. static void BleApp_StoreDescValues (     gattAttribute_t     *pDesc ) {     if (pDesc->handle == mPeerInformation.customInfo.humClientConfig.hHumDesc)     {         /* Store Humidity format*/         FLib_MemCpy(&mPeerInformation.customInfo.humClientConfig.humFormat,                     pDesc->paValue,                     pDesc->valueLength);     }   }      After we store all the data of the Humidity Service, we need to check the notification callback. Every time the Client receives a notification with the BleApp_GattNotificationCallback(),  call the BleApp_PrintHumidity() function and check the Format Value; in this case is 0x27AD  that mean percentage and also have to be the same on the GATT server. static void BleApp_GattNotificationCallback (     deviceId_t serverDeviceId,     uint16_t characteristicValueHandle,     uint8_t* aValue,     uint16_t valueLength ) { /*Compare if the characteristics handle Server is the same of the GATT Server*/     if (characteristicValueHandle == mPeerInformation.customInfo.humClientConfig.hHumidity)     {            BleApp_PrintTemperature(*(uint16_t*)aValue);     }  } BleApp_PrintHumidity() print the value of the Humidity, but first check if the format value is the same. static void BleApp_PrintHumidity (     uint16_t humidity ) {     shell_write("Humidity: ");     shell_writeDec(humidity);      /*If the format value is the same, print the value*/     if (mPeerInformation.customInfo.humClientConfig.humFormat.unitUuid16 == 0x27AD)     {         shell_write(" %\r\n");     }     else     {         shell_write("\r\n");     } } Step to include the file to the demo. 1. Create a clone of the Temperature_Collector with the name of Humidity_Collector 2. Unzip the Humidity_Collector.zip file attached to this post. 3. Save the humidity folder in the fallowing path: <kw40zConnSoft_install_dir>\ConnSw\bluetooth\profiles . 4. Replaces the common folder in the next path: <kw40zConnSoft_install_dir>\ConnSw\examples\bluetooth\humidity_sensor\common . Once you already save the folders in the corresponding path you must to indicate in the demo where they are and drag the file in the humidity folder to the workspace. For test the demo fallow the next steps: Compile the project and run. Press SW1 for the advertising/scanning mode, and wait to connect it. Once the connection finish, press the SW1 of the Humidity Sensor board to get and print the data. Enjoy the demo! NOTE: This demo works with the Humidity Sensor demo. This means that you need one board programmed with the Humidity Sensor application and a second board with the Humidity Collector explained in this post. Figure 3. Example of the Humidity Collector using the Humidity Sensor.
記事全体を表示
HCI Application is a Host Controller Interface application which provides a serial communication to interface with the KW40/KW41 BLE radio part. It enables the user to have a way to control the radio through serial commands. In this section will be discussed how user could send serial commands to the KW40/KW41 device. “HCI app” file is given to test the BLE functionality. User needs to open the COM port with the configuration 115200 8N1N. Then, it is needed to send commands in Hex format, user can make use of Docklight application. Once HCI application is downloaded to the board, next steps need to be followed:         Open the COM port.       Send the next command in Hex format “01 03 0C 00”. It is to perform a Reset to the radio.       Send the next command in Hex format “01 1E 20 03 26 20 00”. It is to set the radio in Transmit test mode. The number 26 specifies the number of the channel in which user wants to see the signal(valid range is from 0x00 to 0x27, this means from BLE Channel 0 to BLE Channel 39). Number 00 specifies the type of the signal that will be sent, in this case, it is a PBRS9 format. (valid range are from 0x00 to 0x07). Refer to the next table to know the meanings of each type of signal.  Finally, 20 is the number that specifies the length that will be sent in the packet or the payload, in this case, it is configured to 20 (32 bytes), VALID RANGE is from 0x00 to 0x25.       In order to set the radio in Receiver Test Mode. The next command in hex format need to be used "01 1D 20 01 04", this command means that radio would be listening in channel 04. Hence, values "01 1D 20 01" is the command to set the radio in Rx mode, the last value "04' defines the channel in which device is going to listen. As an additional example, if channel 06 is desired, command "01 1D 20 01 06" should be used.     If there is a need to change the output power of the radio. The NXP connectivity software provides the Controller_SetTxPowerLevel() which is called inside of the Controller_TaskInit(). Controller_SetTxPowerLevel() function make use of the following defines to determine the default power output in the application:   mAdvertisingDefaultTxPower_c and mConnectionDefaultTxPower_c. The value range for both is from 0 to 31. The range might be different for each device, so, it needs to be corroborated. This range is applicable only for KW41Z device. For example, for KW40Z, range is from 0 to 15.     The defines are defined in the file ble_controller_task_config.h. Finally, HCI applications can be found in the connectivity software package of your desired device. If the KW40Z is the device under test (DUT), the HCI application is called "hci_app", it can be found in the next path: "<insllation_path>\KW40Z_Connectivity_Software_1.0.1\ConnSw\examples\bluetooth\hci_app"   If the KW41Z is the device under test (DUT), the HCI application is called "hci_black_box", it can be found in the next path: "<insllation_path>\MKW41Z_ConnSw_1.0.2\boards\frdmkw41z\wireless_examples\bluetooth\hci_black_box"
記事全体を表示
All FSCI packets contain a checksum field to verify data integrity. Every time a FSCI packet is created (by the Host or a Kinetis device) a new CRC is calculated based on every data byte in the FSCI frame. Compute CRC for TX packet The CRC field is calculated by XORing each byte contained in the FSCI command (opcode group, opcode, payload length and payload data). Checksum field then, accumulates the result of every XOR instruction.    In the firmware, the CRC is calculated in the 'FSCI_transmitPayload()' function wich is located in '<HSDK project>/framework/FSCI/Source/FsciCommunication.c' file. See FSCI_computeChecksum(). Example: TX: AspSetXtalTrim.Request 02 95 0A 01 30 AE    Sync            [1 byte] = 02    OpGroup     [1 byte] = 95    OpCode      [1 byte] = 0A    Length         [1 byte] = 01    trimValue     [1 byte] = 30    CRC            [1 byte] = AE     <------- (0x95) XOR (0A) XOR (0x01) XOR (0x30) = 0xAE Disable CRC field validation Every time a FSCI packet is received, the device verifies the checksum value.  The next changes will allow the board to receive FSCI packets without verifying the CRC field. However, the board will send the FSCI responses to the Host with this CRC field. Go to 'FsciCommunication.c' file. Search for 'fsci_packetStatus_t FSCI_checkPacket( clientPacket_t *pData, uint16_t bytes, uint8_t* pVIntf )' function. Comment all line codes related to checksum verifying. The image below shows what has to be commented. Compile project and load it to the board. Verify functionality with Test Tool. Select any command and check Raw Data checkbox. Delete the CRC data field and send the FSCI message pressing Send Raw. The loaded command set will vary depending on the demo you are using (Thread, ZigBee, BLE, etc.). The FSCI message is sent without a CRC field and the board responses to the command successfully.
記事全体を表示
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
記事全体を表示
Document Purpose This post entry provides an example of a hybrid application (Wireless_UART + GFSK Advertising) by covering Bluetooth Low Energy multiple node connections in parallel with GFSK (Generic Frequency Shift Keying) communication.  This is an additional example for the SDK where we have defined a Hybrid application for Bluetooth LE advertising and scanning in parallel with GFSK communication. Audience The goal of this post is to serve as a guide for software developers who want to use, adapt and integrate GFSK functionality in a Bluetooth Low Energy application.    Setting up the development environment Toolchain:           - IAR Embedded Workbench 8.32 or newer;            https://www.iar.com/iar-embedded-workbench/   SDK:          - This version of firmware has been tested using SDK_2.2.1_FRDM-KW36, that can be downloaded using the following link: https://mcuxpresso.nxp.com/en/select            (please consider to select as Toolchain/IDE: All toolchains);             Hardware:       - 2 to 5 FRDM-KW36 development board:  FRDM-KW36 Development Kit KW36/35 MCUs | NXP  Implementation This demo application is design for the FRDM-KW36 platform and can be easily integrated into any board that is using KW35/36 MCU family. The functionality is based on the coexistence mechanism available on the SDK (Mobile Wireless System - MWS module). Based on the HW link-layer implementation, the Bluetooth Low Energy has a higher priority than the GFSK protocol and as the effect, the GFSK communication is executed during the Idle states (inactive periods) of the Bluetooth LE.  For more details related to the MWS module, please refer to connectivity framework documentation from SDK (Connectivity Framework Reference Manual.pdf). As for functionality on the Bluetooth low energy, both roles, central and peripheral, are supported.  Integration to the KW36 SDK - download the attached file and unzip to ...\SDK_2.2.1_FRDM-KW36\boards\frdmkw36\wireless_examples\hybrid folder: - open IAR project (SDK_2.2.1_FRDM-KW36_2019_07_19\boards\frdmkw36\wireless_examples\hybrid\ble_w_uart_gfsk\freertos\iar\ble_w_uart_gfsk_freertos.eww). - the project is organized like below: Functionality Switches functionality:     - functionality is defined in main.c file, BleApp_Handle Keys function;    - on the FRDM-KW36 we have:                 - SW2 - start scanning - Central device;                 - Long SW2 - start advertising - Peripheral device; (long SW2 - SW2 pressed for more than 3 seconds)                 - SW3 - start/stop GFSK TX operation (advertising);                 - Long SW3 - start/stop GFSK RX operation (long SW3 - SW3 pressed for more than 3 seconds) Logs:    - Serial events for different states of the board;    - BaudRate 115200; Validation The solution has been validated using 1 Master and 4 Slave devices as below: 1. Create the network:     a. Open serial communication of all devices. After reset you will see the following message:    b. On the Central device press SW2 to start scanning;    c. On the Peripheral device press Long SW2 to start advertising and wait for the confirmation on the serial port:   d. Repeat steps b. and c. for all of the slave devices.   e. When the network is completed on the Central device you will see something like below:   f. Check the over the air connections (connection interval = 312.5 ms): 2. Validate functionality on the Bluetooth LE: - from each slave (Peripheral) serial terminal write a message (e.g: testslaveX) and check that the message is printed on the master serial port. - do the same test from the master (Central) serial terminal. - Below is an example of this step:   - over the air log: 3. Initiate GFSK communication: - in one of the board's press SW3 to start GFSK TX operation (Advertising packet with AdvAddress = 0909090909); At every 1 second (gGenFskApp_TxInterval_c), an ADV packet will be sent over the air. - Select other board and press Long Sw3 to initiate GFSK RX operation (RX interval = 100ms = gGenFskApp_RxInterval_c); - Each time an ADV packet from address = 0909090909 is received this will be listed on the serial port as below: - over the air the GFSK TX packets will be listed as a ADV_NONCONN_IND: 4. Validate Bluetooth LE in parallel with GFSK: - write a message on the Master (Central) serial terminal and check the feedback on the slave(Peripheral) serial terminals: Attached is the source code for this application. Regards, Ovidiu
記事全体を表示
By default the clock configuration on the KW2xD demos is set to PLL Engaged External (PEE). In this mode the system clock is derived from the output of the PLL and controlled by an external reference clock. The modem provides a programmable clock source output CLK_OUT that can be used as the external reference clock for the PLL. In the Figure 1 we can see that the CLK_OUT modem signal is internally connected to EXTAL0 in the MCU.   The CLK_OUT output frequency is controlled by programming the modem 3-bit field CLK_OUT_DIV [2:0] in the CLK_OUT_CTRL Register. The default frequency is either 32.787 kHz or 4 MHz depending on the state of the modem GPIO5 at reset determined by the MCU. See section 4.4.2 and 5.6.2 from the MKW2xD Reference Manual for more information on the clock output feature. If the GPIO5 modem pin is low upon POR, then the frequency will be 4 MHz. If this GPIO5 modem pin is high upon POR, then the frequency will be 32.78689 kHz.   In the KW2xD demos, the GPIO5 (PTC0) is held low during the modem reset so the CLK_OUT has a frequency of 4MHz. The clock configuration structure g_defaultClockConfigRun is defined in board.c. Figure 1. Internal Functional Interconnects   In this example project, another clock configuration will be added to the Connectivity Test Project: FLL Engaged Internal (FEI). In this mode, the system clock is derived from the FLL clock that is controlled by the 32kHz Internal reference clock.   In FEI mode the MCU doesn’t need the clock source output CLK_OUT from the modem, so we can disable the radio’s clock output and then set the radio to Hibernate to save power when we are not using the radio.   If the low-power module from the connectivity framework is used to go to a low-power mode, the clock configuration is changed automatically when entering a sleep mode (See the Connectivity Framework Reference Manual for more information about the low-power library).   System Requirements Kinetis MKW2xD and MCR20A Connectivity Software (REV 1.0.0) TWR-KW24D512 IAR Embedded Workbench for ARM 7.60.1 or later Attached project files Application Description The clock configuration can be changed with shortcuts on the serial console: Press “c” to use the PEE clock configuration (default). Press “v” to use the FEI clock configuration and set the radio to Autodoze. Press “b” to use the FEI clock configuration and set the radio to Hibernate.   You must be in the main menu in order to change the radio mode, the mode automatically changes to Autodoze when entering a test menu.   Hibernate mode can only be changed when in FEI mode. This is because in hibernate the radio disables the CLK_OUT and the PEE configuration needs this clock.   Current Measurements The following measurements were done in a TWR-KW24D256 through J2 5-6 to measure the radio current. Table 1. Radio Current Measurements Clock mode/Radio mode Radio Current PEE/Autodoze 615µA FEI/Autodoze 417µA FEI/Hibernate 0.3µA   Code Modifications The following modifications to the source files were made: \boards\twrkw24d512\Board.c Added clock user configuration Added array of clock configs and configuration struct for clock callback   \boards\twrkw24d512\Board.h Include for fsl_clock_manager.h Declaration of clock callback and configuration array used in CLOCK_SYS_Init() function.   \boards\twrkw24d512\Hardware_init.c Added calibration code after BOARD_ClockInit(), this is to calibrate internal clock using the bus clock.   \examples\smac\Connectivity_Test\common\Connectivity_TestApp.c Initialize the clock manager. Disable PTC0 because it is only used at modem reset to select the CLK_OUT default frequency (4MHz). Return clock configuration on idle state. Prepare radio to go to Autodoze when entering a test menu.   \examples\smac\Connectivity_Test\twrkw24d512\common\Connectivity_Test_Platform.c Changed length of the lines to be erased in PrintTestParameters() from 65 to 80 Added clock config and radio mode to be printed in the test parameters. Added the cases in the shortcut parser to change the clock and radio configuration with the keys “c”, “v” and “b”. Added functions at end of file (Explained in the next section).   \examples\smac\Connectivity_Test\twrkw24d512\common\Connectivity_Test_Platform.h Macros for the clock and radio modes. Function prototypes from the source file.   \examples\smac\Connectivity_Test\twrkw24d512\common\ConnectivityMenus.c Shortcuts descriptions.   The modified source files can be found attached to this document.   Functions added The functions PWRLib_Radio_Enter_Hibernate() and PWRLib_Radio_Enter_AutoDoze() were taken from the file PWRLib.c located at <Connectivity_Software_Path>\ConnSw\framework\LowPower\Source\KW2xD. The PWRLib.c file is part of the low-power library from the connectivity framework.   The Clock_Callback() function was implemented to handle when the clock configuration is updated. Inside the function there is a case to handle before and after the clock configuration is changed. Before the clock configuration is changed, the UART clock is disabled and if the clock configuration is PEE, the radio is set to AutoDoze and the CLK_OUT is enabled. After the clock configuration has changed, the Timer module is notified that the clock has changed, the UART is re-initialized and if the clock configuration is FEI, the CLK_OUT is disabled. This behavior is shown in Figure 2. Figure 2. Clock callback diagram   The prepareRadio() function is used when entering a test mode to make sure the radio is set to AutoDoze in case it was in hibernate. The restoreRadio() function is used when leaving the test menu and going to hibernate if it was previously set.
記事全体を表示
Customer is designing QN9090 module. They have IQxel non-signaling equipment and ask if QN9090 can be tested with IQxel-MW. We co-work with ACE Solution Taiwan Co.Ltd. to Integrate QN9090 and IQxel to perform 1M bps, 2M bps and Frame error rate test. This document will address the QN9090 setup and IQxel connection setup. Finally we show the 1M bps, 2M bps and packet error rate results.
記事全体を表示
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
記事全体を表示
Development environment Hardware: i.MX6Q SabreSD connecting rtl8188cus or rtl8192cus wifi dongle Software: FSL JB 4.2.2-1.1.0-GA release   Advantage brought by JB4.2.2 As we may know that in JB4.0.x, Wifi-Direct is exclusive to normal Wifi access AP, so means that you have to turn off  Wifi normal AP access, then turn on Wifi-Direct. But in JB4.2.x, it can support the following topologies in use scene as following: So that means you can keep p2p connection meanwhile access internet throught AP.     Feature verified 1. Wifi connection support internet surf, and DLNA. 2. Wifi-Direct can support files transmission like Gallery sharing based on Wifi-Direct Demo.apk from FSL. 3. Particial support Wifi-Display, but due to unavailability of Wifi-Display sink module, so cannot be verified fully.   Usage: untar the attached file, then "patch -p1 <" in corresponding subdirectories. It would be better to untar the file in an empty directory, so you can understand which subdirectories are newly created (ex. hardware/realtek is newly created), then within these newly created subdirectoies, you need to "git init" first, then do "patch -p1<" to adopt all newly added files and subdirectories. Original Attachment has been moved to: WiFiDirectDemo.apk.zip Original Attachment has been moved to: patch4rtl8188_8192_on_jb4_2_2-ga.tar.gz
記事全体を表示
Brief Description NXP Tire Pressure Monitoring Sensors (TPMS) were preloaded the firmware libraries and test software for a variety of customer use cases. The preloaded TPMS bootloader provides wireless software update function for the aftermarket. This demo uses Kinetis KW01 and Low Frequency emitter to accomplish TPMS over-the-air software update.   Reference Picture   Block Diagram   Features 315 MHz RF 125 KHz LF FSK modulation Manchester Encoding Timer/PWM Modules IAR Embedded Workbench for ARM 7.40 CodeWarrior V6.3   NXP Parts Used MRB-KW019032 (MKW01Z128CHN) TPMS870911 (FXTH870911DT1) LF Emitter Board   Get Software MKW01_TPMS_bootloader.rar MPXY8702_TPMS_bootloader.rar TPMS-MKW01-IAR7v4-Project.zip   General Stage Prototype Launched for Alpha customers     Demo Setup   Hardware Requirements MRB-KW019032 x 2         MRB-KW019032 Board A: Connected with LF Emitter Board         MRB-KW019032 Board B: Standalone TPMS879011 x 1 LF Emitter Board x 1   Hardware Connection   Pin function MRB-KW019032 LF Emitter Board TPM1_CH0 PTB0 (J15-9) J5-20 TPM1_CH1 PTB1 (J14-8) J5-28 GND GND (J15-2) J6-4   Demo Description A prebuild TPMS870911 firmware is stored in MRB-KW019032 Board A and this firmware will be sent to TPMS870911 via 125kHz LF signal. After TPMS870911 completes the firmware update, TPMS870911 will send the information of pressure sensor to MRB-KW019032 Board B via 315 MHz RF signal.   Demo Procedure Download MKW01_TPMS_bootloader into MRB-KW019032 Board A with IAR 7.40 Download TPMS-MKW01-IAR7v4-Project into MRB-KW019032 Board B with IAR 7.40 Download MPXY8702_TPMS_bootloader into TPMS870911 with CodeWarrior V6.3 Connect USB cable between PC and both of MRB-KW019032 boards, and open the terminal with the following settings • 115200 baud rate • 8 data bits • No parity • One stop bit • No flow control    5. Press the reset button on both of MRB-KW019032 boards and then the demo message will be shown on the terminal.     6. Short Pin19 of J15 (PTD6) on MRB-KW019032 Board A as SW3 press to start TPMS870911 over-the-air software update. 7. After TPMS870911 completes software update, MRB-KW019032 Board B will print the received RF message which was sent from TPMS870911 on the terminal.                         Original Attachment has been moved to: TPMS-MKW01-IAR7v4-Project.zip Original Attachment has been moved to: MPXY8702_TPMS_bootloader.rar Original Attachment has been moved to: MKW01_TPMS_bootloader.rar
記事全体を表示
High level description to enable a Linux + KW41Z Border Router. Similar to how it’s shown for the K64 solution in the Kinetis Thread Stack Application Development Guide.   Configure the OpenWrt router to assign the IPv6 ULA prefix 2001:2002:2003::/48. On the LAN network, the router distributes addresses from range 2001:2002:2003::/60 Plug an Ethernet cable between the OpenWrt router and the Linux box. Before creating the Thread network, the Linux box has a global address on its eth interface from range 2001:2002:2003::/60. After creating the Thread network, the BR configures on its Serial TAP interface an address from range 2001:2002:2003::/60. On its 6LoWPAN interface, the BR configures an address from range 2001:2002:2003:c::/64. This is achieved with DHCPv6 prefix delegation - the router is requested to assign a new prefix space to be used by the Thread network. The forth segment in the IPv6 range might be 2, 4, 8 or c, depending of the number of DHCP-PD requests made to the router. After 4 attempts, the router will not lease any other prefixes for some time. In order to force that, you'd require to restart the odhcpd deamon in the OpenWrt router with the following command: /etc/init.d/odhcpd restart . Join the router eligible device, which configures an address in 2001:2002:2003::1/60. We then ping the "Internet" (the LAN interface on the OpenWrt router) and it works. “threadtap0” interface must be bridged with an uplink interface connected to an OpenWrt DHCPv6-PD enabled router; it will act identically as the K64F solution.   Setup Linux PC (Ubuntu) OpenWrt AP/Router with DHCPv6-PD support (OpenWrt version used in this guide: OpenWrt Chaos Calmer 15.05.1) For reference, hardware used on this guide: TP-Link Model TL-WR741ND 150Mbps Wireless N Router OpenWRT firmware supports multiple hardware available at https://openwrt.org/ 1 FRDM-KW41Z (Host Controlled Device, connected to Linux) 1 FRDM-KW41Z (Router Eligible Device or any joiner device) Thread version 1.1.1.20 (from SDK builder at mcuxpresso.nxp.com)   Host Controlled Device firmware, make sure the following macros are enabled: THR_SERIAL_TUN_ROUTER                       /source/config.h     -> Enables TAP interface by default (not TUN) THR_SERIAL_TUN_ENABLE_ND_HOST     /app/common/app_serial_tun.h   OpenWRT router Configure IPv6 ULA-Prefix:   Linux Copy HSDK folder Create 'threadtap0' TAP interface: …/host_sdk/hsdk/demo#   sudo bash make_tap.sh Use "Thread_Shell" or modify “Thread_KW_Tun” demo to enable the SERIAL_TAP macro …/host_sdk/hsdk/demo#   nano Thread_KW_Tun.c #define SERIAL_TAP 0   modify to:  #define SERIAL_TAP  1        Note: For demo purposes, the "Thread_Shell" demo is recommended, it already uses TAP by default and allows input commands. If this is not required and only the TAP bridge is to be used, use the Thread_KW_Tun demo. Bridge the interfaces; assuming eno1 is the interface connected directly to OpenWrt: # brctl addbr br0 # brctl addif br0 eno1 # brctl addif br0 threadtap0 # ifconfig br0 up Note: (Optional) Addresses on the bridged interfaces are lost and need to be reconfigured on the actual bridge. In this example, after bridging eno1 (interface to OpenWrt router), you’d have to run #dhclient br0 to get an IPv4 address on br0 for SSH to the router and/or #dhclient -6 br0 to get an IPv6 address to the br0 interface. There's a note here https://wiki.archlinux.org/index.php/Network_bridge#With_bridge-utils  about this.   Build C demos …/host_sdk/hsdk/demo#   make Run Thread_Shell or Thread_KW_Tun demo. …/host_sdk/hsdk/demo#   sudo ./bin/Thread_Shell /dev/ttyACM0 threadtap0 25 or …/host_sdk/hsdk/demo#   sudo ./bin/Thread_KW_Tun /dev/ttyACM0 threadtap0         Note: Try to run the demo without parameters to get some help on the input parameters   ifconfig Thread_Shell demo Thread_KW_Tun demo Joiner FRDM-KW41Z (shell) Join the Thread network Verify IP addresses Ping Eth LAN interface on OpenWrt router to verify “Internet” connectivity  Regards, JC
記事全体を表示
When developing portable applications using batteries, it is important to keep track of the remaining battery level to inform the user and take action when it drops to a level that might be critical for the correct device functionality. A common measurement method consists of taking a sample of the current battery voltage and correlate it to a percentage depending on its capacity. Then this value is reported to the user in a visual manner. MKW40 is a system on chip (SoC) that embeds a processor and a Bluetooth® Low Energy (BLE)/802.15.4 radio for wireless communications. This posts describes how to obtain the current battery level and report it via BLE using this part. Hardware considerations Typically, the battery voltage is regulated so the MCU has a stable power supply across the whole battery life. This causes the ADC supply voltage to be lower than the actual battery voltage. To address this, a voltage divider is used to adequate the battery voltage to levels that can be read by the ADC. Figure 1 Typical battery level divider circuit The MKW40 includes a voltage divider on its embedded DC-DC converter removing the need to add this voltage divider externally. It is internally connected to the ADC0 channel 23 so reading this channel obtains the current level of the power source connected to the DC-DC converter in. Figure 2 DC-DC converter with battery voltage monitor Software implementation Software implementation consists in acquiring the ADC value, correlate it with a percentage level and transmit it using BLE. The connectivity software includes functions to perform all those actions. A voltage divider connected to the battery and internally wired to an ADC channel is embedded in the SoC. For the MKW40Z it is the ADC0 single ended channel 23 (ADC0_CH23) . There are some examples in the Kinetis Software Development Kit (KSDK) documentation explaining how to configure the ADC module. The connectivity software includes a function named BOARD_InitAdc in the file app.c where this is initialized. void BleApp_Init(void) {     /* Initialize application support for drivers */     BOARD_InitAdc(); <-- Initialization function         /* Initialize Software-timer */     SwTimer_Init();           /* Status Indicator fade initialization */     status_indicator_fade_init();     /* Initialise ECG Acquisition system */     ecg_acquisition_init();     /* Initialize battery charger pin configuration */     power_manager_init();     /* Create Advertising Timer */     advertisingTimerId = SwTimer_CreateTimer(TimerAdvertisingCallback); } Once initialized, this ADC channel must be read to obtain the current voltage present in the divisor. There are also some cool examples in the KSDK documentation on how to do this. The obtained value is a digital representation of the voltage in the divisor and is relative to the VDDA or VREFH voltage (depending on what is used as reference for the ADC). Since the battery voltage varies over the time (unless you use a voltage regulator or use the DC-DC converter in buck mode), the most accurate way to get the battery voltage is to obtain the actual voltage that is referencing the ADC first. For this, the MKW40Z includes a 1V reference voltage channel wired to another ADC channel: ADC0_CH27. Reading this ADC channel obtains the number of counts that correspond to 1V, and VREF can be calculated using the next formula. Once the VRef voltage has been obtained, it is possible to determine the voltage present in the battery voltage divisor by using the following formula. The obtained voltage is still only a portion of the actual battery voltage. To obtain the full voltage, the obtained value must be multiplied by the divisor relation. This relation is selected in the DC-DC register DCDC_REG0:DCDC_VBAT_DIV_CTRL and can be: VBATT, VBATT/2 or VBATT/4. After the full VBAT voltage is obtained, it must be correlated to a percentage depending on the values set for 0% and 100%. Using the slope method is a good approach to correlate the voltage value. For this, the slope m must be calculated using the formula. Where V100% is the voltage in the battery when it is fully charged, and V0% is the voltage in the battery when it is empty. Once m has been calculated, the battery percentage can be obtained using the formula: The Connectivity Software includes a function that obtains the current battery voltage connected to the DC-DC input and returns the battery percentage. It is included in the board.c file. uint8_t BOARD_GetBatteryLevel(void) {     uint16_t batVal, bgVal, batLvl, batVolt, bgVolt = 100; /*cV*/         bgVal = ADC16_BgLvl();     DCDC_AdjustVbatDiv4(); /* Bat voltage  divided by 4 */     batVal = ADC16_BatLvl() * 4; /* Need to multiply the value by 4 because the measured voltage is divided by 4*/         batVolt = bgVolt * batVal / bgVal;         batLvl = (batVolt - MIN_VOLT_BUCK) * (FULL_BAT - EMPTY_BAT) / (MAX_VOLT_BUCK - MIN_VOLT_BUCK);     return ((batLvl <= 100) ? batLvl:100);    } Reporting battery level After the battery level has been determined it can be now reported via BLE. The Connectivity Software includes predefined profile files to be included in custom applications. Battery profile is included in the files battery_service.c and .h, under the Bluetooth folder structure. To make use of them, make sure that they are included in your project. Then, include the file battery_interface.h in your BLE application file. An example using the included BLE applications is shown. In app.c (Connectivity Software examples application file) include the battery service interface #include "battery_interface.h" In the variable declaration section, create a new basConfig_t variable. This is needed to configure a new service. static basConfig_t      basServiceConfig = {service_battery, 0}; The new service needs to be created after the BLE stack has been initialized. When this happens, the function BleApp_Config is executed. Inside this function, the battery service is started.    /* Start services */ hrsServiceConfig.sensorContactDetected = mContactStatus; #if gHrs_EnableRRIntervalMeasurements_d    hrsServiceConfig.pUserData->pStoredRrIntervals = MEM_BufferAlloc(sizeof(uint16_t) * gHrs_NumOfRRIntervalsRecorded_c); #endif    Hrs_Start(&hrsServiceConfig);     Bas_Start(&basServiceConfig);         /* Allocate application timers */     mAdvTimerId = TMR_AllocateTimer(); mMeasurementTimerId = TMR_AllocateTimer(); mBatteryMeasurementTimerId = TMR_AllocateTimer(); Function Bas_Start is used for this purpose. This function starts the battery service functionality indicating that it needs to be reported by the BLE application. After a central has successfully connected to the peripheral device, the battery service must be subscribed so it’ measurements can be reported to the central. For this, the function Bas_Suscribe is used inside the connection callback. Following code shows its implementation in the connectivity software. It takes place in the connection callback function BleApp_ConnectionCallback in app.c switch (pConnectionEvent->eventType) {         case gConnEvtConnected_c:         {             mPeerDeviceId = peerDeviceId;             /* Advertising stops when connected */             mAdvState.advOn = FALSE; #if gBondingSupported_d                /* Copy peer device address information */             mPeerDeviceAddressType = pConnectionEvent->eventData.connectedEvent.peerAddressType;             FLib_MemCpy(maPeerDeviceAddress, pConnectionEvent->eventData.connectedEvent.peerAddress, sizeof(bleDeviceAddress_t)); #endif  #if gUseServiceSecurity_d                        {                 bool_t isBonded = FALSE ;                                if (gBleSuccess_c == Gap_CheckIfBonded(peerDeviceId, &isBonded) &&                     FALSE == isBonded)                 { Gap_SendSlaveSecurityRequest(peerDeviceId, TRUE, gSecurityMode_1_Level_3_c);                 }             } #endif                        /* Subscribe client*/             Bas_Subscribe(peerDeviceId);                    Hrs_Subscribe(peerDeviceId);                                                         /* UI */                        LED_StopFlashingAllLeds();                         /* Stop Advertising Timer*/             mAdvState.advOn = FALSE;             TMR_StopTimer(mAdvTimerId);                        /* Start measurements */ TMR_StartLowPowerTimer(mMeasurementTimerId, gTmrLowPowerIntervalMillisTimer_c, TmrSeconds(mHeartRateReportInterval_c), TimerMeasurementCallback, NULL);               } Once the service has been subscribed, a new measurements can be registered by using the Bas_RecordBatteryMeasurement function at any time. Bas_RecordBatteryMeasurement(basServiceConfig.serviceHandle, basServiceConfig.batteryLevel); This function receives the battery service handler previously defined (static basConfig_t basServiceConfig = {service_battery, 0}) and the current battery level percentage as input parameters. When a disconnection occurs, the battery service must be unsubscribed so no further updates are performed during disconnection. For this, the Bas_Unsuscribe function must be used after a disconnection event. case gConnEvtDisconnected_c:         {             /* Unsubscribe client */             Bas_Unsubscribe();             Hrs_Unsubscribe();             mPeerDeviceId = gInvalidDeviceId_c; Now, updated battery levels can be reported by the BLE device letting the user know when a battery must be replaced or recharged.
記事全体を表示
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; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
記事全体を表示
If the application running in the KW41Z does not operate in low power mode, the device could work without the 32 kHz oscillator. However, for it to work correctly, the clock configuration must be changed. Figure 1.  KW41Z clock distribution By default, the software stack running on the KW41Z selects a clock source that requires the 32 kHz oscillator. However, if the 32 kHz oscillator is not available, the clock configuration must be changed. Fortunately, the option to change it is already implemented, it is only required to change the clock configuration to the desired one. To do this, change the value for the CLOCK_INIT_CONFIG macro located in the app_preinclude.h file. /* Define Clock Configuration */ #define CLOCK_INIT_CONFIG           CLOCK_RUN_32‍‍‍‍‍‍‍‍‍‍ In the selected mode in this example, CLOCK_RUN_32, the selected clock mode is BLPE (Bypassed Low Power External). In this mode, the FLL is bypassed entirely, and clock is derived from the external RF oscillator, in this case, the 32 MHz external clock. These macros are the default available options to change the clock configuration, they are located in the board.h file. It is up to the application and the developer to chose the most appropriate configuration. #define CLOCK_VLPR       1U #define CLOCK_RUN_16     2U #define CLOCK_RUN_32     3U #define CLOCK_RUN_13     4U #define CLOCK_RUN_26     5U #define CLOCK_RUN_48_24  6U #define CLOCK_RUN_48_16  7U #define CLOCK_RUN_20_FLL 8U‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ More information regarding the different clock modes and their clock sources are available in the KW41Z reference manual, Chapter 5: Clock Distribution, section 5.4 Clock definitions, and Chapter 24: Multipurpose Clock Generator.
記事全体を表示
1.    Introduction   1.1 Document Purpose This post entry provides a detailed description of how to integrate the NFC Reader Library to a KW3x Bluetooth Low Energy application.   1.2 Audience The goal of this post is to serve as a guide for software developers who want to use, adapt and integrate the NFC Reader Library to an SDK wireless connectivity example.   1.3 References and Resources - NFC Reader Library:  nxp.com/pages/:NFC-READER-LIBRARY - NCF3320: nxp.com/products/:NCx3320  - CLRC663 plus: nxp.com/products/:CLRC66303HN - FRDM-KW36 board: nxp.com/demoboard/FRDM-KW36 - KW35/KW36 SDK: https://mcuxpresso.nxp.com/en/select - MCUXpresso IDE: nxp.com/products/: MCUXpresso-IDE   2. NFC Reader Library Overview   The NXP NFC Reader Library is a modular software library written in C language, which provides an API that enables customers to create their own software stack and applications for the NXP contactless reader ICs: - PN512; - CLRC633 family; - PN7462 family; - PN5180; This API facilitates the most common operations required in NFC applications such as: - reading or writing data into contactless cards or tags; - exchanging data with other NFC-enabled devices; - allowing NFC reader ICs to emulate cards. The NFC Reader Library is designed in a way to be easily portable to many different microcontrollers with a multi-layered architecture:   As main blocks, we have: - Application Layer (AL) - implements the command sets to interact with MIFARE cards and NFC tags. - NFC activity - implements a configurable Discovery loop for the detection of contactless cards, NFC tags or other NFC devices. - HCE and P2P components, for the emulation of Type 4 tags and P2P data exchange respectively. - Protocol abstraction layer (PAL) - contains the RF protocol implementation of the ISO14443, Felica, vicinity and NFC standards. - Hardware abstraction layer (HAL) - implements the drivers for controlling the NFC frontends RF interface and capabilities. - Driver Abstraction Layer (DAL) - implements the GPIO pinning, the timer configuration and the physical interface (BAL) between the host MCU and the reader IC. - OSAL module, in charge of abstracting the OS or RTOS specifics (tasks events, semaphores, and threads)   3. The KW3x Wireless Microcontroller Overview The KW3x wireless microcontrollers (MCU are highly integrated single-chip devices that enable Bluetooth Low Energy (Bluetooth LE) and Generic FSK connectivity for automotive, industrial and medical/healthcare embedded systems.   The KW36/35 Wireless MCU integrates an Arm® Cortex®-M0+ CPU with up to 512 KB flash and 64 KB SRAM and a 2.4 GHz radio that supports Bluetooth LE 5.0 and Generic FSK modulations. The Bluetooth LE radio supports up to 8 simultaneous connections in any master/slave combination. The KW36A/36Z includes an integrated FlexCAN module enabling seamless integration into an automotive or industrial CAN communication network, enabling communication with external control and sensor monitoring devices over Bluetooth LE.   For more details please refer to the NXP website information: https://www.nxp.com/products/wireless/bluetooth-low-energy:BLUETOOTH-LOW-ENERGY-BLE.   4. NFC Reader Library – integration with FRDM-KW36 The current NFC Reader Library v5.21.01 is not containing support for Kinetis KW3x MCU. We will use a reference the K82 NFC Reader Library package: www.nxp.com/pages/:NFC-READER-LIBRARY. The steps required to integrate the library are: - Hardware preparation (the connection between FRDM-KW36 and NFC reader board); - Setting up the development environment (SDK download, workspace); - Preparing adaptation files for FRDM-KW3x board; - Integrating NFC application to Wireless_UART Bluetooth LE example; - Running the demo;   4.1 Hardware preparation Hardware required: - NCF3320 Antenna v1.0 board as an NFC transceiver; - FRDM-KW36 board as host MCU, used to load and run the Bluetooth Low Energy Stack and NFC application logic;   The communication between the boards will be via the SPI communication using the following pin configuration: ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Master board (FRDM-KW36)         Connects to            Slave board (NCF3320 Antenna v1.0)           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ PTB0  (J2-pin10)                                      -                    IRQ PTB1  (J2-pin9)                                         -                    Reset PTA16 (J2-pin1 - SPI1_Sout)                   -                    MOSI PTA17 (J1-pin5 - SPI1_Sin)                     -                    MISO PTA18 (J1-pin7 - SPI1_SCK)                   -                    SCK PTA19 (J2-pin3 - SPI1_CS)                     -                    CS GND   (J3-pin7)                                        -                    GND ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~   4.2 Setting up the development environment   Install MCUXpresso IDE (for this example we are using v10.2.0 build 759)   - Go to MCUXpresso-IDE webpage and download the latest version of IDE: www.nxp.com/products/: MCUXpresso-IDE. - Install the IDE;     Get the latest NFC Reader Library release (for this example we are using v5.21.00) - Go to NXP NFC Reader Library webpage (www.nxp.com/pages/:NFC-READER-LIBRARY) - Go to the Downloads tab and click on the download button - Download the NFC Reader Library for Kinetis K82F package:     Generate a downloadable SDK package for FRDM-KW36 board (SDK_2.2.1_FRDM-KW36) - Navigate to https://mcuxpresso.nxp.com/en/select and select FRDM-KW36 board; - Select Build MCUXpresso SDK. - As toolchain, please make sure that the MCUXpresso IDE is selected. - Use Download SDK button to start downloading SDK package:   Create MCUXpresso workspace - Open MCUXpresso IDE and create a workspace; - Drag and drop the SDK_2.2.1_FRDM-KW36 into the installed SDKs tab of the MCUXpresso IDE;   - Import Wireless_Uart Example to the current workspace:     4.3 Preparing adaptation files for FRDM-KW3x board This chapter describes the Driver Abstraction Layer (DAL) changes required for FRDM-KW36: - unzip the NFC Reader Library and navigate to boards folder:   - Create an equivalent file for FRDM-KW36 (Board_FRDM_KW36FRc663.h) by setting the right configuration for GPIOs and handlers; - Below are the differences required for FRDM-KW36 board in comparation with a FRDM-K82F board:   - Add the FRMD-KW36 to …DAL\cfg\BoardSelection.h file:   #ifdef PHDRIVER_FRDM_KW36FRC663_BOARD #include <Board_FRDM_KW36FRc663.h> #endif   - In KinetisSDK folder, update the following dependencies: o PIT Driver IRQ name:   o Open drain and pin lock configuration: - phDriver_KinetisSDK.c:   - phbalReg_KinetisSpi.c:   - add PHDRIVER_FRDM_KW36FRC663_BOARD define to …\NxpNfcRdLib\types\ph_NxpBuild_Platform.h file to enable the right NFC transceiver:     4.4  Integrating NFC application to Wireless_UART Bluetooth LE example In this chapter we will integrate the BasicDiscoveryLoop NFC example to Wireless_UART Bluetooth LE application. For this, the following steps are required: - On the wireless_uart project location create an “nfc” folder:   - Copy from modified NFC Reader Library the DAL, NxpNfcRdLib and phOsal folders:   - On the wireless_uart project location, “source” folder create a new “nfc” subfolder to integrate the BasicDiscovery loop files:   - Some changes will be required on the BasicDiscoveryLoop files: o Main function renamed to NFC_BasicDiscoveryLoop_Start; o Removed drivers/OS initialization; (all the changes can be observed in the attachment) - Update MCUXpresso workspace by pressing F5 to see the latest changes:   - Update the linker information (Project Properties -> C/C++ Build -> Settings) and preprocessor defines (Project Properties -> C/C++ Build -> Preprocessor):     - Add dependencies: o PIT module/ PIT module initialization; o Update LED, SW configuration; o Increase heap size (gTotalHeapSize_c); o Add functionality for NFC in wireless_uart.c application; (all the changes can be observed in the attachment);   Considering the attached ZIP archive, we can be easily dragged and drop, frdmkw36_w_uart_ncf3320_basic_discovery.zip file, to the MCUXpresso workspace:       4.5 Running the demo - Create hardware connection based on chapter 4.1; - Open a serial terminal on the corresponding COM port for FRDM-KW36 board. The BaudRate used is 115200. - Press SW2 on FRDM-KW36 to start advertising. - Open Mobile APP - IOT toolbox - Wirreless UART.  The FDRM-KW36 board will be listed as NXP_WU:   - Create Bluetooth LE connection. The serial log will contain the log for Bluetooth LE operations:     - Use NFC Cards close to NCF3320 Antenna v1.0 board to initiate discovery demo. - Once the card is detected, an event is sent to the mobile application including technology and UUID of the card: (https://www.youtube.com/watch?v=wCCz5zDIwHE&feature=youtu.be)     Attached is the source code for this example application (frdmkw36_w_uart_ncf3320_basic_discovery).
記事全体を表示