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 set up and enable an I2C Serial Interface to send a string of data instances using one of the Wireless Bluetooth SDK examples and the Serial Manager API.
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 the 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 an 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 baud rate 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();
}
10. Write a call to the function in a known part of the program. In this example we will add the call to the 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:
/* 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
uint8_t test_data [] = {0x15,0x38};
The sensor is sending the ACK bit accordingly, and the data is being written to the sensor's specified register.