Maxim Integrated's IoT development kit.
Dependencies: MAX30101 MAX30003 MAX113XX_Pixi MAX30205 max32630fthr USBDevice
max30003_app.cpp@13:fba77a5d0fa0, 2018-06-28 (annotated)
- Committer:
- Mahir Ozturk
- Date:
- Thu Jun 28 15:47:24 2018 +0300
- Revision:
- 13:fba77a5d0fa0
* Move each sensor applications to corresponding *_app.cpp files
* Increase notification period to 12 seconds
* Change platform name to "Maxim HMS"
* Remove unused mem_debug.cpp and mem_debug.h files
* Code cleaning
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
Mahir Ozturk |
13:fba77a5d0fa0 | 1 | /* |
Mahir Ozturk |
13:fba77a5d0fa0 | 2 | * max30003_app.c |
Mahir Ozturk |
13:fba77a5d0fa0 | 3 | * |
Mahir Ozturk |
13:fba77a5d0fa0 | 4 | * Created on: Jun 20, 2018 |
Mahir Ozturk |
13:fba77a5d0fa0 | 5 | * Author: Mahir.Ozturk |
Mahir Ozturk |
13:fba77a5d0fa0 | 6 | */ |
Mahir Ozturk |
13:fba77a5d0fa0 | 7 | #include <mbed.h> |
Mahir Ozturk |
13:fba77a5d0fa0 | 8 | #include "max30003_app.h" |
Mahir Ozturk |
13:fba77a5d0fa0 | 9 | #include "MAX30003.h" |
Mahir Ozturk |
13:fba77a5d0fa0 | 10 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 11 | #define MAX30003_IRQ_ASSERTED_SIGNAL_ID 1 |
Mahir Ozturk |
13:fba77a5d0fa0 | 12 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 13 | static Thread *thread = 0; |
Mahir Ozturk |
13:fba77a5d0fa0 | 14 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 15 | /* ECG FIFO nearly full callback */ |
Mahir Ozturk |
13:fba77a5d0fa0 | 16 | void ecgFIFO_callback() { |
Mahir Ozturk |
13:fba77a5d0fa0 | 17 | if (thread != 0) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 18 | thread->signal_set(MAX30003_IRQ_ASSERTED_SIGNAL_ID); |
Mahir Ozturk |
13:fba77a5d0fa0 | 19 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 20 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 21 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 22 | void ecg_config(MAX30003& ecgAFE) |
Mahir Ozturk |
13:fba77a5d0fa0 | 23 | { |
Mahir Ozturk |
13:fba77a5d0fa0 | 24 | // Reset ECG to clear registers |
Mahir Ozturk |
13:fba77a5d0fa0 | 25 | ecgAFE.writeRegister( MAX30003::SW_RST , 0); |
Mahir Ozturk |
13:fba77a5d0fa0 | 26 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 27 | // General config register setting |
Mahir Ozturk |
13:fba77a5d0fa0 | 28 | MAX30003::GeneralConfiguration_u CNFG_GEN_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 29 | CNFG_GEN_r.bits.en_ecg = 1; // Enable ECG channel |
Mahir Ozturk |
13:fba77a5d0fa0 | 30 | CNFG_GEN_r.bits.rbiasn = 1; // Enable resistive bias on negative input |
Mahir Ozturk |
13:fba77a5d0fa0 | 31 | CNFG_GEN_r.bits.rbiasp = 1; // Enable resistive bias on positive input |
Mahir Ozturk |
13:fba77a5d0fa0 | 32 | CNFG_GEN_r.bits.en_rbias = 1; // Enable resistive bias |
Mahir Ozturk |
13:fba77a5d0fa0 | 33 | CNFG_GEN_r.bits.imag = 2; // Current magnitude = 10nA |
Mahir Ozturk |
13:fba77a5d0fa0 | 34 | CNFG_GEN_r.bits.en_dcloff = 1; // Enable DC lead-off detection |
Mahir Ozturk |
13:fba77a5d0fa0 | 35 | ecgAFE.writeRegister( MAX30003::CNFG_GEN , CNFG_GEN_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 36 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 37 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 38 | // ECG Config register setting |
Mahir Ozturk |
13:fba77a5d0fa0 | 39 | MAX30003::ECGConfiguration_u CNFG_ECG_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 40 | CNFG_ECG_r.bits.dlpf = 1; // Digital LPF cutoff = 40Hz |
Mahir Ozturk |
13:fba77a5d0fa0 | 41 | CNFG_ECG_r.bits.dhpf = 1; // Digital HPF cutoff = 0.5Hz |
Mahir Ozturk |
13:fba77a5d0fa0 | 42 | CNFG_ECG_r.bits.gain = 3; // ECG gain = 160V/V |
Mahir Ozturk |
13:fba77a5d0fa0 | 43 | CNFG_ECG_r.bits.rate = 2; // Sample rate = 128 sps |
Mahir Ozturk |
13:fba77a5d0fa0 | 44 | ecgAFE.writeRegister( MAX30003::CNFG_ECG , CNFG_ECG_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 45 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 46 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 47 | //R-to-R configuration |
Mahir Ozturk |
13:fba77a5d0fa0 | 48 | MAX30003::RtoR1Configuration_u CNFG_RTOR_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 49 | CNFG_RTOR_r.bits.wndw = 0b0011; // WNDW = 96ms |
Mahir Ozturk |
13:fba77a5d0fa0 | 50 | CNFG_RTOR_r.bits.rgain = 0b1111; // Auto-scale gain |
Mahir Ozturk |
13:fba77a5d0fa0 | 51 | CNFG_RTOR_r.bits.pavg = 0b11; // 16-average |
Mahir Ozturk |
13:fba77a5d0fa0 | 52 | CNFG_RTOR_r.bits.ptsf = 0b0011; // PTSF = 4/16 |
Mahir Ozturk |
13:fba77a5d0fa0 | 53 | CNFG_RTOR_r.bits.en_rtor = 1; // Enable R-to-R detection |
Mahir Ozturk |
13:fba77a5d0fa0 | 54 | ecgAFE.writeRegister( MAX30003::CNFG_RTOR1 , CNFG_RTOR_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 55 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 56 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 57 | //Manage interrupts register setting |
Mahir Ozturk |
13:fba77a5d0fa0 | 58 | MAX30003::ManageInterrupts_u MNG_INT_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 59 | MNG_INT_r.bits.efit = 0b00011; // Assert EINT w/ 4 unread samples |
Mahir Ozturk |
13:fba77a5d0fa0 | 60 | MNG_INT_r.bits.clr_rrint = 0b01; // Clear R-to-R on RTOR reg. read back |
Mahir Ozturk |
13:fba77a5d0fa0 | 61 | ecgAFE.writeRegister( MAX30003::MNGR_INT , MNG_INT_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 62 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 63 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 64 | //Enable interrupts register setting |
Mahir Ozturk |
13:fba77a5d0fa0 | 65 | MAX30003::EnableInterrupts_u EN_INT_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 66 | EN_INT_r.bits.en_eint = 1; // Enable EINT interrupt |
Mahir Ozturk |
13:fba77a5d0fa0 | 67 | EN_INT_r.bits.en_rrint = 1; // Enable R-to-R interrupt |
Mahir Ozturk |
13:fba77a5d0fa0 | 68 | EN_INT_r.bits.intb_type = 3; // Open-drain NMOS with internal pullup |
Mahir Ozturk |
13:fba77a5d0fa0 | 69 | ecgAFE.writeRegister( MAX30003::EN_INT , EN_INT_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 70 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 71 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 72 | //Dyanmic modes config |
Mahir Ozturk |
13:fba77a5d0fa0 | 73 | MAX30003::ManageDynamicModes_u MNG_DYN_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 74 | MNG_DYN_r.bits.fast = 0; // Fast recovery mode disabled |
Mahir Ozturk |
13:fba77a5d0fa0 | 75 | ecgAFE.writeRegister( MAX30003::MNGR_DYN , MNG_DYN_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 76 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 77 | // MUX Config |
Mahir Ozturk |
13:fba77a5d0fa0 | 78 | MAX30003::MuxConfiguration_u CNFG_MUX_r; |
Mahir Ozturk |
13:fba77a5d0fa0 | 79 | CNFG_MUX_r.bits.openn = 0; // Connect ECGN to AFE channel |
Mahir Ozturk |
13:fba77a5d0fa0 | 80 | CNFG_MUX_r.bits.openp = 0; // Connect ECGP to AFE channel |
Mahir Ozturk |
13:fba77a5d0fa0 | 81 | ecgAFE.writeRegister( MAX30003::CNFG_EMUX , CNFG_MUX_r.all); |
Mahir Ozturk |
13:fba77a5d0fa0 | 82 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 83 | return; |
Mahir Ozturk |
13:fba77a5d0fa0 | 84 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 85 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 86 | void max30003_reader_task(struct max30003_reader_task_args *args) |
Mahir Ozturk |
13:fba77a5d0fa0 | 87 | { |
Mahir Ozturk |
13:fba77a5d0fa0 | 88 | // Constants |
Mahir Ozturk |
13:fba77a5d0fa0 | 89 | const int EINT_STATUS = 1 << 23; |
Mahir Ozturk |
13:fba77a5d0fa0 | 90 | const int RTOR_STATUS = 1 << 10; |
Mahir Ozturk |
13:fba77a5d0fa0 | 91 | const int RTOR_REG_OFFSET = 10; |
Mahir Ozturk |
13:fba77a5d0fa0 | 92 | const float RTOR_LSB_RES = 0.0078125f; |
Mahir Ozturk |
13:fba77a5d0fa0 | 93 | const int FIFO_OVF = 0x7; |
Mahir Ozturk |
13:fba77a5d0fa0 | 94 | const int FIFO_VALID_SAMPLE = 0x0; |
Mahir Ozturk |
13:fba77a5d0fa0 | 95 | const int FIFO_FAST_SAMPLE = 0x1; |
Mahir Ozturk |
13:fba77a5d0fa0 | 96 | const int ETAG_BITS = 0x7; |
Mahir Ozturk |
13:fba77a5d0fa0 | 97 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 98 | uint32_t ecgFIFO, RtoR, readECGSamples, ETAG[32], status; |
Mahir Ozturk |
13:fba77a5d0fa0 | 99 | float BPM; |
Mahir Ozturk |
13:fba77a5d0fa0 | 100 | Timer bleNotifyTimer; |
Mahir Ozturk |
13:fba77a5d0fa0 | 101 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 102 | thread = args->self; |
Mahir Ozturk |
13:fba77a5d0fa0 | 103 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 104 | MAX30003 max30003(args->spiBus, args->spiCS); /* MAX30003WING board */ |
Mahir Ozturk |
13:fba77a5d0fa0 | 105 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 106 | InterruptIn ecgFIFO_int(P5_4); // Config P5_4 as int. in for the |
Mahir Ozturk |
13:fba77a5d0fa0 | 107 | ecgFIFO_int.fall(&ecgFIFO_callback); // ecg FIFO almost full interrupt |
Mahir Ozturk |
13:fba77a5d0fa0 | 108 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 109 | ecg_config(max30003); // Config ECG |
Mahir Ozturk |
13:fba77a5d0fa0 | 110 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 111 | max30003.writeRegister( MAX30003::SYNCH , 0); |
Mahir Ozturk |
13:fba77a5d0fa0 | 112 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 113 | bleNotifyTimer.start(); |
Mahir Ozturk |
13:fba77a5d0fa0 | 114 | while (1) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 115 | // Read back ECG samples from the FIFO |
Mahir Ozturk |
13:fba77a5d0fa0 | 116 | thread->signal_wait(MAX30003_IRQ_ASSERTED_SIGNAL_ID); |
Mahir Ozturk |
13:fba77a5d0fa0 | 117 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 118 | while (1) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 119 | /* Read back ECG samples from the FIFO */ |
Mahir Ozturk |
13:fba77a5d0fa0 | 120 | status = max30003.readRegister( MAX30003::STATUS ); // Read the STATUS register |
Mahir Ozturk |
13:fba77a5d0fa0 | 121 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 122 | if ((status & (RTOR_STATUS | EINT_STATUS)) == 0) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 123 | break; |
Mahir Ozturk |
13:fba77a5d0fa0 | 124 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 125 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 126 | // Check if R-to-R interrupt asserted |
Mahir Ozturk |
13:fba77a5d0fa0 | 127 | if ((status & RTOR_STATUS) == RTOR_STATUS) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 128 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 129 | // printf("R-to-R Interrupt \r\n"); |
Mahir Ozturk |
13:fba77a5d0fa0 | 130 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 131 | // Read RtoR register |
Mahir Ozturk |
13:fba77a5d0fa0 | 132 | RtoR = max30003.readRegister(MAX30003::RTOR) >> RTOR_REG_OFFSET; |
Mahir Ozturk |
13:fba77a5d0fa0 | 133 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 134 | // Convert to BPM |
Mahir Ozturk |
13:fba77a5d0fa0 | 135 | BPM = 1.0f / ( RtoR * RTOR_LSB_RES / 60.0f ); |
Mahir Ozturk |
13:fba77a5d0fa0 | 136 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 137 | if (bleNotifyTimer.read_ms() >= (args->notify_period_sec * 1000)) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 138 | printf("BPM: %.2f\r\n", BPM); |
Mahir Ozturk |
13:fba77a5d0fa0 | 139 | bleGattAttrWrite(args->gatt, (uint8_t *)&BPM, sizeof(BPM)); |
Mahir Ozturk |
13:fba77a5d0fa0 | 140 | bleNotifyTimer.reset(); |
Mahir Ozturk |
13:fba77a5d0fa0 | 141 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 142 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 143 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 144 | // Check if EINT interrupt asserted |
Mahir Ozturk |
13:fba77a5d0fa0 | 145 | if ((status & EINT_STATUS) == EINT_STATUS) { |
Mahir Ozturk |
13:fba77a5d0fa0 | 146 | readECGSamples = 0; // Reset sample counter |
Mahir Ozturk |
13:fba77a5d0fa0 | 147 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 148 | do { |
Mahir Ozturk |
13:fba77a5d0fa0 | 149 | ecgFIFO = max30003.readRegister( MAX30003::ECG_FIFO ); // Read FIFO |
Mahir Ozturk |
13:fba77a5d0fa0 | 150 | ETAG[readECGSamples] = ( ecgFIFO >> 3 ) & ETAG_BITS; // Isolate ETAG |
Mahir Ozturk |
13:fba77a5d0fa0 | 151 | readECGSamples++; // Increment sample counter |
Mahir Ozturk |
13:fba77a5d0fa0 | 152 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 153 | // Check that sample is not last sample in FIFO |
Mahir Ozturk |
13:fba77a5d0fa0 | 154 | } while (ETAG[readECGSamples-1] == FIFO_VALID_SAMPLE || |
Mahir Ozturk |
13:fba77a5d0fa0 | 155 | ETAG[readECGSamples-1] == FIFO_FAST_SAMPLE); |
Mahir Ozturk |
13:fba77a5d0fa0 | 156 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 157 | // Check if FIFO has overflowed |
Mahir Ozturk |
13:fba77a5d0fa0 | 158 | if (ETAG[readECGSamples - 1] == FIFO_OVF){ |
Mahir Ozturk |
13:fba77a5d0fa0 | 159 | max30003.writeRegister( MAX30003::FIFO_RST , 0); // Reset FIFO |
Mahir Ozturk |
13:fba77a5d0fa0 | 160 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 161 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 162 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 163 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 164 | } |
Mahir Ozturk |
13:fba77a5d0fa0 | 165 | |
Mahir Ozturk |
13:fba77a5d0fa0 | 166 |