Important changes to forums and questions
All forums and questions are now archived. To start a new conversation or read the latest updates go to forums.mbed.com.
5 years, 3 months ago.
nRF52-DK & MAX30003 WING ecg sensor
Hi all,
I have been working on a project on the nRF52 development kit and with the ecg sensor breakout board MAX30003 WING.
Ideally, I would like the device to collect all the ecg samples and also the R-to-R intervals and broadcasting it through bluetooth. It would be great to have the ability to only collect the raw data and the R-to-R intervals only upon the interrupt call from MAX30003 WING.
I found some ecg demo projects on mbed but they are written for MAX32630FTHR. I then referred to the demos and tried to integrate it's function on nRF52 DK. Similar to the demo, I am using SPI to communicate with the ecg sensor.
After writing the project, there are some problems that surfaced that I could not understand nor fix,
1. No interrupt calls were triggered from the ecg sensor despite the ecg FIFO being full. From what I have understood from the datasheet, there are a few interrupts that the MAX30003 WING will trigger, including R-to-R interrupt, but none of it were actually being called. Therefore, the no readings are coming in.
2. Setting aside the interrupt calls, I would like to see a working set of data and went ahead to reading the ecg FIFO directly instead. When displayed on the serial plotter, there are actually data coming through and being read, but it is nothing near from a QRS wave and resembles nothing like an ecg signal. R-to-R readings are present but they were not accurate and it seems like they were almost random and arbitrary.
With these problems in mind, I have also discovered that the VDD pin on the nRF52 DK board were not supplying 3.3v as there is a diode that were shown in the schematics that's dropping the voltage by 0.4v0.5v. As the ecg board requires a 3.3v supply and there is a voltage regulator on the board that could take in 5v, I have then tried to run the code with the 3v3 pin of MAX30003WING connected to the 5v pin on nRF52 DK, but the results is similar as before.
Can anyone that might have worked on any of the both devices that could enlighten me on these issues? Thank you so much.
Here is the code that I have pieced up using the sample demo project found on the forum
#include <mbed.h> #include "MAX30003.h" void ecgConfig (MAX30003 &ecgAFE); // Config function prototype /* ECG FIFO nearly full callback */ /*volatile bool ecgFIFOIntFlag = 0; void ecgFIFO_callback() { ecgFIFOIntFlag = 1; } */ int main() { const int EINT_STATUS_MASK = 1 << 23; const int FIFO_OVF_MASK = 0x7; const int FIFO_VALID_SAMPLE_MASK = 0x0; const int FIFO_FAST_SAMPLE_MASK = 0x1; const int ETAG_BITS_MASK = 0x7; printf("START\r\n"); SPI spi(SPI_PSELMOSI1, SPI_PSELMISO1, SPI_PSELSCK1); DigitalOut cs(SPI_PSELSS1); // InterruptIn ecgFIFO_int(p15); // PIN 15 is D5 ecgFIFO_int.fall(&ecgFIFO_callback); ecgFIFO_int.enable_irq(); MAX30003 ecgAFE(spi, SPI_PSELSS1); // New MAX30003 on spiBus, CS = SPI_PSELSS0 ecgConfig( ecgAFE ); // Config ECG ecgAFE.writeRegister( MAX30003::SYNCH , 0); uint32_t ecgFIFO, RtoR, readECGSamples, idx, ETAG[32], status; int16_t ecgSample[32]; float BPM; const int EINT_STATUS = 1 << 23; const int RTOR_STATUS = 1 << 10; const int RTOR_REG_OFFSET = 10; const float RTOR_LSB_RES = 0.0078125f; const int FIFO_OVF = 0x7; const int FIFO_VALID_SAMPLE = 0x0; const int FIFO_FAST_SAMPLE = 0x1; const int ETAG_BITS = 0x7; while(1) { readECGSamples = 0; // Reset sample counter do { ecgFIFO = ecgAFE.readRegister( MAX30003::ECG_FIFO ); // Read FIFO ecgSample[readECGSamples] = ecgFIFO >> 8; // Isolate voltage data ETAG[readECGSamples] = ( ecgFIFO >> 3 ) & ETAG_BITS; // Isolate ETAG readECGSamples++; // Increment sample counter // Check that sample is not last sample in FIFO } while ( ETAG[readECGSamples-1] == FIFO_VALID_SAMPLE || ETAG[readECGSamples-1] == FIFO_FAST_SAMPLE ); printf("%d samples read from FIFO \r\n", readECGSamples); // Check if FIFO has overflowed if( ETAG[readECGSamples - 1] == FIFO_OVF ){ ecgAFE.writeRegister( MAX30003::FIFO_RST , 0); // Reset FIFO } // Print results for( idx = 0; idx < readECGSamples; idx++ ) { printf("Sample : %6d, \tETAG : 0x%x\r\n", ecgSample[idx], ETAG[idx]); } printf("\r\n\r\n\r\n"); // Read back ECG samples from the FIFO if( ecgFIFOIntFlag ) { printf("Interrupt triggered\r\n"); ecgFIFOIntFlag = 0; status = ecgAFE.readRegister( MAX30003::STATUS ); // Read the STATUS register printf("Status : 0x%x\r\n", status); // Check if R-to-R interrupt asserted if( ( status & RTOR_STATUS ) == RTOR_STATUS ){ printf("R-to-R Interrupt \r\n"); // Read RtoR register RtoR = ecgAFE.readRegister( MAX30003::RTOR ) >> RTOR_REG_OFFSET; // Convert to BPM BPM = 1.0f / ( RtoR * RTOR_LSB_RES / 60.0f ); // Print RtoR printf("RtoR : %d\r\n\r\n", RtoR); } // Check if EINT interrupt asserted if ( ( status & EINT_STATUS ) == EINT_STATUS ) { printf("FIFO Interrupt \r\n"); readECGSamples = 0; // Reset sample counter do { ecgFIFO = ecgAFE.readRegister( MAX30003::ECG_FIFO ); // Read FIFO ecgSample[readECGSamples] = ecgFIFO >> 8; // Isolate voltage data ETAG[readECGSamples] = ( ecgFIFO >> 3 ) & ETAG_BITS; // Isolate ETAG readECGSamples++; // Increment sample counter // Check that sample is not last sample in FIFO } while ( ETAG[readECGSamples-1] == FIFO_VALID_SAMPLE || ETAG[readECGSamples-1] == FIFO_FAST_SAMPLE ); printf("%d samples read from FIFO \r\n", readECGSamples); // Check if FIFO has overflowed if( ETAG[readECGSamples - 1] == FIFO_OVF ){ ecgAFE.writeRegister( MAX30003::FIFO_RST , 0); // Reset FIFO } // Print results for( idx = 0; idx < readECGSamples; idx++ ) { printf("Sample : %6d, \tETAG : 0x%x\r\n", ecgSample[idx], ETAG[idx]); } printf("\r\n\r\n\r\n"); } } } } void ecgConfig(MAX30003& ecgAFE) { // Reset ECG to clear registers ecgAFE.writeRegister( MAX30003::SW_RST , 0); // General config register setting MAX30003::GeneralConfiguration_u CNFG_GEN_r; CNFG_GEN_r.bits.en_ecg = 1; // Enable ECG channel CNFG_GEN_r.bits.rbiasn = 1; // Enable resistive bias on negative input CNFG_GEN_r.bits.rbiasp = 1; // Enable resistive bias on positive input CNFG_GEN_r.bits.en_rbias = 1; // Enable resistive bias CNFG_GEN_r.bits.imag = 2; // Current magnitude = 10nA CNFG_GEN_r.bits.en_dcloff = 1; // Enable DC lead-off detection ecgAFE.writeRegister( MAX30003::CNFG_GEN , CNFG_GEN_r.all); // ECG Config register setting MAX30003::ECGConfiguration_u CNFG_ECG_r; CNFG_ECG_r.bits.dlpf = 1; // Digital LPF cutoff = 40Hz CNFG_ECG_r.bits.dhpf = 1; // Digital HPF cutoff = 0.5Hz CNFG_ECG_r.bits.gain = 3; // ECG gain = 160V/V CNFG_ECG_r.bits.rate = 2; // Sample rate = 128 sps ecgAFE.writeRegister( MAX30003::CNFG_ECG , CNFG_ECG_r.all); //R-to-R configuration MAX30003::RtoR1Configuration_u CNFG_RTOR_r; CNFG_RTOR_r.bits.en_rtor = 1; // Enable R-to-R detection ecgAFE.writeRegister( MAX30003::CNFG_RTOR1 , CNFG_RTOR_r.all); //Manage interrupts register setting MAX30003::ManageInterrupts_u MNG_INT_r; MNG_INT_r.bits.efit = 0b00011; // Assert EINT w/ 4 unread samples MNG_INT_r.bits.clr_rrint = 0b01; // Clear R-to-R on RTOR reg. read back ecgAFE.writeRegister( MAX30003::MNGR_INT , MNG_INT_r.all); //Enable interrupts register setting MAX30003::EnableInterrupts_u EN_INT_r; EN_INT_r.all = 1; EN_INT_r.bits.en_eint = 1; // Enable EINT interrupt EN_INT_r.bits.en_rrint = 1; // Disable R-to-R interrupt OR 1 = enable EN_INT_r.bits.intb_type = 3; // Open-drain NMOS with internal pullup ecgAFE.writeRegister( MAX30003::EN_INT , EN_INT_r.all); //Dyanmic modes config MAX30003::ManageDynamicModes_u MNG_DYN_r; MNG_DYN_r.bits.fast = 0; // Fast recovery mode disabled ecgAFE.writeRegister( MAX30003::MNGR_DYN , MNG_DYN_r.all); // MUX Config MAX30003::MuxConfiguration_u CNFG_MUX_r; CNFG_MUX_r.bits.openn = 0; // Connect ECGN to AFE channel CNFG_MUX_r.bits.openp = 0; // Connect ECGP to AFE channel ecgAFE.writeRegister( MAX30003::CNFG_EMUX , CNFG_MUX_r.all); return; }