Chanel's edits
Dependencies: max32630fthr USBDevice
main.cpp@12:ad628acddbf7, 2020-03-09 (annotated)
- Committer:
- saleiferis
- Date:
- Mon Mar 09 06:12:00 2020 +0000
- Revision:
- 12:ad628acddbf7
- Parent:
- 11:cbd9182d14d2
- Child:
- 13:a555fd1253e7
preprossing is complete (raw->bandpass->square->moving integration) -- no BT
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
saleiferis | 0:89ec48e52250 | 1 | #include "mbed.h" |
saleiferis | 0:89ec48e52250 | 2 | #include "math.h" |
saleiferis | 0:89ec48e52250 | 3 | #include "max32630fthr.h" |
saleiferis | 0:89ec48e52250 | 4 | #include "max86150.h" |
saleiferis | 0:89ec48e52250 | 5 | #include "I2C.h" |
saleiferis | 0:89ec48e52250 | 6 | #include "ble/BLE.h" |
saleiferis | 0:89ec48e52250 | 7 | #include "ble/Gap.h" |
saleiferis | 7:4debec043316 | 8 | //#include "ble/services/HeartRateService.h" |
saleiferis | 7:4debec043316 | 9 | #include "ECGService.h" |
saleiferis | 1:6e6f7e3cc1e1 | 10 | #include <events/mbed_events.h> |
saleiferis | 1:6e6f7e3cc1e1 | 11 | #include "bt32630.h" |
saleiferis | 11:cbd9182d14d2 | 12 | #include "filters.h" |
saleiferis | 0:89ec48e52250 | 13 | |
saleiferis | 0:89ec48e52250 | 14 | //Register definitions |
saleiferis | 0:89ec48e52250 | 15 | #define MAX86150_Addr 0xBC //updated per I2Cscanner, 8 bit version of 7 bit code 0x5E |
saleiferis | 0:89ec48e52250 | 16 | #define maxi2cFreq 1000000 |
saleiferis | 0:89ec48e52250 | 17 | #define recommendedi2cFreq 400000 |
saleiferis | 10:28b8729cf5dc | 18 | |
saleiferis | 10:28b8729cf5dc | 19 | #define BaudRate 115200 |
saleiferis | 0:89ec48e52250 | 20 | |
saleiferis | 12:ad628acddbf7 | 21 | #define WINDOW_SIZE 10 // number of samples for moving winfow integration for HR algo preprocessing |
saleiferis | 12:ad628acddbf7 | 22 | #define BUFF_SIZE 136 // FIR filter length |
saleiferis | 0:89ec48e52250 | 23 | |
saleiferis | 10:28b8729cf5dc | 24 | Serial pc(USBTX,USBRX,NULL,BaudRate); |
saleiferis | 10:28b8729cf5dc | 25 | InterruptIn intPin(P5_5); // interrupts currently not used |
saleiferis | 0:89ec48e52250 | 26 | I2C i2c(I2C2_SDA, I2C2_SCL); |
saleiferis | 8:2005014df05c | 27 | MAX86150 max86150Sensor; |
saleiferis | 0:89ec48e52250 | 28 | |
saleiferis | 10:28b8729cf5dc | 29 | ECGService *hrServicePtr; |
saleiferis | 10:28b8729cf5dc | 30 | |
saleiferis | 10:28b8729cf5dc | 31 | //Variables modified in inerrupt routine |
saleiferis | 12:ad628acddbf7 | 32 | /* |
saleiferis | 10:28b8729cf5dc | 33 | volatile uint32_t intCount = 0; |
saleiferis | 8:2005014df05c | 34 | volatile bool intFlag = false; |
saleiferis | 9:171171516ebd | 35 | volatile uint8_t writePointer; |
saleiferis | 9:171171516ebd | 36 | volatile uint8_t readPointer; |
saleiferis | 9:171171516ebd | 37 | volatile uint32_t curr_time; |
saleiferis | 9:171171516ebd | 38 | volatile uint32_t prev_time; |
saleiferis | 9:171171516ebd | 39 | volatile int16_t samplesToRead; |
saleiferis | 12:ad628acddbf7 | 40 | */ |
saleiferis | 9:171171516ebd | 41 | |
saleiferis | 12:ad628acddbf7 | 42 | //Timer timer; |
saleiferis | 9:171171516ebd | 43 | |
saleiferis | 1:6e6f7e3cc1e1 | 44 | static events::EventQueue event_queue(/* event count */ 16 * EVENTS_EVENT_SIZE); |
saleiferis | 1:6e6f7e3cc1e1 | 45 | |
saleiferis | 10:28b8729cf5dc | 46 | /* |
saleiferis | 8:2005014df05c | 47 | void ISR_AFULL() |
saleiferis | 8:2005014df05c | 48 | { |
saleiferis | 9:171171516ebd | 49 | intPin.disable_irq(); |
saleiferis | 8:2005014df05c | 50 | intFlag = true; |
saleiferis | 9:171171516ebd | 51 | readPointer = max86150Sensor.getReadPointer(); |
saleiferis | 9:171171516ebd | 52 | writePointer = max86150Sensor.getWritePointer(); |
saleiferis | 10:28b8729cf5dc | 53 | samplesToRead = (int8_t)writePointer - (int8_t)readPointer; |
saleiferis | 10:28b8729cf5dc | 54 | //if (samplesToRead < 0) samplesToRead+=32; |
saleiferis | 10:28b8729cf5dc | 55 | intCount++; |
saleiferis | 10:28b8729cf5dc | 56 | //intPin.enable_irq(); |
saleiferis | 10:28b8729cf5dc | 57 | |
saleiferis | 10:28b8729cf5dc | 58 | }*/ |
saleiferis | 9:171171516ebd | 59 | |
saleiferis | 10:28b8729cf5dc | 60 | /* |
saleiferis | 10:28b8729cf5dc | 61 | void ISR_DATA_READY() |
saleiferis | 10:28b8729cf5dc | 62 | { |
saleiferis | 10:28b8729cf5dc | 63 | intPin.disable_irq(); |
saleiferis | 10:28b8729cf5dc | 64 | readPointer = max86150Sensor.getReadPointer(); |
saleiferis | 10:28b8729cf5dc | 65 | writePointer = max86150Sensor.getWritePointer(); |
saleiferis | 10:28b8729cf5dc | 66 | samplesToRead = (int8_t)writePointer - (int8_t)readPointer; |
saleiferis | 10:28b8729cf5dc | 67 | //if (samplesToRead < 0) samplesToRead+=32; |
saleiferis | 10:28b8729cf5dc | 68 | intCount++; |
saleiferis | 10:28b8729cf5dc | 69 | char data[3]; |
saleiferis | 10:28b8729cf5dc | 70 | //char *p = data; |
saleiferis | 10:28b8729cf5dc | 71 | max86150Sensor.writeRegister8(MAX86150_Addr,0x07,0x01); |
saleiferis | 10:28b8729cf5dc | 72 | i2c.write(MAX86150_Addr,command, 1); |
saleiferis | 10:28b8729cf5dc | 73 | i2c.read(MAX86150_Addr, data, 3, false); |
saleiferis | 10:28b8729cf5dc | 74 | uint8_t temp[sizeof(int32_t)]; //Array of 4 bytes that we will convert into long |
saleiferis | 10:28b8729cf5dc | 75 | int32_t tempLong; |
saleiferis | 10:28b8729cf5dc | 76 | temp[1] = data[0]; |
saleiferis | 10:28b8729cf5dc | 77 | temp[2] = data[1]; |
saleiferis | 10:28b8729cf5dc | 78 | temp[3] = data[2]; |
saleiferis | 10:28b8729cf5dc | 79 | temp[0] = 0; |
saleiferis | 10:28b8729cf5dc | 80 | //Convert array to long |
saleiferis | 10:28b8729cf5dc | 81 | memcpy(&tempLong, temp, sizeof(tempLong)); |
saleiferis | 10:28b8729cf5dc | 82 | pc.printf("%d\n",tempLong); |
saleiferis | 10:28b8729cf5dc | 83 | intPin.enable_irq(); |
saleiferis | 10:28b8729cf5dc | 84 | }*/ |
saleiferis | 10:28b8729cf5dc | 85 | |
saleiferis | 0:89ec48e52250 | 86 | ////////// |
saleiferis | 10:28b8729cf5dc | 87 | int main(){ |
saleiferis | 0:89ec48e52250 | 88 | max86150Sensor.begin(i2c, recommendedi2cFreq, MAX86150_Addr); |
saleiferis | 0:89ec48e52250 | 89 | wait_ms(300); |
saleiferis | 4:4233f5538abf | 90 | |
saleiferis | 0:89ec48e52250 | 91 | //unsigned char partID = max86150Sensor.readPartID(); |
saleiferis | 0:89ec48e52250 | 92 | unsigned char partID = max86150Sensor.readRegister8(MAX86150_Addr,0xFF); |
saleiferis | 0:89ec48e52250 | 93 | pc.printf("Part ID is: %X\n",partID); |
saleiferis | 10:28b8729cf5dc | 94 | while (partID != 0x1E) {/* Connection to sensor is not established */ } |
saleiferis | 2:a96a53e6c6a3 | 95 | |
saleiferis | 2:a96a53e6c6a3 | 96 | |
saleiferis | 10:28b8729cf5dc | 97 | //***** SETUP SENSOR */ |
saleiferis | 10:28b8729cf5dc | 98 | max86150Sensor.setup(); //Configure sensor |
saleiferis | 10:28b8729cf5dc | 99 | wait_ms(300); |
saleiferis | 10:28b8729cf5dc | 100 | pc.printf("SYSCONTOL REG: %x\n", max86150Sensor.readRegister8(MAX86150_Addr,0x0D)); |
saleiferis | 10:28b8729cf5dc | 101 | pc.printf("FIFO CONFIG: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x08)); |
saleiferis | 10:28b8729cf5dc | 102 | pc.printf("INT_EN1: %X\n", max86150Sensor.readRegister8(MAX86150_Addr,0x02)); |
saleiferis | 10:28b8729cf5dc | 103 | pc.printf("INT_EN2: %X\n", max86150Sensor.readRegister8(MAX86150_Addr,0x03)); |
saleiferis | 10:28b8729cf5dc | 104 | pc.printf("INT STATUS1: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x00)); |
saleiferis | 10:28b8729cf5dc | 105 | pc.printf("INT STATUS2: %X\n",max86150Sensor.readRegister8(MAX86150_Addr,0x01)); |
saleiferis | 10:28b8729cf5dc | 106 | |
saleiferis | 10:28b8729cf5dc | 107 | //*************************************************************// |
saleiferis | 10:28b8729cf5dc | 108 | |
saleiferis | 10:28b8729cf5dc | 109 | max86150Sensor.clearFIFO(); |
saleiferis | 10:28b8729cf5dc | 110 | max86150Sensor.writeRegister8(MAX86150_Addr,0x0D,0x04); //start FIFO |
saleiferis | 10:28b8729cf5dc | 111 | |
saleiferis | 10:28b8729cf5dc | 112 | //******* SETUP BLUETOOTH ********* |
saleiferis | 10:28b8729cf5dc | 113 | eventQueue.call_every(1, periodicCallback); // poll sensor every 1ms. New samples come every 5ms, so polling freq can potentially be decreased |
saleiferis | 1:6e6f7e3cc1e1 | 114 | BLE &ble = BLE::Instance(); |
saleiferis | 10:28b8729cf5dc | 115 | ble.onEventsToProcess(scheduleBleEventsProcessing); |
saleiferis | 10:28b8729cf5dc | 116 | //ble.init(bleInitComplete); |
saleiferis | 8:2005014df05c | 117 | //eventQueue.dispatch_forever(); |
saleiferis | 4:4233f5538abf | 118 | |
saleiferis | 10:28b8729cf5dc | 119 | // Below code is for testing interrupts and sensor polling without involving bluetooth API |
saleiferis | 10:28b8729cf5dc | 120 | // max86150Sensor.clearFIFO(); |
saleiferis | 10:28b8729cf5dc | 121 | //intPin.fall(&ISR_DATA_READY); |
saleiferis | 10:28b8729cf5dc | 122 | // max86150Sensor.writeRegister8(MAX86150_Addr,0x0D,0x04); |
saleiferis | 10:28b8729cf5dc | 123 | int16_t ecgsigned16; |
saleiferis | 11:cbd9182d14d2 | 124 | int i; // loop iteration |
saleiferis | 12:ad628acddbf7 | 125 | int32_t sample_idx = 0; // number of samples read |
saleiferis | 12:ad628acddbf7 | 126 | uint8_t curr; // keept track of buffer |
saleiferis | 12:ad628acddbf7 | 127 | float signal[BUFF_SIZE]={0}; //store signal segment to be filtered |
saleiferis | 12:ad628acddbf7 | 128 | float bp_signal[BUFF_SIZE]={0}; |
saleiferis | 12:ad628acddbf7 | 129 | float derivative[BUFF_SIZE]={0}; |
saleiferis | 12:ad628acddbf7 | 130 | float squared[BUFF_SIZE]={0}; |
saleiferis | 12:ad628acddbf7 | 131 | float integral[BUFF_SIZE] = {0}; |
saleiferis | 12:ad628acddbf7 | 132 | // uint8_t curr_movwin = 0; //keep track of squared[] buffer that is used for moving window integration |
saleiferis | 12:ad628acddbf7 | 133 | |
saleiferis | 12:ad628acddbf7 | 134 | // Variables for preprocessing |
saleiferis | 11:cbd9182d14d2 | 135 | float y = 0.0; //filtered sample to be displayed |
saleiferis | 12:ad628acddbf7 | 136 | float prev_y = 0.0; // keep track of previous output to calculate derivative |
saleiferis | 12:ad628acddbf7 | 137 | float sq_y = 0.0; |
saleiferis | 12:ad628acddbf7 | 138 | float movmean = 0.0; // result of moving window integration |
saleiferis | 12:ad628acddbf7 | 139 | |
saleiferis | 12:ad628acddbf7 | 140 | // Variables for peak-finding |
saleiferis | 12:ad628acddbf7 | 141 | int rr1[8], rr2[8], rravg1, rravg2, rrlow = 0, rrhigh = 0, rrmiss = 0; |
saleiferis | 12:ad628acddbf7 | 142 | //long unsigned int i, j, sample = 0, lastQRS = 0, lastSlope = 0, currentSlope = 0; //TODO: i is already declared FIX |
saleiferis | 12:ad628acddbf7 | 143 | float peak_i = 0, peak_f = 0, threshold_i1 = 0, threshold_i2 = 0, threshold_f1 = 0, threshold_f2 = 0, spk_i = 0, spk_f = 0, npk_i = 0, npk_f = 0; |
saleiferis | 12:ad628acddbf7 | 144 | bool qrs, regular = true, prevRegular; |
saleiferis | 12:ad628acddbf7 | 145 | // Initializing the RR averages |
saleiferis | 12:ad628acddbf7 | 146 | for (i = 0; i < 8; i++) |
saleiferis | 12:ad628acddbf7 | 147 | { |
saleiferis | 12:ad628acddbf7 | 148 | rr1[i] = 0; |
saleiferis | 12:ad628acddbf7 | 149 | rr2[i] = 0; |
saleiferis | 12:ad628acddbf7 | 150 | } |
saleiferis | 12:ad628acddbf7 | 151 | |
saleiferis | 9:171171516ebd | 152 | |
saleiferis | 8:2005014df05c | 153 | while(1){ |
saleiferis | 10:28b8729cf5dc | 154 | if(max86150Sensor.check()>0){ |
saleiferis | 10:28b8729cf5dc | 155 | |
saleiferis | 11:cbd9182d14d2 | 156 | //ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); |
saleiferis | 11:cbd9182d14d2 | 157 | //max86150Sensor.nextSample(); |
saleiferis | 11:cbd9182d14d2 | 158 | //pc.printf("%f\n",(float)ecgsigned16); |
saleiferis | 11:cbd9182d14d2 | 159 | |
saleiferis | 12:ad628acddbf7 | 160 | // if buffer is full |
saleiferis | 11:cbd9182d14d2 | 161 | if (sample_idx >= BUFF_SIZE){ |
saleiferis | 11:cbd9182d14d2 | 162 | for (i=0; i<BUFF_SIZE-1; i++){ //discard oldest sample, shift samples in buffer |
saleiferis | 11:cbd9182d14d2 | 163 | signal[i] = signal[i+1]; |
saleiferis | 12:ad628acddbf7 | 164 | bp_signal[i] = bp_signal[i+1]; |
saleiferis | 12:ad628acddbf7 | 165 | derivative[i] = derivative[i+1]; |
saleiferis | 12:ad628acddbf7 | 166 | integral[i] = integral[i+1]; |
saleiferis | 12:ad628acddbf7 | 167 | squared[i] = squared[i+1]; |
saleiferis | 12:ad628acddbf7 | 168 | |
saleiferis | 11:cbd9182d14d2 | 169 | } |
saleiferis | 11:cbd9182d14d2 | 170 | curr = BUFF_SIZE-1; // indicates that buffer is full |
saleiferis | 12:ad628acddbf7 | 171 | prev_y = y; |
saleiferis | 11:cbd9182d14d2 | 172 | y = 0.0; // reset filter output for current sample |
saleiferis | 11:cbd9182d14d2 | 173 | }else{ //Buffer is not full yet |
saleiferis | 12:ad628acddbf7 | 174 | curr = (uint8_t)sample_idx; //position at buffer is same as sample number |
saleiferis | 11:cbd9182d14d2 | 175 | } |
saleiferis | 11:cbd9182d14d2 | 176 | ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); //read a sample |
saleiferis | 11:cbd9182d14d2 | 177 | max86150Sensor.nextSample(); // advance tail to get sample in next iteration |
saleiferis | 12:ad628acddbf7 | 178 | signal[curr] = (float)ecgsigned16; //add sample to buffer |
saleiferis | 11:cbd9182d14d2 | 179 | sample_idx++; |
saleiferis | 11:cbd9182d14d2 | 180 | |
saleiferis | 11:cbd9182d14d2 | 181 | if (curr< BUFF_SIZE-1){ |
saleiferis | 11:cbd9182d14d2 | 182 | // buffer is not full yet |
saleiferis | 11:cbd9182d14d2 | 183 | }else{ //buffer is full, filter current sample |
saleiferis | 11:cbd9182d14d2 | 184 | for(i = 0; i < BUFF_SIZE; i++){ //FIR bandpass filter |
saleiferis | 11:cbd9182d14d2 | 185 | y = y + FIR_BP[i] * signal[BUFF_SIZE-1-i]; |
saleiferis | 11:cbd9182d14d2 | 186 | } |
saleiferis | 12:ad628acddbf7 | 187 | bp_signal[curr] = y; |
saleiferis | 12:ad628acddbf7 | 188 | } |
saleiferis | 12:ad628acddbf7 | 189 | sq_y = pow(y-prev_y,2); |
saleiferis | 12:ad628acddbf7 | 190 | squared[curr] = sq_y; |
saleiferis | 12:ad628acddbf7 | 191 | //moving window integration |
saleiferis | 12:ad628acddbf7 | 192 | movmean = 0.0; // reset for current sample |
saleiferis | 12:ad628acddbf7 | 193 | for(i=0; i<(int)WINDOW_SIZE/2; i++){ |
saleiferis | 12:ad628acddbf7 | 194 | //pc.printf("%d\n",(int)curr - (int)(WINDOW_SIZE)); |
saleiferis | 12:ad628acddbf7 | 195 | if ((int)curr - (int)(WINDOW_SIZE) > i){ //there are enough samples in squared[] |
saleiferis | 12:ad628acddbf7 | 196 | // movmean = movmean + squared[(curr-i-(int)WINDOW_SIZE/2)] + squared[curr+i-(int)WINDOW_SIZE/2]; |
saleiferis | 12:ad628acddbf7 | 197 | movmean = movmean + squared[curr-i]; |
saleiferis | 12:ad628acddbf7 | 198 | |
saleiferis | 12:ad628acddbf7 | 199 | }else{ |
saleiferis | 12:ad628acddbf7 | 200 | break; |
saleiferis | 12:ad628acddbf7 | 201 | } |
saleiferis | 11:cbd9182d14d2 | 202 | } |
saleiferis | 12:ad628acddbf7 | 203 | movmean = movmean/(float)(i+1); |
saleiferis | 12:ad628acddbf7 | 204 | integral[curr] = movmean; |
saleiferis | 12:ad628acddbf7 | 205 | |
saleiferis | 12:ad628acddbf7 | 206 | pc.printf("%f %f\n",movmean/1000, y/50); |
saleiferis | 12:ad628acddbf7 | 207 | |
saleiferis | 12:ad628acddbf7 | 208 | // Preprocessing done |
saleiferis | 12:ad628acddbf7 | 209 | // Start peak-finding |
saleiferis | 12:ad628acddbf7 | 210 | //qrs = false; |
saleiferis | 12:ad628acddbf7 | 211 | //if (integral[curr] >= threshold_i1 || highpass[current] >= threshold_f1){ |
saleiferis | 12:ad628acddbf7 | 212 | // peak_i = integral[curr]; |
saleiferis | 12:ad628acddbf7 | 213 | // peak_f = highpass[curr]; |
saleiferis | 12:ad628acddbf7 | 214 | //} |
saleiferis | 12:ad628acddbf7 | 215 | |
saleiferis | 12:ad628acddbf7 | 216 | |
saleiferis | 12:ad628acddbf7 | 217 | |
saleiferis | 12:ad628acddbf7 | 218 | |
saleiferis | 10:28b8729cf5dc | 219 | } |
saleiferis | 10:28b8729cf5dc | 220 | } |
saleiferis | 10:28b8729cf5dc | 221 | |
saleiferis | 0:89ec48e52250 | 222 | } |