Enable I2C Serial Interface in Bluetooth KW41Z Heart Rate Sensor Demo Application

Document created by Sebastian Delrio Employee on Sep 11, 2019Last modified by Sebastian Delrio Employee on Nov 19, 2019
Version 7Show Document
  • View in full screen mode

Serial communication protocols are a very convenient way to transfer information between MCUs and other types of electronic devices; this guide will show a way to setup and enable an I2C Serial Interface to send a string of data instance using one of the Wireless Bluetooth SDK examples and the Serial Manager API.

 

Hardware Requirements:

  • FRDM-KW41Z development kit

Software Requirements:

  • MCUXpresso IDE version 10.3.1 or newer
  • KW41Z SDK with BLE stack and examples (It can be downloaded from the SDK Builder)

Serial Manager Setup as I2C Master

1. Import the freertos version of the “heart_rate_sensor” example included in the KW41Z’s SDK.

Note: Be sure to select UART as your debug console.

 

2. Increase the size of the heap that’s going to be used by the RTOS, as by default, the example is configured to only assign enough space for the original example to run.
To increase heap size, you should change the following macro to a bigger number, so that the RTOS has enough memory to create the required semaphore and queues for the Serial Manager:

#define gTotalHeapSize_c 9000

Also increase the number of serial manager instances by adding 1 to the value defined in the following macro:

#define gSerialManagerMaxInterfaces_c 1

Finally, make sure you disable the use of Power Down mode for this example by changing the following macro to a 0:

#define cPWR_UsePowerDownMode 0

These macros can be found in the app_preinclude.h header file, inside the source folder of the example project.

 

3. Create the new header and source files to which you will add your I2C related functions. For this example, we will name the files I2C_Test.h and I2C_Test.c, respectively.

 

4. Enable the desired Serial Interface macros in the SerialManager.h header file (...\framework\SerialManager\Interface\SerialManager.h); in this case, we will change the gSerialMgrUseIIC_c definition to a 1, so that the necessary functions and variables are added to the Serial Manager's code:

 

/* Defines which serial interface can be used */
#ifndef gSerialMgrUseUart_c
#define gSerialMgrUseUart_c (0)
#endif
#ifndef gSerialMgrUseUSB_c
#define gSerialMgrUseUSB_c (0)
#endif
#ifndef gSerialMgrUseUSB_VNIC_c
#define gSerialMgrUseUSB_VNIC_c (0)
#endif
#ifndef gSerialMgrUseIIC_c
#define gSerialMgrUseIIC_c (1)
#endif
#ifndef gSerialMgrUseSPI_c
#define gSerialMgrUseSPI_c (0)
#endif
#ifndef gSerialMgrUseCustomInterface_c
#define gSerialMgrUseCustomInterface_c (0)
#endif

 

5. Add function prototypes to your newly created header file for two functions, I2C_Init and I2C_send.
Also include the serial manager library:

#ifndef I2C_TEST_H_
#define I2C_TEST_H_

#include "SerialManager.h"

serialStatus_t I2C_Init(void);
void I2C_send(void);


#endif /* I2C_TEST_H_ */

NOTE: The gSerialMgrIICAddress_c macro can be used to change slave address for the I2C peripheral while in master mode.

 

6. Define the I2C instance that will be used, as well as a global variable for Identification purposes and a test string to send:

#define I2C_INSTANCE (1)

uint8_t I2C_peripheral_Id;
char test_data [] = "hello world";

Note: for this example we are using I2C1, but it’s also possible to enable I2C0 using this method by changing the I2C_INSTANCE definition to a 0.

 

7. Initialize the Serial Manager if it’s not already initialized, and create a new instance of it configured as a I2C Master:

serialStatus_t I2C_Init(void)
{
serialStatus_t serial_manager_status;
SerialManager_Init();

serial_manager_status = Serial_InitInterface(&I2C_peripheral_Id, gSerialMgrIICMaster_c,I2C_INSTANCE);

return serial_manager_status;
}

NOTE: The Serial_SetBaudRate function in the SerialManager.h header file can be used to change the BaudRate for a SerialManager instance.

 

8. Create a function to send your test string. For this function, we will call a Serial Manager function named Serial_Print, which takes a string and puts it in the Tx buffer to be sent to the serial manager instance:

void I2C_send(void)
{
Serial_Print(I2C_peripheral_Id, test_data, gNoBlock_d);
}

 

 

        9. To initialize our Serial Manager I2C instance, we will need to call the setup function during the MCU's initialization process. We should do this          before the          initialization of the BLE application. For this, we can use the BleApp_Init function in the heart_rate_sensor.c source file, and it          should look like this:

 

/*! *********************************************************************************
* \brief Initializes application specific functionality before the BLE stack init.
*
********************************************************************************** */

void BleApp_Init(void)
{
/* Initialize application support for drivers */
I2C_Init();
BOARD_InitAdc();
}

 

         9. Write a call to the function in a known part of the program. In this example we will add the call to SW3 Button Press event:

These events can be found inside the “BleApp_HandleKeys” function in the heart_rate_sensor.c source file.


case gKBD_EventPressPB2_c:
{
mToggle16BitHeartRate = (mToggle16BitHeartRate)?FALSE:TRUE;
I2C_send();
}

 

 

To see the output by using a logic analyzer, and if you’re using I2C1 as your Serial Manager instance, connect the SDA line to J2 pin 9, and the SCL  line to J2 pin 10.

Note: Also connect a GND line from the board to your logic analyzer, you can use J2 pin 7 as your GND connection.

When pressing SW3, you should see the following output:

This way, we are able to send a raw string of data to the default configured slave address, to send a more useful command via I2C to a sensor, for example, we can do the following changes to our Serial Manager configuration:

Interacting with the combo Accelerometer/Magnetometer sensor (FXOS8700CQ)

  • For this second example, we will communicate with the integrated Accelerometer/Magnetometer sensor (FXOS8700CQ) in the FRDM-KW41Z development board. The sensor is connected to pins 2 and 3 of Port C, so I2C1 will work fine, as we previously configured it to use those pins too.
  • The default slave address for the sensor is 0x1F, so we will need to change the gSerialMgrIICAddress_c definition in the SerialManager.h header file like so:
/* Defines the address of the slave when in master mode*/
#ifndef gSerialMgrIICAddress_c
#define gSerialMgrIICAddress_c (0x1FU)
#endif

NOTE: The slave address by default can only be changed with this macro

  • We will change the value for one of the sensor's internal registers. We will write a 0x38 to the Freefall/Motion configuration register so that we can detect freefall and motion on the X, Y and Z axes, so the new payload will have to contain the address for the internal register (which, according to the sensor's datasheet, is 0x15), and the new configuration value, which will be 0x38. The new payload should look like this:
uint8_t test_data [] = {0x15,0x38};
  • When sending the payload, this time we should get an acknowledge bit coming from the sensor, so the data transmission should look something like this:

The sensor is sending the ACK bit accordingly, and the data is being written to the sensor's specified register.

Attachments

Outcomes