Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependencies: BLE_API mbed nRF51822 paw8001motion25_nrf51_mbed_keil
Fork of BLE_HeartRate by
main.cpp
00001 /* mbed Microcontroller Library 00002 * Copyright (c) 2006-2013 ARM Limited 00003 * 00004 * Licensed under the Apache License, Version 2.0 (the "License"); 00005 * you may not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an "AS IS" BASIS, 00012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 00017 #include "mbed.h" 00018 #include "BLEDevice.h" 00019 #include "HeartRateService.h" 00020 #include "BatteryService.h" 00021 #include "DeviceInformationService.h" 00022 00023 BLEDevice ble; 00024 DigitalOut led1(LED1); 00025 /* --------------------------------------------------------------- 00026 * Below for PAH8001 code 00027 *///-------------------------------------------------------------- 00028 #include "app_util_platform.h" 00029 #include "nrf_soc.h" 00030 #include "app_util.h" 00031 #include "PAH8001Set.h" 00032 extern "C" 00033 { 00034 #include "pxialg.h" 00035 } 00036 Serial pc(USBTX, USBRX); 00037 I2C i2c(I2C_SDA0, I2C_SCL0); 00038 Ticker ticker; 00039 /* Power optimized, 1.0mA @disconnection, 4.5mA @connection */ 00040 #define MIN_CONN_INTERVAL MSEC_TO_UNITS(379, UNIT_1_25_MS) /**< Minimum connection interval (379 ms) */ 00041 #define MAX_CONN_INTERVAL MSEC_TO_UNITS(399, UNIT_1_25_MS) /**< Maximum connection interval (399 ms). */ 00042 #define SLAVE_LATENCY 4 /**< Slave latency. */ 00043 #define CONN_SUP_TIMEOUT MSEC_TO_UNITS(6000, UNIT_10_MS) /**< Connection supervisory timeout (6 seconds). */ 00044 /* --------------------------------------------------------------- 00045 * End of PAH8001 code 00046 *///-------------------------------------------------------------- 00047 00048 const static char DEVICE_NAME[] = "PixArt_HRmbed"; 00049 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE, 00050 GattService::UUID_BATTERY_SERVICE, 00051 GattService::UUID_DEVICE_INFORMATION_SERVICE}; 00052 /* --------------------------------------------------------------- 00053 * Below for PAH8001 code 00054 *///-------------------------------------------------------------- 00055 static volatile bool triggerSensorPolling = false; 00056 void disconnectionCallback(Gap::Handle_t handle, Gap::DisconnectionReason_t reason) 00057 { 00058 ble.startAdvertising(); // restart advertising 00059 triggerSensorPolling = false; 00060 } 00061 void onconnectionCallback(Gap::Handle_t handle, Gap::addr_type_t peerAddrType, const Gap::address_t peerAddr, const Gap::ConnectionParams_t *p_conn_param) 00062 { 00063 triggerSensorPolling = true; 00064 Gap::ConnectionParams_t gap_conn_params; 00065 gap_conn_params.minConnectionInterval = MIN_CONN_INTERVAL; 00066 gap_conn_params.maxConnectionInterval = MAX_CONN_INTERVAL; 00067 gap_conn_params.slaveLatency = SLAVE_LATENCY; 00068 gap_conn_params.connectionSupervisionTimeout = CONN_SUP_TIMEOUT; 00069 ble.updateConnectionParams(handle, &gap_conn_params); 00070 } 00071 00072 void periodicCallback(void) 00073 { 00074 if(triggerSensorPolling == true){ 00075 HR_Cnt++; 00076 CRITICAL_REGION_ENTER(); 00077 Pixart_HRD(); 00078 CRITICAL_REGION_EXIT(); 00079 } 00080 else 00081 HR_Cnt = 0; 00082 } 00083 00084 int main(void) 00085 { uint8_t tmp; 00086 pc.baud (115200); 00087 pc.printf("\n\rStart initialization\n\r"); 00088 00089 led1 = 1; 00090 PAH8001_init(); //PAH8001 initialization 00091 00092 ble.init(); 00093 ble.onDisconnection(disconnectionCallback); 00094 ble.onConnection(onconnectionCallback); 00095 00096 /* Setup primary service. */ 00097 uint8_t hrmCounter = 100; 00098 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); 00099 00100 /* Setup auxiliary services. */ 00101 BatteryService battery(ble); 00102 DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); 00103 00104 /* Setup advertising. */ 00105 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00106 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 00107 ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); 00108 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 00109 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00110 ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */ 00111 ble.startAdvertising(); 00112 00113 pc.printf("Before while 1\n\r"); 00114 while (true) { 00115 if(triggerSensorPolling == true){ 00116 if(!isFIFOEmpty()) 00117 { 00118 led1 = 1; 00119 //pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]); 00120 if(Pop(&ppg_mems_data)) //Get data from FIFO 00121 { 00122 MEMS_Data[0] = ppg_mems_data.MEMS_Data[0]; 00123 MEMS_Data[1] = ppg_mems_data.MEMS_Data[1]; 00124 MEMS_Data[2] = ppg_mems_data.MEMS_Data[2]; 00125 00126 tmp = PxiAlg_Process(ppg_mems_data.HRD_Data, MEMS_Data); 00127 //if( tmp == FLAG_DATA_READY) 00128 if( tmp != FLAG_DATA_READY) 00129 { 00130 pc.printf("AlgoProcssRtn: %d\n\r", tmp); 00131 pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]); 00132 } 00133 else 00134 { 00135 //Check Flag 00136 } 00137 00138 //ready_flag = PxiAlg_GetReadyFlag(); 00139 //motion_flag = PxiAlg_GetMotionFlag() ; 00140 } 00141 led1 = 0; 00142 } 00143 if(HR_Cnt > HR_Rpt) 00144 { 00145 HR_Cnt = 0; 00146 PxiAlg_HrGet(&myHR); 00147 pc.printf("HR: %d\n\r", (uint8_t)myHR); 00148 00149 hrmCounter = (uint8_t)myHR; 00150 hrService.updateHeartRate(hrmCounter); 00151 } 00152 } 00153 else 00154 ble.waitForEvent(); 00155 } 00156 } 00157 00158 00159 00160 void PAH8001_init() 00161 { uint8_t q; 00162 uint8_t bank=0, temp; 00163 00164 if(readRegister(0x00) == 0x30) 00165 pc.printf("PAH8001 I2C Link Successful!\n\r"); 00166 else 00167 pc.printf("PAH8001 I2C Link Fail!\n\r"); 00168 00169 alg_version = PxiAlg_Version(); 00170 pc.printf("Algo Ver: %d\n\r", alg_version); 00171 PxiAlg_EnableFastOutput(true); 00172 00173 #ifdef DEBUG_8001 00174 writeRegister(0x09, 0x5A); writeRegister(0x54, 0xEE); 00175 pc.printf("\n\r~~~Start Test Pattern~~~ \n\r"); 00176 pc.printf("Reg0x09: %d\n\r", readRegister(0x09)); 00177 pc.printf("Reg0x54: %d\n\r", readRegister(0x54)); 00178 pc.printf("Reg0x1E: %d\n\r", readRegister(0x1E)); 00179 00180 float MEMS_Data[3] = {0 ,0, 0}; //apply test pattern 00181 float myHR = 0 ; 00182 for(q=0;q<PPG_PATTERN_SIZE;q++) 00183 PxiAlg_Process((unsigned char*)PPG_Data[q], MEMS_Data); 00184 PxiAlg_HrGet(&myHR); 00185 pc.printf("HR: %f\n\r", myHR); 00186 pc.printf("~~~End of Test Pattern~~~ \n\r"); 00187 while(1); 00188 #endif 00189 00190 #ifndef DEBUG_8001 00191 ticker.attach_us(&periodicCallback, PAH8001_Poll*1000); 00192 00193 pc.printf("\n\r~~~Start Real-time HRM~~~ \n\r"); 00194 //Initialization settings 00195 writeRegister(0x06, 0x82); //Reset sensor 00196 wait_ms(10); //make a delay 00197 00198 for(q=0;q<INIT_PPG_REG_ARRAY_SIZE;q++){ 00199 if(init_ppg_register_array[q][0] == 0x7F) 00200 bank = init_ppg_register_array[q][1]; 00201 00202 if((bank == 0) && (init_ppg_register_array[q][0] == 0x17) ) 00203 { 00204 //read and write bit7=1 00205 temp = readRegister(0x17); 00206 temp |= 0x80 ; 00207 writeRegister(0x17, temp) ; 00208 } 00209 else 00210 writeRegister(init_ppg_register_array[q][0], init_ppg_register_array[q][1]); 00211 } 00212 #endif 00213 } 00214 00215 void writeRegister(uint8_t addr, uint8_t data) 00216 { 00217 char data_write[2]; 00218 00219 data_write[0] = addr; 00220 data_write[1] = data; 00221 i2c.write(I2C_ADDR, data_write, 2, 0); 00222 } 00223 uint8_t readRegister(uint8_t addr) 00224 { 00225 char data_write[2]; 00226 char data_read[2]; 00227 00228 data_write[0] = addr; 00229 i2c.write(I2C_ADDR, data_write, 1, 0); 00230 i2c.read(I2C_ADDR, data_read, 1, 0); 00231 return data_read[0]; 00232 } 00233 00234 bool Pixart_HRD(void) 00235 { 00236 uint8_t tmp=0; 00237 char data_write[2]; 00238 char data_read[4]; 00239 ppg_mems_data_t ppg_mems_data; 00240 //Check Touch Status for power saving 00241 writeRegister(0x7F,0x00); //bank0 00242 tmp = readRegister(0x00); 00243 tmp = readRegister(0x59)&0x80; 00244 led_ctrl(tmp); 00245 00246 //writeRegister(0x7F,0x01); //bank1 00247 ppg_mems_data.HRD_Data[0]=readRegister(0x68)&0x0f; //check status: 0 is not ready, 1 is ready, 2 is loss one data? 00248 00249 if(ppg_mems_data.HRD_Data[0] ==0) 00250 { 00251 writeRegister(0x7F,0x00); //bank0 00252 return false; 00253 } 00254 else 00255 { 00256 //Only support burst read (0x64~0x67), when using I2C interface 00257 data_write[0] = 0x64; 00258 i2c.write(PAH8001_ADDR, data_write, 1, 1); 00259 i2c.read(PAH8001_ADDR, data_read, 4, 0); 00260 ppg_mems_data.HRD_Data[1]=data_read[0]&0xff; 00261 ppg_mems_data.HRD_Data[2]=data_read[1]&0xff; 00262 ppg_mems_data.HRD_Data[3]=data_read[2]&0xff; 00263 ppg_mems_data.HRD_Data[4]=data_read[3]&0xff; 00264 00265 //Only support burst read (0x1A~0x1C), when using I2C interface 00266 data_write[0] = 0x1A; 00267 i2c.write(PAH8001_ADDR, data_write, 1, 1); 00268 i2c.read(PAH8001_ADDR, data_read, 3, 0); 00269 ppg_mems_data.HRD_Data[5]=data_read[0]&0xff; 00270 ppg_mems_data.HRD_Data[6]=data_read[1]&0xff; 00271 ppg_mems_data.HRD_Data[7]=data_read[2]&0xff; 00272 00273 ppg_mems_data.HRD_Data[8]=Frame_Count++; 00274 ppg_mems_data.HRD_Data[9]=40; 00275 ppg_mems_data.HRD_Data[10]=_led_current_change_flag; 00276 writeRegister(0x7F,0x00); //bank0 00277 //bit7 is Touch Flag (bit7=1 is meant Touch, and bit7=0 is meant No Touch) 00278 ppg_mems_data.HRD_Data[11]=(readRegister(0x59)&0x80); //Check Touch Flag 00279 ppg_mems_data.HRD_Data[12]= ppg_mems_data.HRD_Data[6]; 00280 00281 //If no G sensor, please set G_Sensor_Data[3] = {0}; 00282 ppg_mems_data.MEMS_Data[0] = 0;//ReadGSensorX(); 00283 ppg_mems_data.MEMS_Data[1] = 0;//ReadGSensorY(); 00284 ppg_mems_data.MEMS_Data[2] = 0;//ReadGSensorZ(); 00285 Push(&ppg_mems_data); //Save data into FIFO 00286 00287 return true; 00288 } 00289 } 00290 00291 bool isFIFOEmpty(void) 00292 { 00293 return (_write_index == _read_index); 00294 } 00295 00296 bool Push(ppg_mems_data_t *data) 00297 { 00298 int tmp = _write_index; 00299 tmp++; 00300 if(tmp >= FIFO_SIZE) 00301 tmp = 0; 00302 if(tmp == _read_index) 00303 return false; 00304 _ppg_mems_data[tmp] = *data; 00305 _write_index = tmp; 00306 00307 return true; 00308 } 00309 00310 bool Pop(ppg_mems_data_t *data) 00311 { 00312 int tmp; 00313 if(isFIFOEmpty()) 00314 return false; 00315 *data = _ppg_mems_data[_read_index]; 00316 tmp = _read_index + 1; 00317 if(tmp >= FIFO_SIZE) 00318 tmp = 0; 00319 _read_index = tmp; 00320 00321 return true; 00322 } 00323 00324 /***********************LED Control Start***********************************/ 00325 void led_ctrl(uint8_t touch) { 00326 if(touch == 0x80) { 00327 uint8_t data; 00328 //uint16_t Frame_Average, EP_L, EP_H, Exposure_Line; 00329 uint16_t EP_L, EP_H, Exposure_Line; 00330 writeRegister(0x7f,0x00); 00331 writeRegister(0x05,0x98); 00332 writeRegister(0x7f,0x01); 00333 //writeRegister(0x42,0xA4); 00334 writeRegister(0x7f,0x00); 00335 data = readRegister(0x33); 00336 EP_H=data&0x03; 00337 data = readRegister(0x32); 00338 EP_L=data; 00339 Exposure_Line=(EP_H<<8)+EP_L; 00340 writeRegister(0x7f,0x01); 00341 if(_sleepflag==1) { 00342 writeRegister(0x38, (0xE0|DEFAULT_LED_STEP)); 00343 _sleepflag = 0 ; 00344 } 00345 00346 if (_state_count <= STATE_COUNT_TH) { 00347 _state_count++; 00348 _led_current_change_flag = 0; 00349 } 00350 else { 00351 _state_count = 0; 00352 if(_state == 0) { 00353 if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) || (Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) ) { 00354 //writeRegister(0x7f,0x01); 00355 data = readRegister(0x38); 00356 _led_step=data&0x1f; 00357 if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) && (_led_step < LED_CURRENT_HI) ) { 00358 _state = 1 ; 00359 _led_step=_led_step+LED_INC_DEC_STEP; 00360 00361 if(_led_step>LED_CURRENT_HI) 00362 _led_step=LED_CURRENT_HI; 00363 writeRegister(0x38, (_led_step|0xE0)); 00364 _led_current_change_flag = 1; 00365 } 00366 else if((Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) && (_led_step > LED_CURRENT_LOW) ) { 00367 _state = 2 ; 00368 if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP)) 00369 _led_step=LED_CURRENT_LOW; 00370 else 00371 _led_step=_led_step-LED_INC_DEC_STEP; 00372 writeRegister(0x38, (_led_step|0xE0)); 00373 _led_current_change_flag = 1; 00374 } 00375 else { 00376 _state = 0 ; 00377 _led_current_change_flag = 0; 00378 } 00379 } 00380 else { 00381 _led_current_change_flag = 0; 00382 } 00383 } 00384 else if(_state == 1) { 00385 if(Exposure_Line > LED_CTRL_EXPO_TIME_HI) { 00386 _state = 1 ; 00387 _led_step=_led_step+LED_INC_DEC_STEP; 00388 if(_led_step>=LED_CURRENT_HI) { 00389 _state = 0 ; 00390 _led_step=LED_CURRENT_HI; 00391 } 00392 writeRegister(0x38, (_led_step|0xE0)); 00393 _led_current_change_flag = 1; 00394 } 00395 else { 00396 _state = 0 ; 00397 _led_current_change_flag = 0; 00398 } 00399 } 00400 else { 00401 if(Exposure_Line < LED_CTRL_EXPO_TIME_LOW) { 00402 _state = 2 ; 00403 if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP)) { 00404 _state = 0 ; 00405 _led_step=LED_CURRENT_LOW; 00406 } 00407 else 00408 _led_step=_led_step-LED_INC_DEC_STEP; 00409 writeRegister(0x38, (_led_step|0xE0)); 00410 _led_current_change_flag = 1; 00411 } 00412 else { 00413 _state = 0; 00414 _led_current_change_flag = 0; 00415 } 00416 } 00417 } 00418 } 00419 else { 00420 writeRegister(0x7f,0x00); 00421 writeRegister(0x05,0xB8); 00422 writeRegister(0x7F,0x01); 00423 //writeRegister(0x42,0xA0); 00424 _led_step = DEFAULT_LED_STEP; 00425 writeRegister(0x38, 0xFF); 00426 _sleepflag = 1; 00427 _led_current_change_flag = 0; 00428 } 00429 } 00430 /***********************LED Control End ***********************************/ 00431 /* --------------------------------------------------------------- 00432 * End of PAH8001 code 00433 *///--------------------------------------------------------------
Generated on Thu Jul 21 2022 05:01:45 by
