oled_sensor

Dependencies:   max32630fthr Adafruit_FeatherOLED_2020 USBDevice

Committer:
jonaangelica
Date:
Wed Mar 04 22:49:12 2020 +0000
Revision:
7:01495eb5d086
Parent:
6:980318add386
comm;

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jonaangelica 0:cc636f742803 1 /* mbed Microcontroller Library
jonaangelica 0:cc636f742803 2 * Copyright (c) 2006-2015 ARM Limited
jonaangelica 0:cc636f742803 3 *
jonaangelica 0:cc636f742803 4 * Licensed under the Apache License, Version 2.0 (the "License");
jonaangelica 0:cc636f742803 5 * you may not use this file except in compliance with the License.
jonaangelica 0:cc636f742803 6 * You may obtain a copy of the License at
jonaangelica 0:cc636f742803 7 *
jonaangelica 0:cc636f742803 8 * http://www.apache.org/licenses/LICENSE-2.0
jonaangelica 0:cc636f742803 9 *
jonaangelica 0:cc636f742803 10 * Unless required by applicable law or agreed to in writing, software
jonaangelica 0:cc636f742803 11 * distributed under the License is distributed on an "AS IS" BASIS,
jonaangelica 0:cc636f742803 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
jonaangelica 0:cc636f742803 13 * See the License for the specific language governing permissions and
jonaangelica 0:cc636f742803 14 * limitations under the License.
jonaangelica 0:cc636f742803 15 */
jonaangelica 0:cc636f742803 16
jonaangelica 0:cc636f742803 17 #include <events/mbed_events.h>
jonaangelica 0:cc636f742803 18 #include <mbed.h>
jonaangelica 4:727e58d27bf1 19 #include "max32630fthr.h"
jonaangelica 2:786c61e6532a 20 #include "Adafruit_SSD1306.h"//include the adafruit library for the oled display
jonaangelica 0:cc636f742803 21 #include "ble/BLE.h"
jonaangelica 0:cc636f742803 22 #include "ble/Gap.h"
jonaangelica 0:cc636f742803 23 #include "ble/services/HeartRateService.h"
jonaangelica 0:cc636f742803 24 #include "algorithm.h"
jonaangelica 0:cc636f742803 25 #include "MAX30102.h"
jonaangelica 0:cc636f742803 26
jonaangelica 0:cc636f742803 27 #define MAX_BRIGHTNESS 255
jonaangelica 0:cc636f742803 28
jonaangelica 0:cc636f742803 29
jonaangelica 0:cc636f742803 30
jonaangelica 0:cc636f742803 31 DigitalOut led2(LED2, 1);
jonaangelica 4:727e58d27bf1 32 MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
jonaangelica 0:cc636f742803 33
jonaangelica 0:cc636f742803 34 uint32_t aun_ir_buffer[500]; //IR LED sensor data
jonaangelica 0:cc636f742803 35 int32_t n_ir_buffer_length; //data length
jonaangelica 0:cc636f742803 36 uint32_t aun_red_buffer[500]; //Red LED sensor data
jonaangelica 0:cc636f742803 37 int32_t n_sp02; //SPO2 value
jonaangelica 0:cc636f742803 38 int8_t ch_spo2_valid; //indicator to show if the SP02 calculation is valid
jonaangelica 0:cc636f742803 39 int32_t n_heart_rate; //heart rate value
jonaangelica 0:cc636f742803 40 int8_t ch_hr_valid; //indicator to show if the heart rate calculation is valid
jonaangelica 0:cc636f742803 41 uint8_t uch_dummy;
jonaangelica 0:cc636f742803 42 uint32_t un_min, un_max, un_prev_data; //variables to calculate the on-board LED brightness that reflects the heartbeats
jonaangelica 0:cc636f742803 43 int i;
jonaangelica 0:cc636f742803 44 int32_t n_brightness;
jonaangelica 0:cc636f742803 45 float f_temp;
jonaangelica 0:cc636f742803 46 uint8_t hrmCounter;
jonaangelica 5:f18d3d0fe600 47
jonaangelica 6:980318add386 48 I2C I2c(P3_4, P3_5); // SDA, SCL
jonaangelica 6:980318add386 49 //I2C I2c(P5_7, P6_0); // SDA, SCL
jonaangelica 6:980318add386 50
jonaangelica 6:980318add386 51 Adafruit_SSD1306_I2c oled(I2c,0x78); //0111 1000
jonaangelica 0:cc636f742803 52
jonaangelica 0:cc636f742803 53 #ifdef TARGET_MAX32630FTHR
jonaangelica 0:cc636f742803 54 PwmOut led1(LED_RED); //initializes the pwm output that connects to the on board LED
jonaangelica 0:cc636f742803 55 DigitalIn INT(P3_0); //pin P30 connects to the interrupt output pin of the MAX30102
jonaangelica 0:cc636f742803 56 #endif
jonaangelica 0:cc636f742803 57
jonaangelica 0:cc636f742803 58 const static char DEVICE_NAME[] = "HRM";
jonaangelica 0:cc636f742803 59 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE};
jonaangelica 0:cc636f742803 60
jonaangelica 3:bb52b351d6f5 61
jonaangelica 0:cc636f742803 62 static HeartRateService *hrServicePtr;
jonaangelica 0:cc636f742803 63
jonaangelica 0:cc636f742803 64 static EventQueue eventQueue(/* event count */ 16 * EVENTS_EVENT_SIZE);
jonaangelica 0:cc636f742803 65
jonaangelica 0:cc636f742803 66 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params)
jonaangelica 0:cc636f742803 67 {
jonaangelica 0:cc636f742803 68 BLE::Instance().gap().startAdvertising(); // restart advertising
jonaangelica 0:cc636f742803 69 }
jonaangelica 0:cc636f742803 70
jonaangelica 6:980318add386 71 void OLEDInitialise(){
jonaangelica 6:980318add386 72
jonaangelica 6:980318add386 73 Thread::wait(500); // Give the supplies time to settle before initializing the display
jonaangelica 6:980318add386 74 oled.clearDisplay();
jonaangelica 6:980318add386 75 oled.display();
jonaangelica 6:980318add386 76 oled.setTextSize(3);
jonaangelica 6:980318add386 77 }
jonaangelica 6:980318add386 78
jonaangelica 6:980318add386 79 void OLEDTask(int8_t hrmCounter){
jonaangelica 6:980318add386 80
jonaangelica 6:980318add386 81 Thread::wait(500);
jonaangelica 6:980318add386 82 oled.clearDisplay();
jonaangelica 6:980318add386 83 oled.setTextCursor(0,0);
jonaangelica 6:980318add386 84 oled.printf("BP:%u", hrmCounter);
jonaangelica 6:980318add386 85 oled.display();
jonaangelica 6:980318add386 86
jonaangelica 6:980318add386 87 }
jonaangelica 6:980318add386 88
jonaangelica 0:cc636f742803 89 void checkHR(){
jonaangelica 0:cc636f742803 90
jonaangelica 0:cc636f742803 91 i=0;
jonaangelica 0:cc636f742803 92 un_min=0x3FFFF;
jonaangelica 0:cc636f742803 93 un_max=0;
jonaangelica 0:cc636f742803 94
jonaangelica 0:cc636f742803 95 //dumping the first 100 sets of samples in the memory and shift the last 400 sets of samples to the top
jonaangelica 0:cc636f742803 96 for(i=100;i<500;i++)
jonaangelica 0:cc636f742803 97 {
jonaangelica 0:cc636f742803 98 aun_red_buffer[i-100]=aun_red_buffer[i];
jonaangelica 0:cc636f742803 99 aun_ir_buffer[i-100]=aun_ir_buffer[i];
jonaangelica 0:cc636f742803 100
jonaangelica 0:cc636f742803 101 //update the signal min and max
jonaangelica 0:cc636f742803 102 if(un_min>aun_red_buffer[i])
jonaangelica 0:cc636f742803 103 un_min=aun_red_buffer[i];
jonaangelica 0:cc636f742803 104 if(un_max<aun_red_buffer[i])
jonaangelica 0:cc636f742803 105 un_max=aun_red_buffer[i];
jonaangelica 0:cc636f742803 106 }
jonaangelica 0:cc636f742803 107
jonaangelica 0:cc636f742803 108 //take 100 sets of samples before calculating the heart rate.
jonaangelica 0:cc636f742803 109 for(i=400;i<500;i++)
jonaangelica 0:cc636f742803 110 {
jonaangelica 0:cc636f742803 111 un_prev_data=aun_red_buffer[i-1];
jonaangelica 0:cc636f742803 112 while(INT.read()==1);
jonaangelica 0:cc636f742803 113 maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i));
jonaangelica 0:cc636f742803 114
jonaangelica 0:cc636f742803 115 if(aun_red_buffer[i]>un_prev_data)
jonaangelica 0:cc636f742803 116 {
jonaangelica 0:cc636f742803 117 f_temp=aun_red_buffer[i]-un_prev_data;
jonaangelica 0:cc636f742803 118 f_temp/=(un_max-un_min);
jonaangelica 0:cc636f742803 119 f_temp*=MAX_BRIGHTNESS;
jonaangelica 0:cc636f742803 120 n_brightness-=(int)f_temp;
jonaangelica 0:cc636f742803 121 if(n_brightness<0)
jonaangelica 0:cc636f742803 122 n_brightness=0;
jonaangelica 0:cc636f742803 123 }
jonaangelica 0:cc636f742803 124 else
jonaangelica 0:cc636f742803 125 {
jonaangelica 0:cc636f742803 126 f_temp=un_prev_data-aun_red_buffer[i];
jonaangelica 0:cc636f742803 127 f_temp/=(un_max-un_min);
jonaangelica 0:cc636f742803 128 f_temp*=MAX_BRIGHTNESS;
jonaangelica 0:cc636f742803 129 n_brightness+=(int)f_temp;
jonaangelica 0:cc636f742803 130 if(n_brightness>MAX_BRIGHTNESS)
jonaangelica 0:cc636f742803 131 n_brightness=MAX_BRIGHTNESS;
jonaangelica 0:cc636f742803 132 }
jonaangelica 0:cc636f742803 133 #if defined(TARGET_KL25Z) || defined(TARGET_MAX32630FTHR)
jonaangelica 0:cc636f742803 134 led1.write(1-(float)n_brightness/256);
jonaangelica 0:cc636f742803 135 #endif
jonaangelica 0:cc636f742803 136
jonaangelica 0:cc636f742803 137
jonaangelica 0:cc636f742803 138 }
jonaangelica 0:cc636f742803 139 maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
jonaangelica 6:980318add386 140
jonaangelica 6:980318add386 141
jonaangelica 0:cc636f742803 142 }
jonaangelica 0:cc636f742803 143
jonaangelica 0:cc636f742803 144 void updateSensorValue() {
jonaangelica 0:cc636f742803 145 // Do blocking calls or whatever is necessary for sensor polling.
jonaangelica 0:cc636f742803 146 // In our case, we simply update the HRM measurement.
jonaangelica 6:980318add386 147 checkHR();
jonaangelica 6:980318add386 148 if(ch_hr_valid==1&&ch_spo2_valid==1){
jonaangelica 6:980318add386 149 hrmCounter = (uint8_t)n_heart_rate;
jonaangelica 6:980318add386 150 hrServicePtr->updateHeartRate(hrmCounter);
jonaangelica 6:980318add386 151 OLEDTask(n_heart_rate);
jonaangelica 6:980318add386 152 }
jonaangelica 0:cc636f742803 153
jonaangelica 6:980318add386 154
jonaangelica 0:cc636f742803 155
jonaangelica 6:980318add386 156
jonaangelica 6:980318add386 157
jonaangelica 0:cc636f742803 158 }
jonaangelica 0:cc636f742803 159
jonaangelica 0:cc636f742803 160 void periodicCallback(void)
jonaangelica 0:cc636f742803 161 {
jonaangelica 0:cc636f742803 162
jonaangelica 0:cc636f742803 163 if (BLE::Instance().getGapState().connected) {
jonaangelica 0:cc636f742803 164 eventQueue.call(updateSensorValue);
jonaangelica 6:980318add386 165
jonaangelica 0:cc636f742803 166 }
jonaangelica 6:980318add386 167
jonaangelica 6:980318add386 168
jonaangelica 0:cc636f742803 169 }
jonaangelica 0:cc636f742803 170
jonaangelica 0:cc636f742803 171
jonaangelica 0:cc636f742803 172
jonaangelica 0:cc636f742803 173 void onBleInitError(BLE &ble, ble_error_t error)
jonaangelica 0:cc636f742803 174 {
jonaangelica 0:cc636f742803 175 (void)ble;
jonaangelica 0:cc636f742803 176 (void)error;
jonaangelica 0:cc636f742803 177 /* Initialization error handling should go here */
jonaangelica 0:cc636f742803 178 }
jonaangelica 0:cc636f742803 179
jonaangelica 0:cc636f742803 180 void printMacAddress()
jonaangelica 0:cc636f742803 181 {
jonaangelica 0:cc636f742803 182 /* Print out device MAC address to the console*/
jonaangelica 0:cc636f742803 183 Gap::AddressType_t addr_type;
jonaangelica 0:cc636f742803 184 Gap::Address_t address;
jonaangelica 0:cc636f742803 185 BLE::Instance().gap().getAddress(&addr_type, address);
jonaangelica 0:cc636f742803 186 printf("DEVICE MAC ADDRESS: ");
jonaangelica 0:cc636f742803 187 for (int i = 5; i >= 1; i--){
jonaangelica 0:cc636f742803 188 printf("%02x:", address[i]);
jonaangelica 0:cc636f742803 189 }
jonaangelica 0:cc636f742803 190 printf("%02x\r\n", address[0]);
jonaangelica 0:cc636f742803 191 }
jonaangelica 0:cc636f742803 192
jonaangelica 0:cc636f742803 193 void bleInitComplete(BLE::InitializationCompleteCallbackContext *params)
jonaangelica 0:cc636f742803 194 {
jonaangelica 0:cc636f742803 195 BLE& ble = params->ble;
jonaangelica 0:cc636f742803 196 ble_error_t error = params->error;
jonaangelica 0:cc636f742803 197
jonaangelica 0:cc636f742803 198 if (error != BLE_ERROR_NONE) {
jonaangelica 0:cc636f742803 199 onBleInitError(ble, error);
jonaangelica 0:cc636f742803 200 return;
jonaangelica 0:cc636f742803 201 }
jonaangelica 0:cc636f742803 202
jonaangelica 0:cc636f742803 203 if (ble.getInstanceID() != BLE::DEFAULT_INSTANCE) {
jonaangelica 0:cc636f742803 204 return;
jonaangelica 0:cc636f742803 205 }
jonaangelica 0:cc636f742803 206
jonaangelica 0:cc636f742803 207 ble.gap().onDisconnection(disconnectionCallback);
jonaangelica 0:cc636f742803 208
jonaangelica 0:cc636f742803 209 /* Setup primary service. */
jonaangelica 0:cc636f742803 210 hrServicePtr = new HeartRateService(ble, hrmCounter, HeartRateService::LOCATION_WRIST);//initially LOCATION_FINGER
jonaangelica 0:cc636f742803 211
jonaangelica 0:cc636f742803 212 /* Setup advertising. */
jonaangelica 0:cc636f742803 213 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE);
jonaangelica 0:cc636f742803 214 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list));
jonaangelica 0:cc636f742803 215 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR);
jonaangelica 0:cc636f742803 216 ble.gap().accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME));
jonaangelica 0:cc636f742803 217 ble.gap().setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED);
jonaangelica 0:cc636f742803 218 ble.gap().setAdvertisingInterval(1000); /* 1000ms */
jonaangelica 0:cc636f742803 219 ble.gap().startAdvertising();
jonaangelica 0:cc636f742803 220
jonaangelica 0:cc636f742803 221 printMacAddress();
jonaangelica 0:cc636f742803 222 }
jonaangelica 0:cc636f742803 223
jonaangelica 0:cc636f742803 224 void scheduleBleEventsProcessing(BLE::OnEventsToProcessCallbackContext* context) {
jonaangelica 0:cc636f742803 225 BLE &ble = BLE::Instance();
jonaangelica 0:cc636f742803 226 eventQueue.call(Callback<void()>(&ble, &BLE::processEvents));
jonaangelica 0:cc636f742803 227 }
jonaangelica 0:cc636f742803 228
jonaangelica 2:786c61e6532a 229
jonaangelica 2:786c61e6532a 230 void HRMSensorInitialise(){
jonaangelica 4:727e58d27bf1 231 maxim_max30102_reset(); //resets the MAX30102
jonaangelica 0:cc636f742803 232
jonaangelica 0:cc636f742803 233
jonaangelica 0:cc636f742803 234 //read and clear status register
jonaangelica 0:cc636f742803 235 maxim_max30102_read_reg(0,&uch_dummy);
jonaangelica 0:cc636f742803 236
jonaangelica 0:cc636f742803 237
jonaangelica 0:cc636f742803 238 maxim_max30102_init(); //initializes the MAX30102
jonaangelica 0:cc636f742803 239
jonaangelica 0:cc636f742803 240 n_brightness=0;
jonaangelica 0:cc636f742803 241 un_min=0x3FFFF;
jonaangelica 0:cc636f742803 242 un_max=0;
jonaangelica 0:cc636f742803 243
jonaangelica 0:cc636f742803 244 n_ir_buffer_length=500; //buffer length of 100 stores 5 seconds of samples running at 100sps
jonaangelica 0:cc636f742803 245
jonaangelica 0:cc636f742803 246 //read the first 500 samples, and determine the signal range
jonaangelica 0:cc636f742803 247 for(i=0;i<n_ir_buffer_length;i++)
jonaangelica 0:cc636f742803 248 {
jonaangelica 0:cc636f742803 249 while(INT.read()==1); //wait until the interrupt pin asserts
jonaangelica 0:cc636f742803 250
jonaangelica 0:cc636f742803 251 maxim_max30102_read_fifo((aun_red_buffer+i), (aun_ir_buffer+i)); //read from MAX30102 FIFO
jonaangelica 0:cc636f742803 252
jonaangelica 0:cc636f742803 253 if(un_min>aun_red_buffer[i])
jonaangelica 0:cc636f742803 254 un_min=aun_red_buffer[i]; //update signal min
jonaangelica 0:cc636f742803 255 if(un_max<aun_red_buffer[i])
jonaangelica 0:cc636f742803 256 un_max=aun_red_buffer[i]; //update signal max
jonaangelica 0:cc636f742803 257
jonaangelica 0:cc636f742803 258 }
jonaangelica 0:cc636f742803 259 un_prev_data=aun_red_buffer[i];
jonaangelica 0:cc636f742803 260
jonaangelica 0:cc636f742803 261 //calculate heart rate and SpO2 after first 500 samples (first 5 seconds of samples)
jonaangelica 0:cc636f742803 262 maxim_heart_rate_and_oxygen_saturation(aun_ir_buffer, n_ir_buffer_length, aun_red_buffer, &n_sp02, &ch_spo2_valid, &n_heart_rate, &ch_hr_valid);
jonaangelica 6:980318add386 263
jonaangelica 2:786c61e6532a 264 }
jonaangelica 2:786c61e6532a 265
jonaangelica 4:727e58d27bf1 266
jonaangelica 4:727e58d27bf1 267
jonaangelica 2:786c61e6532a 268 void HRMSensorTask(){
jonaangelica 6:980318add386 269
jonaangelica 0:cc636f742803 270 eventQueue.call_every(500, periodicCallback);
jonaangelica 0:cc636f742803 271 BLE &ble = BLE::Instance();
jonaangelica 0:cc636f742803 272 ble.onEventsToProcess(scheduleBleEventsProcessing);
jonaangelica 0:cc636f742803 273 ble.init(bleInitComplete);
jonaangelica 6:980318add386 274 eventQueue.dispatch_forever();
jonaangelica 0:cc636f742803 275
jonaangelica 2:786c61e6532a 276 }
jonaangelica 4:727e58d27bf1 277
jonaangelica 4:727e58d27bf1 278
jonaangelica 4:727e58d27bf1 279
jonaangelica 4:727e58d27bf1 280
jonaangelica 4:727e58d27bf1 281
jonaangelica 4:727e58d27bf1 282
jonaangelica 4:727e58d27bf1 283
jonaangelica 4:727e58d27bf1 284
jonaangelica 4:727e58d27bf1 285
jonaangelica 2:786c61e6532a 286
jonaangelica 5:f18d3d0fe600 287 int ack;
jonaangelica 5:f18d3d0fe600 288 char regaddr[1];
jonaangelica 5:f18d3d0fe600 289 char readdata[8]; // room for length and 7 databytes
jonaangelica 5:f18d3d0fe600 290 char writedata[9]; // room for reg address, length and 7 databytes
jonaangelica 5:f18d3d0fe600 291 DigitalOut bLED(LED3);
jonaangelica 5:f18d3d0fe600 292 DigitalOut gLED(LED2);
jonaangelica 5:f18d3d0fe600 293 int address;
jonaangelica 5:f18d3d0fe600 294 int addresses[2];
jonaangelica 5:f18d3d0fe600 295 char *dataBuff;
jonaangelica 5:f18d3d0fe600 296
jonaangelica 6:980318add386 297 /*
jonaangelica 6:980318add386 298 oled : 0x78
jonaangelica 6:980318add386 299 sensor write : 0xAE
jonaangelica 6:980318add386 300 sensor read : 0xAF
jonaangelica 6:980318add386 301 */
jonaangelica 2:786c61e6532a 302 int main()
jonaangelica 6:980318add386 303 {
jonaangelica 6:980318add386 304 OLEDInitialise();
jonaangelica 6:980318add386 305 Thread::wait(1000);
jonaangelica 6:980318add386 306 HRMSensorInitialise();
jonaangelica 6:980318add386 307 Thread::wait(500);
jonaangelica 5:f18d3d0fe600 308
jonaangelica 6:980318add386 309 bLED = LED_OFF;
jonaangelica 6:980318add386 310 gLED = LED_OFF;
jonaangelica 2:786c61e6532a 311
jonaangelica 2:786c61e6532a 312 while(1)
jonaangelica 2:786c61e6532a 313 {
jonaangelica 6:980318add386 314 HRMSensorTask();
jonaangelica 6:980318add386 315
jonaangelica 5:f18d3d0fe600 316 gLED = LED_ON;
jonaangelica 0:cc636f742803 317 }
jonaangelica 0:cc636f742803 318 }