This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

nRF52840 - ADS1292

Hi,

I want to read register 0x00 (chip ID) of ads1292. i do following...

=============================================================================================================================

///// init spi /////

spi_config.ss_pin = ARDUINO_7_PIN;
spi_config.miso_pin = ARDUINO_12_PIN;
spi_config.mosi_pin = ARDUINO_11_PIN;
spi_config.sck_pin = ARDUINO_13_PIN;
spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
spi_config.mode = NRF_DRV_SPI_MODE_0;
spi_config.frequency = NRF_DRV_SPI_FREQ_4M;
spi_config.orc = 0x00;
APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
NRF_LOG_INFO("SPI example started.");NRF_LOG_FLUSH();

///// reset the board by pulling low hardware pin /////

nrf_gpio_pin_write(ADS1292_PWDN_PIN, action);

delay(100);

nrf_gpio_pin_write(ADS1292_PWDN_PIN, action);

delay(100);

nrf_gpio_pin_write(ADS1292_PWDN_PIN, action);

delay(100);

/////// stop continues data receive mode ///////

spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
spiDataTx[0]=0x11;
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spiDataTx, 1, m_rx_buf, sizeof(m_rx_buf)));
while (!spi_xfer_done){__WFE();}
NRF_LOG_FLUSH();

//////// read chip id register (0x00) ///////////

char tempData[3];
tempData[0]=0x20;
tempData[1]=0x00;
tempData[2]=0x00;
spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tempData, 3, m_rx_buf, sizeof(m_rx_buf)));
while (!spi_xfer_done){__WFE();}
NRF_LOG_FLUSH();

=============================================================================================================================

but i always get garbage value. It should come as 0x73 but every time receiving garbage values.

i did exactly same as described in datasheet of ads1292.

Did i anything wrong as far as nRF52 board concern ? Waiting for better solution.

Thanks in advance.

Parents
  • #include "nrf_drv_spi.h"
    #include "app_util_platform.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "ads1292.h"
    
    #define DEBUG 1
    
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE);  /**< SPI instance. */
    char spiDataTx[1];
    static uint8_t       m_rx_buf[50];    /**< RX buffer. */
    static volatile bool spi_xfer_done;  /**< Flag used to indicate that SPI instance completed the transfer. */
    
    void pinMode(long pinNum, long mode)
    {
      if(mode == OUTPUT)
        nrf_gpio_cfg_output(pinNum);
      else if(mode == INPUT)
        nrf_gpio_cfg_input(pinNum, BUTTON_PULL);
    }
    
    void digitalWrite(long pinNum, long action)
    {
      nrf_gpio_pin_write(pinNum, action);
    }
    
    long digitalRead(long pinNum)
    {
      return nrf_gpio_pin_read(pinNum);
    }
    
    void delay(int amount)
    {
      nrf_delay_ms(amount);
    }
    
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event,
                           void *                    p_context)
    {
        spi_xfer_done = true;
        NRF_LOG_INFO("Transfer completed.");//NRF_LOG_FLUSH();
        if (m_rx_buf[0] != 0)
        {
            NRF_LOG_INFO(" Received:");
            NRF_LOG_HEXDUMP_INFO(m_rx_buf, strlen((const char *)m_rx_buf));
        }
    }
    
    char* ads1292_Read_Data()
    {
        static char SPI_Dummy_Buff[10];
        digitalWrite(ADS1292_CS_PIN, LOW);
        for (int i = 0; i < 9; ++i)
        {
                spiDataTx[0]=CONFIG_SPI_MASTER_DUMMY;
                spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
                APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spiDataTx, 1, m_rx_buf, sizeof(m_rx_buf)));
                while (!spi_xfer_done){__WFE();}
                NRF_LOG_FLUSH();
        }
        digitalWrite(ADS1292_CS_PIN, HIGH);
        return SPI_Dummy_Buff;
    }
    
    void ads1292_Init()
    {
      // initalize the  data ready and chip select pins:
      pinMode(ADS1292_DRDY_PIN, INPUT);  //6
      pinMode(ADS1292_CS_PIN, OUTPUT);    //7
      pinMode(ADS1292_START_PIN, OUTPUT);  //5
      pinMode(ADS1292_PWDN_PIN, OUTPUT);  //4
    
      nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
      //spi_config.ss_pin   = ADS1292_CS_PIN;
      spi_config.miso_pin = ARDUINO_12_PIN;
      spi_config.mosi_pin = ARDUINO_11_PIN;
      spi_config.sck_pin  = ARDUINO_13_PIN;
      spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
      spi_config.mode = NRF_DRV_SPI_MODE_0;
      spi_config.frequency = NRF_DRV_SPI_FREQ_2M;
      spi_config.orc = 0x00;
      APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler, NULL));
      NRF_LOG_INFO("SPI example started.");NRF_LOG_FLUSH();
    
      if(DEBUG){NRF_LOG_INFO("0.0");NRF_LOG_FLUSH();}
      ads1292_Reset();
      delay(100);
      if(DEBUG){NRF_LOG_INFO("0.1");NRF_LOG_FLUSH();}
      ads1292_Disable_Start();
      if(DEBUG){NRF_LOG_INFO("0.2");NRF_LOG_FLUSH();}
      ads1292_Enable_Start();
      
      if(DEBUG){NRF_LOG_INFO("0.3");NRF_LOG_FLUSH();}
      ads1292_Hard_Stop();
      if(DEBUG){NRF_LOG_INFO("0.4");NRF_LOG_FLUSH();}
      ads1292_Start_Data_Conv_Command();
      if(DEBUG){NRF_LOG_INFO("0.5");NRF_LOG_FLUSH();}
      ads1292_Soft_Stop();
      if(DEBUG){NRF_LOG_INFO("0.6");NRF_LOG_FLUSH();}
      delay(50);
      if(DEBUG){NRF_LOG_INFO("0.7");NRF_LOG_FLUSH();}
      ads1292_Stop_Read_Data_Continuous();					// SDATAC command
      delay(300);
      if(DEBUG){NRF_LOG_INFO("0.8");NRF_LOG_FLUSH();}
    
      /// to read chip id register 0x00 ///
      ChipID();
      
    
      /*if(DEBUG){NRF_LOG_INFO("0.9");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_CONFIG1, 0x00); 		//Set sampling rate to 125 SPS
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.10");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_CONFIG2, 0b10100000);	//Lead-off comp off, test signal disabled
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.11");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_LOFF, 0b00010000);		//Lead-off defaults
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.12");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_CH1SET, 0b01000000);	//Ch 1 enabled, gain 6, connected to electrode in
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.13");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_CH2SET, 0b01100000);	//Ch 2 enabled, gain 6, connected to electrode in
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.14");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_RLDSENS, 0b00101100);	//RLD settings: fmod/16, RLD enabled, RLD inputs from Ch2 only
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.15");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_LOFFSENS, 0x00);		//LOFF settings: all disabled
      delay(10);
    														//Skip register 8, LOFF Settings default
      if(DEBUG){NRF_LOG_INFO("0.16");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_RESP1, 0b11110010);		//Respiration: MOD/DEMOD turned only, phase 0
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.17");NRF_LOG_FLUSH();}
      ads1292_Reg_Write(ADS1292_REG_RESP2, 0b00000011);		//Respiration: Calib OFF, respiration freq defaults
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.18");NRF_LOG_FLUSH();}
      ads1292_Start_Read_Data_Continuous();
      delay(10);
      if(DEBUG){NRF_LOG_INFO("0.19");NRF_LOG_FLUSH();}
      ads1292_Enable_Start();*/
    }
    
    void ads1292_Reset()
    {
      digitalWrite(ADS1292_PWDN_PIN, HIGH);
      delay(100);					// Wait 100 mSec
      digitalWrite(ADS1292_PWDN_PIN, LOW);
      delay(100);
      digitalWrite(ADS1292_PWDN_PIN, HIGH);
      delay(100);
    }
    
    void ads1292_Disable_Start()
    {
      digitalWrite(ADS1292_START_PIN, LOW);
      delay(20);
    }
    
    void ads1292_Enable_Start()
    {
      digitalWrite(ADS1292_START_PIN, HIGH);
      delay(20);
    }
    
    void ads1292_Hard_Stop (void)
    {
      digitalWrite(ADS1292_START_PIN, LOW);
      delay(100);
    }
    
    void ads1292_Start_Data_Conv_Command (void)
    {
      ads1292_SPI_Command_Data(START_CONV);					// Send 0x08 to the ADS1x9x
    }
    
    void ads1292_Soft_Stop (void)
    {
      ads1292_SPI_Command_Data(STOP_CONV);                   // Send 0x0A to the ADS1x9x
    }
    
    void ads1292_Start_Read_Data_Continuous (void)
    {
      ads1292_SPI_Command_Data(RDATAC);					// Send 0x10 to the ADS1x9x
    }
    
    void ads1292_Stop_Read_Data_Continuous (void)
    {
      ads1292_SPI_Command_Data(SDATAC);					// Send 0x11 to the ADS1x9x
    }
    
    void ads1292_SPI_Command_Data(unsigned char data_in)
    {
      //byte data[1];
      //data[0] = data_in;
      digitalWrite(ADS1292_CS_PIN, LOW);
      delay(2);
      digitalWrite(ADS1292_CS_PIN, HIGH);
      delay(2);
      digitalWrite(ADS1292_CS_PIN, LOW);
      delay(2);
    
      if(DEBUG){NRF_LOG_INFO("1.0");NRF_LOG_FLUSH();}
      spiDataTx[0]=data_in;
      spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spiDataTx, 1, m_rx_buf, sizeof(m_rx_buf)));
      while (!spi_xfer_done){__WFE();}
      NRF_LOG_FLUSH();
      
      delay(2);
      digitalWrite(ADS1292_CS_PIN, HIGH);
    }
    
    //Sends a write command to SCP1000
    void ads1292_Reg_Write (unsigned char READ_WRITE_ADDRESS, unsigned char DATA)
    {
      switch (READ_WRITE_ADDRESS)
      {
        case 1:
                DATA = DATA & 0x87;
    	    break;
        case 2:
                DATA = DATA & 0xFB;
    	    DATA |= 0x80;		
    	    break;
        case 3:
    	    DATA = DATA & 0xFD;
    	    DATA |= 0x10;
    	    break;
        case 7:
    	    DATA = DATA & 0x3F;
    	    break;
        case 8:
        	    DATA = DATA & 0x5F;
    	    break;
        case 9:
    	    DATA |= 0x02;
    	    break;
        case 10:
    	    DATA = DATA & 0x87;
    	    DATA |= 0x01;
    	    break;
        case 11:
    	    DATA = DATA & 0x0F;
    	    break;
        default:
    	    break;		
      }
      
      // now combine the register address and the command into one byte:
      char dataToSend[1];
      dataToSend[0] = READ_WRITE_ADDRESS | WREG;
      
      digitalWrite(ADS1292_CS_PIN, LOW);
      delay(2);
      digitalWrite(ADS1292_CS_PIN, HIGH);
      delay(2);
      // take the chip select low to select the device:
      digitalWrite(ADS1292_CS_PIN, LOW);
      delay(2);
    
      if(DEBUG){NRF_LOG_INFO("2.0");NRF_LOG_FLUSH();}
      spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, dataToSend, 1, m_rx_buf, sizeof(m_rx_buf)));
      while (!spi_xfer_done){__WFE();}
      NRF_LOG_FLUSH();
      
      if(DEBUG){NRF_LOG_INFO("2.1");NRF_LOG_FLUSH();}
      spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, 0x00, 1, m_rx_buf, sizeof(m_rx_buf)));
      while (!spi_xfer_done){__WFE();}
      NRF_LOG_FLUSH();
      
      if(DEBUG){NRF_LOG_INFO("2.2");NRF_LOG_FLUSH();}
      spiDataTx[0]=DATA;;
      spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spiDataTx, 1, m_rx_buf, sizeof(m_rx_buf)));
      while (!spi_xfer_done){__WFE();}
      NRF_LOG_FLUSH();
      
      delay(2);
      // take the chip select high to de-select:
      digitalWrite(ADS1292_CS_PIN, HIGH);
    }
    
    void ChipID(void)
    {
      //byte data[1];
      //data[0] = data_in;
      digitalWrite(ADS1292_CS_PIN, LOW);
      delay(2);
      digitalWrite(ADS1292_CS_PIN, HIGH);
      delay(2);
      digitalWrite(ADS1292_CS_PIN, LOW);
      delay(2);
    
      char tempData[3]={0x20,0x00,0x00};
      if(DEBUG){NRF_LOG_INFO("3.0");NRF_LOG_FLUSH();}
      spi_xfer_done=false;memset(m_rx_buf,0,sizeof(m_rx_buf));
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tempData, sizeof(tempData), m_rx_buf, sizeof(m_rx_buf)));
      while (!spi_xfer_done){__WFE();}
      NRF_LOG_FLUSH();
      
      delay(2);
      digitalWrite(ADS1292_CS_PIN, HIGH);
    }
    #include "nrf_drv_spi.h"
    #include "app_util_platform.h"
    #include "nrf_gpio.h"
    #include "nrf_delay.h"
    #include "boards.h"
    #include "app_error.h"
    #include <string.h>
    #include "nrf_log.h"
    #include "nrf_log_ctrl.h"
    #include "nrf_log_default_backends.h"
    
    #include "ecg.h"
    #include "ads1292.h"
    
    volatile uint8_t  SPI_Dummy_Buff[30];
    uint8_t DataPacketHeader[16];
    volatile signed long s32DaqVals[8];
    uint8_t data_len = 7;
    volatile char SPI_RX_Buff[15] ;
    volatile static int SPI_RX_Buff_Count = 0;
    volatile char *SPI_RX_Buff_Ptr;
    volatile bool ads1292dataReceived = false;
    unsigned long uecgtemp = 0;
    signed long secgtemp = 0;
    int i, j;
    
    //************** ecg *******************
    int16_t CoeffBuf_40Hz_LowPass[FILTERORDER] =
    {
      -72,    122,    -31,    -99,    117,      0,   -121,    105,     34,
      -137,     84,     70,   -146,     55,    104,   -147,     20,    135,
      -137,    -21,    160,   -117,    -64,    177,    -87,   -108,    185,
      -48,   -151,    181,      0,   -188,    164,     54,   -218,    134,
      112,   -238,     90,    171,   -244,     33,    229,   -235,    -36,
      280,   -208,   -115,    322,   -161,   -203,    350,    -92,   -296,
      361,      0,   -391,    348,    117,   -486,    305,    264,   -577,
      225,    445,   -660,     93,    676,   -733,   -119,    991,   -793,
      -480,   1486,   -837,  -1226,   2561,   -865,  -4018,   9438,  20972,
      9438,  -4018,   -865,   2561,  -1226,   -837,   1486,   -480,   -793,
      991,   -119,   -733,    676,     93,   -660,    445,    225,   -577,
      264,    305,   -486,    117,    348,   -391,      0,    361,   -296,
      -92,    350,   -203,   -161,    322,   -115,   -208,    280,    -36,
      -235,    229,     33,   -244,    171,     90,   -238,    112,    134,
      -218,     54,    164,   -188,      0,    181,   -151,    -48,    185,
      -108,    -87,    177,    -64,   -117,    160,    -21,   -137,    135,
      20,   -147,    104,     55,   -146,     70,     84,   -137,     34,
      105,   -121,      0,    117,    -99,    -31,    122,    -72
    };
    int16_t ECG_WorkingBuff[2 * FILTERORDER];
    unsigned char Start_Sample_Count_Flag = 0;
    unsigned char first_peak_detect = FALSE ;
    unsigned int sample_index[MAX_PEAK_TO_SEARCH + 2] ;
    uint16_t scaled_result_display[150];
    uint8_t indx = 0;
    
    int cnt = 0;
    volatile uint8_t flag = 0;
    
    int QRS_Second_Prev_Sample = 0 ;
    int QRS_Prev_Sample = 0 ;
    int QRS_Current_Sample = 0 ;
    int QRS_Next_Sample = 0 ;
    int QRS_Second_Next_Sample = 0 ;
    
    static uint16_t QRS_B4_Buffer_ptr = 0 ;
    /*   Variable which holds the threshold value to calculate the maxima */
    int16_t QRS_Threshold_Old = 0;
    int16_t QRS_Threshold_New = 0;
    unsigned int sample_count = 0 ;
    
    /* Variable which will hold the calculated heart rate */
    volatile uint16_t QRS_Heart_Rate = 0 ;
    int16_t ecg_wave_buff[1], ecg_filterout[1];
    
    volatile uint8_t global_HeartRate = 0;
    volatile uint8_t global_RespirationRate = 0;
    long status_byte=0;
    uint8_t LeadStatus=0;
    bool leadoff_deteted = true;
    long time_elapsed=0;
    
    void ECG_Init()
    {
      // initalize the  data ready and chip select pins:
      /*pinMode(ADS1292_DRDY_PIN, INPUT);  //6
      pinMode(ADS1292_CS_PIN, OUTPUT);    //7
      pinMode(ADS1292_START_PIN, OUTPUT);  //5
      pinMode(ADS1292_PWDN_PIN, OUTPUT);  //4*/
    
      ads1292_Init();
    
      NRF_LOG_INFO("Initiliziation is done");NRF_LOG_FLUSH();
    }
    
    
    void MeasureHeartRate()
    {
      if ((digitalRead(ADS1292_DRDY_PIN)) == LOW)      // Sampling rate is set to 125SPS ,DRDY ticks for every 8ms
      {
        SPI_RX_Buff_Ptr = ads1292_Read_Data(); // Read the data,point the data to a pointer
    
        for (i = 0; i < 9; i++)
        {
          SPI_RX_Buff[SPI_RX_Buff_Count++] = *(SPI_RX_Buff_Ptr + i);  // store the result data in array
        }
        ads1292dataReceived = true;
      }
    
    
      if (ads1292dataReceived == true)      // process the data
      {
        j = 0;
        for (i = 3; i < 9; i += 3)         // data outputs is (24 status bits + 24 bits Respiration data +  24 bits ECG data)
        {
    
          uecgtemp = (unsigned long) (  ((unsigned long)SPI_RX_Buff[i + 0] << 16) | ( (unsigned long) SPI_RX_Buff[i + 1] << 8) |  (unsigned long) SPI_RX_Buff[i + 2]);
          uecgtemp = (unsigned long) (uecgtemp << 8);
          secgtemp = (signed long) (uecgtemp);
          secgtemp = (signed long) (secgtemp >> 8);
    
          s32DaqVals[j++] = secgtemp;  //s32DaqVals[0] is Resp data and s32DaqVals[1] is ECG data
        }
    
        status_byte = (long)((long)SPI_RX_Buff[2] | ((long) SPI_RX_Buff[1]) <<8 | ((long) SPI_RX_Buff[0])<<16); // First 3 bytes represents the status
        status_byte  = (status_byte & 0x0f8000) >> 15;  // bit15 gives the lead status
        LeadStatus = (unsigned char ) status_byte ;  
    
        if(!((LeadStatus & 0x1f) == 0 ))
          leadoff_deteted  = true; 
        else
          leadoff_deteted  = false;
        
        ecg_wave_buff[0] = (int16_t)(s32DaqVals[1] >> 8) ;  // ignore the lower 8 bits out of 24bits
    
        if(leadoff_deteted == false) 
           {
              ECG_ProcessCurrSample(&ecg_wave_buff[0], &ecg_filterout[0]);   // filter out the line noise @40Hz cutoff 161 order
              QRS_Algorithm_Interface(ecg_filterout[0]);             // calculate 
           }
        else
           ecg_filterout[0] = 0;
    
    
        //if(millis() > time_elapsed)  // update every one second
        {
          if(leadoff_deteted == true) // lead in not connected
          {
            NRF_LOG_INFO("ECG lead error!!! ensure the leads are properly connected");NRF_LOG_FLUSH();
          }
          else
          {
            NRF_LOG_INFO("Heart rate: ");//NRF_LOG_FLUSH();
            NRF_LOG_INFO(global_HeartRate);//NRF_LOG_FLUSH();
            NRF_LOG_INFO("BPM");NRF_LOG_FLUSH();
          }
          //time_elapsed += 1000;
        }
        
      }
    
      ads1292dataReceived = false;
      SPI_RX_Buff_Count = 0;
    }
    
    
    void ECG_FilterProcess(int16_t * WorkingBuff, int16_t * CoeffBuf, int16_t* FilterOut)
    {
    
      int32_t acc = 0;   // accumulator for MACs
      int  k;
    
      // perform the multiply-accumulate
      for ( k = 0; k < 161; k++ )
      {
        acc += (int32_t)(*CoeffBuf++) * (int32_t)(*WorkingBuff--);
      }
      // saturate the result
      if ( acc > 0x3fffffff )
      {
        acc = 0x3fffffff;
      } else if ( acc < -0x40000000 )
      {
        acc = -0x40000000;
      }
      // convert from Q30 to Q15
      *FilterOut = (int16_t)(acc >> 15);
      //*FilterOut = *WorkingBuff;
    }
    
    
    
    
    void ECG_ProcessCurrSample(int16_t *CurrAqsSample, int16_t *FilteredOut)
    {
      static uint16_t ECG_bufStart = 0, ECG_bufCur = FILTERORDER - 1, ECGFirstFlag = 1;
      static int16_t ECG_Pvev_DC_Sample, ECG_Pvev_Sample;/* Working Buffer Used for Filtering*/
      //  static short ECG_WorkingBuff[2 * FILTERORDER];
      int16_t *CoeffBuf;
      int16_t temp1, temp2, ECGData;
    
      /* Count variable*/
      uint16_t Cur_Chan;
      int16_t FiltOut = 0;
      //  short FilterOut[2];
      CoeffBuf = CoeffBuf_40Hz_LowPass;         // Default filter option is 40Hz LowPass
    
      if  ( ECGFirstFlag )                // First Time initialize static variables.
      {
        for ( Cur_Chan = 0 ; Cur_Chan < FILTERORDER; Cur_Chan++)
        {
          ECG_WorkingBuff[Cur_Chan] = 0;
        }
        ECG_Pvev_DC_Sample = 0;
        ECG_Pvev_Sample = 0;
        ECGFirstFlag = 0;
      }
    
      temp1 = NRCOEFF * ECG_Pvev_DC_Sample;       //First order IIR
      ECG_Pvev_DC_Sample = (CurrAqsSample[0]  - ECG_Pvev_Sample) + temp1;
      ECG_Pvev_Sample = CurrAqsSample[0];
      temp2 = ECG_Pvev_DC_Sample >> 2;
      ECGData = (int16_t) temp2;
    
      /* Store the DC removed value in Working buffer in millivolts range*/
      ECG_WorkingBuff[ECG_bufCur] = ECGData;
      ECG_FilterProcess(&ECG_WorkingBuff[ECG_bufCur], CoeffBuf, (int16_t*)&FiltOut);
      /* Store the DC removed value in ECG_WorkingBuff buffer in millivolts range*/
      ECG_WorkingBuff[ECG_bufStart] = ECGData;
    
      /* Store the filtered out sample to the LeadInfo buffer*/
      FilteredOut[0] = FiltOut ;//(CurrOut);
    
      ECG_bufCur++;
      ECG_bufStart++;
    
      if ( ECG_bufStart  == (FILTERORDER - 1))
      {
        ECG_bufStart = 0;
        ECG_bufCur = FILTERORDER - 1;
      }
      return ;
    }
    
    
    void QRS_Algorithm_Interface(int16_t CurrSample)
    {
      //  static FILE *fp = fopen("ecgData.txt", "w");
      static int16_t prev_data[32] = {0};
      int16_t i;
      long Mac = 0;
      prev_data[0] = CurrSample;
    
      for ( i = 31; i > 0; i--)
      {
        Mac += prev_data[i];
        prev_data[i] = prev_data[i - 1];
    
      }
      Mac += CurrSample;
      Mac = Mac >> 2;
      CurrSample = (int16_t) Mac;
      QRS_Second_Prev_Sample = QRS_Prev_Sample ;
      QRS_Prev_Sample = QRS_Current_Sample ;
      QRS_Current_Sample = QRS_Next_Sample ;
      QRS_Next_Sample = QRS_Second_Next_Sample ;
      QRS_Second_Next_Sample = CurrSample ;
    
    
    
      QRS_process_buffer();
    }
    
    static void QRS_process_buffer( void )
    {
    
      int16_t first_derivative = 0 ;
      int16_t scaled_result = 0 ;
    
      static int16_t Max = 0 ;
    
      /* calculating first derivative*/
      first_derivative = QRS_Next_Sample - QRS_Prev_Sample  ;
    
    
    
      /*taking the absolute value*/
    
      if (first_derivative < 0)
      {
        first_derivative = -(first_derivative);
      }
    
    
      scaled_result = first_derivative;
    
      if ( scaled_result > Max )
      {
        Max = scaled_result ;
      }
    
    
      QRS_B4_Buffer_ptr++;
      if (QRS_B4_Buffer_ptr ==  TWO_SEC_SAMPLES)
      {
        QRS_Threshold_Old = ((Max * 7) / 10 ) ;
        QRS_Threshold_New = QRS_Threshold_Old ;
       // if (Max > 70)
          first_peak_detect = TRUE ;
        Max = 0;
     
        //  ecg_wave_buff[0] = first_derivative;
        QRS_B4_Buffer_ptr = 0;
    
    
      }
    
    
      if ( TRUE == first_peak_detect )
      {
        QRS_check_sample_crossing_threshold( scaled_result ) ;
      }
    
    
    }
    
    
    static void QRS_check_sample_crossing_threshold( uint16_t scaled_result )
    {
      /* array to hold the sample indexes S1,S2,S3 etc */
    
      static uint16_t s_array_index = 0 ;
      static uint16_t m_array_index = 0 ;
    
      static unsigned char threshold_crossed = FALSE ;
      static uint16_t maxima_search = 0 ;
      static unsigned char peak_detected = FALSE ;
      static uint16_t skip_window = 0 ;
      static long maxima_sum = 0 ;
      static unsigned int peak = 0;
      static unsigned int sample_sum = 0;
      static unsigned int nopeak = 0;
      uint16_t Max = 0 ;
      uint16_t HRAvg;
      uint16_t  RRinterval = 0;
    
      if ( TRUE == threshold_crossed  )
      {
        /*
        Once the sample value crosses the threshold check for the
        maxima value till MAXIMA_SEARCH_WINDOW samples are received
        */
        sample_count ++ ;
        maxima_search ++ ;
    
        if ( scaled_result > peak )
        {
          peak = scaled_result ;
        }
    
        if ( maxima_search >= MAXIMA_SEARCH_WINDOW )
        {
          // Store the maxima values for each peak
          maxima_sum += peak ;
          maxima_search = 0 ;
    
    
          threshold_crossed = FALSE ;
          peak_detected = TRUE ;
        }
    
      }
      else if ( TRUE == peak_detected )
      {
        /*
        Once the sample value goes below the threshold
        skip the samples untill the SKIP WINDOW criteria is meet
        */
        sample_count ++ ;
        skip_window ++ ;
    
        if ( skip_window >= MINIMUM_SKIP_WINDOW )
        {
          skip_window = 0 ;
          peak_detected = FALSE ;
        }
    
        if ( m_array_index == MAX_PEAK_TO_SEARCH )
        {
          sample_sum = sample_sum / (MAX_PEAK_TO_SEARCH - 1);
          HRAvg =  (uint16_t) sample_sum  ;
    
          // Compute HR without checking LeadOffStatus
          QRS_Heart_Rate = (uint16_t) 60 *  SAMPLING_RATE;
          QRS_Heart_Rate =  QRS_Heart_Rate / HRAvg ;
          if (QRS_Heart_Rate > 250)
            QRS_Heart_Rate = 250 ;
     //     Serial.println(QRS_Heart_Rate);
    
          /* Setting the Current HR value in the ECG_Info structure*/
          maxima_sum =  maxima_sum / MAX_PEAK_TO_SEARCH;
          Max = (int16_t) maxima_sum ;
          /*  calculating the new QRS_Threshold based on the maxima obtained in 4 peaks */
          maxima_sum = Max * 7;
          maxima_sum = maxima_sum / 10;
          QRS_Threshold_New = (int16_t)maxima_sum;
    
          /* Limiting the QRS Threshold to be in the permissible range*/
          if (QRS_Threshold_New > (4 * QRS_Threshold_Old))
          {
            QRS_Threshold_New = QRS_Threshold_Old;
          }
    
          sample_count = 0 ;
          s_array_index = 0 ;
          m_array_index = 0 ;
          maxima_sum = 0 ;
          sample_index[0] = 0 ;
          sample_index[1] = 0 ;
          sample_index[2] = 0 ;
          sample_index[3] = 0 ;
          Start_Sample_Count_Flag = 0;
    
          sample_sum = 0;
        }
      }
      else if ( scaled_result > QRS_Threshold_New )
      {
        /*
          If the sample value crosses the threshold then store the sample index
        */
        Start_Sample_Count_Flag = 1;
        sample_count ++ ;
        m_array_index++;
        threshold_crossed = TRUE ;
        peak = scaled_result ;
        nopeak = 0;
    
        /*  storing sample index*/
        sample_index[ s_array_index ] = sample_count ;
        if ( s_array_index >= 1 )
        {
          sample_sum += sample_index[ s_array_index ] - sample_index[ s_array_index - 1 ] ;
        }
        s_array_index ++ ;
      }
    
      else if (( scaled_result < QRS_Threshold_New ) && (Start_Sample_Count_Flag == 1))
      {
        sample_count ++ ;
        nopeak++;
        if (nopeak > (3 * SAMPLING_RATE))
        {
          sample_count = 0 ;
          s_array_index = 0 ;
          m_array_index = 0 ;
          maxima_sum = 0 ;
          sample_index[0] = 0 ;
          sample_index[1] = 0 ;
          sample_index[2] = 0 ;
          sample_index[3] = 0 ;
          Start_Sample_Count_Flag = 0;
          peak_detected = FALSE ;
          sample_sum = 0;
    
          first_peak_detect = FALSE;
          nopeak = 0;
    
          QRS_Heart_Rate = 0;
    
        }
      }
      else
      {
        nopeak++;
        if (nopeak > (3 * SAMPLING_RATE))
        {
          /* Reset heart rate computation sate variable in case of no peak found in 3 seconds */
          sample_count = 0 ;
          s_array_index = 0 ;
          m_array_index = 0 ;
          maxima_sum = 0 ;
          sample_index[0] = 0 ;
          sample_index[1] = 0 ;
          sample_index[2] = 0 ;
          sample_index[3] = 0 ;
          Start_Sample_Count_Flag = 0;
          peak_detected = FALSE ;
          sample_sum = 0;
          first_peak_detect = FALSE;
          nopeak = 0;
          QRS_Heart_Rate = 0;
        }
      }
    
      global_HeartRate = (uint8_t)QRS_Heart_Rate;
      //Serial.println(global_HeartRate);
    
    }

    i used above two files.

    i used ECG_Init() function. Correct me if i am doing wrong.

    Please also correct me if i am performing wrong sequence.

    I am getting below output.

    <info> app: SPI example started.
    <info> app: 0.0
    <info> app: 0.1
    <info> app: 0.2
    <info> app: 0.3
    <info> app: 0.4
    <info> app: 1.0
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  60                     |`       
    <info> app: 0.5
    <info> app: 1.0
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  60                     |`       
    <info> app: 0.6
    <info> app: 0.7
    <info> app: 1.0
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  60                     |`       
    <info> app: 0.8
    <info> app: 3.0
    <info> app: Transfer completed.
    <info> app: 0.9
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  3F FF FF E0            |?...    
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app: 0.10
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  FF FF E0               |...     
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  40                     |@       
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  FF E0                  |..      
    <info> app: 0.11
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  E0                     |.       
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app: 0.12
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  3F FF FF E0            |?...    
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app: 0.13
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  FF FF E0               |...     
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  40                     |@       
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  FF E0                  |..      
    <info> app: 0.14
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  E0                     |.       
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app: 0.15
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  3F FF FF E0            |?...    
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app: 0.16
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  FF FF E0               |...     
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  40                     |@       
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  FF E0                  |..      
    <info> app: 0.17
    <info> app: 2.0
    <info> app: Transfer completed.
    <info> app: 2.1
    <info> app: Transfer completed.
    <info> app:  Received:
    <info> app:  E0                     |.       
    <info> app: 2.2
    <info> app: Transfer completed.
    <info> app: 0.18
    <info> app: 1.0
    <info> app: Transfer completed.
    <info> app: 0.19
    <info> app: Initiliziation is done
    

    Thanks

  • I will look later today at the sequence, but for now note the following:

    APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, spiDataTx, 1, m_rx_buf, sizeof(m_rx_buf)));
    
    

    SPI transfers as noted elsewhere on this forum clock out as many bits as they clock in, it is a synchronous protocol. The size of the Tx transfer in the code above is only 1 byte but the rx is 50 bytes so you should verify the number of bytes actually being transmitted so that all receive bytes arrive.

    Have you tried Mode 1 and 500kHz clock as I suggested? The code above still shows Mode 0 and 2MHz.

    spi_config.mode = NRF_DRV_SPI_MODE_0;
    spi_config.frequency = NRF_DRV_SPI_FREQ_2M;
    
    
    // Chip Select (CS)
    // CS selects the ADS1291, ADS1292, and ADS1292R for SPI communication. CS must remain low for the entire
    // duration of the serial communication. After the serial communication is finished, always wait four or more tCLK
    // cycles before taking CS high. When CS is taken high, the serial interface is reset, SCLK and DIN are ignored,
    // and DOUT enters a high-impedance state. DRDY asserts when data conversion is complete, regardless of
    // whether CS is high or low
    
    // Sending Multi-Byte Commands
    // The ADS1291, ADS1292, and ADS1292R serial interface decodes commands in bytes and requires 4 tCLK cycles
    // to decode and execute. Therefore, when sending multi-byte commands, a 4 tCLK period must separate the end of
    // one byte (or opcode) and the next.
    // Assume CLK is 512 kHz, then tSDECODE (4 tCLK) is 7.8125 us. When SCLK is 16 MHz, one byte can be
    // transferred in 500 ns. This byte-transfer time does not meet the tSDECODE specification; therefore, a delay must be
    // inserted so the end of the second byte arrives 7.3125 us later. If SCLK is 1 MHz, one byte is transferred in 8 �s.
    // Because this transfer time exceeds the tSDECODE specification, the processor can send subsequent bytes without
    // delay. In this later scenario, the serial port can be programmed to move from single-byte transfer per cycle to
    // multiple bytes.
    

    CS low-High-low prefix is not required.

  • I looked over the code but there is too much for the time available. However in addition to my comments above I would (strongly) suggest that you remove all manual /CS code and instead allow the spi driver to do this:

      spi_config.ss_pin   = ADS1292_CS_PIN;
    

    I also have a question: the ADS1292 will not function unless the internal oscillator is enabled, if the internal oscillator is not enabled then an external oscillator must be present before you can perform any read-write commands. As an illustration, an ADS1292 output port was fed back to the osc select port so the oscillator could be changed from internal to external by SPI command for better synchronous operation; however, a write cannot be made to any register - including to set the output port - unless either the internal oscillator is selected or if not the external oscillator is running. The default in that case would be to the external oscillator, and so the ADS1292 would not start until the external oscillator was enable thus allowing the internal oscillator to be selected via the i/o pins and the external could be turned off. Which oscillator are you using?

Reply
  • I looked over the code but there is too much for the time available. However in addition to my comments above I would (strongly) suggest that you remove all manual /CS code and instead allow the spi driver to do this:

      spi_config.ss_pin   = ADS1292_CS_PIN;
    

    I also have a question: the ADS1292 will not function unless the internal oscillator is enabled, if the internal oscillator is not enabled then an external oscillator must be present before you can perform any read-write commands. As an illustration, an ADS1292 output port was fed back to the osc select port so the oscillator could be changed from internal to external by SPI command for better synchronous operation; however, a write cannot be made to any register - including to set the output port - unless either the internal oscillator is selected or if not the external oscillator is running. The default in that case would be to the external oscillator, and so the ADS1292 would not start until the external oscillator was enable thus allowing the internal oscillator to be selected via the i/o pins and the external could be turned off. Which oscillator are you using?

Children
No Data
Related