BioSignalPi  v2
ecgcapture.cpp
Go to the documentation of this file.
1 
2 #include <libFiles/bcm2835.h>
3 #include "ecgcapture.h"
4 #include <QVector>
5 #include <QDebug>
6 #include "stdio.h"
7 #include "meanFilter.h"
8 
9 #define PIN18 RPI_GPIO_P1_18
10 #define PIN16 RPI_GPIO_P1_16
11 
12 static float vreff = 1.8, ECG_GAIN = 1.4, RESPIRATION_gain = 1;
13 static unsigned int nFrames;
14 
16 {
17  test = 0;
18 }
19 
27 {
28  if (!bcm2835_init()) {
29  qDebug() << ("Could not init bcm2835 in EcgCapture") << endl;
30  exit(EXIT_FAILURE);
31  }
32 
33  spiInit();
34 
35  QByteArray CMREFCTL;
36  CMREFCTL.resize(4);
37 
38  QByteArray FILTCTL;
39  FILTCTL.resize(4);
40 
41  QByteArray FRMCTL;
42  FRMCTL.resize(4);
43 
44  QByteArray ECGCTL;
45  ECGCTL.resize(4);
46 
47  QByteArray RESPCTL;
48  RESPCTL.resize(4);
49 
50  QByteArray TESTTONE;
51  TESTTONE.resize(4);
52 
53  QByteArray LOFFCTL;
54  LOFFCTL.resize(4);
55 
56  //Configure registers depending on source
57  switch (mode) {
58  case ecgCapture:
59  //CMREFCTL is set to 0x85E0000A
60  CMREFCTL[0] = 0x85;
61  CMREFCTL[1] = 0xE0;
62  CMREFCTL[2] = 0x00;
63  CMREFCTL[3] = 0x4A; //0x0A for the first board, 0x4A for the REV_A board
64 
65  //FILTCTL is set to 0x8B000000
66  FILTCTL[0] = 0x8B;
67  FILTCTL[1] = 0x00;
68  FILTCTL[2] = 0x00;
69  FILTCTL[3] = 0x00;
70 
71  //FRMCTL is set to 0x8A1FCE00
72  FRMCTL[0] = 0x8A;
73  FRMCTL[1] = 0x1F;
74  FRMCTL[2] = 0xC6; //CE = pace disabled, C6 = pace disabled LOFF enabled
75  FRMCTL[3] = 0x00;
76 
77  LOFFCTL[0] = 0x82;
78  LOFFCTL[1] = 0x00;
79  LOFFCTL[2] = 0x00;
80  LOFFCTL[3] = 0x15;
81 
82  //ECGCTL is set to 0x81F800AE
83  ECGCTL[0] = 0x81;
84  ECGCTL[1] = 0xF8;
85  ECGCTL[2] = 0x00;
86  ECGCTL[3] = 0xAE;
87 
88  //RESPCTL is set to 0x83002099
89  RESPCTL[0] = 0x83;
90  RESPCTL[1] = 0x00;
91  RESPCTL[2] = 0x20;
92  RESPCTL[3] = 0x99;
93  break;
94  case testToneSquare:
95  //CMREFCTL is set to 0x8500000B
96  CMREFCTL[0] = 0x85;
97  CMREFCTL[1] = 0x00;
98  CMREFCTL[2] = 0x00;
99  CMREFCTL[3] = 0x0B;
100 
101  //TESTTONE is set to 0x88F8001D
102  TESTTONE[0] = 0x88;
103  TESTTONE[1] = 0xF8;
104  TESTTONE[2] = 0x00;
105  TESTTONE[3] = 0x1D;
106 
107  //FILTCTL is set to 0x8B000008
108  FILTCTL[0] = 0x8B;
109  FILTCTL[1] = 0x00;
110  FILTCTL[2] = 0x00;
111  FILTCTL[3] = 0x1D;
112 
113  //FRMCTL is set to 0x8A1FCE10
114  FRMCTL[0] = 0x8A;
115  FRMCTL[1] = 0x1F;
116  FRMCTL[2] = 0xCE;
117  FRMCTL[3] = 0x10;
118 
119  //ECGCTL is set to 0x81F800AE
120  ECGCTL[0] = 0x81;
121  ECGCTL[1] = 0xF8;
122  ECGCTL[2] = 0x00;
123  ECGCTL[3] = 0xAE;
124  break;
125  case testToneLowFreqSin:
126  //CMREFCTL is set to 0x8500000B
127  CMREFCTL[0] = 0x85;
128  CMREFCTL[1] = 0x00;
129  CMREFCTL[2] = 0x00;
130  CMREFCTL[3] = 0x0B;
131 
132  //TESTTONE is set to 0x88F80005
133  TESTTONE[0] = 0x88;
134  TESTTONE[1] = 0xF8;
135  TESTTONE[2] = 0x00;
136  TESTTONE[3] = 0x05;
137 
138  //FILTCTL is set to 0x8B000008
139  FILTCTL[0] = 0x8B;
140  FILTCTL[1] = 0x00;
141  FILTCTL[2] = 0x00;
142  FILTCTL[3] = 0x08;
143 
144  //FRMCTL is set to 0x8A1FCE10
145  FRMCTL[0] = 0x8A;
146  FRMCTL[1] = 0x1F;
147  FRMCTL[2] = 0xCE;
148  FRMCTL[3] = 0x10;
149 
150  //ECGCTL is set to 0x81F800AE
151  ECGCTL[0] = 0x81;
152  ECGCTL[1] = 0xF8;
153  ECGCTL[2] = 0x00;
154  ECGCTL[3] = 0xAE;
155  break;
156  case testToneHighFreqSin:
157  //CMREFCTL is set to 0x8500000B
158  CMREFCTL[0] = 0x85;
159  CMREFCTL[1] = 0x00;
160  CMREFCTL[2] = 0x00;
161  CMREFCTL[3] = 0x0B;
162 
163  //TESTTONE is set to 0x88F8000D
164  TESTTONE[0] = 0x88;
165  TESTTONE[1] = 0xF8;
166  TESTTONE[2] = 0x00;
167  TESTTONE[3] = 0x0D;
168 
169  //FILTCTL is set to 0x8B000008
170  FILTCTL[0] = 0x8B;
171  FILTCTL[1] = 0x00;
172  FILTCTL[2] = 0x00;
173  FILTCTL[3] = 0x08;
174 
175  //FRMCTL is set to 0x8A1FCE10
176  FRMCTL[0] = 0x8A;
177  FRMCTL[1] = 0x1F;
178  FRMCTL[2] = 0xCE;
179  FRMCTL[3] = 0x10;
180 
181  //ECGCTL is set to 0x81F800AE
182  ECGCTL[0] = 0x81;
183  ECGCTL[1] = 0xF8;
184  ECGCTL[2] = 0x00;
185  ECGCTL[3] = 0xAE;
186  break;
187  default:
188  break;
189  }
190 
191  //Set sampling frequency
192  switch (freq) {
193  case lowFreq:
194  FRMCTL[3] = FRMCTL[3] & 0xF3;
195  FRMCTL[3] = FRMCTL[3] | 0x0C;
196  qDebug()<<"Low freq";
197  break;
198  case midFreq:
199  FRMCTL[3] = FRMCTL[3] & 0xF3;
200  FRMCTL[3] = FRMCTL[3] | 0x04;
201  qDebug()<<"Mid freq";
202  break;
203  case highFreq:
204  FRMCTL[3] = FRMCTL[3] & 0xF3;
205  FRMCTL[3] = FRMCTL[3] | 0x00;
206  qDebug()<<"High freq";
207  break;
208  default:
209  break;
210  }
211 
212  if (mode == ecgCapture) {
213  setReg(CMREFCTL);
214  setReg(FILTCTL);
215  setReg(FRMCTL);
216  setReg(ECGCTL);
217  setReg(RESPCTL);
218  setReg(LOFFCTL);
219  leadMode = digital;
220  nFrames = 7;
221  } else {
222  setReg(CMREFCTL);
223  setReg(TESTTONE);
224  setReg(FILTCTL);
225  setReg(FRMCTL);
226  setReg(ECGCTL);
227  leadMode = electrode;
228  nFrames = 6;
229  }
230 }
231 
235 void EcgCapture::spiInit()
236 {
237  bcm2835_gpio_fsel(PIN18, BCM2835_GPIO_FSEL_OUTP);
238  bcm2835_gpio_write(PIN18, LOW);
239  delay(100);
240  bcm2835_gpio_write(PIN18, HIGH);
241  delay(100);
242  bcm2835_spi_begin();
243  bcm2835_spi_setBitOrder(BCM2835_SPI_BIT_ORDER_MSBFIRST);
244  bcm2835_spi_setDataMode(BCM2835_SPI_MODE0);
245  bcm2835_spi_setClockDivider(BCM2835_SPI_CLOCK_DIVIDER_512);
246  bcm2835_spi_chipSelect(BCM2835_SPI_CS0);
247  bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);
248  bcm2835_gpio_fsel(PIN16, BCM2835_GPIO_FSEL_INPT);
249 }
250 
258 {
259  QByteArray TESTIN;
260  TESTIN.resize(4);
261 
262  QByteArray TESTOUT;
263  TESTOUT.resize(4);
264 
265  TESTIN[0] = 0x01;
266  TESTIN[1] = 0x00;
267  TESTIN[2] = 0x00;
268  TESTIN[3] = 0x00;
269 
270  TESTOUT[0] = 0x11;
271  TESTOUT[1] = 0x11;
272  TESTOUT[2] = 0x11;
273  TESTOUT[3] = 0x11;
274 
275  qDebug()<<TESTOUT.toHex();
276 
277  bcm2835_spi_transfernb(TESTIN.data(), TESTOUT.data(), TESTIN.size());
278 
279  qDebug()<<TESTOUT.toHex();
280 
281  if(bcm2835_gpio_lev(PIN16)==LOW) {
282  qDebug()<<"LOW";
283  } else {
284  qDebug()<<"HIGH";
285  }
286 
287  QByteArray FRAMES;
288  QByteArray DATAOUT;
289  FRAMES.resize(4);
290  DATAOUT.resize(4);
291 
292  FRAMES[0] = 0x00;
293  FRAMES[1] = 0x00;
294  FRAMES[2] = 0x00;
295  FRAMES[3] = 0x00;
296 
297  DATAOUT[0] = 0x11;
298  DATAOUT[1] = 0x11;
299  DATAOUT[2] = 0x11;
300  DATAOUT[3] = 0x11;
301 
302  qDebug()<<DATAOUT.toHex();
303  bcm2835_spi_transfernb(FRAMES.data(), DATAOUT.data(), FRAMES.size());
304  qDebug()<<DATAOUT.toHex();
305 }
306 
310 bool EcgCapture::setReg(QByteArray writeCommand)
311 {
312  //Validate the input
313  if (writeCommand.size() != 4)
314  return 0;
315 
316  enableRegisterWrite();
317  bcm2835_spi_transfern(writeCommand.data(), writeCommand.size());
318 
319  return 1;
320 }
321 
325 void EcgCapture::csEnable()
326 {
327  bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, LOW);
328 }
329 
334 void EcgCapture::csDisable()
335 {
336  bcm2835_spi_setChipSelectPolarity(BCM2835_SPI_CS0, HIGH);
337 }
338 
344 void EcgCapture::enableRegisterWrite()
345 {
346  csDisable();
347  csEnable();
348 }
349 
354 {
355  enableRegisterWrite();
356 
357  char FRAMES1[] = {0x40,0x00,0x00,0x00};
358  bcm2835_spi_transfern(FRAMES1,sizeof(FRAMES1));
359 }
360 
361 
363 {
364 
365 }
366 
370 double EcgCapture::ecgVoltageConversion(int ADCDecimal, leadFormat format)
371 {
372  double ecg_voltage = 0;
373 
374  if (format == digital) {
375  if(ADCDecimal> 8388608) {
376  ecg_voltage = ((4*vreff*(-(16777216-ADCDecimal))/ECG_GAIN)/(16777215));
377  } else {
378  ecg_voltage = ((4*vreff*ADCDecimal)/ECG_GAIN)/(16777215);
379  }
380  } else if (format == electrode) {
381  ecg_voltage = (2*ADCDecimal*(vreff/ECG_GAIN))/(16777215);
382  }
383 
384  return ecg_voltage;
385 }
386 
390 double EcgCapture::respVoltageConversion(int ADCDecimal)
391 {
392  return 4*(vreff/(1.6468*RESPIRATION_gain))*ADCDecimal/(16777215);
393 }
394 
400 const QVector<double> EcgCapture::readFrame()
401 {
402  unsigned int counter = 0;
403  char FRAMES[] = {0x00,0x00,0x00,0x00};
404  char DATAOUT[] = {0,0,0,0};
405  int lead = 0;
406  QVector<double> frame;
407  bool ecgFlag = false;
408  bool respFlag = false;
409  bool loffFlag = false;
410 
411  csEnable();
412 
413  while (counter<nFrames) {
414  if(bcm2835_gpio_lev(PIN16)==LOW) {
415  bcm2835_spi_transfernb(FRAMES, DATAOUT, sizeof(FRAMES));
416 
417  //Uncomment theese lines to check if frames are dropped
418  //NOTE: writing to the terminal is slow so for performance reasons
419  // theese code snipped is not used.
420 // if (DATAOUT[0] == 0xb0) {
421 // test++;
422 // if (test%100 == 0) {
423 // printf("%d\n",test);
424 // }
425 // }
426 
427  lead = 0;
428 
429  if (DATAOUT[0] == 0x11) {
430  //Lead I
431  lead |= (DATAOUT[1] << 16);
432  lead |= (DATAOUT[2] << 8);
433  lead |= DATAOUT[3];
434  ecgFlag = true;
435  } else if (DATAOUT[0] == 0x12) {
436  //Lead II
437  lead |= (DATAOUT[1] << 16);
438  lead |= (DATAOUT[2] << 8);
439  lead |= DATAOUT[3];
440  ecgFlag = true;
441  } else if (DATAOUT[0] == 0x13) {
442  //Lead III
443  lead |= (DATAOUT[1] << 16);
444  lead |= (DATAOUT[2] << 8);
445  lead |= DATAOUT[3];
446  ecgFlag = true;
447  } else if (DATAOUT[0] == 27) {
448  //Resp mag.
449  lead |= (DATAOUT[1] << 16);
450  lead |= (DATAOUT[2] << 8);
451  lead |= DATAOUT[3];
452  respFlag = true;
453  } else if (DATAOUT[0] == 0x1D) {
454  //LOFF
455  int mask = 0xF0;
456  int tmp = (DATAOUT[1] & mask) >> 4;
457  if (tmp == 0x00) {
458  //Leads connected
459  lead = 0;
460  } else {
461  //Leads disconnected
462  lead = 1;
463  }
464  loffFlag = true;
465  }
466 
467  if (ecgFlag) {
468  frame.append(ecgVoltageConversion(lead, leadMode));
469  //frame.append(filterEcgVal(ecgVoltageConversion(lead)));
470  } else if (respFlag) {
471  frame.append(filterVal(respVoltageConversion(lead)));
472  } else if (loffFlag) {
473  if (lead == 0) {
474  //Leads connected
475  frame.append(0.0);
476  } else {
477  //Leads disconnected
478  frame.append(1.0);
479  }
480  }
481 
482  ecgFlag = false;
483  respFlag = false;
484  loffFlag = false;
485  counter++;
486  }
487  }
488 
489  csDisable();
490 
491  counter = 0;
492 
493  return frame;
494 }
495 
const QVector< double > readFrame()
Reads a single frame.
Definition: ecgcapture.cpp:400
void testDevice()
Method used to test if the device is working properly.
Definition: ecgcapture.cpp:257
void start()
Start capturing frames from the ADAS1000.
Definition: ecgcapture.cpp:353
void init(OperatingMode, Frequency)
Initiate the device by configuring the registers depending on operating mode and sampling frequency...
Definition: ecgcapture.cpp:26
void stop()
stop capture
Definition: ecgcapture.cpp:362
#define PIN16
Definition: ecgcapture.cpp:10
#define PIN18
Definition: ecgcapture.cpp:9
double filterVal(double val)
Definition: meanFilter.cpp:3