Wireless Connectivity Knowledge Base

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

Wireless Connectivity Knowledge Base

Discussions

Sort by:
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
View full article
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
View full article
High level description to enable a Linux + KW41Z Border Router. Similar to how it’s shown for the K64 solution in the Kinetis Thread Stack Application Development Guide.   Configure the OpenWrt router to assign the IPv6 ULA prefix 2001:2002:2003::/48. On the LAN network, the router distributes addresses from range 2001:2002:2003::/60 Plug an Ethernet cable between the OpenWrt router and the Linux box. Before creating the Thread network, the Linux box has a global address on its eth interface from range 2001:2002:2003::/60. After creating the Thread network, the BR configures on its Serial TAP interface an address from range 2001:2002:2003::/60. On its 6LoWPAN interface, the BR configures an address from range 2001:2002:2003:c::/64. This is achieved with DHCPv6 prefix delegation - the router is requested to assign a new prefix space to be used by the Thread network. The forth segment in the IPv6 range might be 2, 4, 8 or c, depending of the number of DHCP-PD requests made to the router. After 4 attempts, the router will not lease any other prefixes for some time. In order to force that, you'd require to restart the odhcpd deamon in the OpenWrt router with the following command: /etc/init.d/odhcpd restart . Join the router eligible device, which configures an address in 2001:2002:2003::1/60. We then ping the "Internet" (the LAN interface on the OpenWrt router) and it works. “threadtap0” interface must be bridged with an uplink interface connected to an OpenWrt DHCPv6-PD enabled router; it will act identically as the K64F solution.   Setup Linux PC (Ubuntu) OpenWrt AP/Router with DHCPv6-PD support (OpenWrt version used in this guide: OpenWrt Chaos Calmer 15.05.1) For reference, hardware used on this guide: TP-Link Model TL-WR741ND 150Mbps Wireless N Router OpenWRT firmware supports multiple hardware available at https://openwrt.org/ 1 FRDM-KW41Z (Host Controlled Device, connected to Linux) 1 FRDM-KW41Z (Router Eligible Device or any joiner device) Thread version 1.1.1.20 (from SDK builder at mcuxpresso.nxp.com)   Host Controlled Device firmware, make sure the following macros are enabled: THR_SERIAL_TUN_ROUTER                       /source/config.h     -> Enables TAP interface by default (not TUN) THR_SERIAL_TUN_ENABLE_ND_HOST     /app/common/app_serial_tun.h   OpenWRT router Configure IPv6 ULA-Prefix:   Linux Copy HSDK folder Create 'threadtap0' TAP interface: …/host_sdk/hsdk/demo#   sudo bash make_tap.sh Use "Thread_Shell" or modify “Thread_KW_Tun” demo to enable the SERIAL_TAP macro …/host_sdk/hsdk/demo#   nano Thread_KW_Tun.c #define SERIAL_TAP 0   modify to:  #define SERIAL_TAP  1        Note: For demo purposes, the "Thread_Shell" demo is recommended, it already uses TAP by default and allows input commands. If this is not required and only the TAP bridge is to be used, use the Thread_KW_Tun demo. Bridge the interfaces; assuming eno1 is the interface connected directly to OpenWrt: # brctl addbr br0 # brctl addif br0 eno1 # brctl addif br0 threadtap0 # ifconfig br0 up Note: (Optional) Addresses on the bridged interfaces are lost and need to be reconfigured on the actual bridge. In this example, after bridging eno1 (interface to OpenWrt router), you’d have to run #dhclient br0 to get an IPv4 address on br0 for SSH to the router and/or #dhclient -6 br0 to get an IPv6 address to the br0 interface. There's a note here https://wiki.archlinux.org/index.php/Network_bridge#With_bridge-utils  about this.   Build C demos …/host_sdk/hsdk/demo#   make Run Thread_Shell or Thread_KW_Tun demo. …/host_sdk/hsdk/demo#   sudo ./bin/Thread_Shell /dev/ttyACM0 threadtap0 25 or …/host_sdk/hsdk/demo#   sudo ./bin/Thread_KW_Tun /dev/ttyACM0 threadtap0         Note: Try to run the demo without parameters to get some help on the input parameters   ifconfig Thread_Shell demo Thread_KW_Tun demo Joiner FRDM-KW41Z (shell) Join the Thread network Verify IP addresses Ping Eth LAN interface on OpenWrt router to verify “Internet” connectivity  Regards, JC
View full article
A network is basically a set of devices connected to one another and communicating using wired or wireless mediums. There are several standard network frameworks defined for wired and wireless communication by IEEE. This post provides information about the IEEE 802 standard and network modes.   802 Standard The 802 standard is a family of IEEE standards dealing with local and metropolitan area networks. The protocol specified in the 802 standard covers lower two layers of the OSI model that are Physical and Data Link layers. In the 802 standard, the Data link layer (Layer 2 of the OSI model) has been divided into two parts Logical Link Control (LLC) and Media Access Control (MAC) as shown in figure below.   Figure 1. Layer architecture   The active 802 standards are listed below.   Table 1. 802 standards description Standard Name Description 802.1 Internetworking It ensures the management of the Local Area Network (LAN) / Metropolitan Area Network (MAN) network and monitors network capabilities. MAC bridging, data encryption/encoding, and network traffic management services are also provided. 802.3 Ethernet Ethernet based technology that is primarily used for LAN, it can also be used for MAN and Wide Area Network (WAN).     802.3 defines the Physical and MAC sublayer of the Data Link layer that is used in wired networks. Uses Carrier Sense Multiple Access with Collision Detection (CSMA/CD) for collision detection. Data rates can be from 10Mbps to 10Gbps. 802.11 WLAN, Wi-Fi Wireless LAN uses high radio frequencies instead of cables to connect the devices in the network. Portability and setup cost is cheaper compared to wired networks but speed and security are better in wired communication. It uses Carrier Sense Multiple Access with Collision Avoidance (CSMA/CA) for collision avoidance. 802.15 WPAN This covers various protocol definitions for the personal area network like Bluetooth, ZigBee & sensors networks.   WLAN and Wi-Fi Introduction Wireless Local Area Network (WLAN) or Wireless LAN, is a network that links two or more devices using wireless communication to form a local area network within a limited area such as a home, campus, and office building. A WLAN can be built on various wireless technologies i.e. Wi-Fi, Infrared. Wi-Fi is a type of WLAN that follows IEEE 802.11 standards and one of the most commonly used WLAN today. Wi-Fi as a name for the standard is a trademark of the Wi-Fi Alliance. Wi-Fi or WLAN networks use radio waves to exchange information between devices. These radio waves are transmitted on specific frequencies - 2.4 GHz and 5 GHz, depending on the 802.11 standard (IEEE 802.11a/b/g/n/ac/ax) that the device uses. A Wi-Fi connection is established using a wireless adapter to create hotspots – areas in the vicinity of a wireless router that is connected to the network and allow users to access internet services. All Wi-Fi versions uses license free bands (ISM bands) across the globe.   Network Modes Ad-Hoc Mode In this mode wireless nodes communicate to peer nodes directly. It does not use Access Point (AP) instead it uses Mesh topology. It is also called peer to peer mode. An ad-hoc wireless network is more cost-effective than its alternative, since it does not require the installation of an AP to operate. In addition, it also needs less time to set up. Figure 2. Ad-Hoc mode   Infrastructure Mode In this mode, devices can communicate with each other first going through AP. In infrastructure mode, the wireless devices can communicate with each other or can communicate with a wired network as it’s communicating through AP. This mode is the most commonly used network mode. Compared to Ad-Hoc wireless networks, infrastructure mode offers the advantages of scale, centralized security management, and improved reach. Infrastructure mode has half throughput compared to Ad-Hoc mode.   Figure 3. Infrastructure mode   Repeater Mode When two wireless host devices have to be connected and the distance between them is long for the direct connection or obstruction is present, at that time repeater mode is used to bridge the gap. Repeater operates at the physical layer of the OSI model. As a Wireless Repeater, an AP node extends the range of the wireless network by repeating the wireless signal of the remote AP. The Ethernet MAC address of the remote AP is required for the AP to act as a wireless range extender. The repeater mode has certain drawbacks. Throughput is reduced by at least 50% as wireless interference is at least doubled. The bandwidth of any device connected to it is halved. This is due to the repeater receiving the signal, processing it, and then rebroadcasting it in both directions, from the router to the device and vice versa. The Repeater must be kept in the range of AP, but not too close to the AP. Distance between AP and repeater depends on the range of the AP and repeater should be kept in such a way that maximum possible area coverage can be achieved.   Figure 4. Repeater mode   Bridge Mode Bridge connects two or more networks to each other. It operates on the Data link layer of the OSI Model. Bridge mode allows the AP to communicate with another AP capable of point-to-point bridging. An example of this is connecting two buildings through a wireless connection.   Figure 5. Bridge mode
View full article
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.
View full article
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; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
View full article
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.
View full article
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).
View full article
Our customer is evaluating RF characteristics using FRDM-MKW24. Regarding Tx max power, they have one question. The spec of max tx power is +8dBm and I could verify the power using TWR-KW24d512 before. They observed tx power with tx un-modulated cnt transmission and informed that the power was about +2dBm. That is to say, "Power 31" in Connectivity_Test means to +2dBm. I feel that it is small... Would you comment regarding the spec of the max tx power on FRDM-MKW24? Regards, Koichi
View full article
In 802.11 standards, the connection procedure includes three major steps that shall be performed to make the device part of the Wi-Fi network and communicate in the network. Those three steps are device discovery (scanning), device authentication (checking compatibility-capability etc. before connection) and then finally establishment of connection (Association). Going forward, this post provides details for each step. The message exchange in connection procedure is shown below.   Figure 1. Connection Process in open system   Figure 2. Messages exchange in Connection Process   Figure 2 shows Wi-Fi sniffer log for messages exchange procedure between Client and AP device at the time of connection, here Client device is Xiaomi and AP is Marvell device.   Connection Setup Process 1. Scanning To join any network first client or station needs to find it the network. In the wired network, just plugging the cable or jack will find the network. In the wireless world, this requires identification of the compatible network before joining process can begin. This identification process of the network is referred as scanning. Several parameters are needed in the scanning process. These parameters are BSSType, BSSID, channel list, scantype, MinChannelTime and MaxChannelTime. The parameters are set as default depending upon manufacturer Wi-Fi driver, but it can be modified by the user i.e. if the requirement is for hidden network then we can set scantype parameter as passive scan because the active scan is not useful for the hidden network (networks that do not broadcast their SSID). There are two scanning methods, passive scanning and active scanning. By default, radios perform both the types of scanning on all the channels allowed by the country of operation.  While both the types of scanning are available by default, active scanning is performed only by those channels that are allowed to transmit by regional government regulations. Channels that are not authorized for unlicensed use are excluded from active scanning. Passive scan: In Passive Scanning, WLAN station moves to each channel as per the channel list and waits for beacon frames. Beacon frames are used by the access points (and stations in an IBSS) to communicate or to announce themselves. The access point tries to send the beacon at defined interval that is called Target Beacon Transmission Time (TBTT) Nevertheless, access points are just like the any wireless device in the cell. They cannot send if the network is busy. When the time comes for an AP to send a beacon & the network is busy, the AP will delay its beacon transmission until it can gain access to the media. In 802.11, network is busy or not can be checked using CSMA/CA protocol. In CSMA/CA when a frame is ready, the transmitting device checks whether the channel is idle or busy to avoid the collision. If the channel is busy the transmitting device will wait for random duration and check again whether the channel is idle or not. If channel is idle it will send the frame. The Beacon frame structure is as shown below.   Figure 3. Beacon Frame   Description of mandatory field of a Beacon Frame. Timestamp: After receiving the beacon frame, all the stations update their local clocks with this timestamp. This helps with synchronization. Beacon Interval: Represents the number of Time Units (TUs) between Target Beacon Transmission Times (TBTT). Default value is 100TU (102.4 milliseconds). Capability information: It contains information about capability of the device/network SSID: It contains Service set ID of the network. Supported rates: This field contains information of supported data rates by the access point. Notice that this information is not only used by potential clients during passive scanning but also by clients that are already associated to the BSS. A passive scan generally takes more time, since the client must listen and wait for a beacon versus actively probing to find an AP. Another limitation with a passive scan is that if the client does not wait long enough on a channel, then the client may miss an AP beacon.   Active scan: Discovering the network by scanning all possible channels and listening to beacons is not considered to be very efficient. To enhance this discovery process, stations often use what is called active scanning. In the active scanning mode, stations still go through each channel in turn, but instead of passively listening to the signals from AP, stations send a probe request management frame aimed at asking what network is available on this channel. If any AP or active station in an IBSS is presenting that frequency, they should answer with the probe response frame.   Figure 4. Scanning Methods   Once the probe request is sent by the emitting station, it starts a Probe Timer countdown and waits for answers. This Probe Timer value is usually a lot shorter than a beacon interval. Common values are in the 10-millisecond range. At the end of the timer, the station processes the answers it has received. If no answer was received, the station moves to the next channel (on different frequency) and repeats the same discovery process. The purpose of a probe request is typically to discover APs and their supported networks (SSIDs and/or BSSIDs).   Figure 5. Probe Request/Response Frame   This frame contains mainly two fields, the SSID and the rates supported by the mobile station. Stations that receive Probe Request use the information to determine whether the requesting station can join the network. The Probe Response frame fields are very similar to Beacon frame fields that enable mobile stations to match parameters and join the network.   2. Authentication After having performed a network discovery through the probe request/probe response exchange or by listening to beacons, a station wanting to join a network goes through an authentication process, exchanging authentication frames with the access point. On reception of the authentication frame, AP sends acknowledgement and then Authentication Response. The initial purpose of the ‘authentication’ frames to validate the device type, in other words, verify that the requesting station has proper 802.11 capabilities to join the network. Open system authentication: Information related to capabilities are exchanged between station and AP using Authentication Request. If request is accepted, AP sends “success” in Authentication Response. Shared key authentication: IEEE 802.11-1997 standard included a WEP shared key exchange authentication mechanism Called “Shared Key”. This shared key exchange adds two more frames to the default Open System authentication, resulting in a four-frame exchange. This latter method is called Shared Key authentication, requires the use of WEP encryption, and is not widely used (and not recommended) today. First phase of authentication is described above but when WPA or WPA2 is used then second phase of authentication (i.e. 4-way handshaking process) takes place after the device gets associated. The details regarding Open System authentication and Shared-Key authentication is available in 802.11 security post <Link TBD>.   Figure 6. Authentication frame   As shown above, the Authentication Frame consist of the following fields. Authentication Algorithm Number: 0 for Open System & 1 for Shared Key. Authentication Transaction Sequence Number: Indicate current state of progress. Status Code: 0 for Success & 1for Unspecified failures. Challenge Text: Used in Shared Key Authentication frame.   3. Association If the 802.11 authentication phase completes with a Success result, the station moves to the Association phase. The purpose of this exchange is for the station to join the network and obtain an Association ID [AID]. Association request: The first frame sent in the association phase is from the requesting station to the AP (or a station in an IBSS). This frame is the association request frame and the response of this frame is association response frame. Association request is unicast management frame and is always acknowledged.   Figure 7. Association Request   Association response: Once the Association request is acknowledged, the AP examine each field of the request & verify they all match its own 802.11 parameters (refer Figure 6). In case of parameter mismatch, AP checks whether the difference is a blocking or not and based on that AP sends authentication response. -    If the parameter difference is blocking, then response with status code 1 will be sent (to reject the association). -    In case of non-blocking difference/No difference in the parameters, response with status code 0(success) and AP’s own parameters will be sent to the requesting station. Station must be compatible with the AP’s capability otherwise it will drop the association process and start looking for another AP.   Figure 8. Association Response   Connection Teardown Disassociation: Once a station is associated to an AP, either side can terminate the association at any time by sending a disassociation frame. A station can send Disassociation frame before leaving the current network to roam/join another AP. An AP can send this frame in multiple cases like, if the station tries to use invalid parameters, AP itself under configuration change, hackers attack, etc. The disassociation frame (DA) can be the unicast MAC address of the station to disassociate or a broadcast address if the AP needs to disassociate all the stations in its network. In case of unicast frame, the frame will get acknowledge by receiving station and the broadcast frames are not acknowledged.   Figure 9. Disassociation Frame The Disassociation frame is quite small. It contains only one field “Reason code”. A disassociated station is still authenticated. It can try to re-associate by sending a new Association request frame, keeping its authenticated status. A station roaming to another cell may also choose to use a disassociation frame, to be able to keep its authenticated status and accelerate the process when roaming back to the same cell before its authentication timeout expires.   Figure 10. Disassociation Frame Exchange   This frame is also used when parameters change and the station or the AP needs to renegotiate the communications parameters.   De-authentication: The station or AP can also send a de-authentication frame. This frame is used when all communications are terminated, for example, because the AP has to reboot or because the station stops its Wi-Fi communications. It is also used when a frame is received before authentication has completed. For example, a station trying to send an association request or a data frame before having performed the authentication sequence then station will receive a Deauthentication frame from the AP, indicating that authentication must be performed first. The frame format is same as disassociation frame.   Figure 11. Deauthentication Frame Exchange   Roaming Roaming, in the context of an 802.11 wireless network, is the process of a client moving an established Wi-Fi network association from one access point to another access point within the same Extended Service Set (ESS) without losing connection (e.g. within a defined time interval, usually in the range of a few seconds). The roaming time should be smaller for the better performance. In the roaming process, the mobile device will send the disassociation frame to the previously associated Access Point (AP), and will start re-association process by exchanging 802.11 frames with another access point to which the device wants to connect. The client device scans the another AP then exchange authentication frames after that it will send re-association request, here instead of association re-association request is used and the first 2 steps of connection process remains the same.   Figure 12. Message Exchange in Roaming Process     Figure 13. Roaming representation   Wi-Fi APIs used in Connection and Disconnection process Table below shows some of the available APIs in NXP i.MX RT SDK for connection and disconnection process.   Table 1. APIs Available in SDK API Description Can be called from wifi_send_scan_cmd Used for scanning the available network. It supports only single SSID based scan. We can extend this to a list of multiple SSIDs. Station and AP wlan_add_network Add specific network profile to the list of known networks. Station and AP wlan_remove_network Remove specific network profile from the list of known networks. Station and AP wlan_connect Connect with specific network (AP). Station wlan_disconnect Disconnect the station from network (AP). Station wlan_start_network Start specific network. AP wlan_stop_network Stop specific network. AP   For more details on such APIs refer the document “MCUXpresso_SDK_WLAN_Driver_Reference_Manual.pdf” available at location <SDK Documentation>/docs/wifi.
View full article
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.
View full article
The FRDM-KW40Z includes an RTC module with a 32 kHz crystal oscillator. This module generates a 32 kHz clock source for the MCU whilst running on very low power mode. This oscillator includes a set of programmable capacitors used as the C LOAD . Changing the value of these capacitors can modify the frequency the oscillator provides. This configurable capacitance ranges from 1 pF (which is effectively two 2 pF capacitors in series) all the way to 15 pF (30 pF capacitors in series). These values are obtained by combining the enabled capacitors. The values available are 2 pF, 4 pF, 8 pF and 16 pF. Any combination between these four can be done. It is recommended that these internal capacitors are disabled if the external capacitors are available. Figure 1. External capacitors for the 32 kHz crystal To adjust the frequency provided by the oscillator, you must first be able to measure the frequency. Using a frequency counter would be ideal, as it provides a more precise measurement than an oscilloscope. You will also need to output the oscillator frequency. To output the oscillator frequency, using any of the Bluetooth demo applications as an example, you should do the following: 1. Since the RTC module is going to be used to output the oscillator frequency, the RTC_CLKOUT will be the output signal. The output pin for RTC_CLKOUT is PTB3. To configure PTB3 as the oscillator output use the function configure_rtc_pins(RTC instance). Port B clock must be enabled first. Figure 2. PTB3 pin mux   /* hardware_init.c */     /* enable clock for PORTs */   CLOCK_SYS_EnablePortClock(PORTA_IDX);   CLOCK_SYS_EnablePortClock(PORTB_IDX);   CLOCK_SYS_EnablePortClock(PORTC_IDX);   /* RTC CLKOUT */   configure_rtc_pins(0);     //This function changes the pin mux to select RTC_CLKOUT. It is included in the pin_mux.c file. 2.  Modify the System Options Register 1 (SIM_SOPT1) to select the clock source and to allow the selected clock source to be output in PTB3. The field you should change is OSC32KOUT. To select the clock source to be output on PTB3, use the function CLOCK_HAL_SetExternalRefClock32kSrc(). Remember to include the fsl_sim_hal.h file. Figure 3. SIM_SOPT1 register fields /* hardware_init.c */ /* RTC CLKOUT */ configure_rtc_pins(0); SIM_Type *simBase = g_simBase[0];     SIM_SOPT1 = SIM_SOPT1_OSC32KOUT(kClockRtcoutSrc32kHz);                // This field in register SIM_SOPT1 allows a clock source to be output to PTB3 CLOCK_HAL_SetExternalRefClock32kSrc(simBase, kClockEr32kSrcOsc0);     // This function chooses the clock source for the RTC 3.  Make sure the oscillator is enabled. The RTC external clock configurations can be found in the board.h file. This is also where the internal capacitors are enabled. /* board.h */ /* RTC external clock configuration. */ #define RTC_XTAL_FREQ                32768U #define RTC_SC2P_ENABLE_CONFIG       false      // 2 pF capacitors enable #define RTC_SC4P_ENABLE_CONFIG       false      // 4 pF capacitors enable #define RTC_SC8P_ENABLE_CONFIG       false      // 8 pF capacitors enable #define RTC_SC16P_ENABLE_CONFIG      false      // 16 pF capacitors enable #define RTC_OSC_ENABLE_CONFIG        true       // Oscillator enable 4.  You should now be able to measure the oscillator frequency through the PTB3 pin. Measurements should be done with a frequency counter, as change in the output can be very subtle, and an oscilloscope might not be able to pick it up. Remember that these capacitors give you the option to use the 32 kHz oscillator when you do not have the external capacitors. They are not supposed to be used when the external capacitors are being used. Now, to change the internal capacitance, you can simply change the macros contained in the board.h file (step 4). It is important that the oscillator is disabled before making any changes to the enabled capacitors. The fsl_clock_manager.c file already contains the function CLOCK_SYS_RtcOscInit() that configures the oscillator with the values established in the previously mentioned macros, however, the oscillator is not disabled before attempting to change the capacitors (and therefore, no changes are made). To fix this, you can use the RTC_HAL_SetOscillatorCmd() function to disable the oscillator before making changes with the capacitors. /* fsl_clock_manager.c */     // Disable the oscillator in case any changes are made to the capacitors RTC_HAL_SetOscillatorCmd(RTC, false);     // If the oscillator is not enabled and should be enabled. if ((!RTC_HAL_IsOscillatorEnabled(RTC)) && (config->enableOsc)) {     /* Enable the desired capacitors */     RTC_HAL_SetOsc2pfLoadCmd(RTC, config->enableCapacitor2p);     RTC_HAL_SetOsc4pfLoadCmd(RTC, config->enableCapacitor4p);     RTC_HAL_SetOsc8pfLoadCmd(RTC, config->enableCapacitor8p);     RTC_HAL_SetOsc16pfLoadCmd(RTC, config->enableCapacitor16p);         /* Re-enable the oscillator */     RTC_HAL_SetOscillatorCmd(RTC, config->enableOsc); } The fsl_clock_manager.c file can be found in: <KW40Z_connSw_install_dir>\KSDK_1.3.0\platform\system\src\clock Some reference measurements with different values for the internal capacitance: With external capacitors (internal capacitors disabled) Board Revision C LOAD Measured Frequency KW40Z – rev. C C46 & C47 32,769.03 Hz KW40Z – rev. B C46 & C47 32,769.27 Hz With internal capacitors (external capacitors removed) Enabled Capacitors C LOAD Measured Frequency SC2P 1 pF 32,773.21 Hz SC4P 2 pF 32,772.06 Hz SC2P, SC4P 3 pF 32,771.2 Hz SC4P, SC8P 6 pF 32,769.39 Hz SC2P, SC4P, SC8P 7 pF 32,769 Hz SC16P 8 pF 32,768.6 Hz SC2P, SC16P 9 pF 32,768.31 Hz SC4P, SC16P 10 pF 32,768.05 Hz SC2P, SC4P, SC16P 11 pF 32,767.83 Hz SC4P, SC8P, SC16P 14 pF 32,767.27 Hz SC2P, SC4P, SC8P, SC16P 15 pF 32,767.11 Hz Please note that the capacitance is not only composed of the enabled internal capacitance, but also the parasitic capacitances found in the package, bond wires, bond pad and the PCB traces. So, while the reference measurements given before should be close to the actual value, you should also make measurements with your board, to ensure that the frequency is trimmed specifically to your board and layout.
View full article
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
View full article
The Thread Low Power End Device is preconfigured to have both the MCU in low power state and the radio turned off most of the time to preserve battery life. The device wakes up periodically and polls its parent router for data addressed to it or optionally initiates sending data to the network by means of the parent router. The low-power module (LPM) from the connectivity framework simplifies the process of putting a Kinetis-based wireless network node into the low-power or sleep modes. For the MKW41Z there are six low-power modes available. By default, the Thread Low Power End Device uses Deep sleep mode 3, where: MCU in LLS3 mode. Link layers remain idle. RAM is retained. The wake-up sources are: GPIO (push buttons). DCDC power switch (In buck mode). LPTMR with the 32kHz oscillator as clock source. The LPTMR timer is also used to measure the time that the MCU spends in deep sleep to synchronize low-power timers at wake-up. See the Connectivity Framework Reference Manual and PWR_Configuration.h for more information about the sleep deep modes. To change the polling time on deep sleep mode 3, we need to understand two macros:    1. The cPWR_DeepSleepDurationMs macro in \framework\LowPower\Interface\MKW41Z\PWR_Configuration.h. #ifndef cPWR_DeepSleepDurationMs   #define cPWR_DeepSleepDurationMs                3000 #endif ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ This macro determines how long the MCU will go to low power mode (deep sleep). The maximum value is 65535000 ms (18.2 h). 2. The THR_SED_POLLING_INTERVAL_MS macro in \source\config.h. /*! The default value for sleepy end device (SED) polling interval */ #ifndef THR_SED_POLLING_INTERVAL_MS     #define THR_SED_POLLING_INTERVAL_MS                     3000     /* Milliseconds */ #endif ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ This macro determines how often the Low Power End Device will send a poll message to its parent. NOTE: This value does not determine how often the MCU wakes up. The polling interval should be a multiple of the Deep sleep duration value, otherwise the poll will be sent at the next deep sleep time out. As an example, let's say we configure the polling interval to 4000ms and the deep sleep duration to 3000ms. The MCU will wake up every 3000ms but the poll message will be sent every 2 deep sleep timeouts = 6000ms because the timers are synchronized when the MCU wakes up. The following figure shows the behavior of this example. It is recommended that the polling interval is the same as the deep sleep duration, so the MCU doesn't wake up unnecessarily. The following figure shows this behavior. Another macro to keep in mind is THR_SED_TIMEOUT_PERIOD_SEC in app_thread_config.h. #ifndef THR_SED_TIMEOUT_PERIOD_SEC     #define THR_SED_TIMEOUT_PERIOD_SEC                 ((4*THR_SED_POLLING_INTERVAL_MS)/1000 + 3) #endif ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ This value is the timeout period used by the parent to consider a sleepy end device (SED) disconnected. By default, this value is configured to be 4 times the polling interval + 3s. It is recommended to leave this macro as it is. This value is sent to the parent node during the commissioning.
View full article
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.
View full article
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.
View full article
This document is a supplement for USB MSC device bootloader revision for FRDM-KL25Z (IAR) written by Kai Liu and describes the bootloader support for FRDM-K64F. FTFE support, board specific and MCU specific code was added to the initial software. This porting work was done for connectivity purposes but it can be used as support for FRDM-K64F board. Please refer to USB-KW24D512  MSD Bootloader to find out how to use this bootloader, binary files upload and other restrictions. The bootloader has conditional jump to user application. The condition is the state of the SW2 button (PTC6). If the button is pressed (PTC6 grounded) during reset, the bootloader sequence will start, installing BOOTLOADER drive. Else if the button is released during reset, the SP and PC will be updated from address 0xC000. This means, the user application has to be designed so as to have 0xC000 application start address. If a valid SP and PC value is found at address 0xC000, the user application is launched. The bootloader application is located in the flash memory of the MK64FN1M0VLL12 microcontroller, from address 0x0000 to 0xBFFF, so the user application should not access this memory region. The bootloader software was tested under Microsoft Windows 10, Microsoft Windows 8, Microsoft Windows 7 and Ubuntu 14.04 operating systems. Attached files: USB_MSD_Bootloader.bin – boolader binary file for FRDM-K64; Pflash_1024KB_0xC000.icf – IAR linker file for user application development; Demos.7z - user application demo S record files for FRDM-K64F (got from Kinetis SDK demo list).
View full article
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
View full article
In this document we will be seeing how to create a BLE demo application for an adopted BLE profile based on another demo application with a different profile. In this demo, the Pulse Oximeter Profile will be implemented.  The PLX (Pulse Oximeter) Profile was adopted by the Bluetooth SIG on 14th of July 2015. You can download the adopted profile and services specifications on https://www.bluetooth.org/en-us/specification/adopted-specifications. The files that will be modified in this post are, app.c,  app_config.c, app_preinclude.h, gatt_db.h, pulse_oximeter_service.c and pulse_oximeter_interface.h. A profile can have many services, the specification for the PLX profile defines which services need to be instantiated. The following table shows the Sensor Service Requirements. Service Sensor Pulse Oximeter Service Mandatory Device Information Service Mandatory Current Time Service Optional Bond Management Service Optional Battery Service Optional Table 1. Sensor Service Requirements For this demo we will instantiate the PLX service, the Device Information Service and the Battery Service. Each service has a source file and an interface file, the device information and battery services are already implemented, so we will only need to create the pulse_oximeter_interface.h file and the pulse_oximeter_service.c file. The PLX Service also has some requirements, these can be seen in the PLX service specification. The characteristic requirements for this service are shown in the table below. Characteristic Name Requirement Mandatory Properties Security Permissions PLX Spot-check Measurement C1 Indicate None PLX Continuous Measurement C1 Notify None PLX Features Mandatory Read None Record Access Control Point C2 Indicate, Write None Table 2. Pulse Oximeter Service Characteristics C1: Mandatory to support at least one of these characteristics. C2: Mandatory if measurement storage is supported for Spot-check measurements. For this demo, all the characteristics will be supported. Create a folder for the pulse oximeter service in  \ConnSw\bluetooth\profiles named pulse_oximeter and create the pulse_oximeter_service.c file. Next, go to the interface folder in \ConnSw\bluetooth\profiles and create the pulse_oximeter_interface.h file. At this point these files will be blank, but as we advance in the document we will be adding the service implementation and the interface macros and declarations. Clonate a BLE project with the cloner tool. For this demo the heart rate sensor project was clonated. You can choose an RTOS between bare metal or FreeRTOS. You will need to change some workspace configuration.  In the bluetooth->profiles->interface group, remove the interface file for the heart rate service and add the interface file that we just created. Rename the group named heart_rate in the bluetooth->profiles group to pulse_oximeter and remove the heart rate service source file and add the pulse_oximeter_service.c source file. These changes will be saved on the actual workspace, so if you change your RTOS you need to reconfigure your workspace. To change the device name that will be advertised you have to change the advertising structure located in app_config.h. /* Scanning and Advertising Data */ static const uint8_t adData0[1] =  { (gapAdTypeFlags_t)(gLeGeneralDiscoverableMode_c | gBrEdrNotSupported_c) }; static const uint8_t adData1[2] = { UuidArray(gBleSig_PulseOximeterService_d)}; static const gapAdStructure_t advScanStruct[] = { { .length = NumberOfElements(adData0) + 1, .adType = gAdFlags_c, .aData = (void *)adData0 }, { .length = NumberOfElements(adData1) + 1, .adType = gAdIncomplete16bitServiceList_c, .aData = (void *)adData1 }, { .adType = gAdShortenedLocalName_c, .length = 8, .aData = "FSL_PLX" } }; We also need to change the address of the device so we do not have conflicts with another device with the same address. The definition for the address is located in app_preinclude.h and is called BD_ADDR. In the demo it was changed to: #define BD_ADDR 0xBE,0x00,0x00,0x9F,0x04,0x00 Add the definitions in ble_sig_defines.h located in Bluetooth->host->interface for the UUID’s of the PLX service and its characteristics. /*! Pulse Oximeter Service UUID */ #define gBleSig_PulseOximeterService_d         0x1822 /*! PLX Spot-Check Measurement Characteristic UUID */ #define gBleSig_PLXSpotCheckMeasurement_d      0x2A5E /*! PLX Continuous Measurement Characteristic UUID */ #define gBleSig_PLXContinuousMeasurement_d     0x2A5F /*! PLX Features Characteristic UUID */ #define gBleSig_PLXFeatures_d                  0x2A60 /*! Record Access Control Point Characteristic UUID */ #define gBleSig_RecordAccessControlPoint_d     0x2A52 We need to create the GATT database for the pulse oximeter service. The requirements for the service can be found in the PLX Service specification. The database is created at compile time and is defined in the gatt_db.h.  Each characteristic can have certain properties such as read, write, notify, indicate, etc. We will modify the existing database according to our needs. The database for the pulse oximeter service should look something like this. PRIMARY_SERVICE(service_pulse_oximeter, gBleSig_PulseOximeterService_d)     CHARACTERISTIC(char_plx_spotcheck_measurement, gBleSig_PLXSpotCheckMeasurement_d, (gGattCharPropIndicate_c))         VALUE_VARLEN(value_PLX_spotcheck_measurement, gBleSig_PLXSpotCheckMeasurement_d, (gPermissionNone_c), 19, 3, 0x00, 0x00, 0x00)         CCCD(cccd_PLX_spotcheck_measurement)     CHARACTERISTIC(char_plx_continuous_measurement, gBleSig_PLXContinuousMeasurement_d, (gGattCharPropNotify_c))         VALUE_VARLEN(value_PLX_continuous_measurement, gBleSig_PLXContinuousMeasurement_d, (gPermissionNone_c), 20, 3, 0x00, 0x00, 0x00)         CCCD(cccd_PLX_continuous_measurement)     CHARACTERISTIC(char_plx_features, gBleSig_PLXFeatures_d, (gGattCharPropRead_c))         VALUE_VARLEN(value_plx_features, gBleSig_PLXFeatures_d, (gPermissionFlagReadable_c), 7, 2, 0x00, 0x00)     CHARACTERISTIC(char_RACP, gBleSig_RecordAccessControlPoint_d, (gGattCharPropIndicate_c | gGattCharPropWrite_c))         VALUE_VARLEN(value_RACP, gBleSig_RecordAccessControlPoint_d, (gPermissionNone_c), 4, 3, 0x00, 0x00, 0x00)         CCCD(cccd_RACP) For more information on how to create a GATT database you can check the BLE Application Developer’s Guide chapter 7. Now we need to make the interface file that contains all the macros and declarations of the structures needed by the PLX service. Enumerated types need to be created for each of the flags field or status field of every characteristic of the service. For example, the PLX Spot-check measurement field has a flags field, so we declare an enumerated type that will help us keep the program organized and well structured. The enum should look something like this: /*! Pulse Oximeter Service - PLX Spotcheck Measurement Flags */ typedef enum {     gPlx_TimestampPresent_c                      = BIT0,     /* C1 */     gPlx_SpotcheckMeasurementStatusPresent_c     = BIT1,     /* C2 */     gPlx_SpotcheckDeviceAndSensorStatusPresent_c = BIT2,     /* C3 */     gPlx_SpotcheckPulseAmplitudeIndexPresent_c   = BIT3,     /* C4 */     gPlx_DeviceClockNotSet_c                     = BIT4 } plxSpotcheckMeasurementFlags_tag; The characteristics that will be indicated or notified need to have a structure type that contains all the fields that need to be transmitted to the client. Some characteristics will not always notify or indicate the same fields, this varies depending on the flags field and the requirements for each field. In order to notify a characteristic we need to check the flags in the measurement structure to know which fields need to be transmitted. The structure for the PLX Spot-check measurement should look something like this: /*! Pulse Oximeter Service - Spotcheck Measurement */ typedef struct plxSpotcheckMeasurement_tag {     ctsDateTime_t              timestamp;             /* C1 */     plxSpO2PR_t                SpO2PRSpotcheck;       /* M */     uint32_t                   deviceAndSensorStatus; /* C3 */     uint16_t                   measurementStatus;     /* C2 */     ieee11073_16BitFloat_t     pulseAmplitudeIndex;   /* C4 */     uint8_t                    flags;                 /* M */ }plxSpotcheckMeasurement_t; The service has a configuration structure that contains the service handle, the initial features of the PLX Features characteristic and a pointer to an allocated space in memory to store spot-check measurements. The interface will also declare some functions such as Start, Stop, Subscribe, Unsubscribe, Record Measurements and the control point handler. /*! Pulse Oximeter Service - Configuration */ typedef struct plxConfig_tag {     uint16_t      serviceHandle;     plxFeatures_t plxFeatureFlags;     plxUserData_t *pUserData;     bool_t        procInProgress; } plxConfig_t; The service source file implements the service specific functionality. For example, in the PLX service, there are functions to record the different types of measurements, store a spot-check measurement in the database, execute a procedure for the RACP characteristic, validate a RACP procedure, etc. It implements the functions declared in the interface and some static functions that are needed to perform service specific tasks. To initialize the service you use the start function. This function initializes some characteristic values. In the PLX profile, the Features characteristic is initialized and a timer is allocated to indicate the spot-check measurements periodically when the Report Stored Records procedure is written to the RACP characteristic. The subscribe and unsubscribe functions are used to update the device identification when a device is connected to the server or disconnected. bleResult_t Plx_Start (plxConfig_t *pServiceConfig) {         mReportTimerId = TMR_AllocateTimer();         return Plx_SetPLXFeatures(pServiceConfig->serviceHandle, pServiceConfig->plxFeatureFlags); } All of the services implementations follow a similar template, each service can have certain characteristics that need to implement its own custom functions. In the case of the PLX service, the Record Access Control Point characteristic will need many functions to provide the full functionality of this characteristic. It needs a control point handler, a function for each of the possible procedures, a function to validate the procedures, etc. When the application makes a measurement it must fill the corresponding structure and call a function that will write the attribute in the database with the correct fields and then send an indication or notification. This function is called RecordMeasurement and is similar between the majority of the services. It receives the measurement structure and depending on the flags of the measurement, it writes the attribute in the GATT database in the correct format. One way to update a characteristic is to create an array of the maximum length of the characteristic and check which fields need to be added and keep an index to know how many bytes will be written to the characteristic by using the function GattDb_WriteAttribute(handle, index, &charValue[0]). The following function shows an example of how a characteristic can be updated. In the demo the function contains more fields, but the logic is the same. static bleResult_t Plx_UpdatePLXContinuousMeasurementCharacteristic ( uint16_t handle, plxContinuousMeasurement_t *pMeasurement ) {     uint8_t charValue[20];     uint8_t index = 0;     /* Add flags */     charValue[0] = pMeasurement->flags;     index++;     /* Add SpO2PR-Normal */     FLib_MemCpy(&charValue[index], &pMeasurement->SpO2PRNormal, sizeof(plxSpO2PR_t));     index += sizeof(plxSpO2PR_t);         /* Add SpO2PR-Fast */     if (pMeasurement->flags & gPlx_SpO2PRFastPresent_c)     {       FLib_MemCpy(&charValue[index], &pMeasurement->SpO2PRFast, sizeof(plxSpO2PR_t));       index += sizeof(plxSpO2PR_t);     }        return GattDb_WriteAttribute(handle, index, &charValue[0]); } The app.c handles the application specific functionality. In the PLX demo it handles the timer callback to make a PLX continuous measurement every second. It handles the key presses and makes a spot-check measurement each time the SW3 pushbutton is pressed. The GATT server callback receives an event when an attribute is written, and in our application the RACP characteristic is the only one that can be written by the client. When this event occurs, we call the Control Point Handler function. This function makes sure the indications are properly configured and check if another procedure is in progress. Then it calls the Send Procedure Response function, this function validates the procedure and calls the Execute Procedure function. This function will call one of the 4 possible procedures. It can call Report Stored Records, Report Number of Stored Records, Abort Operation or Delete Stored Records. When the project is running, the 4 LEDs will blink indicating an idle state. To start advertising, press the SW4 button and the LED1 will start flashing. When the device has connected to a client the LED1 will stop flashing and turn on. To disconnect the device, hold the SW4 button for some seconds. The device will return to an advertising state. In this demo, the spot-check measurement is made when the SW3 is pressed, and the continuous measurement is made every second. The spot-check measurement can be stored by the application if the Measurement Storage for spot-check measurements is supported (bit 2 of Supported Features Field in the PLX Features characteristic). The RACP characteristic lets the client control the database of the spot-check measurements, you can request the existing records, delete them, request the number of stored records or abort a procedure. To test the demo you can download and install the nRF Master Control application by Nordic Semiconductor on an Android Smartphone that supports BLE. This app lets you discover the services in the sensor and interact with each characteristic. The application will parse known characteristics, but because the PLX profile is relatively new, these characteristics will not be parsed and the values will be displayed in a raw format. Figure 1. nRF Master Control app
View full article
Bluetooth Low Energy offers the ability to broadcast data in format of non-connectable advertising packets while not being in a connection. This GAP Advertisement is widely known as a beacon and there are currently different beacon formats on the market.   This guide will help you to create your own beacon scanner to detect from which type of device is the beacon received from. This guide it’s based on the frdmkw41z_wireless_examples_bluetooth_temperature_collector_freertos  demo in MCUXpresso  The first thing we will do it’s to disable the low power to make the development easier in the app_preinclude.h /* Enable/Disable PowerDown functionality in PwrLib */ #define cPWR_UsePowerDownMode 0‍‍‍‍‍‍   The following changes will be all performed in the temperature_collector.c file We will disable the timer so it keeps scanning the packets received   /* Start advertising timer TMR_StartLowPowerTimer(mAppTimerId, gTmrLowPowerSecondTimer_c, TmrSeconds(gScanningTime_c), ScanningTimeoutTimerCallback, NULL); */‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Then we will define some of the data we want to use as a reference. static uint8_t NXPAd[3] = { /* Company Identifier*/ mAdvCompanyId, /* Beacon Identifier */ 0xBC }; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   static uint8_t iBeaconAd[2] = { 0x4C, 0x00 };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ static uint8_t EddyStoneUIDAd2[3] = { /* ID */ 0xAA, 0xFE, /* Frame Type */ 0x00 }; ‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     static const uint8_t EddyStoneURLAd2[3] = { /* ID */ 0xAA, 0xFE, /* Frame Type */ 0x10 };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍     static const uint8_t EddyStoneTLMAd2[3] = { /* ID */ 0xAA, 0xFE, /* Frame Type */ 0x20 };‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   Once we have those definitions of the beacon structure of each of the types wanted we will change the function static bool_t CheckScanEvent(gapScannedDevice_t* pData) static bool_t CheckScanEvent(gapScannedDevice_t* pData) { uint8_t index = 0; bool_t foundMatch = FALSE; bool_t EddyfoundMatch = 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]; /*DESIRED BEACON SCANNER PARSER CODE */ /* Move on to the next AD elemnt type */ index += adElement.length + sizeof(uint8_t); } if (foundMatch) { SHELL_NEWLINE(); shell_write("\r\Address : "); shell_writeHex(pData->aAddress, 6); } return foundMatch; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   As you can see, there is a comment in the function that mentions the need to add the scanner parser code, depending on the beacon you want to see  will be the code to use there  NXP if (FLib_MemCmp(NXPAD, (adElement.aData), 2)) { shell_write("\r\nFound NXP device!"); SHELL_NEWLINE(); shell_write("\r\nData Received: "); shell_writeHex(adElement.aData, adElement.length); foundMatch=TRUE; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍   iBeacon if (FLib_MemCmp(iBeaconAd, (adElement.aData), 2)) { shell_write("\r\nFound iBeacon device!"); SHELL_NEWLINE(); shell_write("\r\nData Received: "); shell_writeHex(adElement.aData, adElement.length); foundMatch=TRUE; }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍ Eddystone if (FLib_MemCmp(EddyStoneUIDAd1, (adElement.aData), 2)) { shell_write("\r\nFound EddyStone device!"); if (!EddyfoundMatch) { EddyfoundMatch=TRUE; } else{ if(TRUE==EddyfoundMatch && FLib_MemCmp(EddyStoneUIDAd2, (adElement.aData), 3)) { SHELL_NEWLINE(); shell_write("\r\n[UID type] Data Received: "); shell_writeHex(adElement.aData, adElement.length); foundMatch=TRUE; EddyfoundMatch=FALSE; } else if(TRUE==EddyfoundMatch && FLib_MemCmp(EddyStoneURLAd2, (adElement.aData), 3)) { SHELL_NEWLINE(); shell_write("\r\n[URL type] Data Received: "); hell_writeHex(adElement.aData, adElement.length); foundMatch=TRUE; EddyfoundMatch=FALSE; } else if(TRUE==EddyfoundMatch && FLib_MemCmp(EddyStoneTLMAd2, (adElement.aData), 3)) { SHELL_NEWLINE(); shell_write("\r\n[TLM type] Data Received: "); shell_writeHex(adElement.aData, adElement.length); foundMatch=TRUE; EddyfoundMatch=FALSE; } else { EddyfoundMatch=TRUE; } } }‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍
View full article