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

MAX30003 unable to read right datas from ECG_FIFO registers

I tried to drive MAX30003 to get ECG signals through nrf52832.

I use an analog signal instrument to give the standard ECG signals. Now,the nrf's SPI timing sequence is right, and the data I got from the MAX30003 RTOR registers(0X25) is right (HR values is similiar to the signal instrument ).But the data I read from ECG_FIFO is not true. Can I get some help? 

#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "app_uart.h"
#include "app_error.h"
#include "nrf_delay.h"
#include "nrf_gpio.h"
#include "boards.h"
#include "max30003.h"
#include "nrf_drv_spi.h"
#include "SEGGER_RTT.h"
#include "nrf_drv_pwm.h"



#define UART_TX_BUF_SIZE 256                         /**< UART TX buffer size. */
#define UART_RX_BUF_SIZE 1                           /**< UART RX buffer size. */

static nrf_drv_pwm_t m_pwm0 = NRF_DRV_PWM_INSTANCE(0);
#define APP_PWM_DEFAULT_CONFIG_1CH(period_in_us, pin)
#define USED_PWM(idx) (1UL << idx)
static uint8_t m_used = 0;

static void pwm(void)
{
    nrf_drv_pwm_config_t const config0 =
    {
        .output_pins =
        {
            MAX30003_PIN_FCLK | NRF_DRV_PWM_PIN_INVERTED,  // channel 0  Êä³öÒý½Å
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 1
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 2
            NRF_DRV_PWM_PIN_NOT_USED,             // channel 3
        },
        .irq_priority = APP_IRQ_PRIORITY_LOWEST,
        .base_clock   = NRF_PWM_CLK_16MHz,
        .count_mode   = NRF_PWM_MODE_UP,
        .top_value    = 256,
        .load_mode    = NRF_PWM_LOAD_COMMON,
        .step_mode    = NRF_PWM_STEP_AUTO
    };
    APP_ERROR_CHECK(nrf_drv_pwm_init(&m_pwm0, &config0, NULL));
    m_used |= USED_PWM(0);

    
			static uint16_t /*const*/ seq_values[] =
    {
         0x8000,
             0,
    };
    nrf_pwm_sequence_t const seq =
    {
        .values.p_common = seq_values,
        .length          = NRF_PWM_VALUES_LENGTH(seq_values),
        .repeats         = 0,
        .end_delay       = 0
    };

    (void)nrf_drv_pwm_simple_playback(&m_pwm0, &seq, 1, NRF_DRV_PWM_FLAG_LOOP);
}


void uart_error_handle(app_uart_evt_t * p_event)
{
    if (p_event->evt_type == APP_UART_COMMUNICATION_ERROR)
    {
        APP_ERROR_HANDLER(p_event->data.error_communication);
    }
    else if (p_event->evt_type == APP_UART_FIFO_ERROR)
    {
        APP_ERROR_HANDLER(p_event->data.error_code);
    }
}
/**********************************************************************************************
 * Ãè  Êö : ´®¿Ú³õʼ»¯¡£²¨ÌØÂÊ=115200bps
 * Èë  ²Î : ÎÞ
 * ·µ»ØÖµ : ÎÞ
 *********************************************************************************************/ 
void uart_init(void)
{
	  uint32_t err_code;
    const app_uart_comm_params_t comm_params =
    {
          RX_PIN_NUMBER,
          TX_PIN_NUMBER,	
          RTS_PIN_NUMBER,
          CTS_PIN_NUMBER,
          APP_UART_FLOW_CONTROL_DISABLED,
          false, 
          UART_BAUDRATE_BAUDRATE_Baud115200
    };

    APP_UART_FIFO_INIT(&comm_params,
                         UART_RX_BUF_SIZE,
                         UART_TX_BUF_SIZE,
                         uart_error_handle,
                         APP_IRQ_PRIORITY_LOW,
                         err_code);

    APP_ERROR_CHECK(err_code);
}




/**********************************************************************************************
 * Ãè  Êö : mainº¯Êý
 * Èë  ²Î : ÎÞ
 * ·µ»ØÖµ : ÎÞ
 *********************************************************************************************/ 
int main(void)
{
	  uint8_t SPI_temp_32b[4],SPI_temp_32b1[4],SPI_temp_32b2[4];
		uint8_t DataPacketHeader[20];
		signed long ecgdata;
		unsigned long data;

    uart_init();
		SEGGER_RTT_ConfigUpBuffer(0, NULL, NULL, 0, SEGGER_RTT_MODE_NO_BLOCK_SKIP);
	  nrf_delay_ms(100);
		
		nrf_gpio_cfg_output(MAX30003_PIN_FCLK);
		pwm();
		max30003_spi_init();
		max30003_init();
	
    while (true)
    {

			max30003_read_register(MAX30003_REGADDR_ECG_FIFO,SPI_temp_32b2);

			data = (SPI_temp_32b2[0] <<16)|(SPI_temp_32b2[1] <<8)|((SPI_temp_32b2[2] >>6)&0x03);
			ecgdata = (signed long) (data);

			printf("%d\r\n",ecgdata);			

			max30003_read_register(MAX30003_REGADDR_RTOR,SPI_temp_32b);
			unsigned long RTOR_msb = (unsigned long) (SPI_temp_32b[0]);
			unsigned char RTOR_lsb = (unsigned char) (SPI_temp_32b[1]);
	 
			unsigned long rtor = (RTOR_msb<<8 | RTOR_lsb);
			rtor = ((rtor >>2) & 0x3fff) ;		
			float hr =  60 /((float)rtor*0.008); 
			unsigned int HR = (unsigned int)hr;  // type cast to int
			unsigned int RR = (unsigned int)rtor*8 ;  //8ms
			
//			printf("%d\r\n",HR);
	
			DataPacketHeader[0] = 0x0A;
      DataPacketHeader[1] = 0xFA;
      DataPacketHeader[2] = 0x0C;
      DataPacketHeader[3] = 0;
      DataPacketHeader[4] = 0x02;
   
      DataPacketHeader[5] = ecgdata;
      DataPacketHeader[6] = ecgdata>>8;
      DataPacketHeader[7] = ecgdata>>16;
      DataPacketHeader[8] = ecgdata>>24; 
   
      DataPacketHeader[9] =  RR ;
      DataPacketHeader[10] = RR >>8;
      DataPacketHeader[11] = 0x00;
      DataPacketHeader[12] = 0x00; 

      DataPacketHeader[13] = HR ;
      DataPacketHeader[14] = HR >>8;
      DataPacketHeader[15] = 0x00;
      DataPacketHeader[16] = 0x00; 
        
      DataPacketHeader[17] = 0x00;
      DataPacketHeader[18] = 0x0b;
			
//			for(int i=0;i<19;i++)
//			{app_uart_put(DataPacketHeader[i]);}
			
    }	

}

/********************************************END FILE*******************************************/

Parents
  • Hi

    How do you know the data is incorrect?

    What do you receive from the sensor, and what do you expect?

    Have you tried to log the status of the SPI_temp_32b2[] array so you can see if data conversion on line 132 of main.c is correct?

    Best regards
    Torbjørn

  • Hi~ 

    I calculate ECG from the values of the SPI_temp_32b2[] array and compared them with the analog instrument.

    I received values like...figure 1. But when it's drived by arduino, it can received right datas like figure 2 and 3.

     Fig 1    Fig 2       Fig 3  

    I have tried log the  SPI_temp_32b2[] array,the data is incorrect...

    Maybe I read the ECG_FIFO in a wrong way?..

  • Hi

    Are you sure that the nRF52 implementation sends the same setup/configuration commands to the ECG sensor?

    I assume you might have to send some commands to put it in the right state?

    Have you tried to probe the SPI lines when using the Arduino so that you can compare it to the nRF52 implementation, and see if there is a significant difference on the data sent back and forth?

    Best regards
    Torbjørn

  • The register configuration of MAX30003 was same,here is the Arduino codes.

    #include<SPI.h>
    #include <TimerOne.h>
    #include "MAX30003.h"
    
    #define MAX30003_CS_PIN   7
    #define CLK_PIN          6
    
    volatile char SPI_RX_Buff[5] ;
    volatile char *SPI_RX_Buff_Ptr;
    int i=0;
    unsigned long uintECGraw = 0;
    signed long intECGraw=0;
    uint8_t DataPacketHeader[20];
    uint8_t data_len = 8;
    signed long ecgdata;
    unsigned long data;
    
    char SPI_temp_32b[4];
    char SPI_temp_Burst[100];
    
    // 32KHz clock using timer1
    void timerIsr()
    {
        digitalWrite( CLK_PIN, digitalRead(CLK_PIN ) ^ 1 ); // toggle Digital6 attached to FCLK  of MAX30003
    }
    
    void setup() 
    {
        Serial.begin(115200); //Serial begin
        
        pinMode(MAX30003_CS_PIN,OUTPUT);
        digitalWrite(MAX30003_CS_PIN,HIGH); //disable device
    
        SPI.begin();
        SPI.setBitOrder(MSBFIRST); 
        SPI.setDataMode(SPI_MODE0);
      
      //please enable the below lines if you are using older version of Protocentral_max30003 board without 32k f-clock generator
        SPI.setClockDivider(SPI_CLOCK_DIV4);
        pinMode(CLK_PIN,OUTPUT);
         
         //Start CLK timer
        Timer1.initialize(16);              // set a timer of length 100000 microseconds (or 0.1 sec - or 10Hz => the led will blink 5 times, 5 cycles of on-and-off, per second)
        Timer1.attachInterrupt( timerIsr ); // attach the service routine here
    
        MAX30003_begin();   // initialize MAX30003 
    }
    
    void loop() 
    {
        MAX30003_Reg_Read(ECG_FIFO);
    
    //    unsigned long data0 = (unsigned long) (SPI_temp_32b[0]);
    //    data0 = data0 <<24;
    //    unsigned long data1 = (unsigned long) (SPI_temp_32b[1]);
    //    data1 = data1 <<16;
    //    unsigned long data2 = (unsigned long) (SPI_temp_32b[2]);
    //    data2 = data2 >>6;
    //    data2 = data2 & 0x03;
    //    
    //    data = (unsigned long) (data0 | data1 | data2);
    //    ecgdata = (signed long) (data);
    
        unsigned long data0 = (unsigned long) (SPI_temp_32b[0]);
        data0 = data0 <<16;
        unsigned long data1 = (unsigned long) (SPI_temp_32b[1]);
        data1 = data1 <<8;
        unsigned long data2 = (unsigned long) (SPI_temp_32b[2]);
        data2 = data2 >>6;
        data2 = data2 & 0x03;
        
        data = (unsigned long) (data0 | data1 | data2);
        ecgdata = (signed long) (data);
    
        MAX30003_Reg_Read(RTOR);
        unsigned long RTOR_msb = (unsigned long) (SPI_temp_32b[0]);
       // RTOR_msb = RTOR_msb <<8;
        unsigned char RTOR_lsb = (unsigned char) (SPI_temp_32b[1]);
    
        unsigned long rtor = (RTOR_msb<<8 | RTOR_lsb);
        rtor = ((rtor >>2) & 0x3fff) ;
      
        float hr =  60 /((float)rtor*0.008); 
        unsigned int HR = (unsigned int)hr;  // type cast to int
    
        unsigned int RR = (unsigned int)rtor*8 ;  //8ms
    
         Serial.print(ecgdata);
         Serial.print("\n");
    //     Serial.print(RTOR_msb);
    //     Serial.print(",");
    //     Serial.print(RTOR_lsb);
    //     Serial.print(",");
    //     Serial.print(rtor); 
    //     Serial.print(",");
    //     Serial.print(RR);
    //     Serial.print(",");
    //     Serial.println(HR);      
    
          DataPacketHeader[0] = 0x0A;
          DataPacketHeader[1] = 0xFA;
          DataPacketHeader[2] = 0x0C;
          DataPacketHeader[3] = 0;
          DataPacketHeader[4] = 0x02;
       
    //      DataPacketHeader[5] = ecgdata;
    //      DataPacketHeader[6] = ecgdata>>8;
    //      DataPacketHeader[7] = ecgdata>>16;
    //      DataPacketHeader[8] = ecgdata>>24; 
          DataPacketHeader[5] = data0;
          DataPacketHeader[6] = data1;
          DataPacketHeader[7] = data2;
          DataPacketHeader[8] = data;  
       
          DataPacketHeader[9] =  RR ;
          DataPacketHeader[10] = RR >>8;
          DataPacketHeader[11] = 0x00;
          DataPacketHeader[12] = 0x00; 
    
          DataPacketHeader[13] = HR ;
          DataPacketHeader[14] = HR >>8;
          DataPacketHeader[15] = 0x00;
          DataPacketHeader[16] = 0x00; 
            
          DataPacketHeader[17] = 0x00;
          DataPacketHeader[18] = 0x0b;
    //  
    //      for(i=0; i<19; i++) // transmit the data
    //      {
    //        Serial.write(DataPacketHeader[i]);  
    //       }    
    
        delay(8);      
    }
    
    void MAX30003_Reg_Write (unsigned char WRITE_ADDRESS, unsigned long data)
    {
     
        // now combine the register address and the command into one byte:
         byte dataToSend = (WRITE_ADDRESS<<1) | WREG;
      
         // take the chip select low to select the device:
         digitalWrite(MAX30003_CS_PIN, LOW);
         
         delay(2);
         SPI.transfer(dataToSend);   //Send register location
         SPI.transfer(data>>16);     //number of register to wr
         SPI.transfer(data>>8);      //number of register to wr
         SPI.transfer(data);      //Send value to record into register
         delay(2);
         
         // take the chip select high to de-select:
         digitalWrite(MAX30003_CS_PIN, HIGH);
    }
    
    void max30003_sw_reset(void)
    {
        MAX30003_Reg_Write(SW_RST,0x000000);     
        delay(100);
    }
    
    void max30003_synch(void)
    {
        MAX30003_Reg_Write(SYNCH,0x000000);
    }
    
    void MAX30003_Reg_Read(uint8_t Reg_address)
    {
        uint8_t SPI_TX_Buff;
       
        digitalWrite(MAX30003_CS_PIN, LOW);
        
        SPI_TX_Buff = (Reg_address<<1 ) | RREG;
        SPI.transfer(SPI_TX_Buff); //Send register location
         
        for ( i = 0; i < 3; i++)
        {
           SPI_temp_32b[i] = SPI.transfer(0xff);
        }
      
        digitalWrite(MAX30003_CS_PIN, HIGH);
    }
    
    void MAX30003_Read_Data(int num_samples)
    {
        uint8_t SPI_TX_Buff;
      
        digitalWrite(MAX30003_CS_PIN, LOW);   
      
        SPI_TX_Buff = (ECG_FIFO_BURST<<1 ) | RREG;
        SPI.transfer(SPI_TX_Buff); //Send register location
      
        for ( i = 0; i < num_samples*3; ++i)
        {
          SPI_temp_Burst[i] = SPI.transfer(0x00);
        }
        
        digitalWrite(MAX30003_CS_PIN, HIGH);  
    }
    
    void MAX30003_begin()
    {    
        max30003_sw_reset();
        delay(100);
        MAX30003_Reg_Write(CNFG_GEN, 0x081007);
        delay(100);
        MAX30003_Reg_Write(CNFG_CAL, 0x720000);  // 0x700000  
        delay(100);
        MAX30003_Reg_Write(CNFG_EMUX,0x0B0000);
        delay(100);
        MAX30003_Reg_Write(CNFG_ECG, 0x805000);  // d23 - d22 : 10 for 250sps , 00:500 sps
        delay(100);
        MAX30003_Reg_Write(CNFG_RTOR1,0x3fc600);   
        delay(100);  
        max30003_synch();
        delay(100);
        
    }

    I tried to probe the SPI lines through logic analyzer when using the Arduino, but the timing sequence was strange.But when I used NRF,the timing sequence was corresponding to the datasheet. So..I can't obtain the difference.

  • Hi

    Can you send me the max30003 library that you use on the nRF52? 

    Then I should be able to compare it to the Arduino code. 

    It would also be interesting to see the plots from the logic analyzer, to verify that the data is sent in the same way (same polarity, bit order, frequency etc). 

    Best regards
    Torbjørn

  • #include "max30003.h"
    #include "nrf_drv_spi.h"
    #include "nrf_delay.h"
    #include "app_error.h"
    #include "app_util_platform.h"
    
    #define SPI_BUFSIZE  10
    
    uint8_t   SPI_Tx_Buf[SPI_BUFSIZE];
    uint8_t   SPI_Rx_Buf[SPI_BUFSIZE];
    volatile  uint8_t   SPIReadLength, SPIWriteLength;
    
    
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0);
    static volatile bool spi_xfer_done;
    
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
    {
        spi_xfer_done = true;
    }
    
    void max30003_spi_init(void) {
    	nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG(0);
      spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
      spi_config.frequency = NRF_DRV_SPI_FREQ_125K;
      spi_config.irq_priority = APP_IRQ_PRIORITY_HIGHEST;
      spi_config.mode = NRF_DRV_SPI_MODE_0;
      spi_config.miso_pin = MAX30003_PIN_SDO;
      spi_config.sck_pin = MAX30003_PIN_SCLK;
      spi_config.mosi_pin = MAX30003_PIN_SDI;
      spi_config.ss_pin = MAX30003_PIN_CSB;
    //  spi_config.orc = 0x55;
      APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));
    	nrf_delay_ms(200);
    }
    
    void max30003_spi_uninit(void) {
      nrf_drv_spi_uninit(&spi);
    }
    
    void max30003_read_register(uint8_t reg_addr, uint8_t *reg_array) {
      uint8_t tx_data[1] = {MAX30003_READ_ADDR(reg_addr)};
      uint8_t rx_data[4];
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_data, sizeof(tx_data), rx_data, sizeof(rx_data)));
      while (!spi_xfer_done) {
        __WFE();
      }
      // Copy results to array: TEMP
    	for(uint8_t i=0;i<3;i++)
    	{ 
    		reg_array[i]=rx_data[i+1];
    	}
    	
    }
    
    void max30003_write_register(uint8_t reg_addr, uint8_t b0, uint8_t b1, uint8_t b2) {
      uint8_t tx_data[4];
      tx_data[0] = MAX30003_WRITE_ADDR(reg_addr);
      tx_data[1] = b0;
      tx_data[2] = b1;
      tx_data[3] = b2;
    
      // SPI Command
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_data, sizeof(tx_data), NULL, NULL));
      while (!spi_xfer_done) {
        __WFE();
      }
      nrf_delay_ms(5);
    }
    
    void max30003_read_device_info(void) {
      uint8_t dummy_array[3];
      max30003_read_register(MAX30003_REGADDR_INFO, dummy_array);
    }
    
    void max30003_read_device_status(void) {
      uint8_t dummy_array[3];
      max30003_read_register(MAX30003_REGADDR_STAT, dummy_array);
    }
    
    // Control functions>
    void max30003_init(void) {
    	max30003_soft_reset();
    	
    //  // Interrupts and Dynamic Modes
    //  max30003_write_register(MAX30003_REGADDR_EN_INT, 0x00, 0x00, 0x03);   //0x02
    //  max30003_write_register(MAX30003_REGADDR_EN_INT2, 0x00, 0x00, 0x03);  //0x03
    //  max30003_write_register(MAX30003_REGADDR_MNGR_INT, 0x78, 0x00, 0x04); //0x04
    //  max30003_write_register(MAX30003_REGADDR_MNGR_DYN, 0x3f, 0x00, 0x00); //0x05
    
      // Set up ECG Configurations:
      max30003_write_register(MAX30003_REGADDR_CNFG_GEN, 0x08, 0x10, 0x07);   //0x10
      max30003_write_register(MAX30003_REGADDR_CNFG_CAL, 0x70, 0x00, 0x00);   //0x12
      max30003_write_register(MAX30003_REGADDR_CNFG_EMUX, 0x0B, 0x00, 0x00);  //0x14
      max30003_write_register(MAX30003_REGADDR_CNFG_ECG, 0x80, 0x50, 0x00);   //0x15
      max30003_write_register(MAX30003_REGADDR_CNFG_RTOR1, 0x3f, 0xC6, 0x00); //0x1D
    	
    	max30003_sync();
    }
    
    void max30003_readback_registers(void) {
      uint8_t dummy_array[3];
      max30003_read_register(MAX30003_REGADDR_EN_INT, dummy_array);
      max30003_read_register(MAX30003_REGADDR_EN_INT2, dummy_array);
      max30003_read_register(MAX30003_REGADDR_MNGR_INT, dummy_array);
    
      max30003_read_register(MAX30003_REGADDR_CNFG_GEN, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_CAL, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_EMUX, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_ECG, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_RTOR1, dummy_array);
    }
    
    void max30003_soft_reset(void) {
      max30003_write_register(MAX30003_REGADDR_SW_RST, 0x00, 0x00, 0x00);
      nrf_delay_ms(5); // Give time to start up.
    }
    
    void max30003_sync(void) {
      max30003_write_register(MAX30003_REGADDR_SYNCH, 0x00, 0x00, 0x00);
    }
    
    void max30003_read_fifo_data(uint8_t *reg_array) {
      uint8_t tx_data[1] = {MAX30003_READ_ADDR(MAX30003_REGADDR_ECG_FIFO_BURST)};
      uint8_t rx_data[51+1];
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_data, sizeof(tx_data), rx_data, sizeof(rx_data)));
      while (!spi_xfer_done) {
        __WFE();
      }
    		for(uint8_t i=0;i<51;i++)
    	{ 
    		reg_array[i]=rx_data[i+1];
    	}
    
    }
    

    Hi,thanks for your reply.

    Here is the max30003 code. And the main code I have given in the question above.

    I can't see right plots from the logic analyzer when I use Arduino,but it outputs the right data.So I can't compare their timing sequence.

    Best regards.

Reply
  • #include "max30003.h"
    #include "nrf_drv_spi.h"
    #include "nrf_delay.h"
    #include "app_error.h"
    #include "app_util_platform.h"
    
    #define SPI_BUFSIZE  10
    
    uint8_t   SPI_Tx_Buf[SPI_BUFSIZE];
    uint8_t   SPI_Rx_Buf[SPI_BUFSIZE];
    volatile  uint8_t   SPIReadLength, SPIWriteLength;
    
    
    static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(0);
    static volatile bool spi_xfer_done;
    
    void spi_event_handler(nrf_drv_spi_evt_t const * p_event)
    {
        spi_xfer_done = true;
    }
    
    void max30003_spi_init(void) {
    	nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG(0);
      spi_config.bit_order = NRF_DRV_SPI_BIT_ORDER_MSB_FIRST;
      spi_config.frequency = NRF_DRV_SPI_FREQ_125K;
      spi_config.irq_priority = APP_IRQ_PRIORITY_HIGHEST;
      spi_config.mode = NRF_DRV_SPI_MODE_0;
      spi_config.miso_pin = MAX30003_PIN_SDO;
      spi_config.sck_pin = MAX30003_PIN_SCLK;
      spi_config.mosi_pin = MAX30003_PIN_SDI;
      spi_config.ss_pin = MAX30003_PIN_CSB;
    //  spi_config.orc = 0x55;
      APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_event_handler));
    	nrf_delay_ms(200);
    }
    
    void max30003_spi_uninit(void) {
      nrf_drv_spi_uninit(&spi);
    }
    
    void max30003_read_register(uint8_t reg_addr, uint8_t *reg_array) {
      uint8_t tx_data[1] = {MAX30003_READ_ADDR(reg_addr)};
      uint8_t rx_data[4];
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_data, sizeof(tx_data), rx_data, sizeof(rx_data)));
      while (!spi_xfer_done) {
        __WFE();
      }
      // Copy results to array: TEMP
    	for(uint8_t i=0;i<3;i++)
    	{ 
    		reg_array[i]=rx_data[i+1];
    	}
    	
    }
    
    void max30003_write_register(uint8_t reg_addr, uint8_t b0, uint8_t b1, uint8_t b2) {
      uint8_t tx_data[4];
      tx_data[0] = MAX30003_WRITE_ADDR(reg_addr);
      tx_data[1] = b0;
      tx_data[2] = b1;
      tx_data[3] = b2;
    
      // SPI Command
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_data, sizeof(tx_data), NULL, NULL));
      while (!spi_xfer_done) {
        __WFE();
      }
      nrf_delay_ms(5);
    }
    
    void max30003_read_device_info(void) {
      uint8_t dummy_array[3];
      max30003_read_register(MAX30003_REGADDR_INFO, dummy_array);
    }
    
    void max30003_read_device_status(void) {
      uint8_t dummy_array[3];
      max30003_read_register(MAX30003_REGADDR_STAT, dummy_array);
    }
    
    // Control functions>
    void max30003_init(void) {
    	max30003_soft_reset();
    	
    //  // Interrupts and Dynamic Modes
    //  max30003_write_register(MAX30003_REGADDR_EN_INT, 0x00, 0x00, 0x03);   //0x02
    //  max30003_write_register(MAX30003_REGADDR_EN_INT2, 0x00, 0x00, 0x03);  //0x03
    //  max30003_write_register(MAX30003_REGADDR_MNGR_INT, 0x78, 0x00, 0x04); //0x04
    //  max30003_write_register(MAX30003_REGADDR_MNGR_DYN, 0x3f, 0x00, 0x00); //0x05
    
      // Set up ECG Configurations:
      max30003_write_register(MAX30003_REGADDR_CNFG_GEN, 0x08, 0x10, 0x07);   //0x10
      max30003_write_register(MAX30003_REGADDR_CNFG_CAL, 0x70, 0x00, 0x00);   //0x12
      max30003_write_register(MAX30003_REGADDR_CNFG_EMUX, 0x0B, 0x00, 0x00);  //0x14
      max30003_write_register(MAX30003_REGADDR_CNFG_ECG, 0x80, 0x50, 0x00);   //0x15
      max30003_write_register(MAX30003_REGADDR_CNFG_RTOR1, 0x3f, 0xC6, 0x00); //0x1D
    	
    	max30003_sync();
    }
    
    void max30003_readback_registers(void) {
      uint8_t dummy_array[3];
      max30003_read_register(MAX30003_REGADDR_EN_INT, dummy_array);
      max30003_read_register(MAX30003_REGADDR_EN_INT2, dummy_array);
      max30003_read_register(MAX30003_REGADDR_MNGR_INT, dummy_array);
    
      max30003_read_register(MAX30003_REGADDR_CNFG_GEN, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_CAL, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_EMUX, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_ECG, dummy_array);
      max30003_read_register(MAX30003_REGADDR_CNFG_RTOR1, dummy_array);
    }
    
    void max30003_soft_reset(void) {
      max30003_write_register(MAX30003_REGADDR_SW_RST, 0x00, 0x00, 0x00);
      nrf_delay_ms(5); // Give time to start up.
    }
    
    void max30003_sync(void) {
      max30003_write_register(MAX30003_REGADDR_SYNCH, 0x00, 0x00, 0x00);
    }
    
    void max30003_read_fifo_data(uint8_t *reg_array) {
      uint8_t tx_data[1] = {MAX30003_READ_ADDR(MAX30003_REGADDR_ECG_FIFO_BURST)};
      uint8_t rx_data[51+1];
      spi_xfer_done = false;
      APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, tx_data, sizeof(tx_data), rx_data, sizeof(rx_data)));
      while (!spi_xfer_done) {
        __WFE();
      }
    		for(uint8_t i=0;i<51;i++)
    	{ 
    		reg_array[i]=rx_data[i+1];
    	}
    
    }
    

    Hi,thanks for your reply.

    Here is the max30003 code. And the main code I have given in the question above.

    I can't see right plots from the logic analyzer when I use Arduino,but it outputs the right data.So I can't compare their timing sequence.

    Best regards.

Children
  • Hi 

    Thanks for sharing your code. 

    Currently I am on travel, so I haven't been able to look into it unfortunately. I will be back in the office tomorrow and do my best to get you a reply by the end of the day. 

    Best regards
    Torbjørn

  • Hi Victoriaz,

    I see that you have added MAX30003_READ_ADDR() function in the above codes. Where is it defined? Can you post that too?

  • The interpretation of the 24-bit signed numbers here is incorrect:

      max30003_read_register(MAX30003_REGADDR_ECG_FIFO,SPI_temp_32b2);
    
      data = (SPI_temp_32b2[0] <<16)|(SPI_temp_32b2[1] <<8)|((SPI_temp_32b2[2] >>6)&0x03);
      ecgdata = (signed long) (data);

    You might find this a better approach

    // Number of bits in ECG 30003 defines the signed ADC output number format
    #define ADC_NUMBER_OF_BITS   (24u)
    #define ADC_SIGN_MASK        (1u << (ADC_NUMBER_OF_BITS-1))
    #define ADC_NUMBER_MASK      (ADC_SIGN_MASK-1u)
    #define ADC_FIELD_MASK       (ADC_SIGN_MASK | ADC_NUMBER_MASK)
    
    // Sanity check on these 24-bit masks
    STATIC_ASSERT (ADC_FIELD_MASK  == 0xFFFFFF, "ADC_FIELD_MASK  == 0xFFFFFF fails check");
    STATIC_ASSERT (ADC_SIGN_MASK   == 0x800000, "ADC_SIGN_MASK   == 0x800000 fails check");
    STATIC_ASSERT (ADC_NUMBER_MASK == 0x7FFFFF, "ADC_NUMBER_MASK == 0x7FFFFF fails check");
    // Sanity check on this CPU implementation for 4-byte 32-bit signed number
    STATIC_ASSERT (sizeof (int32_t) == 4, "(sizeof (int32_t) == 4) failed");
    
    // Define position in response packet, note high byte is first!
    #define MSB_INDEX  3  // <== choose these in ascending order to match your registers
    #define MID_INDEX  4
    #define LSB_INDEX  5
    
    // Signed 32-bit ECG result
    int32_t value_s32;
    
      max30003_read_register(MAX30003_REGADDR_ECG_FIFO,SPI_buffer);
    
      // Convert to signed 32-bit, sign-extension is not automatic
      value_s32 = (SPI_buffer[MSB_INDEX] << 16) | (SPI_buffer[MID_INDEX] << 8) | (SpiBuffer[LSB_INDEX]);
      // Handle a negative (2's complement) 24-bit value
      if ( value_s32 & ADC_SIGN_MASK )
      {
         // Sign extend the -ve 24-bit value to a -ve 32-bit value
         value_s32 |= ~(int32_t)ADC_NUMBER_MASK;
      }
    
      ecgdata = (signed long) value_s32;

    Note the byte index values are just examples here; SPI_buffer[40] is used for multiple bytes read from 30003

Related