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: max32630fthr USBDevice
main.cpp@13:a555fd1253e7, 2020-03-09 (annotated)
- Committer:
- saleiferis
- Date:
- Mon Mar 09 08:17:00 2020 +0000
- Revision:
- 13:a555fd1253e7
- Parent:
- 12:ad628acddbf7
- Child:
- 14:ee2175578993
plot processed signal
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 | 13:a555fd1253e7 | 21 | #define WINDOW_SIZE 25 // number of samples for moving winfow integration for HR algo preprocessing. Effective window_size is half of this value |
| 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 | 13:a555fd1253e7 | 118 | /*int16_t ecgsigned16; |
| saleiferis | 13:a555fd1253e7 | 119 | |
| saleiferis | 13:a555fd1253e7 | 120 | while(1){ |
| saleiferis | 13:a555fd1253e7 | 121 | if(max86150Sensor.check()>0){ |
| saleiferis | 13:a555fd1253e7 | 122 | |
| saleiferis | 13:a555fd1253e7 | 123 | ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); |
| saleiferis | 13:a555fd1253e7 | 124 | max86150Sensor.nextSample(); |
| saleiferis | 13:a555fd1253e7 | 125 | ble.updateHeartRate(ecgsigned16); |
| saleiferis | 13:a555fd1253e7 | 126 | pc.printf("%f\n",(float)ecgsigned16);*/ |
| saleiferis | 13:a555fd1253e7 | 127 | |
| saleiferis | 4:4233f5538abf | 128 | |
| saleiferis | 10:28b8729cf5dc | 129 | // Below code is for testing interrupts and sensor polling without involving bluetooth API |
| saleiferis | 13:a555fd1253e7 | 130 | |
| saleiferis | 10:28b8729cf5dc | 131 | // max86150Sensor.clearFIFO(); |
| saleiferis | 10:28b8729cf5dc | 132 | //intPin.fall(&ISR_DATA_READY); |
| saleiferis | 10:28b8729cf5dc | 133 | // max86150Sensor.writeRegister8(MAX86150_Addr,0x0D,0x04); |
| saleiferis | 10:28b8729cf5dc | 134 | int16_t ecgsigned16; |
| saleiferis | 13:a555fd1253e7 | 135 | int k; // loop iteration |
| saleiferis | 12:ad628acddbf7 | 136 | int32_t sample_idx = 0; // number of samples read |
| saleiferis | 12:ad628acddbf7 | 137 | uint8_t curr; // keept track of buffer |
| saleiferis | 12:ad628acddbf7 | 138 | float signal[BUFF_SIZE]={0}; //store signal segment to be filtered |
| saleiferis | 12:ad628acddbf7 | 139 | float bp_signal[BUFF_SIZE]={0}; |
| saleiferis | 12:ad628acddbf7 | 140 | float derivative[BUFF_SIZE]={0}; |
| saleiferis | 12:ad628acddbf7 | 141 | float squared[BUFF_SIZE]={0}; |
| saleiferis | 12:ad628acddbf7 | 142 | float integral[BUFF_SIZE] = {0}; |
| saleiferis | 12:ad628acddbf7 | 143 | // uint8_t curr_movwin = 0; //keep track of squared[] buffer that is used for moving window integration |
| saleiferis | 12:ad628acddbf7 | 144 | |
| saleiferis | 12:ad628acddbf7 | 145 | // Variables for preprocessing |
| saleiferis | 11:cbd9182d14d2 | 146 | float y = 0.0; //filtered sample to be displayed |
| saleiferis | 12:ad628acddbf7 | 147 | float prev_y = 0.0; // keep track of previous output to calculate derivative |
| saleiferis | 12:ad628acddbf7 | 148 | float sq_y = 0.0; |
| saleiferis | 12:ad628acddbf7 | 149 | float movmean = 0.0; // result of moving window integration |
| saleiferis | 12:ad628acddbf7 | 150 | |
| saleiferis | 12:ad628acddbf7 | 151 | // Variables for peak-finding |
| saleiferis | 12:ad628acddbf7 | 152 | int rr1[8], rr2[8], rravg1, rravg2, rrlow = 0, rrhigh = 0, rrmiss = 0; |
| saleiferis | 13:a555fd1253e7 | 153 | long unsigned int i, j, sample = 0, lastQRS = 0, lastSlope = 0, currentSlope = 0; |
| saleiferis | 12:ad628acddbf7 | 154 | 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 | 155 | bool qrs, regular = true, prevRegular; |
| saleiferis | 12:ad628acddbf7 | 156 | // Initializing the RR averages |
| saleiferis | 12:ad628acddbf7 | 157 | for (i = 0; i < 8; i++) |
| saleiferis | 12:ad628acddbf7 | 158 | { |
| saleiferis | 12:ad628acddbf7 | 159 | rr1[i] = 0; |
| saleiferis | 12:ad628acddbf7 | 160 | rr2[i] = 0; |
| saleiferis | 12:ad628acddbf7 | 161 | } |
| saleiferis | 12:ad628acddbf7 | 162 | |
| saleiferis | 9:171171516ebd | 163 | |
| saleiferis | 8:2005014df05c | 164 | while(1){ |
| saleiferis | 10:28b8729cf5dc | 165 | if(max86150Sensor.check()>0){ |
| saleiferis | 10:28b8729cf5dc | 166 | |
| saleiferis | 11:cbd9182d14d2 | 167 | //ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); |
| saleiferis | 11:cbd9182d14d2 | 168 | //max86150Sensor.nextSample(); |
| saleiferis | 11:cbd9182d14d2 | 169 | //pc.printf("%f\n",(float)ecgsigned16); |
| saleiferis | 11:cbd9182d14d2 | 170 | |
| saleiferis | 12:ad628acddbf7 | 171 | // if buffer is full |
| saleiferis | 11:cbd9182d14d2 | 172 | if (sample_idx >= BUFF_SIZE){ |
| saleiferis | 13:a555fd1253e7 | 173 | for (k=0; k<BUFF_SIZE-1; k++){ //discard oldest sample, shift samples in buffer |
| saleiferis | 13:a555fd1253e7 | 174 | signal[k] = signal[k+1]; |
| saleiferis | 13:a555fd1253e7 | 175 | bp_signal[k] = bp_signal[k+1]; |
| saleiferis | 13:a555fd1253e7 | 176 | derivative[k] = derivative[k+1]; |
| saleiferis | 13:a555fd1253e7 | 177 | integral[k] = integral[k+1]; |
| saleiferis | 13:a555fd1253e7 | 178 | squared[k] = squared[k+1]; |
| saleiferis | 12:ad628acddbf7 | 179 | |
| saleiferis | 11:cbd9182d14d2 | 180 | } |
| saleiferis | 11:cbd9182d14d2 | 181 | curr = BUFF_SIZE-1; // indicates that buffer is full |
| saleiferis | 12:ad628acddbf7 | 182 | prev_y = y; |
| saleiferis | 11:cbd9182d14d2 | 183 | y = 0.0; // reset filter output for current sample |
| saleiferis | 11:cbd9182d14d2 | 184 | }else{ //Buffer is not full yet |
| saleiferis | 12:ad628acddbf7 | 185 | curr = (uint8_t)sample_idx; //position at buffer is same as sample number |
| saleiferis | 11:cbd9182d14d2 | 186 | } |
| saleiferis | 11:cbd9182d14d2 | 187 | ecgsigned16 = (int16_t) (max86150Sensor.getFIFOECG()>>2); //read a sample |
| saleiferis | 11:cbd9182d14d2 | 188 | max86150Sensor.nextSample(); // advance tail to get sample in next iteration |
| saleiferis | 12:ad628acddbf7 | 189 | signal[curr] = (float)ecgsigned16; //add sample to buffer |
| saleiferis | 11:cbd9182d14d2 | 190 | sample_idx++; |
| saleiferis | 11:cbd9182d14d2 | 191 | |
| saleiferis | 11:cbd9182d14d2 | 192 | if (curr< BUFF_SIZE-1){ |
| saleiferis | 11:cbd9182d14d2 | 193 | // buffer is not full yet |
| saleiferis | 11:cbd9182d14d2 | 194 | }else{ //buffer is full, filter current sample |
| saleiferis | 13:a555fd1253e7 | 195 | for(k = 0; k < BUFF_SIZE; k++){ //FIR bandpass filter |
| saleiferis | 13:a555fd1253e7 | 196 | y = y + FIR_BP[k] * signal[BUFF_SIZE-1-k]; |
| saleiferis | 11:cbd9182d14d2 | 197 | } |
| saleiferis | 12:ad628acddbf7 | 198 | bp_signal[curr] = y; |
| saleiferis | 12:ad628acddbf7 | 199 | } |
| saleiferis | 12:ad628acddbf7 | 200 | sq_y = pow(y-prev_y,2); |
| saleiferis | 12:ad628acddbf7 | 201 | squared[curr] = sq_y; |
| saleiferis | 12:ad628acddbf7 | 202 | //moving window integration |
| saleiferis | 12:ad628acddbf7 | 203 | movmean = 0.0; // reset for current sample |
| saleiferis | 13:a555fd1253e7 | 204 | for(k=0; k<(int)WINDOW_SIZE/2; k++){ |
| saleiferis | 12:ad628acddbf7 | 205 | //pc.printf("%d\n",(int)curr - (int)(WINDOW_SIZE)); |
| saleiferis | 13:a555fd1253e7 | 206 | if ((int)curr - (int)(WINDOW_SIZE) > k){ //there are enough samples in squared[] |
| saleiferis | 13:a555fd1253e7 | 207 | // movmean = movmean + squared[(curr-k-(int)WINDOW_SIZE/2)] + squared[curr+k-(int)WINDOW_SIZE/2]; |
| saleiferis | 13:a555fd1253e7 | 208 | movmean = movmean + squared[curr-k]; |
| saleiferis | 12:ad628acddbf7 | 209 | |
| saleiferis | 12:ad628acddbf7 | 210 | }else{ |
| saleiferis | 12:ad628acddbf7 | 211 | break; |
| saleiferis | 12:ad628acddbf7 | 212 | } |
| saleiferis | 11:cbd9182d14d2 | 213 | } |
| saleiferis | 13:a555fd1253e7 | 214 | movmean = movmean/(float)(k+1); |
| saleiferis | 12:ad628acddbf7 | 215 | integral[curr] = movmean; |
| saleiferis | 12:ad628acddbf7 | 216 | |
| saleiferis | 12:ad628acddbf7 | 217 | pc.printf("%f %f\n",movmean/1000, y/50); |
| saleiferis | 12:ad628acddbf7 | 218 | |
| saleiferis | 12:ad628acddbf7 | 219 | // Preprocessing done |
| saleiferis | 13:a555fd1253e7 | 220 | /* |
| saleiferis | 12:ad628acddbf7 | 221 | // Start peak-finding |
| saleiferis | 13:a555fd1253e7 | 222 | qrs = false; |
| saleiferis | 13:a555fd1253e7 | 223 | if (integral[curr] >= threshold_i1 || highpass[current] >= threshold_f1){ |
| saleiferis | 13:a555fd1253e7 | 224 | peak_i = integral[curr]; |
| saleiferis | 13:a555fd1253e7 | 225 | peak_f = bp_signal[curr]; |
| saleiferis | 13:a555fd1253e7 | 226 | }*/ |
| saleiferis | 12:ad628acddbf7 | 227 | |
| saleiferis | 12:ad628acddbf7 | 228 | |
| saleiferis | 12:ad628acddbf7 | 229 | |
| saleiferis | 12:ad628acddbf7 | 230 | |
| saleiferis | 10:28b8729cf5dc | 231 | } |
| saleiferis | 10:28b8729cf5dc | 232 | } |
| saleiferis | 10:28b8729cf5dc | 233 | |
| saleiferis | 0:89ec48e52250 | 234 | } |