• Ei tuloksia

BLE Application

In document A Healthcare Monitoring Device (sivua 31-0)

5. THE IMPLEMENTATION OF THE PROJECT

5.3. Application Structure

5.3.4. BLE Application

BLE Application consists of several functions:

• BleApp_init(), an initialization function of different peripherals

• BleApp_Start(), a start function which responds for starting advertising

• BleApp_HandleKeys(), a function for handling the buttons (board switches) events (this feature is used in the prototype)

• BleApp_GenericCallback(), BLE Generic callback, which is responsible ei-ther for configurating the BLE Stack by launching service after establishing a connection between the device and a phone or by starting the advertisement

• BleApp_Config(), a configuration of BLE Stack is used for setting up the advertisement, services, etc;

• BleApp_Advertise(), configuration and start of advertisement

• Callbacks for advertising, connection, GATT server, BleApp_Advertising-Callback(), BleApp_ConnectionCallback() and BleApp_GattServerCallback()

• LocalTimeTickTimerCallback() and MeasurementsTimerCallback() callback functions for a local timer and a measurement task timer

• UpdateMeasurementsTimerCallback() for a timed task for updating and up-loading the measurements to internal memory

32 Figure 12. The start of the application

BleApp_init() is launched inside the main thread function, initializing and starting the sensor measuring tasks; after that, the system waits for the interrupt signal from the button of a device which is sent upon the button press. As soon as the interrupt is received, the application configures the advertising parameters.

As soon as the advertising parameters are set, BleApp_GenericCallback() is trig-gered through the event system and starts advertising. BleApp_GenericCallback() also contains an option to start BleApp_Config() in case of an established connec-tion.

33 Figure 13. Generic Callback

App_StartAdvertising is called when the advertising parameters are set; it is a built-in function of Kbuilt-inetis SDK which is responsible for advertisbuilt-ing functionality. If the initialization is complete, BleApp_Config is called.

Figure 14. BleApp_Config() source code

BleConnManager_GapPeripheralConfig() configures the Generic Access Profile peripheral; App_RegisterGattServerCallback sets BleApp_GattServerCallback function as a callback for a GATT server; after that the advertisement variable mAdvState.advOn is set to false to stop advertising, this variable is used later in advertising callback function; then data buffer inside rsServiceConfig structure is

34

set to its default value and starts “Ring Service” by launching Rs_Start function with the reference to the service configuration structure as an argument.

BleApp_ConnectionCallback is called whenever an event linked with connection activities occurs. It begins with the connection manager which fetches event from the Host Stack of BLE.

Figure 15. BleApp_ConnectionCallback diagram

The callback decides whether the application should stop advertising and start BLE service or it should execute BleApp_Start, which simply re-enables advertising.

Rs_Subscribe and Rs_Unsubscribe are service functions, which subscribe GATT client to and unsubscribe GATT client from the Ring service.

35 5.3.5. GATT Profile

Firstly, the GATT profile should be defined. Kinetis SDK provides two files which should be modified if one wants to set up a custom profiles: gatt_uuid128.h and gatt_db.h.

gatt_uuid128.h contains custom 128-bit UUID for services and characteristics.

Figure 16. gatt_uuid128.h

As can be seen from the picture, 128-bit UUIDs for the name characteristic (uuid_service_ring) and the data characteristic (uuid_datachar) are set.

Then service structure should be defined in gatt_db.h file.

Figure 17. gatt_db.h

Service has custom id 0x1825. It has two characteristics:

1. char_device_name which stands for device name characteristic; it is reada-ble and has value “RINGA”

2. char_data which stands for data characteristic; it is readable and contains 20 bytes data buffer; it also contains Client Characteristic Configuration De-scriptor (CCCD) which defines deDe-scriptor for previous characteristic (char_data).

The next step of creating BLE service is to define service functions.

36 5.3.6. BLE Service Functions

Once the GATT profile is configured, drivers are required to handle and to respond to client’s requests properly. Two files were created: ring_service.c and ring_inter-face.h. ring_interface.h consists definitions of functions and data types required for the service functionality; ring_service.c contains service functions.

Functions:

• bleResult_t Rs_Start(rsConfig_t *rServiceConfig) – start service

• bleResult_t Rs_Stop(rsConfig_t *rServiceConfig) = stop service

• bleResult_t Rs_Subscribe(deviceId_t clientDeviceId) – subscribe a specific client to a service

• bleResult_t Rs_Unsubscribe() – unsubscribe a specific client from a service

• bleResult_t Rs_SetService(uint16_t handle, uint8_t* data) – writes data characteristic and invokes Rs_SendDataNotification

• bleResult_t Rs_RecordData(uint16_t serviceHandle, uint8_t* data) – writes data to GATT database making it possible to obtain the data by client

• void Rs_SendDataNotification(uint16_t serviceHandle) – send notification to a client

Data types:

• struct rsConfig_tag, which is also redefined as rsConfig_t

• bleResult_t is pre-defined enum variable type with values for different out-comes

Figure 18. rsConfig_t structure

The objective of the rsConfig_t structure is to store the configuration of service. Its elements are 16bit service handle, which is used as an identification number inside BLE Stack, and 20 bytes data buffer, which is a part of data characteristic.

37

5.3.7. Sensors Interface and Drivers Implementation

This device collects values of such characteristics as: a temperature, a light reflec-tion and steps taken by a user. Those characteristics could be measured with the use of the sensors, which were described in the section 2.1: temperature sensor, LED driver with installed LEDs and a photodiode, IMU. To set up the communication between RTOS and those peripherals, the drivers, which should provide the con-nection to the interfaces of I2C, ADC, GPIO, as it is shown in figure 10, section 5.3, should be written. Kinetis SDK provides functionality for I2C, ADC, GPIO, leaving to write driver code and generalized functions for interfaces.

5.3.8. I2C

I2C interface is supposed to have this functionality:

1. Initializing the transfer 2. Sending commands 3. Receiving commands

In order to initialize I2C communication, device should perform:

1. A release bus function (sequence of 1’s and 0’s sent via SDA and SCL lines using GPIO driver)

2. Initializing board’s ports with specific configuration

3. Creating of the configuration structure and obtaining the frequency of the core clock, these actions are required for initializing master transfer

4. Creating of the master transfer handle with a specified callback function

Figure 19. I2C_init_transfer function

38

As soon as I2C transfer is initialized, MCU is able to communicate with peripherals.

The principle of the communication in Kinetis SDK is similar for both reading and writing:

1. Set up of the transfer of the configuration structure 2. Start the transfer

3. Wait until one of flag variables (acknowledge and completion flags) changes its value from 0 to 1 inside a callback function

Figure 20. I2C_sendcmd function

The difference between sending and receiving bits by using Kinetis SDK is a change in the direction member of the transfer structure i2cmasterXfer from kI2C_Write to kI2C_Read.

retval is a variable for a return value, the function returns 0 on a successful transfer and returns -2 in case of the communication error.

39 Figure 21. Callback function

Callback function is called every time a peripheral device sends acknowledge and completion bits, it can be seen in figure 19, that this function is passed to I2C_Mas-terTransferCreateHandle() as an argument.

5.3.9. Other Peripheral Interfaces

ADC and GPIO peripherals are also used in this project but those modules do not have as much repetitive code as I2C driver thus making it not necessary to create routines for them. However, ADC initialization function was created.

Figure 22. ADC initialization

ADC is used for the light diode and requires choosing a certain ADC channel as there are several pins which can be used as the ADC input.

5.3.10. IMU

Bosch BMI160 requires I2C to intercommunicate with the host. In terms of the pplication it means that code with the specific commands and routines should be written in conjunction with I2C interface described before. Such driver code was provided by Bosch Sensortec.

In this project, the IMU serves as a step detector and a step counter: every time a step detector detects that a step is taken, BMI160 triggers an interrupt. According

40

to BMI160 Data Sheet and BMI160 driver code usage guide, a device should be initialized firstly.

Figure 23. BMI160 initialization function

This function initializes the device by setting up the structure of a structure type bmi160_dev which consists of a device address (I2C address in this case), read, write and millisecond delay functions and calling bmi160_init function with this structure passed as an argument. bmi160_init checks the chip ID number of the connected device and if the number matches, the device is soft-reset.

Figure 24. Configuration of the setup function

The next step is the configuration of power usage. This can be achieved by modi-fying the device structure configuration by setting the accelerometer and gyroscope

41

power configuration.

Figure 25. Interrupt configuration function

Figure 26. Kinetis SDK GPIO interrupt configuration

Then the configuring of the interrupt is ready to be done. The interrupt configura-tion is done by calling bmi160_set_int_config funcconfigura-tion, and GPIO hardware inter-rupt on MCU’s side is set by configuring PORT and GPIO modules of Kinetis SDK.

42 Figure 27. Fast Offset Compensation

Then the start_foc function is called to configurate offsets for higher measuring accuracy.

The last step of the device initialization is setting it to the low-power mode.

Figure 28. Enabling of low-power mode of BMI160

After that, BMI160 is configured, and the interrupt handler for step detection should be written.

43 Figure 29. BMI160 Interrupt handler

Every time the step detector detects a step, the signal is sent via output pin of IMU and sent to GPIO port of a microcontroller. The microcontroller’s interrupt is trig-gered on a signal change and it executes bmi160_read_step_counter() function which records the step amount to global variable g_step_count, that will be used later in a project.

5.3.11. Temperature sensor

LM75B is used in this project for the temperature measurement and it operates over I2C.

According to LM75B documentation, the measured temperature value can be ob-tained by sending a read command over I2C to the sensors register with the address 0x00.

Figure 30. Function for reading the sensor value

The value also should be converted. The sensor returns two data bytes which should be converted by bit-shifting of these bytes, three to the left for the first byte and five to the right for the second byte, because the five least significant bits are equal to 0 and should be ignored, and by performing logical OR operation on those bytes to obtain one value. If the first element of the first data byte is equal to 1, logical OR should be performed on hexadecimal number 0xF800 and the value, obtained by

44

the previous bit-shifting operations, in order to find a two’s complement of the tem-perature data. After that, the resulting value should be multiplied by 0.125 and type casted to float.

Figure 31. Function for converting a read value

Both functions can be wrapped into one function.

Figure 32. LM75B measuring function

The temperature is measured five times and then the average value is returned.

5.3.12. LED and Light Sensor

This section consists of two parts: an LED driver and an analog light sensor oper-ating. An LED driver is supposed to turn on and off certain LED in a defined period;

MCU’s ADC fetches the voltage across the light sensor when the LED is turned on.

LED driver operates over I2C, the photodiode’s value can be read through the ADC peripheral.

As ADC initialization has been already explained in the section 5.3.9, the LED driver control and the obtainment of an ADC value are the things to be considered.

LED driver code is for this thesis in the same manner as Bosch BMI160 driver code, i.e. there were several structure types defined for different operational modes and

45

functions of LED driver and the functions for features of this driver were developed.

However, in this case this peripheral requires resetting of the LED driver device and the function for turning on LEDs.

Figure 33. Initialization of LTC3207 and SFH 2201

Structure ltc3207_dev defines an LTC3207 address, a write function (since this de-vice is read-only) and a delay function. The reset function sets the command register to quick write, which allows to write to all LEDs (Ref. LTC3207 application note

& documentation), sets LEDs to 0 voltage, turns off external enable control and blinking features and disables quick write.

As soon as the initialization is finished, this device conjunction is ready to be used.

Figure 34. Light measuring function

Firstly, a certain LED should be turned on. LED_power is a function which is ded-icated to change the power of a certain LED in a normal operational mode /16/. Its

46

arguments are LED’s number, amount of the voltage which should be given and a device structure, which resembles the device structure of BMI160 driver.

Figure 35. ltc3207_dev structure

When an LED is turned on, ADC configures a needed channel (it is necessary to reconfigure the channel after reading of its status) and records the data from light diode via ADC for 100 times. The average value of the recorded data is converted from a 16 bit unsigned integer to two 8bit unsigned integer array, since the BLE buffer consists of 20 8-bit elements, as it described in the section 2.2.3.

Figure 36. LED_power function

LED_power contains ltc3207_set_uled function, which sets the universal led to a certain mode and to a certain voltage level.

47 Figure 37. ltc3207_set_uled function

5.3.13. Ring buffer

The ring buffer structure of this project is a structure with two integer elements for head and tail elements and the array of 20 bytes arrays where each 20 byte array is the information to send over BLE. In the case of this project, the ring buffer over-writes data if the buffer is full.

Figure 38. Ring buffer structure

Figure 39. Ring buffer initialization function

Initialization function RBUFF_init() sets every value of every element of globally defined ring buffer to zero.

48

Figure 40. Function for adding elements to a buffer

Figure 41. __fill_in_buff()

RBUFF_add_element function adds new 20 byte array from a globally stored g_sensors_data_buff, which is used in global sensors interface, by calling __fill_in_buff() routine. __increment_index() is a routine which increments head or tail and manages the case when the value of the argument is equal to maximum size of a ring buffer.

Figure 42. Function for obtaining elements from a buffer

49

RBUFF_get_element() obtains an element of the ring buffer, removes it from the same ring buffer and stores the obtained data in an array, which reference is pro-vided as an argument of this function. __free_data_buff() sets every value of a tail element to zero.

5.3.14. Global Sensors Interface Implementation

Global sensors interface is a function which wraps all the previously described in-terfaces and stores the obtained data into a ring buffer structure.

Figure 43. Sensors interface initialization

To initialize a global sensors interface, the next steps are proceeded:

1. Set the global sensor buffer to 0 2. Initialize the I2C transfer

3. Enable ADC and initialize the LTC3207 device 4. Enable the accelerometer interrupt pin

5. Initialize the BMI160 device 6. Initialize the global ring buffer

As soon as every part of global sensor interface is initialized, the device is ready to measure the necessary values and store them in the ring buffer by calling sen-sors_interface_measure() procedure.

50 Figure 44. sensors_interface_measure procedure

This function collects information described in section 14: LED/photodiode con-junction values are obtained by calling LED_measure, the temperature is collected by executing LM75B_measure, and set_steps() sets steps detected by the accel-erometer to the global sensor buffer. After that, the data, which is contained in the global sensor buffer, is added to the global ring buffer.

51 6. TESTING

This chapter describes the testing phase of the project. The point of this chapter is to show how the testing was done as well as show the results of the testing.

6.1. Preparations

Firstly, necessary equipment should be prepared for testing. The used equipment was:

• A KW41Z microcontroller board with a micro-USB cable plugged to the working PC

• A PC with installed Kinetis SDK and the suitable drivers

• An Android mobile phone with the custom application for communicating with the smart wearable unit (the development board in this case)

• The conjunction of a photodiode and LTC3207

• A BMI160 sensor

• A LM75B sensor

• A breadboard

• Resistors, capacitors, wires, etc

Figure 45. Prototype testing configuration

52

Secondly, all of the components were connected to the microcontroller board the way it was described in section 5.1. Each of the sensors is connected to the common ground and to the common voltage source (GND and P3V3 board pins); each sensor having I2C is connected to I2C lanes leading to PTC2 and PTC3 and each of I2C connection has a pull up resistor to the voltage source.

Thirdly, MCUXpresso software with installed Kinetis SDK was run and the firm-ware for a wearable unit was loaded to the board.

After every connection was made and the firmware was loaded, the microprocessor started the program, the LED driver started lighting up LEDs in certain order, sen-sors started measuring necessary data and the BLE module started advertising.

6.2. Testing phase

The testing phase has several stages. The first stage is a test of BLE connection between microcontroller board and the mobile phone application. During this stage, the buffer containing 1XXX XXXX XXXX XXXX XXX1 bytes, where X is either 1 or 0, was sent to the mobile phone periodically. As soon as the mobile application started to correctly receive packages, the testing process moved to the next stage.

The second stage of testing is to check the microcontroller’s ability of obtaining the data from sensors. In order to proceed this testing step, the source code for each module (the LED driver and light sensor conjunction, the temperature sensor, the accelerometer source code) was carried out to separate projects and was tested in-dividually. After completing this stage, the testing of functionality of the ring buffer was performed.

During the third of stage, the ring buffer was made to gather and to remove (push and pop operations) random data periodically. When the ring buffer successfully performed processing of incoming and outcoming data, the testing phase moved to the last step of the complete testing of the system.

The objective of this step is to make each part of the project work with the other parts. The source code of the sensors and the ring buffer was integrated into the BLE source code. The sensors successfully obtained data and passed it to the board;

the ring buffer interface was able to store in and return data from the ring buffer;

53

finally, the BLE connection between the board and the application was established and the data was correctly sent via a Bluetooth connection.

The whole testing went successfully, and the project was made to operate as desired without any flaws: the sensor data was gathered, stored and sent over a Bluetooth connection. The mobile phone application received exactly the same information the microcontroller board sent to it.

54

7. CONCLUSION AND FUTURE WORK

In this thesis project, the prototype of a device was built and the software for that device was written to provide the base for a mobile health-monitoring skin-analyz-ing device as a solution. The goal was to develop a firmware for a low-power device which can operate the sensors, store the information gathered from sensors in the internal memory and send it with the use of Bluetooth Low-Energy technology.

The developed system is made of a Kinetis® KW41Z microcontroller board, a LED

The developed system is made of a Kinetis® KW41Z microcontroller board, a LED

In document A Healthcare Monitoring Device (sivua 31-0)