【MAX86174】美信MAX86174驱动及应用

介绍

网上没有MAX86174的开源驱动,自己对照芯片手册研究了一周,写了一份,移植到项目实测可用,share出来,欢迎工友们讨论~

芯片手册

芯片手册官网可以直接下载:美信官网资料
结合自己的理解,介绍一下需要用到的部分:

MAX86174A 和 MAX86174B

区别就是MAX86174A有两路PPG通道,MAX86174B只有一路。
在这里插入图片描述

接口(I2C和SPI)

使用SPI

应用

自行划分了两种模式:血氧模式和心率模式。
硬件设计使用了双PD。
心率模式:开两个绿灯,2个PD采集到的结果分别打到PPG1和PPG2两个通道;
血氧模式:先后打开红灯和红外,2个PD采集的结果都打到PPG1通道;
PD和PP通道选择是可以通过MEASx_PDSEL寄存器配置的:

应用例程

ppg_task.c

/*------------------------------------------------------------------------------
 Section: Includes
 ------------------------------------------------------------------------------*/
#include <string.h>
#include "nrf_drv_spi.h"
#include "nrf_gpio.h"
#include "MAX86174.h"
#include "FreeRTOS.h"
#include "task.h"
#include "SEGGER_RTT.h"
#include "sys_params.h"
/*------------------------------------------------------------------------------
 Section: Macro Definitions
 ------------------------------------------------------------------------------*/	
#define 	HEART_MODE	(1)
#define 	SPO2_MODE	(2)
/*------------------------------------------------------------------------------
 Section: Type Definitions
 ------------------------------------------------------------------------------*/


/*------------------------------------------------------------------------------
 Section: Local Variables
 ------------------------------------------------------------------------------*/

 //MAX86174
static uint8_t fifo_buf[PPG_BUFF_LEN]; // 256 fifo, 2 channel  2 pd , 3 bytes per channel

MEASx_enable_cfg_t measx_cfg;
PPG_data_t ppg_data;
	
/*------------------------------------------------------------------------------
 Section: Function Prototypes
 ------------------------------------------------------------------------------*/	
/***************************************************************************
* 描  述 : MAX86174_Init 
* 入  参 : 无 
* 返回值 : 
**************************************************************************/
static void ppg_MAX86174_Init(int mode)
{
	SEGGER_RTT_printf(0, "chip ID:[0x%.2x] \r\n", max86174A_read_chipID());
	if(mode == HEART_MODE)
	{
		measx_cfg.meas1_enable = 1;
		measx_cfg.meas2_enable = 0;
		measx_cfg.meas3_enable = 0;
		measx_cfg.meas4_enable = 0;
		measx_cfg.meas5_enable = 0;
		measx_cfg.meas6_enable = 0;
	}
	else if(mode == SPO2_MODE)
	{
		measx_cfg.meas1_enable = 0;
		measx_cfg.meas2_enable = 1;
		measx_cfg.meas3_enable = 1;
		measx_cfg.meas4_enable = 0;
		measx_cfg.meas5_enable = 0;
		measx_cfg.meas6_enable = 0;

	}


	max86174A_Init_From_datasheet(&measx_cfg);
}


/***************************************************************************
* 描  述 : MAX86174_Test 
* 入  参 : 无 
* 返回值 : 
**************************************************************************/
static void ppg_MAX86174_Test(void)
{
	ppg_var_t para_ppg;

	memset(fifo_buf, 0 ,sizeof(fifo_buf));

	// if(nrf_gpio_pin_read(SPI_AFE_INTB_PIN) == 0)
	if(max86174A_FIFO_data_ready())
	{
		ppg_data.fifo_count = max86174A_read_FIFO_Data(fifo_buf);
		// SEGGER_RTT_printf(0, "sample_count:[%d] \n", ppg_data.fifo_count);
		
		// for(int i = 0; i < ppg_data.fifo_count; i++)
		// {
		// 	SEGGER_RTT_printf(0, "0x%.2X  0x%.2x  0x%.2x\r\n", fifo_buf[i * 3], fifo_buf[i * 3 + 1], fifo_buf[i * 3 + 2]);
		// }

		for(int i = 0; i < ppg_data.fifo_count; i++)
		{
			ppg_data.pd_data = (fifo_buf[i * 3 + 0] << 16) | (fifo_buf[i * 3 + 1] << 8) | (fifo_buf[i * 3 + 2] << 0);
			ppg_data.tag = ppg_data.pd_data >> 20;

			if(ppg_data.tag != 12)
			{
				// SEGGER_RTT_printf(0, "tag:[%d]  \t ppg:%d \r\n", ppg_data.tag, (ppg_data.pd_data & 0x7ffff));

				// 2 channels
				if(ppg_data.tag == 0)
				{
					para_ppg.green_1 = (ppg_data.pd_data & 0x7ffff);
					Var_Write(VAR_PPG_GREEN_1, &para_ppg.green_1, 4);
				}
				if (ppg_data.tag == 6)
				{
					para_ppg.green_2 = (ppg_data.pd_data & 0x7ffff);
					Var_Write(VAR_PPG_GREEN_2, &para_ppg.green_2, 4);
				}
			}
		}
	}
	max86174A_flushFIFO();
}


/**
 ******************************************************************************
 * @brief       max86174_thread
 ******************************************************************************
 */
void ppg_max86174_thread(void * pvParameter)
{
    UNUSED_PARAMETER(pvParameter);

	//初始化SPI & 初始化PPG模块
    SPI_PPG_Init();
	ppg_MAX86174_Init(HEART_MODE);

    // nrf_gpio_cfg_input(SPI_AFE_INTB_PIN, NRF_GPIO_PIN_NOPULL);	//MAX86174 INTB pin cfg

    while (true)
    {
        ppg_MAX86174_Test();

        // /* Delay a task for a given number of ticks */
        vTaskDelay(1000);

        // /* Tasks must be implemented to never return... */
    }
}



驱动源码

MAX86174.h

#ifndef _MAX86174_H_
#define _MAX86174_H_

#include <stdint.h>

/*------------------------------------------------------------------------------
 Section: Macro Definitions
 ------------------------------------------------------------------------------*/	
#define  PPG_BUFF_LEN				(256 * 2 * 2 * 3)

//SPI引脚定义
#define  SPI_AFE_SS_PIN             16
#define  SPI_AFE_SCK_PIN            14
#define  SPI_AFE_MISO_PIN           15
#define  SPI_AFE_MOSI_PIN           12
#define	 SPI_AFE_INTB_PIN			24

#define    SPI_PPG_CS_LOW   	nrf_gpio_pin_clear(SPI_AFE_SS_PIN)   //片选输出低电平:使能芯片
#define    SPI_PPG_CS_HIGH    	nrf_gpio_pin_set(SPI_AFE_SS_PIN)     //片选输出高电平:取消片选

#define SPI_READ_CMD					0x80
#define SPI_WRITE_CMD					0x00

//Chip ID 
#define MAX86174_CHIP_ID				0x40

//寄存器地址定义-----

//中断状态寄存器1
#define ADDR_REG_INT_STATUS1 			0X00
//中断状态寄存器2
#define ADDR_REG_INT_STATUS2 			0X01

//FIFO 队列写指针
#define ADDR_REG_FIFO_WRITE_PTR 		0x03
//队列读指针
#define ADDR_REG_FIFO_READ_PTR 			0x04
//队列溢出计数器1
#define ADDR_REG_FIFO_OVF_COUNTER_1 	0x05
//队列数据计数器2
#define ADDR_REG_FIFO_DATA_COUNTER_2 	0x06
//队列数据
#define ADDR_REG_FIFO_DATA 				0x07
//队列配置寄存器1
#define ADDR_REG_FIFO_CONFIG1 			0x08
//队列配置寄存器2
#define ADDR_REG_FIFO_CONFIG2 			0x09

// System control
//系统控制寄存器	
#define ADDR_REG_SYS_SYNC 				0X10
#define ADDR_REG_SYS_CONFIG_1			0x11
#define ADDR_REG_SYS_CONFIG_2			0x12
#define ADDR_REG_SYS_CONFIG_3			0x13


//PPG Filter setup
#define ADDR_REG_PPG_FILTER_SETUP		0x14
//光电二极管偏置寄存器
#define ADDR_REG_PHOTO_DIODE_BIAS 		0x15
#define ADDR_REG_PIN_FUNCTIONAL_CONFIG 	0x16
#define ADDR_REG_OUTPUT_PIN_CONFIG 		0x17
#define ADDR_REG_I2C_BOARDCAST 			0x18


//PPG Frame Rate Clock
#define ADDR_REG_FR_CLK_FREQ_SELECT 	0x1A
#define ADDR_REG_FR_CLK_DIVIDER_MSB 	0x1B
#define ADDR_REG_FR_CLK_DIVIDER_LSB		0x1C


//PPG MEAS1 Setup
#define ADDR_REG_MEAS1_SELECT		 	0x20
#define ADDR_REG_MEAS1_CONFIG_1		 	0x21
#define ADDR_REG_MEAS1_CONFIG_2		 	0x22
#define ADDR_REG_MEAS1_CONFIG_3		 	0x23
#define ADDR_REG_MEAS1_CONFIG_4		 	0x24
#define ADDR_REG_MEAS1_LEDA_CURRENT		0x25
#define ADDR_REG_MEAS1_LEDB_CURRENT		0x26

//PPG MEAS2 Setup
#define ADDR_REG_MEAS2_SELECT		 	0x28
#define ADDR_REG_MEAS2_CONFIG_1		 	0x29
#define ADDR_REG_MEAS2_CONFIG_2		 	0x2A
#define ADDR_REG_MEAS2_CONFIG_3		 	0x2B
#define ADDR_REG_MEAS2_CONFIG_4		 	0x2C
#define ADDR_REG_MEAS2_LEDA_CURRENT		0x2D
#define ADDR_REG_MEAS2_LEDB_CURRENT		0x2E

//PPG MEAS3 Setup
#define ADDR_REG_MEAS3_SELECT		 	0x30
#define ADDR_REG_MEAS3_CONFIG_1		 	0x31
#define ADDR_REG_MEAS3_CONFIG_2		 	0x32
#define ADDR_REG_MEAS3_CONFIG_3		 	0x33
#define ADDR_REG_MEAS3_CONFIG_4		 	0x34
#define ADDR_REG_MEAS3_LEDA_CURRENT		0x35
#define ADDR_REG_MEAS3_LEDB_CURRENT		0x36

//PPG MEAS4 Setup
#define ADDR_REG_MEAS4_SELECT		 	0x38
#define ADDR_REG_MEAS4_CONFIG_1		 	0x39
#define ADDR_REG_MEAS4_CONFIG_2		 	0x3A
#define ADDR_REG_MEAS4_CONFIG_3		 	0x3B
#define ADDR_REG_MEAS4_CONFIG_4		 	0x3C
#define ADDR_REG_MEAS4_LEDA_CURRENT		0x3D
#define ADDR_REG_MEAS4_LEDB_CURRENT		0x3E

//PPG MEAS5 Setup
#define ADDR_REG_MEAS5_SELECT		 	0x40
#define ADDR_REG_MEAS5_CONFIG_1		 	0x41
#define ADDR_REG_MEAS5_CONFIG_2		 	0x42
#define ADDR_REG_MEAS5_CONFIG_3		 	0x43
#define ADDR_REG_MEAS5_CONFIG_4		 	0x44
#define ADDR_REG_MEAS5_LEDA_CURRENT		0x45
#define ADDR_REG_MEAS5_LEDB_CURRENT		0x46


//PPG MEAS6 Setup
#define ADDR_REG_MEAS6_SELECT		 	0x48
#define ADDR_REG_MEAS6_CONFIG_1		 	0x49
#define ADDR_REG_MEAS6_CONFIG_2		 	0x4A
#define ADDR_REG_MEAS6_CONFIG_3		 	0x4B
#define ADDR_REG_MEAS6_CONFIG_4		 	0x4C
#define ADDR_REG_MEAS6_LEDA_CURRENT		0x4D
#define ADDR_REG_MEAS6_LEDB_CURRENT		0x4E

//PPG Threshold Interrupts
#define ADDR_REG_THRESHOLD_MEAS_SEL		0x50
#define ADDR_REG_THRESHOLD_HYST			0x51
#define ADDR_REG_PPG_HI_THRESHOLD_1		0x52
#define ADDR_REG_PPG_LO_THRESHOLD_1		0x53
#define ADDR_REG_PPG_HI_THRESHOLD_2		0x54
#define ADDR_REG_PPG_LO_THRESHOLD_2		0x55

//Interrupt Enables
#define ADDR_REG_INTERRUPT_ENABLE_1		0x58
#define ADDR_REG_INTERRUPT_ENABLE_2		0x59

//part id 寄存器
#define ADDR_REG_PART_ID 				0XFF

/*------------------------------------------------------------------------------
 Section: Type Definitions
 ------------------------------------------------------------------------------*/	

//中断状态寄存器1  0x00
typedef union
{
	struct
	{
		unsigned char PWR_RDY : 1;
		unsigned char THRESH1_HILO : 1;
		unsigned char THRESH2_HILO : 1;
		unsigned char EXP_OVF : 1;
		unsigned char ALC_OVF : 1;
		unsigned char FIFO_DATA_RDY : 1;
		unsigned char FRAME_RDY : 1;
		unsigned char A_FULL : 1;
	} bits;
	unsigned char byte;
} dsRegIntStatus1;


//中断状态寄存器2  0x01
typedef union
{
	struct
	{
		unsigned char LED1_COMPB : 1;
		unsigned char LED2_COMPB : 1;
		unsigned char LED3_COMPB : 1;
		unsigned char LED4_COMPB : 1;
		unsigned char rsv : 3;
		unsigned char INVALID_CFG : 1;
	} bits;
	unsigned char byte;
} dsRegIntStatus2;


// 0X08 FIFO 配置寄存器1
typedef union
{
	struct
	{
		unsigned char FIFO_A_FULL : 8;
	} bits;
	unsigned char byte;
} dsRegFifoConfig1;


// 0x09 FIFO 配置寄存器2
typedef union
{
	struct
	{
		unsigned char rsv1 : 1;
		unsigned char FIFO_RO : 1;
		unsigned char A_FULL_TYPE : 1;
		unsigned char FIFO_STAT_CLR : 1;
		unsigned char FLUSH_FIFO : 1;
		unsigned char FIFO_MARK : 1;
		unsigned char rsv2 : 2;
	} bits;
	unsigned char byte;
} dsRegFifoConfig2;


// 0x10 System Sync 寄存器
typedef union
{
	struct
	{
		unsigned char rsv1 : 6;
		unsigned char SW_FORCE_SYNC : 1;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegSystemSync;


// 0x11 System config 1 寄存器
typedef union
{
	struct
	{
		unsigned char RESET : 1;
		unsigned char SHDN : 1;
		unsigned char PPG1_PWRDN : 1;
		unsigned char PPG2_PWRDN : 1;
		unsigned char SYNC_MODE : 2;
		unsigned char rsv : 1;
		unsigned char DISABLE_I2C : 1;
	} bits;
	unsigned char byte;
} dsRegSystemConfig1;


// 0x12 System config 2 寄存器
typedef union
{
	struct
	{
		unsigned char MESA1_EN : 1;
		unsigned char MESA2_EN : 1;
		unsigned char MESA3_EN : 1;
		unsigned char MESA4_EN : 1;
		unsigned char MESA5_EN : 1;
		unsigned char MESA6_EN : 1;
		unsigned char rsv : 2;
	} bits;
	unsigned char byte;
} dsRegSystemConfig2;


// 0x13 System config 3 寄存器
typedef union
{
	struct
	{
		unsigned char MESA1_CONFIG_SEL : 1;
		unsigned char COLLECT_RAW_DATA : 1;
		unsigned char PROX_AUTO : 1;
		unsigned char PROX_DATA_EN : 1;
		unsigned char ALC_DISABLE : 1;
		unsigned char rsv : 3;
	} bits;
	unsigned char byte;
} dsRegSystemConfig3;


// 0x15 System Control Photodiode Bias 寄存器
typedef union
{
	struct
	{
		unsigned char PD1_BIAS : 2;
		unsigned char PD2_BIAS : 2;
		unsigned char rsv : 4;
	} bits;
	unsigned char byte;
} dsRegSystemControl_Photodiode_Bias;


// 0x16 pin functional config
typedef union
{
	struct
	{
		unsigned char TRIG_ICFG : 1;
		unsigned char INTB_FCFG : 2;
		unsigned char rsv : 5;
	} bits;
	unsigned char byte;
} dsRegPinFunctionalConfig;


// 0x17 Output Pin config
typedef union
{
	struct
	{
		unsigned char TRIGLED4_SEL : 1;
		unsigned char INTB_OCFG : 2;
		unsigned char rsv : 5;
	} bits;
	unsigned char byte;
} dsRegOutputPinConfig;


// PPG MEAS1 Setup
// 0x20 PPG MEAS1 SELECT寄存器
typedef union
{
	struct
	{
		unsigned char MEAS1_DRVA : 2;
		unsigned char MEAS1_DRVB : 2;
		unsigned char rsv1 : 2;
		unsigned char MEAS1_AMB : 1;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas1_select;


// 0x21 PPG MEAS1 Config1 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS1_AVER : 3;
		unsigned char MEAS1_TINT : 2;
		unsigned char rsv : 1;
		unsigned char MEAS1_PDSEL : 2;
	} bits;
	unsigned char byte;
} dsRegppg_meas1_config1;


// 0x22 PPG MEAS1 Config2 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS1_PPG1_ADC_RGE : 2;
		unsigned char MEAS1_PPG2_ADC_RGE : 2;
		unsigned char MEAS1_LED_RGE : 2;
		unsigned char MEAS1_FILT_SEL : 1;
		unsigned char MEAS1_SINC3_SEL : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas1_config2;


// 0x23 PPG MEAS1 Config3 寄存器
typedef union
{
	struct
	{
		unsigned char rsv : 3;
		unsigned char MEAS1_LED_SETLNG : 2;
		unsigned char MEAS1_PD_SETLNG : 3;
	} bits;
	unsigned char byte;
} dsRegppg_meas1_config3;


// 0x24 PPG MEAS1 Config4 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS1_PPG1_DACOFF : 3;
		unsigned char rsv1 : 1;
		unsigned char MEAS1_PPG2_DACOFF : 3;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas1_config4;

//MEAS2 MEAS3 ...... 与MEAS1相同
// PPG MEAS2 Setup
// 0x28 PPG MEAS2 SELECT寄存器
typedef union
{
	struct
	{
		unsigned char MEAS2_DRVA : 2;
		unsigned char MEAS2_DRVB : 2;
		unsigned char rsv1 : 2;
		unsigned char MEAS2_AMB : 1;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas2_select;


// 0x29 PPG MEAS2 Config1 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS2_AVER : 3;
		unsigned char MEAS2_TINT : 2;
		unsigned char rsv : 1;
		unsigned char MEAS2_PDSEL : 2;
	} bits;
	unsigned char byte;
} dsRegppg_meas2_config1;


// 0x2A PPG MEAS2 Config2 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS2_PPG1_ADC_RGE : 2;
		unsigned char MEAS2_PPG2_ADC_RGE : 2;
		unsigned char MEAS2_LED_RGE : 2;
		unsigned char MEAS2_FILT_SEL : 1;
		unsigned char MEAS2_SINC3_SEL : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas2_config2;


// 0x2B PPG MEAS2 Config3 寄存器
typedef union
{
	struct
	{
		unsigned char rsv : 3;
		unsigned char MEAS2_LED_SETLNG : 2;
		unsigned char MEAS2_PD_SETLNG : 3;
	} bits;
	unsigned char byte;
} dsRegppg_meas2_config3;


// 0x2C PPG MEAS2 Config4 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS2_PPG1_DACOFF : 3;
		unsigned char rsv1 : 1;
		unsigned char MEAS2_PPG2_DACOFF : 3;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas2_config4;



// PPG MEAS3 Setup
// 0x30 PPG MEAS3 SELECT寄存器
typedef union
{
	struct
	{
		unsigned char MEAS3_DRVA : 2;
		unsigned char MEAS3_DRVB : 2;
		unsigned char rsv1 : 2;
		unsigned char MEAS3_AMB : 1;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas3_select;


// 0x31 PPG MEAS3 Config1 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS3_AVER : 3;
		unsigned char MEAS3_TINT : 2;
		unsigned char rsv : 1;
		unsigned char MEAS3_PDSEL : 2;
	} bits;
	unsigned char byte;
} dsRegppg_meas3_config1;


// 0x32 PPG MEAS3 Config2 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS3_PPG1_ADC_RGE : 2;
		unsigned char MEAS3_PPG2_ADC_RGE : 2;
		unsigned char MEAS3_LED_RGE : 2;
		unsigned char MEAS3_FILT_SEL : 1;
		unsigned char MEAS3_SINC3_SEL : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas3_config2;


// 0x33 PPG MEAS3 Config3 寄存器
typedef union
{
	struct
	{
		unsigned char rsv : 3;
		unsigned char MEAS3_LED_SETLNG : 2;
		unsigned char MEAS3_PD_SETLNG : 3;
	} bits;
	unsigned char byte;
} dsRegppg_meas3_config3;


// 0x34 PPG MEAS3 Config4 寄存器
typedef union
{
	struct
	{
		unsigned char MEAS3_PPG1_DACOFF : 3;
		unsigned char rsv1 : 1;
		unsigned char MEAS3_PPG2_DACOFF : 3;
		unsigned char rsv2 : 1;
	} bits;
	unsigned char byte;
} dsRegppg_meas3_config4;


// 0x58 Interrupt Enables 1 
typedef union
{
	struct
	{
		unsigned char rsv : 1;
		unsigned char THRESH1_HILO_EN : 1;
		unsigned char THRESH2_HILO_EN : 1;
		unsigned char EXP_OVF_EN : 1;
		unsigned char ALC_OVF_EN : 1;
		unsigned char FIFO_DATA_RDY_EN : 1;
		unsigned char FRAME_RDY_EN : 1;
		unsigned char A_FULL_EN : 1;
	} bits;
	unsigned char byte;
} dsRegppg_interrupt_enable1;



typedef struct
{
	//中断状态寄存器
	dsRegIntStatus1 intStatus1;
	dsRegIntStatus2 intStatus2;

	// FIFO 配置寄存器1
	dsRegFifoConfig1 fifoConfig1;
	dsRegFifoConfig2 fifoConfig2;

	//系统控制寄存器
	dsRegSystemSync sysSync;
	dsRegSystemConfig1 sys_cfg1;
	dsRegSystemConfig2 sys_cfg2;
	dsRegSystemConfig3 sys_cfg3;

	//光电二极管偏置寄存器
	dsRegSystemControl_Photodiode_Bias	pdBias;

	dsRegPinFunctionalConfig pin_func_cfg;
	dsRegOutputPinConfig output_pin_cfg;

	// PPG MEAS1 Setup
	dsRegppg_meas1_select meas1_sel;
	dsRegppg_meas1_config1 meas1_cfg1;
	dsRegppg_meas1_config2 meas1_cfg2;
	dsRegppg_meas1_config3 meas1_cfg3;
	dsRegppg_meas1_config4 meas1_cfg4;

	// PPG MEAS2 Setup
	dsRegppg_meas2_select meas2_sel;
	dsRegppg_meas2_config1 meas2_cfg1;
	dsRegppg_meas2_config2 meas2_cfg2;
	dsRegppg_meas2_config3 meas2_cfg3;
	dsRegppg_meas2_config4 meas2_cfg4;

	// PPG MEAS3 Setup
	dsRegppg_meas3_select meas3_sel;
	dsRegppg_meas3_config1 meas3_cfg1;
	dsRegppg_meas3_config2 meas3_cfg2;
	dsRegppg_meas3_config3 meas3_cfg3;
	dsRegppg_meas3_config4 meas3_cfg4;

	//Interrupt Enables
	dsRegppg_interrupt_enable1	int_enable_1;
} dsPPGRegs_t;


typedef struct
{
	unsigned char meas1_enable;
	unsigned char meas2_enable;
	unsigned char meas3_enable;
	unsigned char meas4_enable;
	unsigned char meas5_enable;
	unsigned char meas6_enable;
} MEASx_enable_cfg_t;


typedef struct
{
	//采样次数
	unsigned short fifo_count;

	//曝光读取回来的数据
	unsigned char tag;
	unsigned int pd_data;
} PPG_data_t;


/*------------------------------------------------------------------------------
 Section: Global Function prototypes
 ------------------------------------------------------------------------------*/	
void SPI_PPG_Init(void);

uint8_t max86174A_readReg(uint8_t reg);

void max86174A_flushFIFO(void);
uint8_t max86174A_read_chipID(void);
uint8_t max86174A_FIFO_data_ready(void);
uint16_t max86174A_get_FIFO_count(void);
uint16_t max86174A_read_FIFO_Data(uint8_t* data);

void max86174A_Init_From_datasheet(MEASx_enable_cfg_t *measx_cfg);

#endif

MAX86174.c

/*------------------------------------------------------------------------------
 Section: Includes
 ------------------------------------------------------------------------------*/
#include "MAX86174.h"
#include "nrf_gpio.h"
#include "nrf_drv_spi.h"
#include "SEGGER_RTT.h"

#include <string.h>
#include <stdint.h>
#include <stdbool.h>

/*------------------------------------------------------------------------------
 Section: Macro Definitions
 ------------------------------------------------------------------------------*/	
//SPI驱动程序实例ID,ID和外设编号对应,0:SPI0  1:SPI1 2:SPI2
#define SPI_INSTANCE_PPG  0

#define MEAS1_ENABLE 	1
#define MEAS2_ENABLE 	0
#define MEAS3_ENABLE 	0
#define MEAS4_ENABLE 	0
#define MEAS5_ENABLE 	0
#define MEAS6_ENABLE 	0

/*------------------------------------------------------------------------------
 Section: Type Definitions
 ------------------------------------------------------------------------------*/	
/* None */	

/*------------------------------------------------------------------------------
 Section: Global Function prototypes
 ------------------------------------------------------------------------------*/	
/* None */

/*------------------------------------------------------------------------------
 Section: Local Function prototypes
 ------------------------------------------------------------------------------*/	
/* None */

/*------------------------------------------------------------------------------
 Section: Global Variables
 ------------------------------------------------------------------------------*/	
/* None */

/*------------------------------------------------------------------------------
 Section: Local Variables
 ------------------------------------------------------------------------------*/
dsPPGRegs_t ppgRegs;

//定义名称为spi的SPI驱动程序实例
static const nrf_drv_spi_t spi = NRF_DRV_SPI_INSTANCE(SPI_INSTANCE_PPG);  
//SPI传输完成标志
static volatile bool spi_ppg_xfer_done;  
// //SPI发送缓存数组,使用EasyDMA时一定要定义为static类型
// static uint8_t    spi_tx_buf[6];  
// //SPI接收缓存数组,使用EasyDMA时一定要定义为static类型
// static uint8_t    spi_rx_buf[6];  

 /*------------------------------------------------------------------------------
 Section: Function Definitions
 ------------------------------------------------------------------------------*/	

 /***************************************************************************
* 描  述 : spi_ppg_event_handler 	SPI事件处理函数
* 入  参 :  
* 返回值 : 
**************************************************************************/
void spi_ppg_event_handler(nrf_drv_spi_evt_t const * p_event, void * p_context)
{
  	//设置SPI传输完成  
	spi_ppg_xfer_done = true;
}

 /***************************************************************************
* 描  述 : SPI_PPG_Init 	
* 入  参 :  
* 返回值 : 
**************************************************************************/
void SPI_PPG_Init(void)
{
	//配置用于SPI片选的引脚为输出
	nrf_gpio_cfg_output(SPI_AFE_SS_PIN);
	//拉低CS
	// SPI_PPG_CS_LOW;
	SPI_PPG_CS_HIGH;
	//使用默认配置参数初始化SPI配置结构体
	nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
	//重写SPI信号连接的引脚配置
	spi_config.ss_pin   = NRF_DRV_SPI_PIN_NOT_USED;
	spi_config.miso_pin = SPI_AFE_MISO_PIN;
	spi_config.mosi_pin = SPI_AFE_MOSI_PIN;
	spi_config.sck_pin  = SPI_AFE_SCK_PIN;
	//初始化SPI
	APP_ERROR_CHECK(nrf_drv_spi_init(&spi, &spi_config, spi_ppg_event_handler, NULL));
}


 /***************************************************************************
* 描  述 : spi_read_write
* 入  参 :  
* 返回值 : 
**************************************************************************/
static uint8_t spi_read_write(uint8_t data)
{
	uint8_t ret;

	//传输完成标志设置为false
	spi_ppg_xfer_done = false;

	//启动数据传输
	APP_ERROR_CHECK(nrf_drv_spi_transfer(&spi, &data, 1, &ret, 1));
	//等待SPI传输完成
	while(!spi_ppg_xfer_done);

	return ret;		
}


//  /***************************************************************************
// * 描  述 : max86174A_readReg
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
uint8_t max86174A_readReg(uint8_t reg)
{
	uint8_t ret;
	uint8_t cmd = SPI_READ_CMD;

	SPI_PPG_CS_LOW;
	spi_read_write(reg);
	spi_read_write(cmd);
	ret = spi_read_write(0xff);
	SPI_PPG_CS_HIGH;

	return ret;
}

//  /***************************************************************************
// * 描  述 : max86174A_readRegEx
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static uint8_t max86174A_readRegEx(uint8_t reg, uint8_t *buf, uint16_t len)
{
	uint16_t i, temp;
	uint8_t cmd = SPI_READ_CMD;

	SPI_PPG_CS_LOW;
	spi_read_write(reg);
	spi_read_write(cmd);

	for(i = 0; i < len; i++)
	{
		temp = spi_read_write(0xff);
		buf[i] = temp;
	}
	SPI_PPG_CS_HIGH;

	return 1;
}

//  /***************************************************************************
// * 描  述 : max86174A_writeReg
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_writeReg(uint8_t reg, uint8_t value)
{
	uint8_t cmd = SPI_WRITE_CMD;

	SPI_PPG_CS_LOW;
	spi_read_write(reg);
	spi_read_write(cmd);
	spi_read_write(value);
	SPI_PPG_CS_HIGH;
}

//  /***************************************************************************
// * 描  述 : max86174A_checkReg
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_checkReg(uint8_t reg, uint8_t value)
{
	uint8_t read;
	uint8_t cmd = SPI_READ_CMD;

	SPI_PPG_CS_LOW;
	spi_read_write(reg);
	spi_read_write(cmd);
	read = spi_read_write(0xff);
	SPI_PPG_CS_HIGH;

	if(value != read)
	{
		SEGGER_RTT_printf(0, "[write error]addr:0x%.2x \r\n", reg);
	}
}


//  /***************************************************************************
// * 描  述 : max86174A_reset
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_reset(void)
{
	// ppgRegs.sys_cfg1.bits.DISABLE_I2C = 0x00;
	// ppgRegs.sys_cfg1.bits.PPG1_PWRDN = 0x00;
	// ppgRegs.sys_cfg1.bits.PPG2_PWRDN = 0x00;
	ppgRegs.sys_cfg1.bits.RESET = 0x01;
	// ppgRegs.sys_cfg1.bits.SHDN = 0x00;
	// ppgRegs.sys_cfg1.bits.SYNC_MODE = 0x00;
	max86174A_writeReg(ADDR_REG_SYS_CONFIG_1, ppgRegs.sys_cfg1.byte);
}


//  /***************************************************************************
// * 描  述 : max86174A_shutdown
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_shutdown(void)
{
	ppgRegs.sys_cfg1.bits.SHDN = 0x01;
	max86174A_writeReg(ADDR_REG_SYS_CONFIG_1, ppgRegs.sys_cfg1.byte);
}


//  /***************************************************************************
// * 描  述 : max86174A_start
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_start(void)
{
	ppgRegs.sys_cfg1.bits.SHDN = 0x00;
	max86174A_writeReg(ADDR_REG_SYS_CONFIG_1, ppgRegs.sys_cfg1.byte);
}



//  /***************************************************************************
// * 描  述 : max86174A_enable_MEAS
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_enable_MEAS(uint8_t meas_1, uint8_t meas_2, uint8_t meas_3, uint8_t meas_4, uint8_t meas_5, uint8_t meas_6)
{
	ppgRegs.sys_cfg2.bits.MESA1_EN = meas_1;
	ppgRegs.sys_cfg2.bits.MESA2_EN = meas_2;
	ppgRegs.sys_cfg2.bits.MESA3_EN = meas_3;
	ppgRegs.sys_cfg2.bits.MESA4_EN = meas_4;
	ppgRegs.sys_cfg2.bits.MESA5_EN = meas_5;
	ppgRegs.sys_cfg2.bits.MESA6_EN = meas_6;
	max86174A_writeReg(ADDR_REG_SYS_CONFIG_2, ppgRegs.sys_cfg2.byte);
	max86174A_checkReg(ADDR_REG_SYS_CONFIG_2, ppgRegs.sys_cfg2.byte);
}


//  /***************************************************************************
// * 描  述 : max86174A_sys_config
// * 入  参 :  
// * 返回值 : 
// **************************************************************************/
static void max86174A_sys_config(void)
{
	ppgRegs.sys_cfg1.bits.DISABLE_I2C = 0x01;
	ppgRegs.sys_cfg1.bits.PPG1_PWRDN = 0x00;
	ppgRegs.sys_cfg1.bits.PPG2_PWRDN = 0x00;
	ppgRegs.sys_cfg1.bits.RESET = 0x00;
	ppgRegs.sys_cfg1.bits.SHDN = 0x00;
	ppgRegs.sys_cfg1.bits.SYNC_MODE = 0x00;
	max86174A_writeReg(ADDR_REG_SYS_CONFIG_1, ppgRegs.sys_cfg1.byte);
	max86174A_checkReg(ADDR_REG_SYS_CONFIG_1, ppgRegs.sys_cfg1.byte);

	ppgRegs.sys_cfg3.bits.ALC_DISABLE = 0x00;
	ppgRegs.sys_cfg3.bits.COLLECT_RAW_DATA = 0x00;		//0x00:CDM or FDM 滤掉环境光后的数据放入FIFO;   0x01:原始数据直接放入FIFO;
	ppgRegs.sys_cfg3.bits.MESA1_CONFIG_SEL = 0x00;
	ppgRegs.sys_cfg3.bits.PROX_AUTO = 0x00;
	ppgRegs.sys_cfg3.bits.PROX_DATA_EN = 0x00;
	max86174A_writeReg(ADDR_REG_SYS_CONFIG_3, ppgRegs.sys_cfg3.byte);
	max86174A_checkReg(ADDR_REG_SYS_CONFIG_3, ppgRegs.sys_cfg3.byte);
}



 /***************************************************************************
* 描  述 : max86174A_FIFO_Config
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_FIFO_Config(void)
{
	// ppgRegs.fifoConfig1.bits.FIFO_A_FULL = 0;
	// max86174A_writeReg(ADDR_REG_FIFO_CONFIG1, ppgRegs.fifoConfig1.byte);
	// max86174A_checkReg(ADDR_REG_FIFO_CONFIG1, ppgRegs.fifoConfig1.byte);

	ppgRegs.fifoConfig2.bits.FIFO_RO = 0x00;	//0x00:lose new     0x01: lose old
	ppgRegs.fifoConfig2.bits.A_FULL_TYPE = 0x00;
	ppgRegs.fifoConfig2.bits.FIFO_STAT_CLR = 0x01;
	ppgRegs.fifoConfig2.bits.FLUSH_FIFO = 0x00;
	ppgRegs.fifoConfig2.bits.FIFO_MARK = 0x00;
	max86174A_writeReg(ADDR_REG_FIFO_CONFIG2, ppgRegs.fifoConfig2.byte);
	max86174A_checkReg(ADDR_REG_FIFO_CONFIG2, ppgRegs.fifoConfig2.byte);

	ppgRegs.int_enable_1.bits.A_FULL_EN = 0x00;			//The INTB pin is trigged when A_FULL is set to 1
	ppgRegs.int_enable_1.bits.ALC_OVF_EN = 0x00;
	ppgRegs.int_enable_1.bits.EXP_OVF_EN = 0x00;
	ppgRegs.int_enable_1.bits.FIFO_DATA_RDY_EN = 0x00;
	ppgRegs.int_enable_1.bits.FRAME_RDY_EN = 0x00;
	ppgRegs.int_enable_1.bits.THRESH1_HILO_EN = 0x00;
	ppgRegs.int_enable_1.bits.THRESH2_HILO_EN = 0x00;
	max86174A_writeReg(ADDR_REG_INTERRUPT_ENABLE_1, ppgRegs.int_enable_1.byte);
	max86174A_checkReg(ADDR_REG_INTERRUPT_ENABLE_1, ppgRegs.int_enable_1.byte);
}


 /***************************************************************************
* 描  述 : max86174A_PHOTODIODE_BIAS_Config
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_PHOTODIODE_BIAS_Config(void)
{
	ppgRegs.pdBias.bits.PD1_BIAS = 0x01;
	ppgRegs.pdBias.bits.PD2_BIAS = 0x01;
	max86174A_writeReg(ADDR_REG_PHOTO_DIODE_BIAS, ppgRegs.pdBias.byte);
	max86174A_checkReg(ADDR_REG_PHOTO_DIODE_BIAS, ppgRegs.pdBias.byte);
}



 /***************************************************************************
* 描  述 : max86174A_INTB_Config
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_INTB_Config(void)
{
	ppgRegs.pin_func_cfg.bits.INTB_FCFG = 0x01;
	ppgRegs.pin_func_cfg.bits.TRIG_ICFG = 0x00;
	max86174A_writeReg(ADDR_REG_PIN_FUNCTIONAL_CONFIG, ppgRegs.pin_func_cfg.byte);
	max86174A_checkReg(ADDR_REG_PIN_FUNCTIONAL_CONFIG, ppgRegs.pin_func_cfg.byte);

	ppgRegs.output_pin_cfg.bits.INTB_OCFG = 0x00;
	ppgRegs.output_pin_cfg.bits.TRIGLED4_SEL = 0x01;	//0x00:digital input TRIG  	0x01:LED4_DRV
	max86174A_writeReg(ADDR_REG_OUTPUT_PIN_CONFIG, ppgRegs.output_pin_cfg.byte);
	max86174A_checkReg(ADDR_REG_OUTPUT_PIN_CONFIG, ppgRegs.output_pin_cfg.byte);
}



 /***************************************************************************
* 描  述 : max86174A_FPS_Config
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_FPS_Config(uint16_t fps)
{
	uint16_t FR_CLK_DIV;

	FR_CLK_DIV = 32768 / fps;

	max86174A_writeReg(ADDR_REG_FR_CLK_DIVIDER_MSB, FR_CLK_DIV >> 8);
	max86174A_checkReg(ADDR_REG_FR_CLK_DIVIDER_MSB, FR_CLK_DIV >> 8);
	max86174A_writeReg(ADDR_REG_FR_CLK_DIVIDER_LSB, FR_CLK_DIV & 0xff);
	max86174A_checkReg(ADDR_REG_FR_CLK_DIVIDER_LSB, FR_CLK_DIV & 0xff);

	// set to 1 fps
	// max86174A_writeReg(ADDR_REG_FR_CLK_DIVIDER_MSB, 0x7f);
	// max86174A_checkReg(ADDR_REG_FR_CLK_DIVIDER_MSB, 0x7f);
	// max86174A_writeReg(ADDR_REG_FR_CLK_DIVIDER_LSB, 0xfe);
	// max86174A_checkReg(ADDR_REG_FR_CLK_DIVIDER_LSB, 0xfe);
}


 /***************************************************************************
* 描  述 : max86174A_MEAS1_Config  使用 Green LED 用于测量心率
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_MEAS1_Config(void)
{
	ppgRegs.meas1_sel.bits.MEAS1_AMB = 0x00;
	ppgRegs.meas1_sel.bits.MEAS1_DRVA = 0x00;	//0x00 0x01:green   0x02:red  0x03:ir
	ppgRegs.meas1_sel.bits.MEAS1_DRVB = 0x01;
	max86174A_writeReg(ADDR_REG_MEAS1_SELECT, ppgRegs.meas1_sel.byte);
	max86174A_checkReg(ADDR_REG_MEAS1_SELECT, ppgRegs.meas1_sel.byte);

	ppgRegs.meas1_cfg1.bits.MEAS1_AVER = 0x00;
	ppgRegs.meas1_cfg1.bits.MEAS1_TINT = 0x03;
	ppgRegs.meas1_cfg1.bits.MEAS1_PDSEL = 0x02;
	max86174A_writeReg(ADDR_REG_MEAS1_CONFIG_1, ppgRegs.meas1_cfg1.byte);
	max86174A_checkReg(ADDR_REG_MEAS1_CONFIG_1, ppgRegs.meas1_cfg1.byte);

	ppgRegs.meas1_cfg2.bits.MEAS1_SINC3_SEL = 0x00;
	ppgRegs.meas1_cfg2.bits.MEAS1_FILT_SEL = 0x01;
	ppgRegs.meas1_cfg2.bits.MEAS1_LED_RGE = 0x03;
	ppgRegs.meas1_cfg2.bits.MEAS1_PPG2_ADC_RGE = 0x00;
	ppgRegs.meas1_cfg2.bits.MEAS1_PPG1_ADC_RGE = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS1_CONFIG_2, ppgRegs.meas1_cfg2.byte);
	max86174A_checkReg(ADDR_REG_MEAS1_CONFIG_2, ppgRegs.meas1_cfg2.byte);

	ppgRegs.meas1_cfg3.bits.MEAS1_PD_SETLNG = 0x00;		
	ppgRegs.meas1_cfg3.bits.MEAS1_LED_SETLNG = 0x03;	
	max86174A_writeReg(ADDR_REG_MEAS1_CONFIG_3, ppgRegs.meas1_cfg3.byte);
	max86174A_checkReg(ADDR_REG_MEAS1_CONFIG_3, ppgRegs.meas1_cfg3.byte);

	// ppgRegs.meas1_cfg4.bits.MEAS1_PPG1_DACOFF = 0x00;
	// ppgRegs.meas1_cfg4.bits.MEAS1_PPG2_DACOFF = 0x00;
	// max86174A_writeReg(ADDR_REG_MEAS1_CONFIG_4, ppgRegs.meas1_cfg4.byte);
	// max86174A_checkReg(ADDR_REG_MEAS1_CONFIG_4, ppgRegs.meas1_cfg4.byte);

	max86174A_writeReg(ADDR_REG_MEAS1_LEDA_CURRENT, 0x04);
	max86174A_checkReg(ADDR_REG_MEAS1_LEDA_CURRENT, 0x04);
	max86174A_writeReg(ADDR_REG_MEAS1_LEDB_CURRENT, 0x04);
	max86174A_checkReg(ADDR_REG_MEAS1_LEDB_CURRENT, 0x04);
}


 /***************************************************************************
* 描  述 : max86174A_MEAS2_Config	使用 IR/red LED 用于测量血氧
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_MEAS2_Config(void)
{
	ppgRegs.meas2_sel.bits.MEAS2_AMB = 0x00;
	ppgRegs.meas2_sel.bits.MEAS2_DRVA = 0x02;		//0x00 0x01:green   0x02:red  0x03:ir
	ppgRegs.meas2_sel.bits.MEAS2_DRVB = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS2_SELECT, ppgRegs.meas2_sel.byte);
	max86174A_checkReg(ADDR_REG_MEAS2_SELECT, ppgRegs.meas2_sel.byte);

	ppgRegs.meas2_cfg1.bits.MEAS2_AVER = 0x00;
	ppgRegs.meas2_cfg1.bits.MEAS2_TINT = 0x03;
	ppgRegs.meas2_cfg1.bits.MEAS2_PDSEL = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS2_CONFIG_1, ppgRegs.meas2_cfg1.byte);
	max86174A_checkReg(ADDR_REG_MEAS2_CONFIG_1, ppgRegs.meas2_cfg1.byte);

	ppgRegs.meas2_cfg2.bits.MEAS2_SINC3_SEL = 0x00;
	ppgRegs.meas2_cfg2.bits.MEAS2_FILT_SEL = 0x01;
	ppgRegs.meas2_cfg2.bits.MEAS2_LED_RGE = 0x03;
	ppgRegs.meas2_cfg2.bits.MEAS2_PPG2_ADC_RGE = 0x00;
	ppgRegs.meas2_cfg2.bits.MEAS2_PPG1_ADC_RGE = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS2_CONFIG_2, ppgRegs.meas2_cfg2.byte);
	max86174A_checkReg(ADDR_REG_MEAS2_CONFIG_2, ppgRegs.meas2_cfg2.byte);

	ppgRegs.meas2_cfg3.bits.MEAS2_PD_SETLNG = 0x00;
	ppgRegs.meas2_cfg3.bits.MEAS2_LED_SETLNG = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS2_CONFIG_3, ppgRegs.meas2_cfg3.byte);
	max86174A_checkReg(ADDR_REG_MEAS2_CONFIG_3, ppgRegs.meas2_cfg3.byte);

	// ppgRegs.meas2_cfg4.bits.MEAS2_PPG1_DACOFF = 0x00;
	// ppgRegs.meas2_cfg4.bits.MEAS2_PPG2_DACOFF = 0x00;
	// max86174A_writeReg(ADDR_REG_MEAS2_CONFIG_4, ppgRegs.meas2_cfg4.byte);
	// max86174A_checkReg(ADDR_REG_MEAS2_CONFIG_4, ppgRegs.meas2_cfg4.byte);

	max86174A_writeReg(ADDR_REG_MEAS2_LEDA_CURRENT, 0x04);
	max86174A_checkReg(ADDR_REG_MEAS2_LEDA_CURRENT, 0x04);
	max86174A_writeReg(ADDR_REG_MEAS2_LEDB_CURRENT, 0x00);
	max86174A_checkReg(ADDR_REG_MEAS2_LEDB_CURRENT, 0x00);
}


 /***************************************************************************
* 描  述 : max86174A_MEAS3_Config
* 入  参 :  
* 返回值 : 
**************************************************************************/
static void max86174A_MEAS3_Config(void)
{
	ppgRegs.meas3_sel.bits.MEAS3_AMB = 0x00;		//如果启用环境光测量,将忽略LED配置和电流配置
	ppgRegs.meas3_sel.bits.MEAS3_DRVA = 0x03;
	ppgRegs.meas3_sel.bits.MEAS3_DRVB = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS3_SELECT, ppgRegs.meas3_sel.byte);

	ppgRegs.meas3_cfg1.bits.MEAS3_AVER = 0x00;
	ppgRegs.meas3_cfg1.bits.MEAS3_PDSEL = 0x00;
	ppgRegs.meas3_cfg1.bits.MEAS3_TINT = 0x03;
	max86174A_writeReg(ADDR_REG_MEAS3_CONFIG_1, ppgRegs.meas3_cfg1.byte);

	ppgRegs.meas3_cfg2.bits.MEAS3_SINC3_SEL = 0x00;
	ppgRegs.meas3_cfg2.bits.MEAS3_FILT_SEL = 0x01;
	ppgRegs.meas3_cfg2.bits.MEAS3_LED_RGE = 0x03;
	ppgRegs.meas3_cfg2.bits.MEAS3_PPG2_ADC_RGE = 0x00;
	ppgRegs.meas3_cfg2.bits.MEAS3_PPG1_ADC_RGE = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS3_CONFIG_2, ppgRegs.meas3_cfg2.byte);

	ppgRegs.meas3_cfg3.bits.MEAS3_PD_SETLNG = 0x00;
	ppgRegs.meas3_cfg3.bits.MEAS3_LED_SETLNG = 0x00;
	max86174A_writeReg(ADDR_REG_MEAS3_CONFIG_3, ppgRegs.meas3_cfg3.byte);

	max86174A_writeReg(ADDR_REG_MEAS3_LEDA_CURRENT, 0x01);
	max86174A_checkReg(ADDR_REG_MEAS3_LEDA_CURRENT, 0x01);
	max86174A_writeReg(ADDR_REG_MEAS3_LEDB_CURRENT, 0x00);
	max86174A_checkReg(ADDR_REG_MEAS3_LEDB_CURRENT, 0x00);
}


//---------------------------------------提供给外部的借口----------------------------------------------------
 /***************************************************************************
* 描  述 : max86174A_FIFO_Config
* 入  参 :  
* 返回值 : 
**************************************************************************/
void max86174A_flushFIFO(void)
{
	// Empty the FIFO by set the FLUSH_FIFO bit to 1, in register MAX86174A_FIFO_Configuration_2 (0x09)	
	max86174A_writeReg(ADDR_REG_FIFO_CONFIG2, 0x01 << 4);
}


 /***************************************************************************
* 描  述 : max86174A_read_chipID
* 入  参 :  
* 返回值 : 
**************************************************************************/
uint8_t max86174A_read_chipID(void)
{
	uint8_t ret = 0;
	uint8_t cmd = SPI_READ_CMD;

	SPI_PPG_CS_LOW;
	spi_read_write(ADDR_REG_PART_ID);
	spi_read_write(cmd);
	ret = spi_read_write(0xff);
	SPI_PPG_CS_HIGH;

	return ret;
}


 /***************************************************************************
* 描  述 : max86174A_FIFO_data_ready
* 入  参 :  
* 返回值 : 
**************************************************************************/
uint8_t max86174A_FIFO_data_ready(void)
{
	uint8_t ret;

	ret = ((max86174A_readReg(ADDR_REG_INT_STATUS1) >> 5) & 0x01);
	// SEGGER_RTT_printf(0, "status 1 rdy bit:%d \r\n", ret);

	return ret;
}



 /***************************************************************************
* 描  述 : max86174A_get_FIFO_count
* 入  参 :  
* 返回值 : 
**************************************************************************/
uint16_t max86174A_get_FIFO_count(void)
{
	uint16_t fifo_count_msb, fifo_count_lsb, fifo_count;

	fifo_count_msb = max86174A_readReg(ADDR_REG_FIFO_OVF_COUNTER_1) & 0x80;	//FIFO data count the most significant bit
	fifo_count_lsb = max86174A_readReg(ADDR_REG_FIFO_DATA_COUNTER_2);	//FIFO data count low 8-bit

	fifo_count = ((fifo_count_msb << 1) | fifo_count_lsb);

	return fifo_count;
}


 /***************************************************************************
* 描  述 : max86174A_Init_From_datasheet
* 入  参 :  
* 返回值 : 
**************************************************************************/
void max86174A_Init_From_datasheet(MEASx_enable_cfg_t *measx_cfg)		//初始化策略来自数据手册
{
	//reset
	max86174A_reset();
	max86174A_shutdown();

	//System Configuration
	max86174A_enable_MEAS(measx_cfg->meas1_enable, 
						  measx_cfg->meas2_enable, 
						  measx_cfg->meas3_enable, 
						  measx_cfg->meas4_enable, 
						  measx_cfg->meas5_enable, 
						  measx_cfg->meas6_enable);
	max86174A_sys_config();

	//光电二极管偏置 配置
	max86174A_PHOTODIODE_BIAS_Config();

	//INTB pin config
	max86174A_INTB_Config();

	//config PPG frame rate
	max86174A_FPS_Config(50);

	//Measurement 1 Setup	
	max86174A_MEAS1_Config();	//use two Green LEDs
	// //Measurement 2 Setup
	max86174A_MEAS2_Config();	//use Red LED
	// //Measurement 3 Setup
	max86174A_MEAS3_Config();	//use IR LED

	//FIFO config
	max86174A_FIFO_Config();

	max86174A_flushFIFO();

	max86174A_start();
}

 /***************************************************************************
* 描  述 : max86174A_read_FIFO_Data
* 入  参 :  
* 返回值 : 
**************************************************************************/
uint16_t max86174A_read_FIFO_Data(uint8_t* data)
{
	// The data can only be readout from FIFO, each data is 3 bytes, 
	//so for reading one data, should read 3 byte from I2C, 
	//the register address is MAX86174A_FIFO_Data_Register (0x07)

	//Configure the interrupt callback, read the data from FIFO of max86174 after the INTB signals received.
	uint16_t fifo_count;
	uint8_t overflow_count = 0;
	uint16_t avail_count = 0;

	max86174A_readReg(ADDR_REG_INT_STATUS1);
	max86174A_readReg(ADDR_REG_INT_STATUS2);

	overflow_count = (max86174A_readReg(ADDR_REG_FIFO_OVF_COUNTER_1) & 0x7f);
	fifo_count = max86174A_get_FIFO_count();

	// SEGGER_RTT_printf(0, "[driver]fifo_count:%d | fifo_ovf:%d\n", fifo_count, overflow_count);

	if(overflow_count == 0)		//no data overflow
	{
		avail_count = fifo_count;
	}
	else
	{
		avail_count = 255;		//overflow occurred and data has been lost
	}

	max86174A_readRegEx(ADDR_REG_FIFO_DATA, data, avail_count * 3);

	return fifo_count;
}

能力有限,研究不深;
有问题欢迎留言讨论!
个人邮箱:imxyp9x@163.com

  • 4
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值