Update

Dependents:   COG_UART_Base

ADXL362.cpp

Committer:
APS_Lab
Date:
2019-01-11
Revision:
0:860fafcf34d6

File content as of revision 0:860fafcf34d6:

#include "ADXL362.h"

#define WAIT_US(value)		(0.000001 * ((float)value))

#define REGADDR_WRITE		(0x80)
#define REGADDR_WR_L		(0x00)
#define REGADDR_WR_H		(0x01)

#define GET_VAL_L(value)	((value >> 0) & 0xFF)
#define GET_VAL_H(value)	((value >> 8) & 0xFF)

// define for EV-COG-AD3029LZ
#define SPI_CS    SPI1_CS3

/** ==========================================
 *  Public ( initializing )
 *  ========================================== */
ADXL362::ADXL362(Serial *setUart, SPI* spi1) {	
    int check;

	uart = setUart;  
	_spi = spi1;
	_cs = new DigitalOut(SPI_CS);
	
	_spi->format(8,3);
	_spi->frequency(1000000);
	
	chipSelOff();

	/* start */
	check = regRD(DEVID_AD);
	if (check != DEVID_AD_ADXL362) {	
		return;
	}
	check = regRD(DEVID_MST);
	if (check != DEVID_MST_ADXL362) {	
		return;
	}
	check = regRD(PARTID);
	if (check != PARTID_ADXL362) {	
		return;
	}

	/* init MIN/MAX store */
	initMinMax(&minStore, &maxStore);	
	/* set convert parameter */		
	SoftReset();

	scaleAccel = PARAM_ADXL362_SCALE_ACCEL;
    scaleThermal = PARAM_ADXL362_SCALE_THERMAL;
    offsetThermal = PARAM_ADXL362_THERMAL_OFFSET;
	
	//SetMesureParam(POWER_CTL_PARAM_LOWNOISE_ULTRA);
	//StartMesure();
}

ADXL362::~ADXL362() {
    delete this->_cs;
}


/** ==========================================
 *  Private ( Control Pins )
 *  ========================================== */
/* Assert CHIP_SEL = enable */
void ADXL362::chipSelOn() {
	chipSelDelay();
	*_cs = 0;
}

/* Assert CHIP_SEL = disable */
void ADXL362::chipSelOff() {
	*_cs = 1;
}

/* delay for CHIP_SEL */
void ADXL362::chipSelDelay() {
    wait(WAIT_US(0.2));
}
/** ==========================================
 *  Public ( ADXL Configuration )
 *  ========================================== */
void ADXL362::set_gravity(int g)
{
	int value;
	unsigned char g_reg;
	
	switch(g)
	{
		case GRAVITY_2G:
			gravity = GRAVITY_2G;
			g_reg = 0x00;
			break;
		case GRAVITY_4G:
			gravity = GRAVITY_4G;
			g_reg = 0x40;
			break;
		case GRAVITY_8G:
			gravity = GRAVITY_8G;
			g_reg = 0x80;
			break;
		default:
			gravity = GRAVITY_2G;
			g_reg = 0x00;
			break;
	}
	value = regRD(FILTER_CTL);
	value &= 0x3f;
	value |= g_reg;
	regWR(FILTER_CTL, value);
	set_scalefactor();
}

void ADXL362::set_ODR(int o)
{
	int value;
	unsigned char o_reg;
	
	switch(o)
	{
		case ODR_12:
			odr = ODR_12;
			o_reg = 0x00; 
			break;
		case ODR_25:
			odr = ODR_25;
			o_reg = 0x01; 
			break;
		case ODR_50:
			odr = ODR_50;
			o_reg = 0x02; 
			break;
		case ODR_100:
			odr = ODR_100;
			o_reg = 0x03; 
			break;
		case ODR_200:
			odr = ODR_200;
			o_reg = 0x04; 
			break;
		case ODR_400:
			odr = ODR_400;
			o_reg = 0x07; 
			break;
		default:
			odr = ODR_100;
			o_reg = 0x03;
			break;
	}
	value = regRD(FILTER_CTL);
	value &= 0xf8;
	value |= o_reg;
	regWR(FILTER_CTL, value);
}

void ADXL362::set_powermode(int m)
{
	ADXL362::SetMesureParam(m);
}

void ADXL362::set_wakeupmode(void)
{
	regWR(THRESH_ACT_L, 0x50);
	regWR(THRESH_ACT_H, 0x00);
	regWR(TIME_ACT, 0x00);
	regWR(THRESH_INACT_L, 0xff);
	regWR(THRESH_INACT_H, 0x07);
	regWR(TIME_INACT_L, 0x06);
	regWR(TIME_INACT_H, 0x00);
	regWR(ACT_INACT_CTL, 0x1F);
	regWR(INTMAP1, 0xC0);
	regWR(POWER_CTL, 0x0E);
}

void ADXL362::set_scalefactor(void)
{
	float base, sf;
	
	base = (gravity / 2.0f);
	sf = base*(0.001f)*9.80665f;
	scaleAccel = sf;
}

void ADXL362::start(void)
{
	int value;
	value = regRD(POWER_CTL);
	value &= 0xfc;
	value |= POWER_CTL_MESURE;
	regWR(POWER_CTL, value);
    wait_ms(5);
	GetStatus();
}
	
void ADXL362::stop(void)
{
	int value;
	value = regRD(POWER_CTL);
	value &= 0xfc;
	value |= POWER_CTL_STOP;
	regWR(POWER_CTL, value);
	wait_ms(5);
	GetStatus();
}

/** ==========================================
 *  Public ( Send Command to Device )
 *  ========================================== */
/* Write 16bit-Aligned Register */
void ADXL362::SoftReset() {
	regWR(SOFT_RESET, SOFT_RESET_ADXL362);
	wait(0.5);	
}

void ADXL362::SetMesureParam(int param) {
	int value;
	value = regRD(POWER_CTL);
	param &= ~(POWER_CTL_MODEMASK);
	value &= POWER_CTL_MODEMASK;
	value |= param;
	regWR(POWER_CTL, value);
}

void ADXL362::StartMesure() {
	int value;
	GetStatus();
	value = regRD(POWER_CTL);
	value &= ~(POWER_CTL_MODEMASK);
	value |= POWER_CTL_MESURE;
	regWR(POWER_CTL, POWER_CTL_MESURE);
	value = regRD(POWER_CTL);	
    wait_ms(5);
	GetStatus();
}

int ADXL362::GetStatus() {
	int value;
	value = regRD(STATUS);
	return value;
}

/** ==========================================
 *  Public ( Sensing )
 *  ========================================== */
void ADXL362::SensorRead(AccelTemp *pAT) {
	int burstBuf[8];
	/* Xx2 + Yx2 + Zx2 + Tempx2 = 8*/
	regBurstRD(XDATA_L, 8, burstBuf);
	convertSensorData(pAT, burstBuf);
#if 0	
	uart->printf("ADXL362[ax] = 0x%02x\n", pAT->ax);
	uart->printf("ADXL362[ay] = 0x%02x\n", pAT->ay);
	uart->printf("ADXL362[az] = 0x%02x\n", pAT->az);
	uart->printf("ADXL362[tm] = 0x%02x\n", pAT->tm)
#endif	
	updateMinMax(&minStore, &maxStore, pAT);	
}

/** ==========================================
 *  Public ( Sub Infomation )
 *  ========================================== */
/* Get Internal Store (for Min Info) */
AccelTemp* ADXL362::GetMinInfo(void) {
	return &minStore;
}

/* Get Internal Store (for Max Info) */
AccelTemp* ADXL362::GetMaxInfo(void) {
	return &maxStore;
}

/* Convert CtrlValue to Real for Accelerometer */
float ADXL362::ConvAccel(int ctrlval) {
	return scaleAccel * (float)ctrlval;
}

/* Convert CtrlValue to Real for Thermal Sensor */
float ADXL362::ConvThermal(int ctrlval) {
	return (scaleThermal * (float)ctrlval) + offsetThermal;
}

/** ==========================================
 *  Private ( convert sensing value )
 *  ========================================== */
void ADXL362::convertSensorData(AccelTemp *at, int *buf) {
	at->ax = ext12bitToInt(buf[0], buf[1]);
	at->ay = ext12bitToInt(buf[2], buf[3]);
	at->az = ext12bitToInt(buf[4], buf[5]);
	at->tm = ext12bitToInt(buf[6], buf[7]);	
}

int ADXL362::ext12bitToInt(int l, int h)
{
	h <<= 8;
	h &= 0x0f00;
	h |= l & 0xff;
	if ((h & 0x800) != 0) {
		h |= 0xfffff000;
	}
	return h;
}

/** ==========================================
 *  Private ( SPI Communication )
 *  ========================================== */
#define ADXL362_SPI_CMD_WR		0x0A
#define ADXL362_SPI_CMD_RD		0x0B
#define ADXL362_SPI_CMD_RD_FIFO	0x0D
 
/* Read Single Register */
int ADXL362::regRD(int regAddr) {
	int recvData;
	regBurstRD(regAddr, 1, &recvData);
	return recvData;
}

/* Read Multi Register */
void ADXL362::regBurstRD(int regAddr, int numBurst, int *recvBuf) {
	int cnt;

	/* SPI Burst Read Loop **
	 * Write A -> Write B : Read A -> Write C : Read B -> ... */
	_spi->lock();
	chipSelOn();
	/* WriteADDR[n] and ReadData[n-1] */
	_spi->write(ADXL362_SPI_CMD_RD);
	_spi->write(regAddr);		
	for (cnt = 0; cnt < numBurst; cnt++) {
		/* WriteADDR[n] and ReadData[n-1] */
		recvBuf[cnt] = _spi->write(0x00);		
	}
	chipSelOff();	
	_spi->unlock();
	return;
}

/* Write 16bit-Aligned Register */
void ADXL362::regWR(int regAddr, int value) {
	_spi->lock();
	chipSelOn();
	_spi->write(ADXL362_SPI_CMD_WR);	
	_spi->write(regAddr);
	_spi->write(value);
	chipSelOff();
	_spi->unlock();
	return;
}

/** ==========================================
 *  Private ( Control internal Stores )
 *  ========================================== */
/* clear internal Min/Max infomation */	
void ADXL362::initMinMax
(AccelTemp *minData, AccelTemp *maxData) {
    minData->ax = INT_MAX;
    minData->ay = INT_MAX;
    minData->az = INT_MAX;
    minData->tm = INT_MAX;

    maxData->ax = INT_MIN;
    maxData->ay = INT_MIN;
    maxData->az = INT_MIN;
    maxData->tm = INT_MIN;
}

/* update internal Min/Max infomation */
#define TEST_MIN_AND_SET(now, test) (now = (now >= test)? test : now)
#define TEST_MAX_AND_SET(now, test) (now = (now <= test)? test : now)
void ADXL362::updateMinMax
(AccelTemp *minData, AccelTemp *maxData, AccelTemp *getData) {
    TEST_MIN_AND_SET(minData->ax, getData->ax);
    TEST_MIN_AND_SET(minData->ay, getData->ay);
    TEST_MIN_AND_SET(minData->az, getData->az);
	TEST_MIN_AND_SET(minData->tm, getData->tm);

    TEST_MAX_AND_SET(maxData->ax, getData->ax);
    TEST_MAX_AND_SET(maxData->ay, getData->ay);
    TEST_MAX_AND_SET(maxData->az, getData->az);
    TEST_MAX_AND_SET(maxData->tm, getData->tm);
}