1741 views|5 replies

28

Posts

0

Resources
The OP
 

ECG display based on ST [Copy link]

 This post was last edited by Xiaomi Zha on 2022-10-16 16:09

1. Introduction of the Work
The main control part of this system is based on ST's STM32F750, and the ECG signal acquisition uses ADI's ADAS1000 series chips. The two together constitute this system. The MCU will collect the data, perform calculations, and transmit the data to the host computer via USB, and the host computer will display the data. Note that the chips used here are not self-made, but official development boards, and their names are STM32F7508-DK (official provision of this competition) and ADAS1000SDZ (engineer face recognition).

2. System Block Diagram

The system function block diagram is as above. Since two development boards are used, the communication interface SPI between the boards is directly connected with DuPont wires. For the communication between STM32 and PC, since STM32F7508-DK comes with two Micro AB connectors, the design uses HS high-speed communication interface CN12 and PC connection. Since the collection of ECG electrocardiogram signals is used in medical treatment, it cannot be used in practice. The electrical design in medical treatment must comply with relevant national requirements. For details, please refer to GB 9706.1-2020

3. Functional description of each part

The above picture shows the development board of ST's STM32F7508-DK. The system is powered by JP2. In the experiment, I provided Vin=5V, and the board has an LDO, so the core voltage of the system is 3.3V, which can be confirmed in the system schematic diagram. CN4-CN7 mainly provides some external interfaces. The official description is as follows:

I mainly used SPI2 to communicate with ADAS1000.

The figure above shows the development board of ADAS1000. The official description of each interface is as follows:

In fact, I only care about the part that I want to connect to the ST board, which is explained as follows:

  1. Power supply:

    From the description of J5, we can see that different power supplies are needed in the system. It is troublesome to use external power supply. It is better to directly choose J7 or J9 to supply 5V power directly. As mentioned above, ST's development board Vin=5V, which is convenient for experiments.
  2. SPI interface:

    Here you can see that there are two groups of SPI interfaces. Since two ADAS1000s are used on the development board to implement ten leads, and this experiment only implements five leads (RA RL LA LL V1) to observe ECG signals, combined with the description of each module in the above figure, we chose ADAS1000 MASTER, and combined with the schematic diagram, we can choose the SPI0 related interface.
  3. Connection with the human body
    As can be seen in the figure above, the ECG ELECTRODE Connector interface is a connection line interface, using a DB15 interface, and the interface definition is as follows:


As mentioned above, five leads are actually used, so it is necessary to fly out Pin9-RA Pin10-LA Pin11-LL Pin12-V1 Pin14-RLD, connect the electrodes and stick them on the human body.

4. Source Code

4.1 Communication Protocol
4.1.1 Protocol Format

Header (1 byte)

Device address (1 byte)

Command (1 byte)

Data length (2 bytes)

Data (nbyte)

CRC(2byte)

0x55

The device address starts at 1, and 0xFF represents the broadcast address.

High byte first.

Calculate CRC16 from the header

4.1.2 Start ADAS1000 measurement command: 0x06

Send from host computer

Start flag (1 byte)

1: Enable 0: Disable

Lower machine reply

Reply (1 byte)

  1. There are two phases of response to a launch, the accept state and the execute state.
  2. For closure, just reply with acceptance status.

1: Accept success 0: Accept failure

3: Execution successful 2: Execution failed

(Expandable failure reason)

4.1.3 ECG Data 0x07

Actively uploaded from the lower computer to the upper computer 600/500 sps

Channel flag (2 bytes)

Self-incrementing serial number

(4 bytes)

Number of data groups (1 byte)

Data Group 1 Channel 0

(4byte)

Data set 1 channel n

(4byte)

Data Group 2 Channel 0

(4byte)

Data set 2 channel n

(4byte)

Bit0-10:

0: disable

1: enable

Bit14-15:

0:600sps

1:500sps

Starting from 0

Floating point values

Floating point values

Floating point values

Floating point values

4.1.4 Sending filtered data 0x04

Self-incrementing serial number (4 bytes)

Bandpass filter data 1

Bandpass filter data 2

Differential filter data 1

Differential filter data 2

Dynamic minimum peak value

Dynamic noise value

Starting from 0

Floating point values

Floating point values

Floating point values

Floating point values

Floating point values

Floating point values

4.1.5 Enable filter data upload 0x05

Send from host computer

Enable flag (1 byte)

1: Enable 0: Disable

Lower machine reply

Reply (1 byte)

1: Accept success 0: Accept failure

4.1.6 ADAS1000 status upload, 0x0C

The lower computer actively uploads (set to 0 for normal, set to 1 for abnormal). Once an abnormality occurs, the lower computer will upload once every 4 seconds; it will stop sending when it returns to normal.

STATUS (1 byte)

[0:5]

ADC_STATUS (1 byte)

[0:2] (out of range)

DCLO_HI_STATUS (1byte)[5:0]

Leads off

DCLO_LO_STATUS (1byte) [5:0]

Lead short circuit or grounding

Bit0: Data overflow

Bit1: Device internal error

Bit2: Lead off (not used)

Bit3: DC lead off

Bit4: ADC out of range

Bit5: Data CRC error

Bit0: LA

Bit1: LL

Bit2: RA

Bit0: RLD.

Bit1: LA.

Bit2: LL.

Bit3: RA.

Bit0: RLD.

Bit1: LA.

Bit2: LL.

Bit3: RA.

4.1.7 The host computer obtains CHIP status, 0x0D

Send from host computer

Without content

Lower machine reply

ADAS1000 operation (1 byte)

STATUS (1 byte)

[0:5]

ADC_STATUS (1 byte)

[0:2]

DCLO_HI_STATUS (1byte)[5:0]

Leads off

DCLO_LO_STATUS (1byte) [5:0]

Lead short circuit or grounding

AD5940 operation (1 byte)

STATUS (4 bytes)

0: Idle

1: At work

Bit0: Data overflow

Bit1: Device internal error

Bit2: Lead off (not used)

Bit3: DC lead off

Bit4: ADC out of range

Bit5: Data CRC error

Bit0: LA

Bit1: LL

Bit2: RA

Bit0: RLD.

Bit1: LA.

Bit2: LL.

Bit3: RA.

Bit0: RLD.

Bit1: LA.

Bit2: LL.

Bit3: RA.

0: Idle

1: At work

Bit4, ADC Minimum Value

Bit5, ADC Maximum Value

Bit6, ADC Delta Ready

Bit17, Sequencer Timeout Command Error.

Bit23, Data FIFO Full Interrupt.

Bit29, Outlier Int

ADAS Drivers:

#include "ADAS1000.h"				

/*****************************************************************************/
/************************ Variables Definitions ******************************/
/*****************************************************************************/
static unsigned long frameSize 		 = 0; //ADAS1000 frame size in bytes
static unsigned long frameRate 		 = 0; //ADAS1000 frame rate
static unsigned long inactiveWordsNo = 0; //number of inactive words in a frame


bool ADAS1000_StartMea()
{     
    unsigned int reg = 0;
	//store the selected frame rate
	frameRate = ADAS1000_2KHZ_FRAME_RATE;	
	// Reset the ADAS1000.
	//ADAS1000_SoftwareReset();
    ADAS1000_HardwareReset();
    
 
    //Set the frame rate
	if (!ADAS1000_SetFrameRate(frameRate, 2))  //2kHz, skip=1x
    {
        return false;
    }
    
    //Reduce the frame size to the minimum
	inactiveWordsNo = ADAS1000_FRMCTL_PACEDIS | ADAS1000_FRMCTL_RESPMDIS | 
						 ADAS1000_FRMCTL_RESPPHDIS |
						 ADAS1000_FRMCTL_GPIODIS;
	ADAS1000_SetInactiveFrameWords(inactiveWordsNo);  
    
    //Configure VCM = WCT = (LA+LL+RA)/3. RLD is enabled onto RL, Shield amplifier enabled. 
    reg =  ADAS1000_CMREFCTL_SHLDEN | ADAS1000_CMREFCTL_RLD_EN | ADAS1000_CMREFCTL_DRVCM |
        ADAS1000_CMREFCTL_LACM | ADAS1000_CMREFCTL_LLCM | ADAS1000_CMREFCTL_RACM;
    ADAS1000_SetRegisterValue(ADAS1000_CMREFCTL, reg);
	//DC Leads off enabled, leads off current  0x05 50nA   
    reg = ADAS1000_LOFFCTL_LOFFEN | (0x07<<2);       //0x07 70na 
	ADAS1000_SetRegisterValue(ADAS1000_LOFFCTL, reg);
	//Powers up device, enables all ECG channels in gain  GAIN1:2.1 1.4,   00 = GAIN 0 = x1.4, 01 = GAIN 1 = x2.1, 10 = GAIN 2 = x2.8, 11 = GAIN 3 = x4.2 */
	//low noise mode, Master device using XTAL input source
    reg = ADAS1000_ECGCTL_PWREN | ADAS1000_ECGCTL_CNVEN | ADAS1000_ECGCTL_HP | ADAS1000_ECGCTL_MASTER |
        ADAS1000_ECGCTL_VREFBUF | (1<<8) | ADAS1000_ECGCTL_LAEN |
        ADAS1000_ECGCTL_LLEN | ADAS1000_ECGCTL_RAEN; // | ADAS1000_ECGCTL_V1EN | ADAS1000_ECGCTL_V2EN;
	ADAS1000_SetRegisterValue(ADAS1000_ECGCTL, reg);
    
	return true;
}

bool ADAS1000_StopMea()
{
    // Reset the ADAS1000.
    ADAS1000_HardwareReset();
    return true;
}

/***************************************************************************//**
 * @brief  Reads the value of the selected register
 *
 * @param regAddress - The address of the register to read.
 * @param regVal - Pointer to a variable where to store the read data.
 *
 * @return  None.
*******************************************************************************/
void ADAS1000_GetRegisterValue(unsigned char regAddress, 
							   unsigned long* regVal)
{
	unsigned char readCmd[4]	= {0, 0, 0, 0};
	unsigned char readData[4]	= {0, 0, 0, 0};

	// Select the register (For register reads, data is shifted out
	// during the next word).
	readCmd[0] = regAddress;	// Register address.
    ADAS1000_CsClr();
    ADAS1000_Delay1us(10);    
	ADAS1000_Write(readCmd, 4);
	
	// Read the data from the device.
	ADAS1000_Read(readData, 4);
    ADAS1000_CsSet();
	*regVal = ((unsigned long)readData[1] << 16) +
			  ((unsigned long)readData[2] << 8) +
			  ((unsigned long)readData[3] << 0);
}

/***************************************************************************//**
 * @brief Writes a value to the selected register
 *
 * @param regAddress - The address of the register to write to.
 * @param regValue - The value to write to the register.
 *
 * @return None.    
*******************************************************************************/
void ADAS1000_SetRegisterValue(unsigned char regAddress,
                               unsigned long regVal)
{
	unsigned char writeCmd[4] = {0, 0, 0, 0};
	
	writeCmd[0] = 0x80 + regAddress;	// Write bit and register address.
	writeCmd[1] = (unsigned char)((regVal & 0xFF0000) >> 16);
	writeCmd[2] = (unsigned char)((regVal & 0x00FF00) >> 8);
	writeCmd[3] = (unsigned char)((regVal & 0x0000FF) >> 0);
    ADAS1000_CsClr();
    ADAS1000_Delay1us(10); 
	ADAS1000_Write(writeCmd, 4);
    ADAS1000_CsSet();
}

/***************************************************************************//**
 * @brief Resets the ADAS1000 part.
 *
 * @return None.
*******************************************************************************/
void ADAS1000_SoftwareReset(void)
{
	// Clear all registers to their reset value.
	ADAS1000_SetRegisterValue(ADAS1000_ECGCTL, ADAS1000_ECGCTL_SWRST);

	// The software reset requires a NOP command to complete the reset.
	ADAS1000_SetRegisterValue(ADAS1000_NOP, 0);
    ADAS1000_Delay1us(3000);
}

void ADAS1000_HardwareReset(void)
{
    ADAS1000_RstClr();
    ADAS1000_Delay1us(500);
    ADAS1000_RstSet(); //下降沿开始复位, drdy goes high,return low when the reset complete
    ADAS1000_Delay1us(3000);  //最大1.5ms
}

/***************************************************************************//**
 * @brief Selects which words are not included in a data frame.
 *
 * @param channelsMask - Specifies the words to be excluded from the data 
 * 						 frame using a bitwise or of the corresponding bits
 * 						 from the Frame Control Register.
 * 
 * @return None.
*******************************************************************************/
void ADAS1000_SetInactiveFrameWords(unsigned long wordsMask)
{
	unsigned long frmCtrlRegVal = 0;
	unsigned char i = 0;
	
	// Read the current value of the Frame Control Register
	ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);

	//set the inactive channles
	frmCtrlRegVal &= ~ADAS1000_FRMCTL_WORD_MASK;
	frmCtrlRegVal |= wordsMask;

	// Write the new value to the Frame Coontrol register.
	ADAS1000_SetRegisterValue(ADAS1000_FRMCTL, frmCtrlRegVal);
	
	//compute the number of inactive words
	inactiveWordsNo = 0;
	for(i = 0; i < 32; i++)
	{
		if(wordsMask & 0x00000001ul)
		{
			inactiveWordsNo++;
		}
		wordsMask >>= 1;
	}
	
	//compute the new frame size
	switch(frameRate)
	{
		case ADAS1000_16KHZ_FRAME_RATE:
			frameSize = (ADAS1000_16KHZ_WORD_SIZE / 8) *
						(ADAS1000_16KHZ_FRAME_SIZE - inactiveWordsNo);
		break;
		case ADAS1000_128KHZ_FRAME_RATE:
			frameSize = (ADAS1000_128KHZ_WORD_SIZE / 8) *
						(ADAS1000_128KHZ_FRAME_SIZE - inactiveWordsNo);
		break;
		case ADAS1000_31_25HZ_FRAME_RATE:
			frameSize = ((ADAS1000_31_25HZ_WORD_SIZE / 8) *
						(ADAS1000_31_25HZ_FRAME_SIZE - inactiveWordsNo)) / 100;
		break;
		default: // ADAS1000_2KHZ__FRAME_RATE
			frameSize = (ADAS1000_2KHZ_WORD_SIZE / 8) *
						(ADAS1000_2KHZ_FRAME_SIZE - inactiveWordsNo);
		break;
	}
}

bool ADAS1000TestFirstComm()
{
    unsigned long frmCtrlRegVal = 0;
    ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);
    if (frmCtrlRegVal != 0x079000)
    {
        return false;
    }
    return true;
}

/***************************************************************************//**
 * @brief Sets the frame rate.
 *
 * @param rate - ADAS1000 frame rate.
 * 
 * @return None.
*******************************************************************************/
bool ADAS1000_SetFrameRate(unsigned long rate, unsigned char skip)
{
	unsigned long frmCtrlRegVal = 0;
	
	// Store the selected frame rate
	frameRate = rate;
	
	// Read the current value of the Frame Control Register
	ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);
    if (frmCtrlRegVal != 0x079000)
    {
        return false;
    }
	frmCtrlRegVal &= ~ADAS1000_FRMCTL_FRMRATE_MASK;
	
	// Compute the new frame size and update the Frame Control Register value
	switch(frameRate)
	{
		case ADAS1000_16KHZ_FRAME_RATE:
			frameSize = (ADAS1000_16KHZ_WORD_SIZE / 8) *
						(ADAS1000_16KHZ_FRAME_SIZE - inactiveWordsNo);
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_16KHZ;
		break;
		case ADAS1000_128KHZ_FRAME_RATE:
			frameSize = (ADAS1000_128KHZ_WORD_SIZE / 8) *
						(ADAS1000_128KHZ_FRAME_SIZE - inactiveWordsNo);
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_128KHZ;
		break;
		case ADAS1000_31_25HZ_FRAME_RATE:
			frameSize = ((ADAS1000_31_25HZ_WORD_SIZE / 8) *
						(ADAS1000_31_25HZ_FRAME_SIZE - inactiveWordsNo)) / 100;
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_31_25HZ;
		break;
		default: // ADAS1000_2KHZ__FRAME_RATE
			frameSize = (ADAS1000_2KHZ_WORD_SIZE / 8) *
						(ADAS1000_2KHZ_FRAME_SIZE - inactiveWordsNo);
			frmCtrlRegVal |= ADAS1000_FRMCTL_FRMRATE_2KHZ;
		break;
	}
	frmCtrlRegVal |= (skip<<2);
	// Write the new Frame control Register value
	ADAS1000_SetRegisterValue(ADAS1000_FRMCTL, frmCtrlRegVal);
    
    //frmCtrlRegVal = 0;
    //ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &frmCtrlRegVal);
    
    //ADAS1000_Delay1us(1); 
    return true;
}

bool ADAS1000_ReadHeader()
{
    unsigned char readCmd[4]	= {0, 0, 0, 0};
	// Select the register (For register reads, data is shifted out
	// during the next word).
	readCmd[0] = ADAS1000_FRAMES;	// Register address.
    ADAS1000_CsClr();
    ADAS1000_Delay1us(1);    
	ADAS1000_Write(readCmd, 4);	
    ADAS1000_CsSet(); 
    return true;
}

bool ADAS1000_ReadDataOne(unsigned char* pDataBuffer, int len)
{
    ADAS1000_CsClr();
    ADAS1000_Delay1us(1);    
	ADAS1000_Read(pDataBuffer, len);
    ADAS1000_CsSet();
    return true; 
}

/***************************************************************************//**
 * @brief Reads the specified number of frames.
 *
 * @param pDataBuffer - Buffer to store the read data.
 * @param frameCnt - Number of frames to read.
 * @param startRead - Set to 1 if a the frames read sequence must be started.
 * @param stopRead - Set to 1 if a the frames read sequence must be sopped 
 *					 when exiting the function.
 * @param waitForReady - Set to 1 if the function must wait for the READY bit 
 *						 to be set in the header.
 * @param readyRepeat - Set to 1 if the device was configured to repeat the 
 *						header until the READY bit is set.
 *
 * @return  None.
*******************************************************************************/
void ADAS1000_ReadData(unsigned char* pDataBuffer, unsigned long frameCnt,
					   unsigned char startRead, unsigned char stopRead,
					   unsigned char waitForReady, unsigned char readyRepeat)
{
	unsigned char readCmd[4]	= {0, 0, 0, 0};
	unsigned long ready = 0;
	
	// If the read sequence must be started send a FRAMES command.
	if(startRead)
	{
		readCmd[0] = ADAS1000_FRAMES;	// Register address.
		ADAS1000_Write(readCmd, 4);
	}

	// Read the number of requested frames.
	while(frameCnt)
	{
		// If waiting for the READY bit to be set read the header until the bit is set, otherwise just read the entire frame.
		if(waitForReady)
		{
			ready = 1;
			while(ready == 1)
			{
				//if the header is repeated until the READY bit is set read only the header, otherwise read the entire frame
				if(readyRepeat)
				{
					ADAS1000_Read(pDataBuffer, 4);
					ready = *pDataBuffer & 0x40;
					if(ready == 0)
					{
						ADAS1000_Read(pDataBuffer + 4, frameSize - 4);
						pDataBuffer += frameSize;
						frameCnt--;
					}
				}
				else
				{
					ADAS1000_Read(pDataBuffer, frameSize);
					ready = *pDataBuffer & 0x40;
					if(ready == 0)
					{
						pDataBuffer += frameSize;			
						frameCnt--;
					}
				}
			}
		}
		else
		{
			ADAS1000_Read(pDataBuffer, frameSize);
			pDataBuffer += frameSize;			
			frameCnt--;
		}
	}

	// If the frames read sequence must be stopped read a register to stop the frames read.
	if(stopRead)
	{
		ADAS1000_GetRegisterValue(ADAS1000_FRMCTL, &ready);
	}
}

/***************************************************************************//**
 * @brief Computes the CRC for a frame.
 *
 * @param pBuf - Buffer holding the frame data.
 *
 * @return Returns the CRC value for the given frame.
*******************************************************************************/
unsigned long ADAS1000_ComputeFrameCrc(unsigned char *pBuf, int len)
{
	unsigned char i = 0;
    unsigned long crc = 0x00FFFFFF;
	unsigned long poly = 0;
	unsigned char bitCnt = 0;	
	unsigned long frmSize = 0;
	
	// Select the CRC poly and word size based on the frame rate.

    poly = CRC_POLY_2KHZ_16KHZ;
    bitCnt = 24;

	frmSize = len;

	// Compute the CRC.
	while(frmSize--)
	{
		crc ^= (((unsigned long)*pBuf++) << (bitCnt - 8));
		for(i = 0; i < 8; i++)
		{
			if(crc & (1ul << (bitCnt - 1)))
				crc = (crc << 1) ^ poly;
            else
				crc <<= 1;
		}
	}
	
	return crc;
}

bool CheckADAS1000CRC16(unsigned char * Buffer,unsigned int BufSizeBytes)
{
	/* Calculate 16-bit CRC */
	unsigned int Calc_CRC = ADAS1000_ComputeFrameCrc(Buffer,BufSizeBytes);

	/* Compare the calculated CRC with the 16-bit CRC constant */
	bool Result = (Calc_CRC == CRC_CHECK_CONST_2KHZ_16KHZ);

	/* Return CRC Check Pass or Fail */
	return Result;
}
#include "ADAS1000Port.h"

bool ADAS1000_Write(unsigned char *pSendBuffer,unsigned long length)
{
    return SPI2_Write(pSendBuffer, length);
}

bool ADAS1000_Read(unsigned char *pRecvBuff,unsigned long length)
{
    return SPI2_Read(pRecvBuff, length);
}

bool ADAS1000_ReadWriteNBytes(unsigned char *pSendBuffer,unsigned char *pRecvBuff,unsigned long length)
{
    return SPI2_ReadWriteNBytes(pSendBuffer, pRecvBuff, length);
}
   
void ADAS1000_PDClr(void)
{
    DigitalIO_SetRealOutPutN(ADAS1000_MASTER_PD_PIN, false);
}
void ADAS1000_PDSet(void)
{
    DigitalIO_SetRealOutPutN(ADAS1000_MASTER_PD_PIN, true);
}

void ADAS1000_CsClr(void)
{
   DigitalIO_SetRealOutPutN(ADAS1000_MASTER_CS_PIN, false);
}

void ADAS1000_CsSet(void)
{
   DigitalIO_SetRealOutPutN(ADAS1000_MASTER_CS_PIN, true);
}

void ADAS1000_RstClr(void)
{
   DigitalIO_SetRealOutPutN(ADAS1000_MASTER_RESET_PIN, false);
}

void ADAS1000_RstSet(void)
{
   DigitalIO_SetRealOutPutN(ADAS1000_MASTER_RESET_PIN, true);
}

bool ADAS1000_DrdyGet(void)
{
    return DigitalIO_GetRealIutPutN(ADAS1000_MASTER_DRDY_PIN);   
}

void ADAS1000_Delay1us(uint32_t time)
{
    if (time < 1000)
    {
        delay_us(time);   
    }
    else
    {
        delay_ms(time/1000);
    }
}


uint32_t ADAS1000_MCUResourceInit(void)
{  
    ADAS1000_PDSet();
    delay_ms(1);
    ADAS1000_CsSet();
    ADAS1000_RstSet();
    delay_ms(10);
    return 0;
}

The two header files are as follows:

#ifndef _ADAS1000_H_
#define _ADAS1000_H_

#include "ADAS1000Port.h"

/******************************************************************************/
/* ADAS1000 SPI Registers Memory Map 										  */
/******************************************************************************/
#define	ADAS1000_NOP			0x00	/* NOP (No operation) */
#define	ADAS1000_ECGCTL			0x01	/* ECG Setting Register */
#define	ADAS1000_LOFFCTL		0x02	/* Leads off Control Register  */
#define	ADAS1000_RESPCTL		0x03	/* Respiration Control Register */
#define	ADAS1000_PACECTL		0x04	/* Pace Detection Control Register */
#define	ADAS1000_CMREFCTL		0x05	/* Common Mode Reference and Shield Drive Control Register */
#define	ADAS1000_GPIOCTL		0x06	/* GPIO Control Register */
#define	ADAS1000_PACEAMPTH		0x07	/* Pace Amplitude Threshold2 */
#define	ADAS1000_TESTTONE		0x08	/* Test Tone */
#define	ADAS1000_CALDAC			0x09	/* Calibration DAC */
#define	ADAS1000_FRMCTL			0x0A	/* Frame Control Register */
#define	ADAS1000_FILTCTL		0x0B	/* Filter Control Register */
#define	ADAS1000_LOFFUTH		0x0C	/* Leads off Upper Threshold */
#define	ADAS1000_LOFFLTH		0x0D	/* Leads off Lower Threshold */
#define	ADAS1000_PACEEDGETH		0x0E	/* Pace Edge Threshold */
#define	ADAS1000_PACELVLTH		0x0F	/* Pace Level Threshold */
#define	ADAS1000_LADATA			0x11	/* LA or LEAD I Data */
#define	ADAS1000_LLDATA			0x12	/* LL or LEAD II Data */
#define	ADAS1000_RADATA			0x13	/* RA or LEAD III Data */
#define	ADAS1000_V1DATA			0x14	/* V1 or V1?Data */
#define	ADAS1000_V2DATA			0x15	/* V2 or V2?Data */
#define	ADAS1000_PACEDATA		0x1A	/* Read Pace Detection Data */
#define	ADAS1000_RESPMAG		0x1B	/* Read Respiration Data Magnitude */
#define	ADAS1000_RESPPH			0x1C	/* Read Respiration Data Phase */
#define	ADAS1000_LOFF			0x1D	/* Leads Off Status */
#define	ADAS1000_DCLEADSOFF		0x1E	/* DC Leads off Register */
#define ADAS1000_OPSTAT         0x1F    /* Operating State Register */
#define	ADAS1000_EXTENDSW		0x20	/* Extended Switch for respiration inputs */
#define	ADAS1000_CALLA			0x21	/* User gain calibration LA */
#define	ADAS1000_CALLL			0x22	/* User gain calibration LL */
#define	ADAS1000_CALRA			0x23	/* User gain calibration RA */
#define	ADAS1000_CALV1			0x24	/* User gain calibration V1 */
#define	ADAS1000_CALV2			0x25	/* User gain calibration V2 */
#define	ADAS1000_LOAMLA			0x31	/* Leads off Amplitude for LA */
#define	ADAS1000_LOAMLL			0x32	/* Leads off Amplitude for LL */
#define	ADAS1000_LOAMRA			0x33	/* Leads off Amplitude for RA */
#define	ADAS1000_LOAMV1			0x34	/* Leads off Amplitude for V1 */
#define	ADAS1000_LOAMV2			0x35	/* Leads off Amplitude for V2 */
#define	ADAS1000_PACE1_DATA		0x3A	/* Pace1 Width & Amplitude2 */
#define	ADAS1000_PACE2_DATA		0x3B	/* Pace2 Width & Amplitude2 */
#define	ADAS1000_PACE3_DATA		0x3C	/* Pace3 Width & Amplitude2 */
#define	ADAS1000_FRAMES			0x40	/* Frame Header - Read Data Frames */
#define	ADAS1000_CRC			0x41	/* Frame CRC */

/******************************************************************************/
/* ECG Setting Register 													  */
/******************************************************************************/
#define ADAS1000_ECGCTL_LAEN		(1ul << 23)	/* 	ECG Channel Enable, shuts down power to the channel, the input is 
													now HiZ : 1 = enabled, 0 = disabled */
#define ADAS1000_ECGCTL_LLEN		(1ul << 22)	/* 	ECG Channel Enable, shuts down power to the channel, the input is 
													now HiZ : 1 = enabled, 0 = disabled */
#define ADAS1000_ECGCTL_RAEN		(1ul << 21)	/* 	ECG Channel Enable, shuts down power to the channel, the input is 
													now HiZ : 1 = enabled, 0 = disabled */
#define ADAS1000_ECGCTL_V1EN		(1ul << 20)	/* 	ECG Channel Enable, shuts down power to the channel, the input is 
													now HiZ : 1 = enabled, 0 = disabled */
#define ADAS1000_ECGCTL_V2EN		(1ul << 19)	/* 	ECG Channel Enable, shuts down power to the channel, the input is 
													now HiZ : 1 = enabled, 0 = disabled */
#define ADAS1000_ECGCTL_CHCONFIG	(1ul << 10)	/* 	Setting this bit selects the differential AFE input: 
														0 = Single Ended Input ?Digital Lead Mode or Electrode Mode, 
														1 = Differential Input ?Analog Lead Mode */
#define ADAS1000_ECGCTL_GAIN 		(1ul << 8)	/* 	Pre-Amp & Anti-Aliasing Filter Overall Gain: 
														00 = GAIN 0 = x1.4, 01 = GAIN 1 = x2.1, 
														10 = GAIN 2 = x2.8, 11 = GAIN 3 = x4.2 */
#define ADAS1000_ECGCTL_VREFBUF 	(1ul << 7)	/* 	VREF Buffer Enable:   0 = Disabled, 1 = Enabled (when using internal 
													VREF, the VREFBUF must be enabled) */
#define ADAS1000_ECGCTL_CLKEXT		(1ul << 6)	/* 	Use external clock instead of crystal oscillator. The crystal oscillator 
													is automatically disabled if configured as SLAVE in Gang mode and the 
													Slave device should receive the CLK from the Master device:  
														0 = XTAL is CLK source, 1 = CLK_IO is CLK source. */
#define ADAS1000_ECGCTL_MASTER		(1ul << 5)	/* 	In gang mode, this bit selects the master (SYNC_GANG pin is configured 
													as an output). When in Single Channel Mode (GANG = 0), this bit is ignored:  
														0 = Slave, 1 = Master  */
#define ADAS1000_ECGCTL_GANG		(1ul << 4)	/* 	Enable gang mode. Setting this bit causes the CLK_IO and to be activated: 
														0 = Single Channel mode,  1 = Gang Mode */
#define ADAS1000_ECGCTL_HP			(1ul << 3)	/* 	Selects the noise/power performance, this bit controls the ADC sampling 
													frequency. See specifications for further details: 
														0 = 1MSPS - low power,  1 = 2 MSPS ?High performance/low noise */
#define ADAS1000_ECGCTL_CNVEN		(1ul << 2)	/* 	Convert Enable ?Setting this bit enables the ADC conversion and filters: 
														0 = Idle, 1 = Conversion Enable */
#define ADAS1000_ECGCTL_PWREN		(1ul << 1)	/* 	Power Enable ?clearing this bit powers down the device. All analog blocks 
													are powered down and the external crystal is disabled:  
														0 = Power Down,  1 = Power Enable */
#define ADAS1000_ECGCTL_SWRST		(1ul << 0)	/* 	Software Reset ?setting this bit clears all registers to their reset value. 
													This bit automatically clears itself. The software reset requires a NOP 
													command to complete the reset: 0 = NOP,  1 = Reset */

/******************************************************************************/
/* Leads off Control Register 												  */
/******************************************************************************/
#define ADAS1000_LOFFCTL_LAPH 		(1ul << 23)	/* 	AC Leads Off Phase: 0 = in phase, 1 = 180?out of phase */
#define ADAS1000_LOFFCTL_LLPH 		(1ul << 22)	/* 	AC Leads Off Phase: 0 = in phase, 1 = 180?out of phase */
#define ADAS1000_LOFFCTL_RAPH		(1ul << 21)	/* 	AC Leads Off Phase: 0 = in phase, 1 = 180?out of phase */
#define ADAS1000_LOFFCTL_V1PH		(1ul << 20)	/* 	AC Leads Off Phase: 0 = in phase, 1 = 180?out of phase */
#define ADAS1000_LOFFCTL_V2PH		(1ul << 19)	/* 	AC Leads Off Phase: 0 = in phase, 1 = 180?out of phase */
#define ADAS1000_LOFFCTL_CEPH		(1ul << 18)	/* 	AC Leads Off Phase: 0 = in phase, 1 = 180?out of phase */
#define ADAS1000_LOFFCTL_LAACLOEN	(1ul << 17)	/* 	Individual electrode AC Leads off enable. AC Leads off enables are 
													the OR of ACSEL and the individual AC Leads off Channel enables. 
														0 = AC Leads off disabled, 1 = AC Leads off enabled */
#define ADAS1000_LOFFCTL_LLACLOEN	(1ul << 16)	/*	Individual electrode AC Leads off enable. AC Leads off enables are 
													the OR of ACSEL and the individual AC Leads off Channel enables. 
														0 = AC Leads off disabled, 1 = AC Leads off enabled */
#define ADAS1000_LOFFCTL_RAACLOEN	(1ul << 15)	/* 	Individual electrode AC Leads off enable. AC Leads off enables are
													the OR of ACSEL and the individual AC Leads off Channel enables. 
														0 = AC Leads off disabled, 1 = AC Leads off enabled */
#define ADAS1000_LOFFCTL_V1ACLOEN	(1ul << 14)	/* 	Individual electrode AC Leads off enable. AC Leads off enables are 
													the OR of ACSEL and the individual AC Leads off Channel enables. 
														0 = AC Leads off disabled, 1 = AC Leads off enabled */
#define ADAS1000_LOFFCTL_V2ACLOEN	(1ul << 13)	/* 	Individual electrode AC Leads off enable. AC Leads off enables are 
													the OR of ACSEL and the individual AC Leads off Channel enables. 
														0 = AC Leads off disabled, 1 = AC Leads off enabled */
#define ADAS1000_LOFFCTL_CEACLOEN	(1ul << 12)	/* 	Individual electrode AC Leads off enable. AC Leads off enables are 
													the OR of ACSEL and the individual AC Leads off Channel enables. 
														0 = AC Leads off disabled, 1 = AC Leads off enabled */
#define ADAS1000_LOFFCTL_ACCURREN	(1ul << 7)	/* Set Current level for AC leads off (only active for ACSEL = 1). 
														00 = 12.5nA rms, 01  =  25nA rms, 
														10  =  50nA rms, 11  =  100nA rms */
#define ADAS1000_LOFFCTL_DCCURRENT	(1ul << 2)	/* 	Set Current level for DC leads off (only active for ACSEL = 0) 
														000 = 0nA, 001  =  10nA, 010  =  20nA, 011  =  30nA, 
														100  =  40nA, 101  =  50nA, 110  =  60nA, 111  =  70nA */
#define ADAS1000_LOFFCTL_ACSEL 		(1ul << 1)	/* 	DC or AC (out of band) Leads Off Detection. If LOFFEN = 0, this bit
													is don抰 care. If LOFFEN = 1, 0 = DC Leads Off Detection enabled. 
													(Individual AC leads off may be enabled through bits 12-17), 
													1  = DC Leads off Detection disabled. AC Leads Off Detection enabled 
													(all electrodes except CE electrode). */
#define ADAS1000_LOFFCTL_LOFFEN		(1ul << 0)	/* 	Enable Leads Off Detection: 
														0 = Leads Off Disabled, 1 = Leads Off Enabled */

/******************************************************************************/
/* Respiration Control Register 											  */
/******************************************************************************/
#define ADAS1000_RESPCTL_RESPEXTSYNC	(1ul << 15)	/* 	Set to one to enable the MSB of the respiration DAC to be driven
														out onto the GPIO[3] pin. This 64kHz signal can be used to 
														synchronize an external generator to the respiration carrier.
														0 = normal GPIO3 function, 1 = MSB of RESPDAC driven onto GPIO[3] */
#define ADAS1000_RESPCTL_RESPEXTAMP		(1ul << 14)	/* 	For use with external instrumentation amplifier with respiration 
														circuit. Bypasses the on chip amplifier stage and input directly 
														to the ADC. */
#define ADAS1000_RESPCTL_RESPOUT		(1ul << 13)	/* 	Selects external respiration drive output. RESPDAC_RA is 
														automatically selected when RESPCAP = 1, 0 = RESPDAC _LL, 1 = RESPDAC_LA */
#define ADAS1000_RESPCTL_RESPCAP		(1ul << 12)	/* 	Selects source of Respiration Capacitors. 
															0 = Use internal capacitors, 1 = Use external capacitors */
#define ADAS1000_RESPCTL_RESPGAIN		(1ul << 8)	/* 	Respiration Inamp Gain (saturates at 10): 
															0000 = x1 gain, 0001 = x2 gain, 0010 = x3 gain, 
															... 
															1000 = x9 gain, 1001 = x10 gain, 11xx = x10 gain */
#define ADAS1000_RESPCTL_RESPEXTSEL 	(1ul << 7)	/* 	Selects between EXT_RESP _LA or EXT_RESP_LL paths. Only applies
														if External Respiration is selected in RESPSEL. EXT_RESP_RA 
														automatically gets enabled. 0 = EXT_RESP_LL, 1 = EXT_RESP _LA */
#define ADAS1000_RESPCTL_RESPSEL		(1ul << 5)	/* 	Set Leads for Respiration Measurement: 
														00 = Lead I, 01 = Lead II, 
														10 = Lead III, 11 = External Respiration path */
#define ADAS1000_RESPCTL_RESPAMP 		(1ul << 3)	/* 	Set the test tone amplitude for respiration:  
															00 = Amplitude/8, 01  = Amplitude/4, 
															10  = Amplitude/2, 11  = Amplitude */
#define ADAS1000_RESPCTL_RESPFREQ		(1ul << 1)	/* 	Set Frequency for Respiration: 
															00 = 56kHz, 01 = 54kHz, 10 = 52kHz, 11 = 50kHz */
#define ADAS1000_RESPCTL_RESPEN			(1ul << 0)	/* 	Enable Respiration: 
															0 = Respiration Disabled, 1  = Respiration Enabled */

#define ADAS1000_RESPCTL_RESPGAIN_MASK	(0x0000000Ful << 8)														
#define ADAS1000_RESPCTL_RESPSEL_MASK	(0x00000003ul << 5)														
															
/******************************************************************************/
/* Pace Detection Control Register 											  */
/******************************************************************************/
#define ADAS1000_PACECTL_PACEFILTW		(1ul << 11)	/* 	Pace width Filter: 
															0 = Filter Disabled, 1 = Filter Enabled */
#define ADAS1000_PACECTL_PACETFILT2		(1ul << 10)	/* 	Pace validation filter 2: 
															0 = Filter Disabled, 1 = Filter Enabled */
#define ADAS1000_PACECTL_PACETFILT1		(1ul << 9)	/* 	Pace validation filter 2: 
															0 = Filter Disabled, 1 = Filter Enabled */
#define ADAS1000_PACECTL_PACE3SEL 		(1ul << 7)	/* 	Set Lead for Pace Detection Measurement: 
															00 = Lead I, 01 = Lead II, 10 = Lead III, 11 = Lead aVF */
#define ADAS1000_PACECTL_PACE2SEL 		(1ul << 5)	/* 	Set Lead for Pace Detection Measurement: 
															00 = Lead I, 01 = Lead II, 10 = Lead III, 11 = Lead aVF */
#define ADAS1000_PACECTL_PACE1SEL 		(1ul << 3)	/* 	Set Lead for Pace Detection Measurement: 
															00 = Lead I, 01 = Lead II, 10 = Lead III, 11 = Lead aVF */
#define ADAS1000_PACECTL_PACE3EN		(1ul << 2)	/* 	Enable Pace Detection Algorithm: 
															0 = Pace Detection Disabled, 1  = Pace Detection Enabled */
#define ADAS1000_PACECTL_PACE2EN		(1ul << 1)	/* 	Enable Pace Detection Algorithm: 
															0 = Pace Detection Disabled, 1  = Pace Detection Enabled */
#define ADAS1000_PACECTL_PACE1EN		(1ul << 0)	/* 	Enable Pace Detection Algorithm: 
															0 = Pace Detection Disabled, 1  = Pace Detection Enabled */

#define ADAS1000_PACECTL_PACE3SEL_MASK	(0x00000003ul << 7)
#define ADAS1000_PACECTL_PACE2SEL_MASK	(0x00000003ul << 5)
#define ADAS1000_PACECTL_PACE1SEL_MASK	(0x00000003ul << 3)
															
/******************************************************************************/
/* Common Mode Reference and Shield Drive Control Register 					  */
/******************************************************************************/
#define ADAS1000_CMREFCTL_LACM		(1ul << 23)	/*	Common Mode Electrode Select 										 */
#define ADAS1000_CMREFCTL_LLCM		(1ul << 22)	/*	Any combination of the 5 input electrodes can be used to create the  */
#define ADAS1000_CMREFCTL_RACM		(1ul << 21)	/*	Common Mode signal, or the Common Mode signal can be driven from the */
#define ADAS1000_CMREFCTL_V1CM		(1ul << 20)	/*	internal reference. Bits 23:19 are ignored when bit 2 is selected.   */
#define ADAS1000_CMREFCTL_V2CM		(1ul << 19)	/*	The Common Mode is the average of the selected electrodes. When a 	 */
												/*	single electrode is selected, the Common Mode is the signal level of */
												/*	that electrode alone.												 */	
												/*		0 = does not contribute to the common mode						 */
												/*		1 = contributes to the common mode 								 */
#define ADAS1000_CMREFCTL_LARLD		(1ul << 14)	/*	RLD Summing Junction
														0 = does not contribute to RLD input
														1   = contributes to RLD input */
#define ADAS1000_CMREFCTL_LLRLD		(1ul << 13)	/*	RLD Summing Junction
														0 = does not contribute to RLD input
														1   = contributes to RLD input */
#define ADAS1000_CMREFCTL_RARLD		(1ul << 12)	/*	RLD Summing Junction
														0 = does not contribute to RLD input
														1   = contributes to RLD input */
#define ADAS1000_CMREFCTL_V1RLD		(1ul << 11)	/*	RLD Summing Junction
														0 = does not contribute to RLD input
														1   = contributes to RLD input */
#define ADAS1000_CMREFCTL_V2RLD		(1ul << 10)	/*	RLD Summing Junction
														0 = does not contribute to RLD input
														1   = contributes to RLD input */
#define ADAS1000_CMREFCTL_CERLD		(1ul << 9)	/*	RLD Summing Junction
														0 = does not contribute to RLD input
														1   = contributes to RLD input */
#define ADAS1000_CMREFCTL_CEREFEN	(1ul << 8)	/*	Common Electrode Reference
														0 = Common Electrode disabled
														1   = Common Electrode enabled */
#define ADAS1000_CMREFCTL_RLDSEL	(1ul << 4)	/*	Select electrode for reference drive
														0000 = RL, 0001 = LA, 0010 = LL,
														0011 = RA, 0100 = V1, 0101 = V2,
														0110 to 1111 = Reserved */
#define ADAS1000_CMREFCTL_DRVCM		(1ul << 3)	/*	Common mode output ?when set, the internally derived common mode
													signal is driven out the common mode pin. This bit has no effect 
													if external common mode is selected. 
														0 = common mode is not driven out
														1   = common mode is driven out the external common mode pin */
#define ADAS1000_CMREFCTL_EXTCM		(1ul << 2)	/*	Select the source of Common Mode 
													(use when operating multiple devices together)
														0 = Internal Common Mode selected
														1 = External Common Mode selected */
#define ADAS1000_CMREFCTL_RLD_EN	(1ul << 1)	/*	Enable Right Leg Drive Reference Electrode
														0 = Disabled
														1  = Enabled */
#define ADAS1000_CMREFCTL_SHLDEN	(1ul << 0)	/*	Enable Shield Drive
														0 = Shield Drive Disabled
														1  = Shield Drive Enabled */

#define ADAS1000_CMREFCTL_RLDSEL_MASK (0x0000000Ful << 4)
														
/******************************************************************************/
/* GPIO Control Register 													  */
/******************************************************************************/
#define ADAS1000_GPIOCTL_SPIFW		(1ul << 18)	/*	Frame secondary SPI words with chip select 
														0 = MCS asserted for entire frame
														1 = MCS asserted for individual word */
#define ADAS1000_GPIOCTL_SPIEN		(1ul << 16)	/*	Secondary SPI Enable (ADAS1000 and ADAS1000-2 only) (SPI interface
													providing ECG data at 128kHz data rate for external digital pace 
													algorithm detection ?uses GPIO0, GPIO1, GPIO2 pins)
														0 = Disabled
														1 = Enabled. The individual control bits for GPIO0, GPIO1, 
															GPIO2 are ignored. GPIO3 is not affected by SPIEN */
#define ADAS1000_GPIOCTL_G3CTL		(1ul << 14)	/*	State of GPIO<3>
														00 = High Impedance, 01 = Input,
														10 = Output, 11 = Open Drain */
#define ADAS1000_GPIOCTL_G3OUT		(1ul << 13)	/*	Output Value to be written to GPIO<3> when pad is configured as an
													output or open drain
														0  = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G3IN		(1ul << 12)	/*	(Read Only) Input Value read from GPIO<3> when pad is configured 
													as an input
														0 = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G2CTL 		(1ul << 10)	/*	State of GPIO<2>
														00 = High Impedance, 01 = Input,
														10 = Output, 11 = Open Drain */
#define ADAS1000_GPIOCTL_G2OUT		(1ul << 9)	/*	Output Value to be written to GPIO<2> when pad is configured as an 
													output or open drain
														0 = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G2IN		(1ul << 8)	/*	(Read Only) Input Value read from GPIO<2> when pad is configured as
													an input.
														0 = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G1CTL		(1ul << 6)	/*	State of GPIO<1>
														00 = High Impedance, 01 = Input,
														10 = Output, 11 = Open Drain */
#define ADAS1000_GPIOCTL_G1OUT		(1ul << 5)	/*	Output Value to be written to GPIO<1> when pad is configured as an
													output or open drain.
														0 = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G1IN		(1ul << 4)	/*	(Read Only) Input Value read from GPIO<1> when pad is configured as
													an input.
														0 = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G0CTL		(1ul << 2)	/*	State of GPIO<0>
														00 = High Impedance, 01 = Input,
														10 = Output, 11 = Open Drain */
#define ADAS1000_GPIOCTL_G0OUT		(1ul << 1)	/*	Output Value to be written to GPIO<0> when pad is configured as an
													output or open drain.
														0 = Low Value
														1 = High Value */
#define ADAS1000_GPIOCTL_G0IN		(1ul << 0)	/*	(Read Only) Input Value read from GPIO<0> when pad is configured 
													as an input
														0 = Low Value
														1 = High Value */

#define ADAS1000_GPIOCTL_G3CTL_MASK	(0x00000003ul << 14)
#define ADAS1000_GPIOCTL_G2CTL_MASK	(0x00000003ul << 10)
#define ADAS1000_GPIOCTL_G1CTL_MASK	(0x00000003ul << 6)
#define ADAS1000_GPIOCTL_G0CTL_MASK	(0x00000003ul << 2)
														
/******************************************************************************/
/* Pace Amplitude Threshold2 Register										  */
/******************************************************************************/
#define ADAS1000_PACEAMPTH_PACE3AMPTH	(1ul << 16)	/*	Pace Amplitude Thresold			*/
#define ADAS1000_PACEAMPTH_PACE2AMPTH	(1ul << 8)	/*	Threshold = N ?VREF/GAIN/216 	*/
#define ADAS1000_PACEAMPTH_PACE1AMPTH	(1ul << 0)	

#define ADAS1000_PACEAMPTH_PACE3AMPTH_MASK		(0x000000FFul << 16)
#define ADAS1000_PACEAMPTH_PACE2AMPTH_MASK		(0x000000FFul << 8)
#define ADAS1000_PACEAMPTH_PACE1AMPTH_MASK		(0x000000FFul << 0)

/******************************************************************************/
/* Test Tone Register														  */
/******************************************************************************/
#define ADAS1000_TESTTONE_TONLA		(1ul << 23)	/*	Tone Select 													  */
#define ADAS1000_TESTTONE_TONLL		(1ul << 22)	/* 	0 = 1.3V VCM_REF												  */
#define ADAS1000_TESTTONE_TONRA		(1ul << 21)	/*	1 = 1mV sinewave or squarewave for toneint, no connect for tonext */
#define ADAS1000_TESTTONE_TONV1		(1ul << 20)
#define ADAS1000_TESTTONE_TONV2		(1ul << 19)
#define ADAS1000_TESTTONE_TONTYPE	(1ul << 3)	/*	00 = 10Hz Sine Wave
													01 = 150Hz Sine Wave
													1x = 1Hz 1mV Square Wave */
#define ADAS1000_TESTTONE_TONINT	(1ul << 2)	/*	Test Tone Internal or External
													0 = External Test Tone
													1  = Internal Test Tone */
#define ADAS1000_TESTTONE_TONOUT	(1ul << 1)	/*	Test Tone out Enable
													0 = disconnects test tone from CAL_DAC_IO during internal mode only
													1 = Connects CAL_DAC_IO to test tone during internal mode. */
#define ADAS1000_TESTTONE_TONEN		(1ul << 0)	/*	Enables an internal test tone to drive entire signal chain, from 
													pre-amp to SPI interface. This tone comes from the CAL DAC and goes
													to the pre-amps through the internal mux. When TONEN (CALDAC) is 
													enabled, AC Leads off is disabled.
													0 = Disable the test tone
													1  = Enable the CALDAC 1mV SineWave test tone (Cal Mode has priority) */

#define ADAS1000_TESTTONE_TONTYPE_MASK (0x00000003ul << 3)
													
/******************************************************************************/
/* Calibration DAC Register													  */
/******************************************************************************/
#define ADAS1000_CALDAC_CALCHPEN	(1ul << 13)	/*	Calibration Chop Clock Enable. The CALDAC output can be chopped to
													lower 1/f noise. Chopping is done at 256kHz. 
														0 = Disabled
														1  = Enabled. */
#define ADAS1000_CALDAC_CALMODEEN	(1ul << 12)	/*	Calibration Mode Enable
														0 = Disable Calibration mode
														1 = Enable Calibration mode ?connect CAL DAC_IO, 
															begin data acquisition on ECG channels. */
#define ADAS1000_CALDAC_CALINT		(1ul << 11)	/*	Calibration Internal or External
														0 = External Cal ?calibration to be performed externally by
															looping CAL_DAC_IO around into ECG channels. 
														1 = Internal Cal ?disconnects external switches for all ECG 
															channels and connects CALDAC internally to all ECG channels. */
#define ADAS1000_CALDAC_CALDACEN	(1ul << 10)	/*	Enable 10-bit calibration DAC for cal mode or external use. 
														0 = Disable CALDAC
														1 = Enable CALDAC, if a master device and not in calibration 
															mode then also connects CAL_DAC out to its_IO pin for 
															external use, if in Slave mode, the CALDAC will disable to
															allow master to drive CAL_DAC_IO pin. When CALDAC is enabled, 
															AC Leads off is disabled. */
#define ADAS1000_CALDAC_CALDATA		(1ul << 0)	/*	Set the CAL DAC value 	*/

#define ADAS1000_CALDAC_CALDATA_MASK (0x000003FFul << 0)

/******************************************************************************/
/* Frame Control Register 													  */
/******************************************************************************/
#define ADAS1000_FRMCTL_LEAD_I_LADIS	(1ul << 23)	/*	Include/Exclude word from ECG data frame, if electrode/lead is	*/
#define ADAS1000_FRMCTL_LEAD_II_LLDIS	(1ul << 22)	/*	included in the data word and the electrode falls off, then the */
#define ADAS1000_FRMCTL_LEAD_III_RADIS	(1ul << 21)	/*	data word will be undefined. 									*/
#define ADAS1000_FRMCTL_V1DIS			(1ul << 20)	/*		0 = Included in Frame										*/
#define ADAS1000_FRMCTL_V2DIS			(1ul << 19)	/*		1 = Exclude from Frame 										*/
#define ADAS1000_FRMCTL_PACEDIS			(1ul << 14)	/*	Include/Exclude word from ECG data frame
															0 = Included in Frame
															1 = Exclude from Frame	*/
#define ADAS1000_FRMCTL_RESPMDIS		(1ul << 13)	/*	Respiration Magnitude
															0 = Included in Frame
															1 = Exclude from Frame */
#define ADAS1000_FRMCTL_RESPPHDIS		(1ul << 12)	/*	Respiration Phase
															0 = Included in Frame
															1 = Exclude from Frame */
#define ADAS1000_FRMCTL_LOFFDIS			(1ul << 11)	/*	Leads Off Status
															0 = Included in Frame
															1 = Exclude from Frame */
#define ADAS1000_FRMCTL_GPIODIS			(1ul << 10)	/*	GPIO Word disable
															0 = Included in Frame
															1 = Exclude from Frame	*/
#define ADAS1000_FRMCTL_CRCDIS			(1ul << 9)	/*	CRC  Word disable
															0 = Included in Frame
															1 = Exclude from Frame */
#define ADAS1000_FRMCTL_SIGNEDEN		(1ul << 8)	/*	In a master device configured for Lead Mode, the ECG data will
														be signed. When in slave mode (electrode format), the ECG data 
														format is unsigned. Use this bit when using multiple devices to 
														make the slave device signed data. 
															0 = unsigned data (default)
															1 = signed data */
#define ADAS1000_FRMCTL_ADIS			(1ul << 7)	/*	Automatically disable PACE, RESP, LOFF words if their flags are
														not set in the header.
															0 = fixed frame format
															1 = auto disable words */
#define ADAS1000_FRMCTL_RDYRPT			(1ul << 6)	/*	Ready Repeat ?if this bit is set and the frame header indicates
														data is not ready, the frame header is continuously sent until 
														data is ready. 
															0 = always send entire frame
															1 = repeat frame header until ready */
#define ADAS1000_FRMCTL_DATAFMT			(1ul << 4)	/*	Sets the Output Data Format
															0 = Lead/Vector Format 
																(only available in 2kHz & 16kHz data rates)
															1  = Electrode Format */
#define ADAS1000_FRMCTL_SKIP			(1ul << 2)	/*	Skip interval ?this field provides a way to decimate the data
															00 = output every frame
															01 = output every other frame
															1x = output every 4th frame */
#define ADAS1000_FRMCTL_FRMRATE_2KHZ	0x00		/*	Sets the Output Data Rate to 2 kHz */
#define ADAS1000_FRMCTL_FRMRATE_16KHZ	0x01		/*	Sets the Output Data Rate to 16 kHz */
#define ADAS1000_FRMCTL_FRMRATE_128KHZ	0x10		/*	Sets the Output Data Rate to 128 kHz */
#define ADAS1000_FRMCTL_FRMRATE_31_25HZ	0x11		/*	Sets the Output Data Rate to 31.25 Hz */

#define ADAS1000_FRMCTL_WORD_MASK	(ADAS1000_FRMCTL_LEAD_I_LADIS 	| \
									 ADAS1000_FRMCTL_LEAD_II_LLDIS 	| \
									 ADAS1000_FRMCTL_LEAD_III_RADIS | \
									 ADAS1000_FRMCTL_V1DIS 			| \
									 ADAS1000_FRMCTL_V2DIS 			| \
									 ADAS1000_FRMCTL_PACEDIS 		| \
									 ADAS1000_FRMCTL_RESPMDIS 		| \
									 ADAS1000_FRMCTL_RESPPHDIS		| \
									 ADAS1000_FRMCTL_LOFFDIS 		| \
									 ADAS1000_FRMCTL_GPIODIS 		| \
									 ADAS1000_FRMCTL_CRCDIS)
#define ADAS1000_FRMCTL_SKIP_MASK		(0x00000003ul << 2)
#define ADAS1000_FRMCTL_FRMRATE_MASK	(0x00000003ul << 0)

/******************************************************************************/
/* Filter Control Register 													  */
/******************************************************************************/
#define ADAS1000_FILTCTL_MN2K	(1ul << 5)	/*	2kHz notch bypass for SPI Master
													0 = notch filter bypassed
													1 = notch filter present */
#define ADAS1000_FILTCTL_N2KBP	(1ul << 4)	/*	2kHz notch bypass
													0 = notch filter present
													1 = notch filter bypassed */
#define ADAS1000_FILTCTL_LPF	(1ul << 2)	/*	00 = 40Hz
												01 = 150Hz
												10 = 250 Hz
												11 = 450Hz */

#define ADAS1000_FILTCTL_LPF_MASK	(0x00000003ul << 2)

/******************************************************************************/
/* Leads off Upper Threshold Register										  */
/******************************************************************************/
#define ADAS1000_LOFFUTH_ADCOVER	(1ul << 16)	/*	ADC over range threshold. An ADC out-of-range error will be flagged
													if the ADC output is greater than the over range threshold. 
													The over range threshold is offset from the maximum value.
													Threshold = max_value ?ADCOVER*2^6
														0000 = max value (disabled)
														0001 = max_value ?64
														0010 = max_value ?128
														...
														1111: max_value ?960 */
#define ADAS1000_LOFFUTH_LOFFUTH	(1ul << 0)	/*	AC Leads off upper Threshold. Leads off will be detected if the DC
													or AC output is = N * 2 * VREF/GAIN/2^16. 0 = 0V */

#define ADAS1000_LOFFUTH_ADCOVER_MASK	(0x0000000Ful << 16)
#define ADAS1000_LOFFUTH_LOFFUTH_MASK	(0x0000FFFFul << 0)

/******************************************************************************/
/* Leads off Lower Threshold Register										  */
/******************************************************************************/
#define ADAS1000_LOFFLTH_ADCUNDR	(1ul << 16)	/*	ADC under range threshold. An ADC out-of-range error will be flagged 
													if the ADC output is less than the under range threshold. 
													Threshold = min_value + ADCUNDR?^6
														0000 = min value (disabled)
														0001 = min_value + 64
														0010 = min _value + 128
														...
														1111: min _value + 960 */
#define ADAS1000_LOFFLTH_LOFFLTH	(1ul << 0)	/*	AC Leads off lower Threshold. Leads off will be detected if the DC 
													or AC output is = N * 2 * VREF/GAIN/2^16. 0 = 0V */

#define ADAS1000_LOFFLTH_ADCUNDR_MASK	(0x0000000Ful << 16)
#define ADAS1000_LOFFLTH_LOFFLTH_MASK	(0x0000FFFFul << 0)

/******************************************************************************/
/* Pace Edge Threshold Register												  */
/******************************************************************************/
#define ADAS1000_PACEEDGETH_PACE3EDGTH	(1ul << 16)	/*	Pace edge trigger threshold	*/
#define ADAS1000_PACEEDGETH_PACE2EDGTH	(1ul << 8)	/*		0 = PACEAMPTH/2			*/
#define ADAS1000_PACEEDGETH_PACE1EDGTH	(1ul << 0)	/*		1 = VREF/GAIN/2^16		*/
													/*		N = N * VREF/GAIN/2^16	*/

#define ADAS1000_PACEEDGETH_PACE3EDGTH_MASK	(0x000000FFul << 16)
#define ADAS1000_PACEEDGETH_PACE2EDGTH_MASK	(0x000000FFul << 8)
#define ADAS1000_PACEEDGETH_PACE1EDGTH_MASK	(0x000000FFul << 0)													
													
/******************************************************************************/
/* Pace Level Threshold Register											  */
/******************************************************************************/
#define ADAS1000_PACELVLTH_PACE3LVLTH	(1ul << 16)	/*	Pace level threshold. This is a signed value.	*/
#define ADAS1000_PACELVLTH_PACE2LVLTH	(1ul << 8)	/*		-1 = 0xFFF = -VREF/GAIN/2^16				*/
#define ADAS1000_PACELVLTH_PACE1LVLTH	(1ul << 0)	/*		 0 = 0x0000 = 0V							*/
													/*		+1 = 0x001 = +VREF/GAIN/2^16				*/
													/*		 N = N * VREF/GAIN/2^16						*/

#define ADAS1000_PACELVLTH_PACE3LVLTH_MASK	(0x000000FFul << 16)
#define ADAS1000_PACELVLTH_PACE2LVLTH_MASK	(0x000000FFul << 8)
#define ADAS1000_PACELVLTH_PACE1LVLTH_MASK	(0x000000FFul << 0)													

/***********************************************************************************/
/* LA or LEAD I, LL or LEAD II, RA or LEAD III, V1 or V1? V2 or V2?Data Register */
/***********************************************************************************/
 #define ADAS1000_LADATA_ADDRESS		(1ul << 24)	/* 	0x11 : LA or LEAD I
													0x12 : LL or LEAD II
													0x13 : RA or LEAD II
													0x14 : V1 or V1?
													0x15 : V2 or V2?*/
#define ADAS1000_LADATA_ECG_DATA	(1ul << 0)	/*	Channel Data Value. Data left justified (MSB) irrespective of data
													rate. In electrode format, the value is an unsigned integer. 
													In Vector format, the value is a signed 2抯 complement integer format. 
													Vector format had 2x range compared to electrode format since it can 
													swing from +VREF to 朧REF, therefore the LSB size is double. 
													Electrode Format
														Min value (000...) = 0V
														Max value (1111...) = VREF/GAIN
														LSB = (VREF/GAIN)/2N
													Lead/Vector Format
														Min value (1000...) = -(VREF/GAIN)
														Max value (0111...) = +VREF/GAIN
														LSB = 2?VREF/GAIN)/2N
													Where N = # of data bits, 16 for 128kHz data rate or 24 for 
													2kHz/16kHz data rate. */

#define ADAS1000_LADATA_ADDRESS_MASK	(0x000000FFul << 24)
#define ADAS1000_LADATA_ECG_DATA_MASK	(0x00FFFFFFul << 0)

/******************************************************************************/
/* Read Pace Detection Data Register										  */
/******************************************************************************/
#define ADAS1000_PACEDATA_ADDRESS			(1ul << 24)	/*	0001 1010 = Pace Detection 	*/
#define ADAS1000_PACEDATA_PACE3_DETECTED	(1ul << 23)	/*	Pace 3 detected. This bit will be set once a pace pulse is
															detected. This bit is set on the trailing edge of the pace pulse. 
																0 = Pace pulse not detected in current frame
																1 = Pace pulse detected in this frame */
#define ADAS1000_PACEDATA_PACE_CH3_WIDTH	(1ul << 20)	/*	This is log2(Width)-1 of the pace pulse. 
															N: Width = 2^(N+1) / 128kHz */
#define ADAS1000_PACEDATA_PACE_CH3_HEIGHT	(1ul << 16)	/*	This is the log2(height) of the pace pulse
															N: height = 2^N * VREF / GAIN / 2^16 */
#define ADAS1000_PACEDATA_PACE2_DETECTED	(1ul << 15)	/*	Pace 2 detected. This bit will be set once a pace pulse is 
															detected. This bit is set on the trailing edge of the pace pulse. 
															   0 = Pace pulse not detected in current frame
															   1 = Pace pulse detected in this frame*/
#define ADAS1000_PACEDATA_PACE_CH2_WIDTH	(1ul << 12)	/*	This is log2(Width)-1 of the pace pulse. 
															N: Width = 2^(N+1) / 128kHz */
#define ADAS1000_PACEDATA_PACE_CH2_HEIGHT	(1ul << 8)	/*	This is the log2(height) of the pace pulse
															N: height = 2^N * VREF / GAIN / 2^16 */
#define ADAS1000_PACEDATA_PACE1_DETECTED	(1ul << 7)	/*	Pace 1 detected. This bit will be set once a pace pulse is 
															detected. This bit is set on the trailing edge of the pace pulse. 
															   0 = Pace pulse not detected in current frame
															   1 = Pace pulse detected in this frame */
#define ADAS1000_PACEDATA_PACE_CH1_WIDTH	(1ul << 4)	/*	"This is log2(Width)-1 of the pace pulse. 
															N: Width = 2^(N+1) / 128kHz */
#define ADAS1000_PACEDATA_CH1_HEIGHT		(1ul << 0)	/*	This is the log2(height) of the pace pulse
															N: height = 2^N * VREF / GAIN / 2^16 */

#define ADAS1000_PACEDATA_ADDRESS_MASK			(0x000000FFul << 24)
#define ADAS1000_PACEDATA_PACE_CH3_WIDTH_MASK	(0x00000007ul << 20)
#define ADAS1000_PACEDATA_PACE_CH3_HEIGHT_MASK	(0x0000000Ful << 16)
#define ADAS1000_PACEDATA_PACE_CH2_WIDTH_MASK	(0x00000007ul << 12)
#define ADAS1000_PACEDATA_PACE_CH2_HEIGHT_MASK	(0x0000000Ful << 8)
#define ADAS1000_PACEDATA_PACE_CH1_WIDTH_MASK	(0x00000007ul << 4)
#define ADAS1000_PACEDATA_PACE_CH1_HEIGHT_MASK	(0x0000000Ful << 0)

/******************************************************************************/
/* Read Respiration Data Magnitude Register									  */
/******************************************************************************/
#define ADAS1000_RESPMAG_ADDRESS	(1ul << 24)	/*	0001 1011 = Respiration Magnitude */
#define ADAS1000_RESPMAG_MAGNITUDE	(1ul << 0)	/*	Magnitude of respiration signal. This is an unsigned value. */

#define ADAS1000_RESPMAG_ADDRESS_MASK	(0x000000FFul << 24)
#define ADAS1000_RESPMAG_MAGNITUDE_MASK	(0x00FFFFFFul << 0)

/******************************************************************************/
/* Read Respiration Data Phase Register										  */
/******************************************************************************/
#define ADAS1000_RESPPH_ADDRESS	(1ul << 24)	/*	0001 1100 = Respiration Phase */
#define ADAS1000_RESPPH_PHASE	(1ul << 0)	/*	Phase of respiration signal. Can be interpreted as either signed or 
												unsigned value. If unsigned, the range is from 0 to 2pi. If as a 
												signed value, the range is from 杙i to +pi.
													0x000000 = 0
													0x000001 = 2pi / 2^24
													0x400000 = pi/2
													0x800000 = +pi = -pi 
													0xC00000 = +3pi/2 = -pi/2
													0xFFFFFF = +2pi(1 - 2^(-24)) = -2p / 2^24 */

#define ADAS1000_RESPPH_ADDRESS_MASK	(0x000000FFul << 24)
#define ADAS1000_RESPPH_PHASE_MASK		(0x00FFFFFFul << 0)

/******************************************************************************/
/* Leads Off Status Register												  */
/******************************************************************************/
#define ADAS1000_LOFF_ADDRESS				(1ul << 24)	/*	Address bits define the word data 0001 1101 = Leads Off			*/
#define ADAS1000_LOFF_RL_LEADS_OFF_STATUS	(1ul << 23)	/*	Electrode Connection Status. If either DC or AC leads off		*/
#define ADAS1000_LOFF_LA_LEADS_OFF_STATUS	(1ul << 22)	/*	is enabled, these bits are the corresponding leads off status.	*/
#define ADAS1000_LOFF_LL_LEADS_OFF_STATUS	(1ul << 21)	/*	If both DC and AC leads off are enabled, these bits reflect 	*/
#define ADAS1000_LOFF_RA_LEADS_OFF_STATUS	(1ul << 20)	/*	only the AC leads off status. DC leads off is available in 		*/
#define ADAS1000_LOFF_V1_LEADS_OFF_STATUS	(1ul << 19)	/*	the DCLEADSOFF register. The common electrodes only have DC 	*/
#define ADAS1000_LOFF_V2_LEADS_OFF_STATUS	(1ul << 18)	/*	leads off detection. An AC leads off signal can be injected 	*/
#define ADAS1000_LOFF_CELO					(1ul << 13)	/*	into the common electrode, but there is no ADC input to measure	*/
														/*	its amplitude. If the common electrode is off, it will affect 	*/
														/*	the AC leads off amplitude of the other electrodes. These bits 	*/
														/*	accumulate in the frame buffer and are cleared when the frame 	*/
														/*	buffer is loaded into the SPI buffer. 							*/
														/*	   0 = Electrode is connected									*/
														/*	   1 = Electrode is disconnected								*/
#define ADAS1000_LOFF_LAADCOR				(1ul << 12)	/*	ADC out of range error.											*/
#define ADAS1000_LOFF_LLADCOR				(1ul << 11)	/*	These status bits indicate the resulting ADC code is out of 	*/
#define ADAS1000_LOFF_RAADCOR				(1ul << 10)	/*	range. These bits accumulate in the frame buffer and are 		*/
#define ADAS1000_LOFF_V1ADCOR				(1ul << 9)	/*	cleared when the frame buffer is loaded into the SPI buffer. 	*/
#define ADAS1000_LOFF_V2ADCOR				(1ul << 8)

#define ADAS1000_LOFF_ADDRESS_MASK			(0x000000FFul << 24)

/******************************************************************************/
/* DC Leads off Register 													  */
/******************************************************************************/
#define ADAS1000_DCLEADSOFF_ADDRESS				(1ul << 24)	/*	Address bits define the word data 0001 1110 = DC Leads Off	  */
#define ADAS1000_DCLEADSOFF_RL_INPUT_OVERRANGE	(1ul << 23)	/*	The DC leads off detection is comparator based and compares	  */
#define ADAS1000_DCLEADSOFF_LA_INPUT_OVERRANGE	(1ul << 22)	/*	to a fixed level. Per electrode bits flag if the DC leads off */
#define ADAS1000_DCLEADSOFF_LL_INPUT_OVERRANGE	(1ul << 21)	/*	comparator threshold level has been exceeded.				  */
#define ADAS1000_DCLEADSOFF_RA_INPUT_OVERRANGE	(1ul << 20)	/*	   0 = electrode < overrange threshold, 2.4 V				  */
#define ADAS1000_DCLEADSOFF_CE_INPUT_OVERRANGE	(1ul << 13)	/*	   1 = electrode > overrange threshold, 2.4 V				  */

#define ADAS1000_DCLEADSOFF_RL_INPUT_UNDERRANGE	(1ul << 12)	/*	The DC leads off detection is comparator based and compares	  */
#define ADAS1000_DCLEADSOFF_LA_INPUT_UNDERRANGE	(1ul << 11)	/*	to a fixed level. Per electrode bits flag if the DC leads off */
#define ADAS1000_DCLEADSOFF_LL_INPUT_UNDERRANGE	(1ul << 10)	/*	comparator threshold level has been exceeded.   			  */
#define ADAS1000_DCLEADSOFF_RA_INPUT_UNDERRANGE	(1ul << 9)	/*		0 = electrode > underrange threshold, 0.2 V			  	  */
#define ADAS1000_DCLEADSOFF_CE_INPUT_UNDERRANGE	(1ul << 2)	/*	   	1 = electrode < underrange threshold, 0.2 V				  */

#define ADAS1000_DCLEADSOFF_ADDRESS_MASK		(0x000000FFul << 24)

/******************************************************************************/
/* Extended Switch for Respiration Inputs Register							  */
/******************************************************************************/
#define ADAS1000_EXTENDSW_EXTRESP_RA_LA		(1ul << 23)	/* 	External Respiration electrode input switch to channel 	*/
#define ADAS1000_EXTENDSW_EXTRESP_RA_LL		(1ul << 22)	/*	electrode input.										*/
#define ADAS1000_EXTENDSW_EXTRESP_RA_RA		(1ul << 21)	/*		0 = switch open										*/
#define ADAS1000_EXTENDSW_EXTRESP_RA_V1		(1ul << 20)	/*		1 = switch closed									*/
#define ADAS1000_EXTENDSW_EXTRESP_RA_V2		(1ul << 19)
#define ADAS1000_EXTENDSW_EXTRESP_LL_LA		(1ul << 18)
#define ADAS1000_EXTENDSW_EXTRESP_LL_LL		(1ul << 17)
#define ADAS1000_EXTENDSW_EXTRESP_LL_RA		(1ul << 16)
#define ADAS1000_EXTENDSW_EXTRESP_LL_V1		(1ul << 15)
#define ADAS1000_EXTENDSW_EXTRESP_LL_V2		(1ul << 14)
#define ADAS1000_EXTENDSW_EXTRESP_LA_LA		(1ul << 13)
#define ADAS1000_EXTENDSW_EXTRESP_LA_LL		(1ul << 12)
#define ADAS1000_EXTENDSW_EXTRESP_LA_RA		(1ul << 11)
#define ADAS1000_EXTENDSW_EXTRESP_LA_V1		(1ul << 10)
#define ADAS1000_EXTENDSW_EXTRESP_LA_V2		(1ul << 9)

#define ADAS1000_EXTENDSW_FREE_V1			(1ul << 8)	/*	V1 and V2 electrodes may be used for measurement purposes 		*/
#define ADAS1000_EXTENDSW_FREE_V2			(1ul << 7)	/*	other than ECG. To 	achieve this, they need to be disconnected  */
														/*	from the patient VCM voltage provided from the internal common 	*/
														/*	mode buffer and instead connected to the internal VCM_REF level */
														/*	of 1.3V. Set FREE_Vx bits high to connect negative input of V1 	*/
														/* 	channel will be tied to internal VCM_REF level. This allows user*/ 
														/*	to make alternative measurements on V1 channel relative to the	*/ 
														/*	VCM_REF level. If using Digital lead mode, uses these bits in 	*/
														/*	conjunction with NO_MATH_Vx bits [6:5].							*/

#define ADAS1000_EXTENDSW_NOMATH_V1			(1ul << 6)	/*	In Digital Lead Mode, the digital core calculates the math on V1 */
#define ADAS1000_EXTENDSW_NOMATH_V2			(1ul << 5)	/*	and V2 with respect to WCT (LA+LL+RA)/3 providing V1?and V2? 	 */
														/*	Where V1 or V2 are used for measurement of something other than	 */ 
														/*	ECG, then the math calculation needs to be disabled. These bits	 */ 
														/*	are most likely used in conjunction with bits FREE_Vx [8:7].	 */
														/*	Set NOMATH_Vx bits high to disable the math calculation in V1	 */ 
														/*	and V2 respectively. 											 */

/******************************************************************************/
/* User gain calibration LA, LL, RA, V1, V2	Register						  */
/******************************************************************************/
#define	ADAS1000_CAL_ADDRESS	(1ul << 24)	/*	0x21 : CAL LA
												0x22 : CAL LL
												0x23 : CAL RA
												0x24 : CAL V1
												0x25 : CAL V2 */
#define	ADAS1000_CAL_USRCAL		(1ul << 23)	/*	User can choose between:
													0 = default calibration values
													1 = user calibration values */
#define	ADAS1000_CAL_CALVALUE	(1ul << 0)	/*	Gain Calibration value. 
												Result = data * (1 + GAIN * 2^(-17))
												The value read from this register is the current gain calibration value.
												If the USRCAL bit is clear, this register returns the default value for 
												the current gain setting. 
													0x7FF (+2047) = *1.00000011111111111b
													0x001 (+1) 	  = *1.00000000000000001b
													0x000 (0)     = *1.00000000000000000b
													0xFFF (-1)    = *0.11111111111111111b
													0x800 (-2048) = *0.11111100000000000b */

#define	ADAS1000_CAL_ADDRESS_MASK	(0x000000FFul << 24)
#define	ADAS1000_CAL_CALVALUE_MASK	(0x00000FFFul << 0)

/******************************************************************************/
/* Leads off Amplitude for LA, LL, RA, V1, V2 Register						  */
/******************************************************************************/
#define	ADAS1000_LOAM_ADDRESS	(1ul << 24)	/*	0x31 : LA AC Leads off Magnitude
												0x32 : LL AC Leads off Magnitude
												0x33 : RA AC Leads off Magnitude
												0x34 : V1 AC Leads off Magnitude
												0x35 : V2 AC Leads off Magnitude */
#define	ADAS1000_LOAM_LOFFAM	(1ul << 0)	/*	Measured Amplitude.
												When AC leads off is selected, the data is the average of the rectified
												2kHz bandpass filter with an update rate of 8Hz and cutoff frequency at 
												2Hz. The output is the amplitude of the 2kHz signal scaled by 2/pi 
												approximately = 0.6 (average of rectified sine wave). To convert to RMS, 
												scale the output by pi / (2*sqrt(2)). 
												Leads off (unsigned):
													Min 0x0000 = 0V
													LSB 0x0001= VREF / GAIN / 2^16
													Max 0xFFFF = VREF / GAIN */

#define	ADAS1000_LOAM_ADDRESS_MASK	(0x000000FFul << 24)
#define	ADAS1000_LOAM_LOFFAM_MASK	(0x0000FFFFul << 0)


/******************************************************************************/
/* Pace1, Pace2, Pace3 Width & Amplitude2 Register							  */
/******************************************************************************/
#define	ADAS1000_PACE_DATA_ADDRESS	(1ul << 24)	/*	0x3A : PACE1DATA
													0x3B : PACE2DATA
													0x3C : PACE3DATA */
#define	ADAS1000_PACE_DATA_HEIGHT	(1ul << 8)	/*	Measured pace height in signed 2抯 complement value
														0 = 0 
														1 = VREF / GAIN / 2^16
														N = N * VREF / GAIN / 2^16 */
#define	ADAS1000_PACE_DATA_WIDTH	(1ul << 0)	/*	Measured pace width in 128kHz samples
														N:   N / 128kHz   = width
														12:  12 / 128kHz  = 93us
														255: 255 / 128kHz = 2.0ms */

#define	ADAS1000_PACE_DATA_ADDRESS_MASK	(0x000000FFul << 24)
#define	ADAS1000_PACE_DATA_HEIGHT_MASK	(0x0000FFFFul << 8)
#define	ADAS1000_PACE_DATA_WIDTH_MASK	(0x000000FFul << 0)

/******************************************************************************/
/* Frame Header - Read Data Frames Register									  */
/******************************************************************************/
#define ADAS1000_FRAMES_MARKER					(1ul << 31)	/*	Header marker, set to ??for the header */
#define ADAS1000_FRAMES_READY_BIT				(1ul << 30)	/*	Ready bit indicates if ECG frame data is calculated and
																ready for reading. 
																   0 = Ready, data frame follows
																   1 = Busy	*/
#define ADAS1000_FRAMES_OVERFLOW				(1ul << 28)	/*	Overflow bits indicate that since the last frame read, 
																a number of frames have been missed. This field saturates
																at the maximum count. The data in the frame including 
																this header word is valid but old if the overflow bits 
																are > 0. When using Skip mode (FRMCTL register (0x0A)[3:2]), 
																the Overflow bit acts as a flag, where a non-zero value 
																indicates an overflow. 
																	00 = 0 missed
																	01 = 1 frame missed
																	10 = 2 frames missed
																	11 = 3 or more frames missed	*/
#define ADAS1000_FRAMES_FAULT					(1ul << 27)	/*	Internal device error detected.
																	0 = normal operation
																	1 = error condition	*/
#define ADAS1000_FRAMES_PACE3_DETECTED			(1ul << 26)	/*	PACE 3 Indicates Pacing Artifact was qualified at most 
																recent point.
																	0 = No Pacing Artifact
																	1 = Pacing Artifact Present	*/
#define ADAS1000_FRAMES_PACE2_DETECTED			(1ul << 25)	/*	PACE 2 Indicates Pacing Artifact was qualified at most 
																recent point.
																	0 = No Pacing Artifact
																	1 = Pacing Artifact Present	*/
#define ADAS1000_FRAMES_PACE1_DETECTED			(1ul << 24)	/*	PACE 1 Indicates Pacing Artifact was qualified at most 
																recent point.
																	0 = No Pacing Artifact
																	1 = Pacing Artifact Present	*/
#define ADAS1000_FRAMES_RESPIRATION				(1ul << 23)	/*	0 = no new respiration data
																1 = respiration data updated */
#define ADAS1000_FRAMES_LEADS_OFF_DETECTED		(1ul << 22)	/*	If both DC & AC leads off are enabled, this bit is the 
																OR of all the AC leads off detect flags. If only AC or 
																DC leads off is enabled (but not both, this bit reflects 
																the OR of all DC & AC leads off flags.
																	0 = all leads connected
																	1 = one or more leads off detected	*/
#define ADAS1000_FRAMES_DC_LEADS_OFF_DETECTED	(1ul << 21)	/*	0 = all leads connected
																1 = one or more leads off detected	*/
#define ADAS1000_FRAMES_ADC_OUT_OF_RANGE		(1ul << 20)	/*	0 = ADC within range
																1 = ADC out of range */

/******************************************************************************/
/* Frame CRC Register														  */
/******************************************************************************/
#define ADAS1000_CRC_MASK	(0x00FFFFFF << 0)	/*	Cyclic Redundancy Check */

/******************************************************************************/
/* ADAS1000 data rates, word sizes and frame sizes							  */
/******************************************************************************/
#define ADAS1000_31_25HZ_FRAME_RATE	3125
#define ADAS1000_2KHZ_FRAME_RATE	2000
#define ADAS1000_16KHZ_FRAME_RATE	16000
#define ADAS1000_128KHZ_FRAME_RATE	128000

#define ADAS1000_31_25HZ_WORD_SIZE	32
#define ADAS1000_2KHZ_WORD_SIZE		32
#define ADAS1000_16KHZ_WORD_SIZE	32
#define ADAS1000_128KHZ_WORD_SIZE	16

#define ADAS1000_31_25HZ_FRAME_SIZE 12
#define ADAS1000_2KHZ_FRAME_SIZE	12
#define ADAS1000_16KHZ_FRAME_SIZE	12
#define ADAS1000_128KHZ_FRAME_SIZE	15

/******************************************************************************/
/* ADAS1000 CRC constants													  */
/******************************************************************************/
//#define CRC_POLY_2KHZ_16KHZ			0x005D6DCBul
//#define CRC_CHECK_CONST_2KHZ_16KHZ	0x0015A0BAul

//#define CRC_POLY_128KHZ				0x00001021ul
//#define CRC_CHECK_CONST_128KHz		0x00001D0Ful

#define CRC_POLY_2KHZ_16KHZ				0x015D6DCB
#define CRC_POLY_128KHZ				    0x00011021
#define CRC_CHECK_CONST_2KHZ_16KHZ	    0x0015A0BA
#define CRC_CHECK_CONST_128KHz	        0x00001D0F

/******************************************************************************/
/* Functions Prototypes                                                       */
/******************************************************************************/
/* Initializes the communication with ADAS1000 and checks if the device is present.*/
extern bool ADAS1000_StartMea();

extern bool ADAS1000_StopMea();

/* Reads the value of a ADAS1000 register */
extern void ADAS1000_GetRegisterValue(unsigned char regAddress, unsigned long* regVal);

/* Writes a value into a ADAS1000 register */
extern void ADAS1000_SetRegisterValue(unsigned char regAddress, unsigned long regVal);

/* Performs a software reset of the ADAS1000 */
extern void ADAS1000_SoftwareReset(void);

extern void ADAS1000_HardwareReset(void);

/* Selects which words are not included in a data frame */
extern void ADAS1000_SetInactiveFrameWords(unsigned long wordsMask);

extern bool ADAS1000TestFirstComm();
/* Sets the frame rate */
extern bool ADAS1000_SetFrameRate(unsigned long rate, unsigned char skip);

extern bool ADAS1000_ReadHeader();

extern bool ADAS1000_ReadDataOne(unsigned char* pDataBuffer, int len);

/* Reads the specified number of frames */
extern void ADAS1000_ReadData(unsigned char* pDataBuffer, unsigned long frameCnt,
								unsigned char startRead, unsigned char stopRead,
								unsigned char waitForReady, unsigned char readyRepeat);
								
/* Computes the CRC for a frame */
extern unsigned long ADAS1000_ComputeFrameCrc(unsigned char *pBuf, int len);
extern bool CheckADAS1000CRC16(unsigned char * Buffer,unsigned int BufSizeBytes);

#endif /* _ADAS1000_H_ */
#ifndef _ADAS1000_PORT_H
#define _ADAS1000_PORT_H

#include "common.h"
#include "dio.h"
#include "delay.h"
#include "spi_adas1021.h"


extern bool ADAS1000_Write(unsigned char *pSendBuffer,unsigned long length);
extern bool ADAS1000_Read(unsigned char *pRecvBuff,unsigned long length);
extern bool ADAS1000_ReadWriteNBytes(unsigned char *pSendBuffer,unsigned char *pRecvBuff,unsigned long length);

extern void ADAS1000_PDClr(void);
extern void ADAS1000_PDSet(void);

extern void ADAS1000_CsClr(void);
extern void ADAS1000_CsSet(void);

extern void ADAS1000_RstClr(void);
extern void ADAS1000_RstSet(void);

extern bool ADAS1000_DrdyGet(void);

extern void ADAS1000_Delay1us(uint32_t time);

extern uint32_t ADAS1000_MCUResourceInit(void);


#endif

The main control part collects the data of ADAS1000 and forwards the port. Here is the source code of the serial port part. The other parts are relatively easy to implement:

#include "uart4_dma.h"

int g_txFlag = 0;  //有数据发送
int g_rxFlag = 0;  //有数据接受
int g_rxLedNum = 10;  //短闪表示收到数据,30长闪表示数据通过CRC有效

static UART_HandleTypeDef m_UART4_Handler; //UART句柄

static DMA_HandleTypeDef  m_UART4TxDMA_Handler;      //DMA
static DMA_HandleTypeDef  m_UART4RxDMA_Handler;      //DMA


//数据缓冲区
static volatile u8 uart4_TxBuf[MAX_UART4_TX_BUFFER_SIZE] = {0};
static volatile u8 uart4_RxBuf[MAX_UART4_RX_BUFFER_SIZE] = {0};
//发送队列
static sRingBuffer uart4_TxQueue; 
//接收队列
static sRingBuffer uart4_RxQueue;   


static bool m_rx4FrameState = false;

//DMA缓冲
static volatile u8 m_dma_rx4_buff[UART4_DMA_RX_BUFF_LEN] = {0};
#if !UART4_BULK_TX
static volatile u8 m_dma_tx4_buff[UART4_DMA_TX_BUFF_LEN] = {0};
#endif


            


//初始化循环队列
static void Uart4_Init_Queue()
{
    InitQueue(&uart4_TxQueue, (void *)uart4_TxBuf, MAX_UART4_TX_BUFFER_SIZE);
    InitQueue(&uart4_RxQueue, (void *)uart4_RxBuf, MAX_UART4_RX_BUFFER_SIZE);

}
//循环队列中循环写入一个数据
static void Uart4_Write_Queue(sRingBuffer *pQueue,u8 inData)
{
    u8 *p = (u8 *)(pQueue->pData);
    *(p+pQueue->wCounter) = inData;
    WriteQueueLoopOffset(pQueue);
}

//循环队列循环写入批量数据
static void Uart4_Write_Queue_Bulk(sRingBuffer *pQueue,u8 *pData, int len)
{
    int space = 0;
    int rightSpace = 0;
    if (len > pQueue->maxLen)
    {
        return;
    }
    u8 *p = (u8 *)(pQueue->pData);
    //检查剩余空间,是否需要移动读指针
    space = CalcNumSpace(pQueue);
    if (len > space)
    {
        ReadQueueOffsetBulk(pQueue, len-space);
    }
    //检查右侧空间,是否需要分段复制
    rightSpace = pQueue->maxLen - pQueue->wCounter;
    if (len > rightSpace)
    {
        memcpy(p+pQueue->wCounter, pData, rightSpace);
        memcpy(p, pData+rightSpace, len-rightSpace);        
    }
    else
    {
        memcpy(p+pQueue->wCounter, pData, len);
    }
    WriteQueueOffsetBulk(pQueue, len);
    return;    
}

//从循环队列中读出一个数据
static bool Uart4_Read_Queue(sRingBuffer *pQueue, u8 *pOutData)
{
    u8 *p = (u8 *)(pQueue->pData);
    if (IsEmptyQueue(pQueue))
    {
        return false;
    }
    *pOutData = *(p+pQueue->rCounter);
    *(p+pQueue->rCounter) = 0;
    ReadQueueOffset(pQueue);
    return true;
}
//循环队列中读出批量数据
static int Uart4_Read_Queue_Bulk(sRingBuffer *pQueue, u8 **ppDataAddress)
{
    int len = 0;
    int rightSpace = 0;
    u8 *p = (u8 *)(pQueue->pData);
    if (IsEmptyQueue(pQueue))
    {
        return 0;
    }
    *ppDataAddress = p+pQueue->rCounter;
    rightSpace = pQueue->maxLen - pQueue->rCounter;
    if (rightSpace > pQueue->len)
    {
        len = pQueue->len;
    }
    else
    {
        len = rightSpace;
    }
    ReadQueueOffsetBulk(pQueue, len);
    return len;
}

void UART4_GPIO_Config()
{
    RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
    //GPIO端口设置
    GPIO_InitTypeDef GPIO_Initure;
    
    PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_UART4;
    PeriphClkInitStruct.Uart4ClockSelection = RCC_UART4CLKSOURCE_PCLK1;
    HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);

    __HAL_RCC_GPIOA_CLK_ENABLE();			//使能GPIOA时钟
    __HAL_RCC_UART4_CLK_ENABLE();	       //使能USART4时钟, APB1 54M

    GPIO_Initure.Pin=GPIO_PIN_11 | GPIO_PIN_12;			//RX:PA11 TX:PA12
    GPIO_Initure.Mode=GPIO_MODE_AF_PP;		//复用推挽输出
    GPIO_Initure.Pull=GPIO_NOPULL;			//上拉
    GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;		//高速
    GPIO_Initure.Alternate=GPIO_AF6_UART4;	//复用为USART4
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);	   	//初始化

}

static bool UART4_RX_DMA_Config()
{ 
    __HAL_RCC_DMA1_CLK_ENABLE();//	
    
    __HAL_LINKDMA(&m_UART4_Handler,hdmarx,m_UART4RxDMA_Handler);    //
    
    //Rx DMA配置
    m_UART4RxDMA_Handler.Instance=DMA1_Stream2;                            //数据流选择
    m_UART4RxDMA_Handler.Init.Channel=DMA_CHANNEL_4;                                //通道选择
    m_UART4RxDMA_Handler.Init.Direction=DMA_PERIPH_TO_MEMORY;             //内存到外设
    m_UART4RxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //外设非增量模式
    m_UART4RxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //内存增量模式
    m_UART4RxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;    //外设数据长度1byte
    m_UART4RxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;       //内存数据长度1byte
    m_UART4RxDMA_Handler.Init.Mode=DMA_NORMAL;                            //普通模式
    m_UART4RxDMA_Handler.Init.Priority=DMA_PRIORITY_VERY_HIGH;               //中等优先级
    m_UART4RxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;              //         
    m_UART4RxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;      //   
    m_UART4RxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;                 //内存单次突发传输
    m_UART4RxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;              //外设单次突发传输
    
    HAL_DMA_DeInit(&m_UART4RxDMA_Handler);   
    if (HAL_DMA_Init(&m_UART4RxDMA_Handler) != HAL_OK)
    {
      return false;
    }
    return true;
} 

static bool UART4_TX_DMA_Config()
{ 
    __HAL_RCC_DMA1_CLK_ENABLE();//	
    
    __HAL_LINKDMA(&m_UART4_Handler,hdmatx,m_UART4TxDMA_Handler);    //
    
    //Tx DMA配置
    m_UART4TxDMA_Handler.Instance=DMA1_Stream4;                            //数据流选择
    m_UART4TxDMA_Handler.Init.Channel=DMA_CHANNEL_4;                                //通道选择
    m_UART4TxDMA_Handler.Init.Direction=DMA_MEMORY_TO_PERIPH;             //内存到外设
    m_UART4TxDMA_Handler.Init.PeriphInc=DMA_PINC_DISABLE;                 //外设非增量模式
    m_UART4TxDMA_Handler.Init.MemInc=DMA_MINC_ENABLE;                     //内存增量模式
    m_UART4TxDMA_Handler.Init.PeriphDataAlignment=DMA_PDATAALIGN_BYTE;    //外设数据长度1byte
    m_UART4TxDMA_Handler.Init.MemDataAlignment=DMA_MDATAALIGN_BYTE;       //内存数据长度1byte
    m_UART4TxDMA_Handler.Init.Mode=DMA_NORMAL;                            //普通模式
    m_UART4TxDMA_Handler.Init.Priority=DMA_PRIORITY_MEDIUM;               //中等优先级
    m_UART4TxDMA_Handler.Init.FIFOMode=DMA_FIFOMODE_DISABLE;              //         
    m_UART4TxDMA_Handler.Init.FIFOThreshold=DMA_FIFO_THRESHOLD_FULL;      //   
    m_UART4TxDMA_Handler.Init.MemBurst=DMA_MBURST_SINGLE;                 //内存单次突发传输
    m_UART4TxDMA_Handler.Init.PeriphBurst=DMA_PBURST_SINGLE;              //外设单次突发传输
    
    HAL_DMA_DeInit(&m_UART4TxDMA_Handler);   
    if (HAL_DMA_Init(&m_UART4TxDMA_Handler) != HAL_OK)
    {
      return false;
    }
    return true;
} 


static bool UART4_Config(u32 baud)
{
    //UART 初始化设置
    m_UART4_Handler.Instance=UART4;			             //UART4
    m_UART4_Handler.Init.BaudRate=baud;				    //波特率
    m_UART4_Handler.Init.WordLength=UART_WORDLENGTH_8B;   //字长为8位数据格式
    m_UART4_Handler.Init.StopBits=UART_STOPBITS_1;	    //一个停止位
    m_UART4_Handler.Init.Parity=UART_PARITY_NONE;		    //无奇偶校验位
    m_UART4_Handler.Init.HwFlowCtl=UART_HWCONTROL_NONE;   //无硬件流控
    m_UART4_Handler.Init.Mode=UART_MODE_TX_RX;		    //收发模式
    m_UART4_Handler.Init.OverSampling = UART_OVERSAMPLING_16;
    m_UART4_Handler.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    m_UART4_Handler.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
    if (HAL_UART_Init(&m_UART4_Handler) != HAL_OK)
    {
        return false;
    }
    return true;
}

//初始化IO 串口1 
//baud:波特率
void uart4_init(u32 baud)
{	
    
    UART4_Config(baud);
    
    UART4_RX_DMA_Config();
    UART4_TX_DMA_Config();
    
    Uart4_Init_Queue();

    __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_IT_IDLE);
    __HAL_UART_ENABLE_IT(&m_UART4_Handler,UART_IT_IDLE); 
#if !UART4_RX_USE_DMA
    __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_IT_RXNE);
    __HAL_UART_ENABLE_IT(&m_UART4_Handler,UART_IT_RXNE);  
    HAL_UART_Receive_IT(&m_UART4_Handler, (u8 *)m_dma_rx4_buff, UART4_DMA_RX_BUFF_LEN);
#else   
    __HAL_DMA_CLEAR_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_TCIF1_5);
    __HAL_DMA_ENABLE_IT(&m_UART4RxDMA_Handler, DMA_IT_TC);    
    HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);				
    HAL_NVIC_SetPriority(DMA1_Stream2_IRQn,0,2);
    HAL_UART_Receive_DMA(&m_UART4_Handler, (u8 *)m_dma_rx4_buff, UART4_DMA_RX_BUFF_LEN); //开始接受
#endif
    __HAL_DMA_CLEAR_FLAG(&m_UART4TxDMA_Handler, DMA_FLAG_TCIF3_7);
    __HAL_DMA_ENABLE_IT(&m_UART4TxDMA_Handler, DMA_IT_TC);    
    HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);				
    HAL_NVIC_SetPriority(DMA1_Stream4_IRQn,0,3);			

    HAL_NVIC_EnableIRQ(UART4_IRQn);				//使能USART1中断通道
    HAL_NVIC_SetPriority(UART4_IRQn,0,1);			//抢占优先级,子优先级
}

//使能去使能串口1中断
void setUart4NVIC(bool flag)
{
    if (flag)
    {
        HAL_NVIC_EnableIRQ(UART4_IRQn);
    }
    else
    {
        HAL_NVIC_DisableIRQ(UART4_IRQn);
    }
}
//使能去使能DMA接受中断
void setDMATx4NVIC(bool flag)
{
    if (flag)
    {
        HAL_NVIC_EnableIRQ(DMA1_Stream4_IRQn);
    }
    else
    {
        HAL_NVIC_DisableIRQ(DMA1_Stream4_IRQn);
    }
}
//使能去使能DMA发送中断
void setDMARx4NVIC(bool flag)
{
    if (flag)
    {
        HAL_NVIC_EnableIRQ(DMA1_Stream2_IRQn);
    }
    else
    {
        HAL_NVIC_DisableIRQ(DMA1_Stream2_IRQn);
    }
}

//串口发送数据
void Uart4DMATx(u8 *pData, u32 len)
{
    g_txFlag = 1;
#if UART4_BULK_TX
    setDMATx4NVIC(false);  //关闭串口DMA发送中断
    Uart4_Write_Queue_Bulk(&uart4_TxQueue, pData, len);
    setDMATx4NVIC(true);
    u8 *pTx = NULL;
    int txLen = Uart4_Read_Queue_Bulk(&uart4_TxQueue, &pTx);
    if ((m_UART4_Handler.gState == HAL_UART_STATE_READY)
        && (m_UART4_Handler.hdmatx->State == HAL_DMA_STATE_READY))    //串口空闲,直接发送数据
    {
        HAL_UART_Transmit_DMA(&m_UART4_Handler, pTx, txLen);
    }
#else    
    int rLen = CalcNumNotRead(&uart4_TxQueue);
    if ((rLen == 0) && (m_UART4_Handler.gState == HAL_UART_STATE_READY)
        && (m_UART4_Handler.hdmatx->State == HAL_DMA_STATE_READY))    //缓存里没有要等待发送的数据,并且串口空闲,直接发送数据
    {
        memcpy((void *)m_dma_tx4_buff, pData, len);
        HAL_UART_Transmit_DMA(&m_UART4_Handler, (uint8_t *)m_dma_tx4_buff, len);
        return;
    }
    setDMATx4NVIC(false);  //关闭串口DMA发送中断
    for (int i=0;i<len;i++)
    {
        Uart4_Write_Queue(&uart4_TxQueue, pData);
    }
    setDMATx4NVIC(true);
#endif
}

//读取串口接受数据
int Uart4DMARxData(u8 *pData, int maxLen)
{
    int index = 0;
    while(index <= maxLen)
    {
        if (!Uart4_Read_Queue(&uart4_RxQueue, pData+index))
        {
            break;
        }
        index++;
    }
    return index;
}

bool getUart4RxFrameState()
{
    return m_rx4FrameState;
}

void setUart4RxFrameState(bool state)
{
    m_rx4FrameState = state;
}

//串口1中断服务程序
void UART4_IRQHandler(void)                	
{ 
    static u32 len = 0;
    if(__HAL_UART_GET_FLAG(&m_UART4_Handler,UART_FLAG_IDLE) != RESET)  //接收空闲中断
    {
        __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_CLEAR_IDLEF);
#if UART4_RX_USE_DMA                            
        m_UART4_Handler.RxState = HAL_UART_STATE_READY;
        HAL_DMA_Abort(m_UART4_Handler.hdmarx);
        //HAL_UART_RxDMAStop(&m_UART4_Handler);
        //SCB_InvalidateDCache(); //同步内存和dcache
        SCB_CleanInvalidateDCache_by_Addr((u32 *)m_dma_rx4_buff, (UART4_DMA_RX_BUFF_LEN/4));
        
        len = UART4_DMA_RX_BUFF_LEN - m_UART4_Handler.hdmarx->Instance->NDTR;
        if (len > 0)
        {
            for(int i=0;i<len;i++)
            {
                Uart4_Write_Queue(&uart4_RxQueue, m_dma_rx4_buff);     
            }
            m_rx4FrameState = true;         
        }
        //SCB_CleanDCache();
        HAL_UART_Receive_DMA(&m_UART4_Handler, (u8 *)m_dma_rx4_buff, UART4_DMA_RX_BUFF_LEN); //开始接受
#else
        if (len > 0)
        {
            for(int i=0;i<len;i++)
            {
                Uart4_Write_Queue(&uart4_RxQueue, m_dma_rx4_buff);     
            }
            m_rx4FrameState = true;   
            g_rxFlag = 1;
            g_rxLedNum = 10; 
        }
        len = 0;
#endif
        
    }
    else if (__HAL_UART_GET_FLAG(&m_UART4_Handler,UART_FLAG_RXNE) != RESET)
    {
#if !UART4_RX_USE_DMA
        __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_FLAG_RXNE);
        m_dma_rx4_buff[len++] = (u8)(m_UART4_Handler.Instance->RDR & (u8)m_UART4_Handler.Mask);
#endif        
    }
    else if (__HAL_UART_GET_FLAG(&m_UART4_Handler,UART_FLAG_ORE) != RESET) 
    {
        __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_FLAG_ORE);
    }
    else if (__HAL_UART_GET_FLAG(&m_UART4_Handler,UART_FLAG_NE) != RESET)
    {
        __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_FLAG_NE);
    }
    else if (__HAL_UART_GET_FLAG(&m_UART4_Handler,UART_FLAG_FE) != RESET)
    {
        __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_FLAG_FE);
    }
    else if (__HAL_UART_GET_FLAG(&m_UART4_Handler,UART_FLAG_PE) != RESET)
    {
        __HAL_UART_CLEAR_IT(&m_UART4_Handler,UART_FLAG_PE);
    }
    //HAL_UART_IRQHandler(&m_UART4_Handler);	

} 

//串口4DMA接受完成中断服务程序
void DMA1_Stream2_IRQHandler(void)
{
    if (__HAL_DMA_GET_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_TCIF2_6) != RESET) //接受中断,防止溢出
    {
        __HAL_DMA_CLEAR_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_TCIF2_6);
        for(int i=0;i<UART4_DMA_RX_BUFF_LEN;i++)
        {
            Uart4_Write_Queue(&uart4_RxQueue, m_dma_rx4_buff);     
        }
        HAL_DMA_Abort(m_UART4_Handler.hdmarx);
        m_UART4_Handler.RxState = HAL_UART_STATE_READY; 
        //HAL_UART_RxDMAStop(&m_UART4_Handler);
        HAL_UART_Receive_DMA(&m_UART4_Handler, (u8 *)m_dma_rx4_buff, UART4_DMA_RX_BUFF_LEN); //开始接受
    }
    else if (__HAL_DMA_GET_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_TEIF2_6) != RESET)
    {
        __HAL_DMA_CLEAR_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_TEIF2_6);
    }
    else if (__HAL_DMA_GET_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_DMEIF2_6) != RESET)
    {
        __HAL_DMA_CLEAR_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_DMEIF2_6);
    }
    else if (__HAL_DMA_GET_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_FEIF2_6) != RESET)
    {
        __HAL_DMA_CLEAR_FLAG(&m_UART4RxDMA_Handler, DMA_FLAG_FEIF2_6);
    }
    //HAL_DMA_IRQHandler(&m_UART4RxDMA_Handler);
}

//串口4DMA发送完成中断服务程序
void DMA1_Stream4_IRQHandler(void)
{
    u8 *pTx = NULL;
    int txLen = 0;
    if (__HAL_DMA_GET_FLAG(&m_UART4TxDMA_Handler, DMA_FLAG_TCIF0_4) != RESET) //发送完成中断
    {
        __HAL_DMA_CLEAR_FLAG(&m_UART4TxDMA_Handler, DMA_FLAG_TCIF0_4);
#if UART4_BULK_TX
        m_UART4_Handler.gState = HAL_UART_STATE_READY; 
        HAL_DMA_Abort(m_UART4_Handler.hdmatx);   
        //HAL_UART_TxDMAStop(&m_UART4_Handler);
        txLen = Uart4_Read_Queue_Bulk(&uart4_TxQueue, &pTx);
        if (txLen > 0)
        {
            HAL_UART_Transmit_DMA(&m_UART4_Handler, pTx, txLen);
        }       
#else
        int len = 0;
        len = CalcNumNotRead(&uart4_TxQueue);
        len = len<UART4_DMA_TX_BUFF_LEN?len:UART4_DMA_TX_BUFF_LEN;
        if (len > 0)
        {
            for (int i=0;i<len;i++)
            {
                Uart4_Read_Queue(&uart4_TxQueue, (u8 *)m_dma_tx4_buff+i);  //可以考虑使用二维数组来增加发送效率
            }  
        }
        m_UART4_Handler.gState = HAL_UART_STATE_READY; 
        HAL_DMA_Abort(m_UART4_Handler.hdmatx);
        //HAL_UART_TxDMAStop(&m_UART4_Handler);
        if (len > 0)
        {
            HAL_UART_Transmit_DMA(&m_UART4_Handler, (u8 *)m_dma_tx4_buff, len);
        }
#endif
    }
    //HAL_DMA_IRQHandler(&m_UART4TxDMA_Handler);
}

The difficulty of the project lies in QRS filtering. The algorithm here is as follows:


/* Include Files */
#include <math.h>
#include <string.h>
#include "QRSDetection.h"

float m_minHeightSet = MIN_PEAK_HEIGHT; //设置最小peak高度
unsigned int m_peakBlankCntSet = MIN_PEAK_BLANK_CNT; //设置peak空白长度

/* Variable Definitions */
static float m_minHeight = MIN_PEAK_HEIGHT; //动态最小高度
static unsigned long long m_dataCnt = 0; //数据序号
static bool m_qrsFlag = false; //是否R点
static int m_heightCnt = 0; //R peak序号
static float maxPeak = 0.0; //peak
static float lastDatum = 0.0; //上一个值
static int timeSinceMax = 0; //最大值延时
static int count = 0; //上一个R点起计数
static int qpkcnt = 0; //起始调整高度计数
static int lastQRSDelay = 0; //RR间隔
static int preBlankCnt = 0; //peak后空白计数
static float tempPeak = 0.0; //记录上一个peak
static int findCnt = 0; //无peak计数
static int m_noiseCnt = 0; //noise计数
static float m_meanNoise = 0.0; //平均噪音




static int MS80()
{
    int FS = 500;
    return 80 * FS / 1000;
}

static int MS95()
{
    int FS = 500;
    return 95 * FS / 1000;
}

static int MS196()
{
    int FS = 500;
    return 196 * FS / 1000;

}

static int MS360()
{
    int FS = 500;
    return 360 * FS / 1000;

}

static int MS1000()
{
    int FS = 500;
    return 1000 * FS / 1000;

}

static int MS1650()
{
    int FS = 500;
    return 1650 * FS / 1000;

}

static bool isZero(float v)
{
    return (fabs(v) <= 0.000001)?true:false;
}

//每8个R点动态计算R点高度阈值
static float calcMinHeight(float v, bool flag)
{
    static float peak[R_PEAK_AVG_CNT] = {0};
    float sum = 0.0;
    peak[m_heightCnt] = v;
    m_heightCnt = (m_heightCnt+1)%R_PEAK_AVG_CNT;
    if (flag)
    {
        for(int i=0;i<R_PEAK_AVG_CNT;i++)
        {
            sum += peak;
        }
        sum = sum/R_PEAK_AVG_CNT/3;  //使用平均R值的三分之一作为新的高度阈值 sqrt(1/3) = 0.57
        if (sum < m_minHeightSet)
        {
            sum = m_minHeightSet;
        }
    }
    return sum;
}
//计算噪音
static float calcNoise(float v, bool flag)
{
    static float noise[R_PEAK_AVG_CNT] = {0};
    float sum = 0.0;
    noise[m_noiseCnt] = v;
    m_noiseCnt = (m_noiseCnt+1)%R_PEAK_AVG_CNT;
    if (flag)
    {
        for(int i=0;i<R_PEAK_AVG_CNT;i++)
        {
            sum += noise;
        }
        sum = 1.5*sum/R_PEAK_AVG_CNT;  //sqrt(1.5) = 1.2
    }
    return sum;
    
    
}

/*
 * Description:
 *    QRS Dectector based on the band-pass filtered ECG signal.
 *    The QRS detection rules reference the PIC based QRS detector
 *    implemented by Patrick S. Hamilton in picqrs.c
 *    from Open Source ECG Analysis (OSEA)
 *    http://www.eplimited.com/confirmation.htm
 *
 *  INPUT:
 *   u : bandpass filtered and moving averaged ECG signal
 *
 *  OUTPUTS:
 *   heartRate: detected heart rate (beat per minute)
 *   peak     : detected local peaks (mainly R peaks)
 *   threshold: the detection threshold is calculated based on
 *              the mean estiamtes of the average QRS peak and
 *              the average noise peak.
 *
 *  Detection Rules:
 *  Rule 1. Ignore all peaks that precede or follow larger peaks by less
 *          than 196 ms (306bpm). The EC13 Standard specifies that the
 *          QRS detector should accurately detect QRS complexes at rates
 *          as high as 250 beats-per-minute (bpm), and should not report
 *          heart rates lower than 250bpm when rates as high as 300bpm occur.
 *  Rule 2. If a peak occurs, check to see whether the raw signal
 *          contained both positive and negative slopes. If yes,
 *            report a peak being found, otherwise, the peak
 *            represents a baselien shift.
 *  Rule 3. If the peak is larger than the detection threshold
 *            classify it as a QRS complex, otherwise classify
 *            it as noise.
 *  Rule 4. If no QRS has been detected within 1.5 R-to-R intervals,
 *          there was a peak that was larger than half the
 *          detection threshold, and the peak followed the preceding
 *          detection by at least 360ms, classify that peak as a QRS
 *          complex.
 * Arguments    : const double u[2000]
 *                short *RRIntvl
 *                double *peak
 *                double *loc
 *                short *qrsIndex
 *                double *b_threshold
 * Return Type  : void
 */
void QRSDetection(float *u, int len,  int *RRIntvl, float *peak, unsigned long long
                  *loc, int *delay)
{
  int idx;
  float peakTemp;
  float peakTemp1;
  *peak = 0.0;
  *loc = 0;

  /*  Prevents detections of peaks smaller than 150 uV. */
  m_dataCnt += len;
  m_qrsFlag = false;
  for (idx = 0; idx < len; idx++)
  {
    /*  For a frame of input signal, process one sample at a time */
    /*  peak() takes a datum as input and returns a peak height */
    /*  when the signal returns to half its peak height, or it has been */
    /*  95 ms since the peak height was detected. */
    /*  function QRSDetection */
    peakTemp = 0.0;
    u[idx] = u[idx]*fabs(u[idx]);
    if (timeSinceMax > 0) {
      timeSinceMax++;
    }

    if ((u[idx] > lastDatum) && (u[idx] > maxPeak))/*  rising slope */
    {
        maxPeak = u[idx];
        if (maxPeak > MAX_PEAK_HEIGHT)
        {
          /*  reset timeSinceMax  */
          timeSinceMax = 1U;
        }
    }
    else if (u[idx] < maxPeak/2) //find a peak
    {
    /*  middle of falling slope */
    /*  Less than half the peak height */
        peakTemp = maxPeak;
        maxPeak = 0.0;
        timeSinceMax = 0U;
    }
    else
    {
        if (timeSinceMax > MS95()) {
          peakTemp = maxPeak;
          maxPeak = 0.0;
          timeSinceMax = 0U;
        }
    }

    lastDatum = u[idx];

    //peak must bigger than min height
    if (peakTemp < m_minHeight)
    {
      peakTemp = 0.0;
      findCnt++;
      if (findCnt > MS1650()) //1650ms内没有peak,则动态高度变成最小高度
      {
          findCnt = 0;
          m_minHeight = m_minHeightSet;//
          m_meanNoise = 0.0;
          qpkcnt = 0; //重新等待8个点计算最小高度
      }
    }
    else
    {
        findCnt = 0;
    }


    /*  returns adjusted peak */
    /*  there can only be one QRS complex in any 196ms (306bpm) window */
    if (isZero(peakTemp) && (preBlankCnt == 0))
    {
      peakTemp1 = 0.0;
    }
    else if (isZero(peakTemp) && (preBlankCnt != 0))
    {
      /*  if we have held onto a peak for 196ms, pass it on for eval */
      preBlankCnt--;
      if (preBlankCnt == 0) {
        peakTemp1 = tempPeak; //R
      } else {
        peakTemp1 = 0.0;
      }
    }
    else if (!isZero(peakTemp) && (preBlankCnt == 0))
    {
      /*  if there has been no peak for 196ms, save this one and start */
      /*  counting */
      tempPeak = peakTemp;
      preBlankCnt = m_peakBlankCntSet;//MS196();
      peakTemp1 = 0.0;
    }
    else
    {
      /*  (pk~=0) &&  (preBlankCnt~=0) */
      /*  if we were holding a peak, but this one is bigger, */
      /*  save it and start counting to 196ms again */
      if (peakTemp > tempPeak) {  //peakTemp is noise
        if (qpkcnt >= R_PEAK_AVG_CNT)
        {
            m_meanNoise = calcNoise(tempPeak, true);
        }
        else
        {
            m_meanNoise = calcNoise(tempPeak, false);
        }
        tempPeak = peakTemp;
        preBlankCnt = m_peakBlankCntSet;//MS196();
        peakTemp1 = 0.0;
      } else {
        preBlankCnt--;
        if (preBlankCnt == 0) {
          peakTemp1 = tempPeak; //R
        } else {
          peakTemp1 = 0.0;
        }
      }
    }

    count++;

    /*  Initialize the QRS peak buffer with the first eight  */
    /*  local maximum peaks detected */
    //if ((peakTemp1 >= m_minHeight)&& (peakTemp1 >= m_meanNoise)) //R点,先取消噪音检测
    if (peakTemp1 >= m_minHeight) 
    {
        if (qpkcnt < R_PEAK_AVG_CNT) {
          if (!isZero(peakTemp1)) {

            //m_qrsFlag = true;
            qpkcnt++;
            if (qpkcnt == R_PEAK_AVG_CNT) {
              m_minHeight = calcMinHeight(peakTemp1, true);
              count = 0;
            }
            else
            {
              m_minHeight = calcMinHeight(peakTemp1, false);
            }
          }
        } else {
          /*  qpkcnt >= 8 */
            m_minHeight = calcMinHeight(peakTemp1, true);
            m_qrsFlag = true;
            lastQRSDelay = count;
            count = 0;
        }
    }


    //R
    if (m_qrsFlag) {
      *peak = peakTemp1;
      *loc = m_dataCnt-(len)+idx-m_peakBlankCntSet; //MS196()
      *RRIntvl = lastQRSDelay;
      *delay = m_dataCnt-(*loc+1);
      m_qrsFlag = false;
    }
  }

}


/*
 * Arguments    : void
 * Return Type  : void
 */
void maxPeak_not_empty_init(void)
{
    maxPeak = 0.0;
    lastDatum = LOWEST_PEAK_VALUE;
    timeSinceMax = 0U;
}

/*
 * Arguments    : void
 * Return Type  : void
 */
void qrs_det_init(void)
{
  count = 0;
  qpkcnt = 0;
  lastQRSDelay = 0;

  /*  EC13: QRS detector should not detect QRS complexes with  */
  /*   amplitudes of less than 0.15mV and 1mV QRS complexes with width */
  /*   less than 10ms (6000bpm) */
  m_minHeight = m_minHeightSet;
  tempPeak = 0.0;
  preBlankCnt = 0;
  m_heightCnt = 0;
  m_meanNoise = 0;
  m_noiseCnt = 0;
}



void QRSInit()
{
    maxPeak_not_empty_init();
    qrs_det_init();
    m_dataCnt = 0;
}

float getDynamicMinHeight()
{
    return m_minHeight;
}

float getDynamicNoise()
{
    return m_meanNoise;
}

void setMinHeight(float value)
{
    m_minHeightSet = value;
}
void setPeakBlankCnt(unsigned int cnt)
{
    m_peakBlankCntSet = cnt;
}

5. Demonstration video of the work’s functions

f9c07f83e86c8a63cdcf48a8660b4126

6. Project Summary

In fact, the difficulty lies in ADAS data filtering, how to obtain a clean waveform.


This post is from DigiKey Technology Zone

Latest reply

Have you found a suitable solution?   Details Published on 2022-10-17 11:06
 
 

2

Posts

0

Resources
2
 

How many bits does your AD have? What's the accuracy? How many channels does it have?

We have used ADS131 24bit before and want to find a replacement chip

This post is from DigiKey Technology Zone

Comments

This is not AD. 24-bit AD has high precision. Why change it?  Details Published on 2022-10-17 11:06
This is not AD. 24-bit AD has high precision. Why change it?  Details Published on 2022-10-17 11:05
 
 
 

6818

Posts

11

Resources
3
 
Congratulations on completing your assignment!
This post is from DigiKey Technology Zone
 
 
 

28

Posts

0

Resources
4
 
xiang90721 posted on 2022-10-16 22:18 Brother, how many bits does your AD have? What is the accuracy? How many channels does it have? We used ADS131 24bit before and want to find a replacement chip

This is not AD. 24-bit AD has high precision. Why change it?

This post is from DigiKey Technology Zone
 
 
 

280

Posts

7

Resources
5
 
xiang90721 posted on 2022-10-16 22:18 Brother, how many bits does your AD have? What is the accuracy? How many channels does it have? We used ADS131 24bit before and want to find a replacement chip

Have you found a suitable solution?

This post is from DigiKey Technology Zone

Comments

When choosing AD, first look at the signal rate you need to collect and then look at the accuracy. ADI has a lot of 7655 9231  Details Published on 2022-10-17 16:32
 
 
 

28

Posts

0

Resources
6
 
sipower posted on 2022-10-17 11:06 Have you found a suitable solution?

When choosing AD, first look at the signal rate you need to collect and then look at the accuracy. ADI has a lot of 7655 9231

This post is from DigiKey Technology Zone
 
 
 

Guess Your Favourite
Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list