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 paw8001motion32_5_m0_keil_split
Fork of Pixart 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 "BLE.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 void rs232talk(void); 00045 /* --------------------------------------------------------------- 00046 * End of PAH8001 code 00047 *///-------------------------------------------------------------- 00048 00049 const static char DEVICE_NAME[] = "PixArt_HRmbed"; 00050 static const uint16_t uuid16_list[] = {GattService::UUID_HEART_RATE_SERVICE, 00051 GattService::UUID_BATTERY_SERVICE, 00052 GattService::UUID_DEVICE_INFORMATION_SERVICE}; 00053 /* --------------------------------------------------------------- 00054 * Below for PAH8001 code 00055 *///-------------------------------------------------------------- 00056 static volatile bool triggerSensorPolling = false; 00057 void disconnectionCallback(const Gap::DisconnectionCallbackParams_t *params) 00058 { 00059 ble.gap().startAdvertising(); 00060 triggerSensorPolling = false; 00061 PxiAlg_Close();//close and reset algorithm 00062 } 00063 00064 void onconnectionCallback(const Gap::ConnectionCallbackParams_t *p_conn_param) 00065 //void onconnectionCallback(Gap::Handle_t handle, Gap::addr_type_t peerAddrType, const Gap::address_t peerAddr, const Gap::ConnectionParams_t *p_conn_param) 00066 { 00067 triggerSensorPolling = true; 00068 Gap::ConnectionParams_t gap_conn_params; 00069 gap_conn_params.minConnectionInterval = MIN_CONN_INTERVAL; 00070 gap_conn_params.maxConnectionInterval = MAX_CONN_INTERVAL; 00071 gap_conn_params.slaveLatency = SLAVE_LATENCY; 00072 gap_conn_params.connectionSupervisionTimeout = CONN_SUP_TIMEOUT; 00073 ble.gap().updateConnectionParams(p_conn_param->handle, &gap_conn_params); 00074 } 00075 00076 void periodicCallback(void) 00077 {uint8_t tmp; 00078 if(triggerSensorPolling == true){ 00079 HR_Cnt++; 00080 //CRITICAL_REGION_ENTER(); 00081 Pixart_HRD(); 00082 //CRITICAL_REGION_EXIT(); 00083 00084 led1 = 1; 00085 if(Pop(&ppg_mems_data)) //Get data from FIFO 00086 { 00087 MEMS_Data[0] = ppg_mems_data.MEMS_Data[0]; 00088 MEMS_Data[1] = ppg_mems_data.MEMS_Data[1]; 00089 MEMS_Data[2] = ppg_mems_data.MEMS_Data[2]; 00090 00091 tmp = PxiAlg_Process(ppg_mems_data.HRD_Data, MEMS_Data); 00092 if( tmp != FLAG_DATA_READY) 00093 { 00094 pc.printf("AlgoProcssRtn: %d\n\r", tmp); 00095 pc.printf("PPG[8]: %d\n\r", ppg_mems_data.HRD_Data[8]); 00096 } 00097 else{ 00098 PxiAlg_HrGet(&myHR); 00099 PxiAlg_GetSigGrade(&grade); 00100 } 00101 } 00102 led1 = 0; 00103 00104 00105 } 00106 else 00107 HR_Cnt = 0; 00108 } 00109 00110 int main(void) 00111 { 00112 pc.baud (115200); 00113 pc.printf("\n\rStart initialization\n\r"); 00114 i2c.frequency(400000); 00115 00116 led1 = 1; 00117 PAH8001_init(); //PAH8001 initialization 00118 00119 ble.init(); 00120 ble.gap().onDisconnection(disconnectionCallback); 00121 ble.gap().onConnection(onconnectionCallback); 00122 /* Setup primary service. */ 00123 uint8_t hrmCounter = 100; 00124 HeartRateService hrService(ble, hrmCounter, HeartRateService::LOCATION_FINGER); 00125 00126 /* Setup auxiliary services. */ 00127 BatteryService battery(ble); 00128 DeviceInformationService deviceInfo(ble, "ARM", "Model1", "SN1", "hw-rev1", "fw-rev1", "soft-rev1"); 00129 00130 /* Setup advertising. */ 00131 ble.accumulateAdvertisingPayload(GapAdvertisingData::BREDR_NOT_SUPPORTED | GapAdvertisingData::LE_GENERAL_DISCOVERABLE); 00132 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LIST_16BIT_SERVICE_IDS, (uint8_t *)uuid16_list, sizeof(uuid16_list)); 00133 ble.accumulateAdvertisingPayload(GapAdvertisingData::GENERIC_HEART_RATE_SENSOR); 00134 ble.accumulateAdvertisingPayload(GapAdvertisingData::COMPLETE_LOCAL_NAME, (uint8_t *)DEVICE_NAME, sizeof(DEVICE_NAME)); 00135 ble.setAdvertisingType(GapAdvertisingParams::ADV_CONNECTABLE_UNDIRECTED); 00136 ble.setAdvertisingInterval(1600); /* 1000ms; in multiples of 0.625ms. */ 00137 ble.startAdvertising(); 00138 00139 pc.printf("Before while 1\n\r"); 00140 while (true) { 00141 rs232talk(); 00142 00143 if(triggerSensorPolling == true) 00144 { 00145 if( (HR_Cnt>HR_Rpt) && (ppg_mems_data.HRD_Data[11]==0x80) ) 00146 { 00147 HR_Cnt = 0; 00148 00149 pc.printf("SG: %d ", (uint8_t)grade); 00150 pc.printf("HR: %d\n\r", (uint8_t)myHR); 00151 00152 hrmCounter = (uint8_t)myHR; 00153 hrService.updateHeartRate(hrmCounter); 00154 } 00155 } 00156 else 00157 ble.waitForEvent(); 00158 } 00159 } 00160 00161 00162 00163 void PAH8001_init() 00164 { uint16_t q; 00165 uint8_t bank=0, temp; float grade=0; 00166 00167 if(readRegister(0x00) == 0x30) 00168 pc.printf("PAH8001 I2C Link Successful!\n\r"); 00169 else 00170 pc.printf("PAH8001 I2C Link Fail!\n\r"); 00171 00172 alg_version = PxiAlg_Version(); 00173 pc.printf("Algo Ver: %d\n\r", alg_version); 00174 00175 00176 #ifdef DEBUG_8001 00177 writeRegister(0x09, 0x5A); writeRegister(0x54, 0xEE); 00178 pc.printf("\n\r~~~Start Test Pattern~~~ \n\r"); 00179 pc.printf("Reg0x09: %d\n\r", readRegister(0x09)); 00180 pc.printf("Reg0x54: %d\n\r", readRegister(0x54)); 00181 pc.printf("Reg0x1E: %d\n\r", readRegister(0x1E)); 00182 00183 float MEMS_Data[3] = {0 ,0, 0}; //apply test pattern 00184 float myHR = 0 ; 00185 /*for(q=0;q<PPG_PATTERN_SIZE;q++) 00186 PxiAlg_Process((unsigned char*)PPG_Data[q], MEMS_Data); 00187 PxiAlg_HrGet(&myHR); 00188 pc.printf("HR: %f\n\r", myHR);*/ 00189 00190 PxiAlg_SetMemsScale(1); 00191 for(q=0;q<PPG_PATTERN_SIZE;q++) 00192 { 00193 PxiAlg_Process((unsigned char*)PPG_Data[q], (float*)iMEMS_Data[q]); 00194 PxiAlg_HrGet(&myHR); PxiAlg_GetSigGrade(&grade); 00195 pc.printf("SG: %f ", grade); 00196 pc.printf("HR: %f\n\r", myHR); 00197 } 00198 pc.printf("~~~End of Test Pattern~~~ \n\r"); 00199 while(1); 00200 #endif 00201 00202 #ifndef DEBUG_8001 00203 PxiAlg_SetMemsScale(1); 00204 //PxiAlg_EnableFastOutput(true); 00205 PxiAlg_EnableFastOutput(false); 00206 PxiAlg_EnableAutoMode(true); 00207 PxiAlg_EnableMotionMode(false); 00208 ticker.attach_us(&periodicCallback, PAH8001_Poll*1000); 00209 00210 pc.printf("\n\r~~~Start Real-time HRM~~~ \n\r"); 00211 //Initialization settings 00212 writeRegister(0x06, 0x82); //Reset sensor 00213 wait_ms(10); //make a delay 00214 00215 for(q=0;q<INIT_PPG_REG_ARRAY_SIZE;q++){ 00216 if(init_ppg_register_array[q][0] == 0x7F) 00217 bank = init_ppg_register_array[q][1]; 00218 00219 if((bank == 0) && (init_ppg_register_array[q][0] == 0x17) ) 00220 { 00221 //read and write bit7=1 00222 temp = readRegister(0x17); 00223 temp |= 0x80 ; 00224 writeRegister(0x17, temp) ; 00225 } 00226 else 00227 writeRegister(init_ppg_register_array[q][0], init_ppg_register_array[q][1]); 00228 } 00229 #endif 00230 } 00231 00232 void writeRegister(uint8_t addr, uint8_t data) 00233 { 00234 char data_write[2]; 00235 00236 data_write[0] = addr; 00237 data_write[1] = data; 00238 i2c.write(I2C_ADDR, data_write, 2, 0); 00239 } 00240 uint8_t readRegister(uint8_t addr) 00241 { 00242 char data_write[2]; 00243 char data_read[2]; 00244 00245 data_write[0] = addr; 00246 i2c.write(I2C_ADDR, data_write, 1, 0); 00247 i2c.read(I2C_ADDR, data_read, 1, 0); 00248 return data_read[0]; 00249 } 00250 00251 bool Pixart_HRD(void) 00252 { 00253 uint8_t tmp=0; 00254 char data_write[2]; 00255 char data_read[4]; 00256 ppg_mems_data_t ppg_mems_data; 00257 //Check Touch Status for power saving 00258 writeRegister(0x7F,0x00); //bank0 00259 tmp = readRegister(0x59)&0x80; 00260 led_ctrl(tmp); 00261 00262 //writeRegister(0x7F,0x01); //bank1 00263 ppg_mems_data.HRD_Data[0]=readRegister(0x68)&0x0f; //check status: 0 is not ready, 1 is ready, 2 is loss one data? 00264 00265 if(ppg_mems_data.HRD_Data[0] ==0) 00266 { 00267 writeRegister(0x7F,0x00); //bank0 00268 return false; 00269 } 00270 else 00271 { 00272 //Only support burst read (0x64~0x67), when using I2C interface 00273 data_write[0] = 0x64; 00274 i2c.write(PAH8001_ADDR, data_write, 1, 1); 00275 i2c.read(PAH8001_ADDR, data_read, 4, 0); 00276 ppg_mems_data.HRD_Data[1]=data_read[0]&0xff; 00277 ppg_mems_data.HRD_Data[2]=data_read[1]&0xff; 00278 ppg_mems_data.HRD_Data[3]=data_read[2]&0xff; 00279 ppg_mems_data.HRD_Data[4]=data_read[3]&0xff; 00280 00281 //Only support burst read (0x1A~0x1C), when using I2C interface 00282 data_write[0] = 0x1A; 00283 i2c.write(PAH8001_ADDR, data_write, 1, 1); 00284 i2c.read(PAH8001_ADDR, data_read, 3, 0); 00285 ppg_mems_data.HRD_Data[5]=data_read[0]&0xff; 00286 ppg_mems_data.HRD_Data[6]=data_read[1]&0xff; 00287 ppg_mems_data.HRD_Data[7]=data_read[2]&0xff; 00288 00289 ppg_mems_data.HRD_Data[8]=Frame_Count++; 00290 ppg_mems_data.HRD_Data[9]=0; 00291 ppg_mems_data.HRD_Data[10]=_led_current_change_flag; 00292 writeRegister(0x7F,0x00); //bank0 00293 //bit7 is Touch Flag (bit7=1 is meant Touch, and bit7=0 is meant No Touch) 00294 ppg_mems_data.HRD_Data[11]=(readRegister(0x59)&0x80); //Check Touch Flag 00295 ppg_mems_data.HRD_Data[12]= ppg_mems_data.HRD_Data[6]; 00296 00297 //If no G sensor, please set G_Sensor_Data[3] = {0}; 00298 ppg_mems_data.MEMS_Data[0] = 0;//ReadGSensorX(); 00299 ppg_mems_data.MEMS_Data[1] = 0;//ReadGSensorY(); 00300 ppg_mems_data.MEMS_Data[2] = 0;//ReadGSensorZ(); 00301 Push(&ppg_mems_data); //Save data into FIFO 00302 00303 return true; 00304 } 00305 } 00306 00307 bool isFIFOEmpty(void) 00308 { 00309 return (_write_index == _read_index); 00310 } 00311 00312 bool Push(ppg_mems_data_t *data) 00313 { 00314 int tmp = _write_index; 00315 tmp++; 00316 if(tmp >= FIFO_SIZE) 00317 tmp = 0; 00318 if(tmp == _read_index) 00319 return false; 00320 _ppg_mems_data[tmp] = *data; 00321 _write_index = tmp; 00322 00323 return true; 00324 } 00325 00326 bool Pop(ppg_mems_data_t *data) 00327 { 00328 int tmp; 00329 if(isFIFOEmpty()) 00330 return false; 00331 *data = _ppg_mems_data[_read_index]; 00332 tmp = _read_index + 1; 00333 if(tmp >= FIFO_SIZE) 00334 tmp = 0; 00335 _read_index = tmp; 00336 00337 return true; 00338 } 00339 00340 /***********************LED Control Start***********************************/ 00341 void led_ctrl(uint8_t touch) { 00342 if(touch == 0x80) { 00343 uint8_t data; 00344 //uint16_t Frame_Average, EP_L, EP_H, Exposure_Line; 00345 uint16_t EP_L, EP_H, Exposure_Line; 00346 writeRegister(0x7f,0x00); 00347 writeRegister(0x05,0x98); 00348 writeRegister(0x7f,0x01); 00349 //writeRegister(0x42,0xA4); 00350 writeRegister(0x7f,0x00); 00351 data = readRegister(0x33); 00352 EP_H=data&0x03; 00353 data = readRegister(0x32); 00354 EP_L=data; 00355 Exposure_Line=(EP_H<<8)+EP_L; 00356 writeRegister(0x7f,0x01); 00357 if(_sleepflag==1) { 00358 writeRegister(0x38, (0xE0|DEFAULT_LED_STEP)); 00359 _sleepflag = 0 ; 00360 } 00361 00362 if (_state_count <= STATE_COUNT_TH) { 00363 _state_count++; 00364 _led_current_change_flag = 0; 00365 } 00366 else { 00367 _state_count = 0; 00368 if(_state == 0) { 00369 if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) || (Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) ) { 00370 //writeRegister(0x7f,0x01); 00371 data = readRegister(0x38); 00372 _led_step=data&0x1f; 00373 if( (Exposure_Line>=LED_CTRL_EXPO_TIME_HI_BOUND) && (_led_step < LED_CURRENT_HI) ) { 00374 _state = 1 ; 00375 _led_step=_led_step+LED_INC_DEC_STEP; 00376 00377 if(_led_step>LED_CURRENT_HI) 00378 _led_step=LED_CURRENT_HI; 00379 writeRegister(0x38, (_led_step|0xE0)); 00380 _led_current_change_flag = 1; 00381 } 00382 else if((Exposure_Line<=LED_CTRL_EXPO_TIME_LOW_BOUND) && (_led_step > LED_CURRENT_LOW) ) { 00383 _state = 2 ; 00384 if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP)) 00385 _led_step=LED_CURRENT_LOW; 00386 else 00387 _led_step=_led_step-LED_INC_DEC_STEP; 00388 writeRegister(0x38, (_led_step|0xE0)); 00389 _led_current_change_flag = 1; 00390 } 00391 else { 00392 _state = 0 ; 00393 _led_current_change_flag = 0; 00394 } 00395 } 00396 else { 00397 _led_current_change_flag = 0; 00398 } 00399 } 00400 else if(_state == 1) { 00401 if(Exposure_Line > LED_CTRL_EXPO_TIME_HI) { 00402 _state = 1 ; 00403 _led_step=_led_step+LED_INC_DEC_STEP; 00404 if(_led_step>=LED_CURRENT_HI) { 00405 _state = 0 ; 00406 _led_step=LED_CURRENT_HI; 00407 } 00408 writeRegister(0x38, (_led_step|0xE0)); 00409 _led_current_change_flag = 1; 00410 } 00411 else { 00412 _state = 0 ; 00413 _led_current_change_flag = 0; 00414 } 00415 } 00416 else { 00417 if(Exposure_Line < LED_CTRL_EXPO_TIME_LOW) { 00418 _state = 2 ; 00419 if(_led_step<=(LED_CURRENT_LOW+LED_INC_DEC_STEP)) { 00420 _state = 0 ; 00421 _led_step=LED_CURRENT_LOW; 00422 } 00423 else 00424 _led_step=_led_step-LED_INC_DEC_STEP; 00425 writeRegister(0x38, (_led_step|0xE0)); 00426 _led_current_change_flag = 1; 00427 } 00428 else { 00429 _state = 0; 00430 _led_current_change_flag = 0; 00431 } 00432 } 00433 } 00434 } 00435 else { 00436 writeRegister(0x7f,0x00); 00437 writeRegister(0x05,0xB8); 00438 writeRegister(0x7F,0x01); 00439 //writeRegister(0x42,0xA0); 00440 _led_step = DEFAULT_LED_STEP; 00441 writeRegister(0x38, 0xFF); 00442 _sleepflag = 1; 00443 _led_current_change_flag = 0; 00444 } 00445 } 00446 /***********************LED Control End ***********************************/ 00447 00448 00449 void rs232talk(void) 00450 {uint8_t tmp, reg_tmp[5], reg[2]; 00451 if(pc.readable()) { 00452 //pc.putc(pc.getc()); 00453 tmp = pc.getc(); 00454 if(tmp == 's')//for start polling 00455 { 00456 pc.printf("\n\rForce Start Polling\n\r"); 00457 triggerSensorPolling = true; 00458 } 00459 if(tmp == 'p')//for stop polling 00460 { 00461 pc.printf("\n\rForce Stop Polling\n\r"); 00462 triggerSensorPolling = false; 00463 PxiAlg_Close();//close and reset algorithm 00464 } 00465 00466 if(tmp == 'w')//write register 00467 { 00468 //writeRegister(0x06, 0x08); 00469 } 00470 if(tmp == 'r')//read register 00471 { 00472 //writeRegister(0x06, 0x00); 00473 } 00474 } 00475 } 00476 /* --------------------------------------------------------------- 00477 * End of PAH8001 code 00478 *///--------------------------------------------------------------
Generated on Sun Jul 31 2022 00:11:08 by
1.7.2
