Hello NFC community,
The purpose of this document is to show the steps to port the Bluetooth pairing example for NTAG I²C Plus from KW41Z to KW36.
Setup
For this, we will work with following boards:
1. Arduino NTAG I²C plus board (OM23221ARD) development kit.
2. KW36 Freedom board.
Download SDK as mentioned in chapter 2.1.3 of KW41Z User Manual and pay close attention to include NTAG I²C middleware.
Now, repeat the same procedure above for FRDM KW36, this will be the SDK on which we will be making the modifications for the porting.
NOTE: Unlike KW41Z, for KW36 there is no NTAG I²C plus middleware as shown in the image below:

Save changes and build the SDK. NTAG I²C middleware will have to be imported from KW41Z's SDK in MCUXPresso.
Install the SDK and import hid _device freertos example into the workspace:

Copy ntag_i2c_plus_1.0.0 folder from KW41Z workspace to KW36's

Open folder properties and uncheck Exclude resources from build, then apply and close.

In board.c file add the following code below BOARD_DCDCInit()
BOARD_DCDCInit();
#ifdef NTAG_I2C
BOARD_InitI2C();
#endif
In AppIMain.c add the following code in main_task before calling App_Thread()
#ifdef NTAG_I2C
HAL_I2C_InitDevice(HAL_I2C_INIT_DEFAULT, I2C_MASTER_CLK_SRC, NTAG_I2C_MASTER_BASEADDR);
SystemCoreClockUpdate();
ntag_handle = NFC_InitDevice((NTAG_ID_T)0, NTAG_I2C_MASTER_BASEADDR);
#endif
In ApplMain.c add the following under Public memory declarations
...
#ifdef NTAG_I2C
NFC_HANDLE_T ntag_handle;
#endif
Include new headers to the following:
In ApplMain.c include the following
#ifdef NTAG_I2C
#include "HAL_I2C_driver.h"
#include <app_ntag.h>
#endif
In hid_device.c include the following
#ifdef NTAG_I2C
#include <app_ntag.h>
#endif
Copy app_ntag.c and app_ntag.h files from KW41Z workspace to KW36's.

The app_ntag.c source file contains sample functions for working with NDEF messages. Function NFC_MsgWrite() creates and writes the NDEF message in the Type-2 Tag format to the NTAG I2C chip through the ntag_i2c_plus middleware. The write algorithm is NFC-Forum compliance. Function NDEF_Pairing_Write() contains a procedure to create a BTSSP record via using the NDEF library. The same is performing function NDEF_Demo_Write() function. Here is shown how to create NDEF multi-record that contains several types of NDEF records.
The app_ntag.h header file contains predefined blocks of constants (constant fields of data) that are written to the NTAG I2C chip by default during the communication which requires set the default content to the chip’s registers or erase the NTAG I2C chip user memory and registers of lock bytes.
NOTE: Please change the I²C Master base address and I²C Master clock source from I2C1 to I2C0 as below in app_ntag.h:

In hid_device.c make the implementation in BleApp_HandleKeys() as below. This is an extension for BLE pairing and writing NDEF messages to NTAG I²C.
void BleApp_HandleKeys(key_event_t events)
{
#ifdef NTAG_I2C
uint32_t timeout = NDEF_WRITE_TIMEOUT;
switch (events)
{
case gKBD_EventPressPB1_c:
{
BleApp_Start();
TurnOffLeds();
if (NDEF_Demo_Write())
{
LED_RED_ON;
}
else
{
LED_RED_ON;
LED_GREEN_ON;
}
TMR_StartLowPowerTimer(
mNDEFTimerId,
gTmrLowPowerSecondTimer_c,
TmrSeconds(timeout),
NDEFTimerCallback,
NULL);
break;
}
case gKBD_EventPressPB2_c:
{
TurnOffLeds();
if (NDEF_Pairing_Write())
{
LED_RED_ON;
}
else
{
LED_GREEN_ON;
}
TMR_StartLowPowerTimer(
mNDEFTimerId,
gTmrLowPowerSecondTimer_c,
TmrSeconds(timeout),
NDEFTimerCallback,
NULL);
break;
}
case gKBD_EventLongPB1_c:
{
if (mPeerDeviceId != gInvalidDeviceId_c)
{
Gap_Disconnect(mPeerDeviceId);
boNDEFState = FALSE;
}
break;
}
case gKBD_EventLongPB2_c:
{
#if gAppUsePrivacy_d
if( mAdvState.advOn )
{
mAppPrivacyChangeReq = reqOff_c;
TMR_StopTimer(mAdvTimerId);
Gap_StopAdvertising();
}
else if( gBleSuccess_c == BleConnManager_DisablePrivacy() )
{
TMR_StartLowPowerTimer(mPrivacyDisableTimerId, gTmrLowPowerSingleShotMillisTimer_c,
TmrSeconds(mPrivacyDisableDurationSec_c), PrivacyEnableTimerCallback, NULL);
}
#endif
break;
}
default:
break;
}
#else
switch (events)
{
case gKBD_EventPressPB1_c:
{
BleApp_Start();
break;
}
case gKBD_EventPressPB2_c:
{
hidProtocolMode_t protocolMode;
Hid_GetProtocolMode(service_hid, &protocolMode);
protocolMode = (protocolMode == gHid_BootProtocolMode_c)?gHid_ReportProtocolMode_c:gHid_BootProtocolMode_c;
Hid_SetProtocolMode(service_hid, protocolMode);
break;
}
case gKBD_EventLongPB1_c:
{
if (mPeerDeviceId != gInvalidDeviceId_c)
Gap_Disconnect(mPeerDeviceId);
break;
}
case gKBD_EventLongPB2_c:
{
#if gAppUsePrivacy_d
if( mAdvState.advOn )
{
mAppPrivacyChangeReq = reqOff_c;
TMR_StopTimer(mAdvTimerId);
Gap_StopAdvertising();
}
else if( gBleSuccess_c == BleConnManager_DisablePrivacy() )
{
TMR_StartLowPowerTimer(mPrivacyDisableTimerId, gTmrLowPowerSingleShotMillisTimer_c,
TmrSeconds(mPrivacyDisableDurationSec_c), PrivacyEnableTimerCallback, NULL);
}
#endif
break;
}
default:
break;
}
#endif
}
Add the declaration of the timer handler in Private memory declarations section of hid_device.c
...
#ifdef NTAG_I2C
static tmrTimerID_t mNDEFTimerId;
static bool boNDEFState = FALSE;
#endif
Add the declaration of the timer callback function in Private functions prototypes of hid_device.c
...
#ifdef NTAG_I2C
static void NDEFTimerCallback(void *);
#endif
Allocate / Initialize the timer
There are 3 timers used within the HID_device demo application. The NDEF timer is also necessary to allocate in the function BleApp_Config() in the hid_device.c file, at the same place as the common timers are allocated. Function TMR_AllocateTimer() returns timer ID value which is stored in the variable mNDEFTimerId. The timer ID allocation must be added behind the other timer as it is done at following C-code printout
mAdvTimerId = TMR_AllocateTimer();
mHidDemoTimerId = TMR_AllocateTimer();
mBatteryMeasurementTimerId = TMR_AllocateTimer();
#ifdef NTAG_I2C
mNDEFTimerId = TMR_AllocateTimer();
#endif
Add the timer callback function
It is necessary to add the NDEFTimerCallback() function at the end of the hid_device.c file. If NDEF timer counter expires timer is stopped. Then RGB LED is switched off. There is the printout of the call back function at the following lines.
#ifdef NTAG_I2C
static void NDEFTimerCallback(void * pParam)
{
TMR_StopTimer(mNDEFTimerId);
TurnOffLeds();
}
#endif
Note: Change the size for timer task in app_preinclude.h file as follows:
#ifdef NTAG_I2C
#define gTmrTaskStackSize_c 1024
#else
#define gTmrTaskStackSize_c 500
#endif
Security change
The sample project for adding NTAG I2C middleware is hid_device and is described in chapter 3.1.1. This project requires to enter the password “999999” during the Bluetooth pairing. From this reason is necessary to decrease the security level to remove the password sequence.
Security level is a part of the configuration and is set in the app_config.c file. In this file following parameter must be changed
gSecurityMode_1_Level_3_c
to the new parameter:
gSecurityMode_1_Level_1_c
Parameter gSecurityMode_1_Level_3_c is used on several places within the app_config.c file. Use the FIND function (short key is “CTRL+F”) of the IDE to find it and update.
There are last two parameters of the gPairingParameters structure which are necessary to change.
parameter:
.securityModeAndLevel = gSecurityMode_1_Level_3_c,
has to be changed to:
.securityModeAndLevel = gSecurityMode_1_Level_1_c,
parameter:
.localIoCapabilities = gIoDisplayOnly_c,
has to be changed to:
.localIoCapabilities = gIoNone_c,
parameter
.leSecureConnectionSupported = TRUE,
has to be changed to:
.leSecureConnectionSupported = FALSE,
Symbols
Add the following symbols to project settings -> Preprocessor. The ones in red are for integration of ntag_i2c_plus middleware and the one in green is for adding the NDEF library, please see below:

Include paths
Please add the following includes in project settings. The ones in red are for NTAG I²C Plus middleware and the ones in green for the NDEF Library, please see below:

With the previous setup it shall be able to run Bluetooth pairing example as for FRDM-KW41Z.
Hope this helps!