Lab_interaccio/2012/ASK-Shield/References/waspmote-api-v.021/WaspACC.cpp
Miguel Angel de Heras 451795bb92 Second commit
2025-03-05 15:57:19 +01:00

657 lines
18 KiB
C++

/*
* Copyright (C) 2009 Libelium Comunicaciones Distribuidas S.L.
* http://www.libelium.com
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 2.1 of the License, or
* (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* Version: 0.8
* Design: David Gascón
* Implementation: David Cuartielles, Alberto Bielsa
*/
#ifndef __WPROGRAM_H__
#include "WaspClasses.h"
#endif
// Variables ///////////////////////////////////////////////////////////////////
// Constructors ////////////////////////////////////////////////////////////////
WaspACC::WaspACC()
{
// nothing to do
}
// Public Methods //////////////////////////////////////////////////////////////
/*******************************************************************************
* QUICK BOOTING AND CONFIGURATION OF THE SENSOR
*******************************************************************************/
/*
* ON (void) - It opens I2C bus and powers the accelerometer
*
* It opens I2C bus and powers the accelerometer
*/
void WaspACC::ON(void)
{
begin();
setMode(ACC_ON);
}
/*
* begin (void) - initialize the accelerometer
*
* It initializes communication with I2C bus
* it makes no tests and checks nothing from the communication, therefore
* returns nothing and modifies no flags
*/
void WaspACC::begin(void)
{
// Sets RTC on to enable I2C
if( !RTC.isON) RTC.setMode(RTC_ON, RTC_I2C_MODE);
accMode = ACC_ON; // by default the accelerometer will be in continuous mode
// this should be changed once Wasp is released, by default
// the system should be in standby, and with the communication
// disabled
if( !Wire.I2C_ON ) Wire.begin(); // join i2c bus (address optional for master)
}
/*
* boot (void) - reboot the accelerometer
*
* takes for granted the accelerometer is on and forces the sensor to reboot
* by writing to the control register #2 into the right pin
* it makes no tests and checks nothing from the communication, therefore
* returns nothing and modifies no flags
*/
void WaspACC::boot(void)
{
// send reboot command
writeRegister(ctrlReg2, B00010000);
delay(1); // make a short pause after rebooting
writeRegister(ctrlReg2, B00000000);
}
/*
* close (void) - closes I2C bus
*
* It closes I2C bus. Accelerometer uses I2C to communicate with microcontroller.
*
* It is used to keep the battery to the maximum
*/
void WaspACC::close(void)
{
setMode(ACC_HIBERNATE);
if( Wire.I2C_ON && RTC.isON!=1){
PWR.closeI2C();
RTC.setMode(RTC_OFF, RTC_I2C_MODE);
}
}
/*******************************************************************************
* CHECK ACCELEROMETER'S STATUS
*******************************************************************************/
/*
* getStatus (void) - gets the accelerometer status
*
* returns a byte containing the status of the accelerometer as read from
* the proper register. It won't activate any flags by itself, but activates
* ACC_COMM_ERROR in case there was an error writing to the register
*/
uint8_t WaspACC::getStatus(void)
{
return (uint8_t) readRegister(statusReg);
}
/*
* getWhoAmI (void) - checks if there is an accelerometer on board
*
* sends the accelerometer dummy register on 0x0F that should always answer 0x3A
*
* This function can be used to determine if the accelerometer is on the board
* but also to check if it is still working properly. Any answer other than
* 0x3A means there is an error
*
* since it calls readRegister, getWhoAmI won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::check(void)
{
return (uint8_t) readRegister(whoAmIReg);
}
/*******************************************************************************
* HANDLE THE CONFIGURATION REGISTERS, BOTH READ AND WRITE
*******************************************************************************/
/*
* getCTRL1 (void) - checks accelerometer's control register 1
*
* returns the contents of control register 1
*
* since it calls readRegister, getCTRL1 won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::getCTRL1(void)
{
return (uint8_t) readRegister(ctrlReg1);
}
/*
* setCTRL1 (void) - sets accelerometer's control register 1
*
* sets the contents of control register 1, returns 1 if error
*
* since it calls writeRegister, setCTRL1 won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::setCTRL1(uint8_t val)
{
return (uint8_t) writeRegister(ctrlReg1, val);
}
/*
* getCTRL2 (void) - checks accelerometer's control register 2
*
* returns the contents of control register 2
*
* since it calls readRegister, getCTRL2 won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::getCTRL2(void)
{
return (uint8_t) readRegister(ctrlReg2);
}
/*
* setCTRL2 (void) - sets accelerometer's control register 2
*
* sets the contents of control register 2, returns 1 if error
*
* since it calls writeRegister, setCTRL2 won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::setCTRL2(uint8_t val)
{
return (uint8_t) writeRegister(ctrlReg2, val);
}
/*
* getCTRL3 (void) - checks accelerometer's control register 3
*
* returns the contents of control register 3
*
* since it calls readRegister, getCTRL3 won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::getCTRL3(void)
{
return (uint8_t) readRegister(ctrlReg3);
}
/*
* setCTRL3 (void) - sets accelerometer's control register 3
*
* sets the contents of control register 3, returns 1 if error
*
* since it calls writeRegister, setCTRL3 won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::setCTRL3(uint8_t val)
{
return (uint8_t) writeRegister(ctrlReg3, val);
}
/*
* getADCmode (void) - gets the accelerometer's ADC mode
*
* returns '0' if success, '-1' if error
*
* since it calls readRegister, getADCmode won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::getADCmode(void)
{
return readRegister(ctrlReg2) && B01;
}
/*
* setADCmode (bit) - sets the accelerometer's ADC mode
*
* writes, inside the CTRL2 whether the ADC should operate in 12 or 16bits. Values
* are zero (0) for 12 bits right aligned (MSB represents the sign) and one (1)
* for 16 bits left aligned
*
* since it calls writeRegister, setADCmode won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::setADCmode(uint8_t val)
{
uint8_t aux = readRegister(ctrlReg2);
aux &= B11111110;
aux |= val;
return writeRegister(ctrlReg2, aux);
}
/*
* setSamplingRate (rate) - sets the accelerometer's sampling rate
*
* writes, inside the CTRL1 the samplin rate desired
*
* since it calls writeRegister, setADCmode won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::setSamplingRate(uint8_t rate)
{
uint8_t aux = readRegister(ctrlReg1);
aux &= B11001111;
switch( rate )
{
case ACC_RATE_40 : aux |= rate;
break;
case ACC_RATE_160 : aux |= B00010000;
break;
case ACC_RATE_640 : aux |= B00100000;
break;
case ACC_RATE_2560 : aux |= B00110000;
break;
}
return writeRegister(ctrlReg1, aux);
}
/*******************************************************************************
* GET ACCELERATION ON THE THREE AXIS
*******************************************************************************/
/*
* getX (void) - checks accelerometer's acceleration on OX
*
* returns the combined contents of data registers outXhigh and outXlow as an
* integer according to ADC's configuration
*
* since it calls readRegister, getX won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
int16_t WaspACC::getX(void)
{
int16_t aux = ((int8_t)readRegister(outXhigh)*256) + (uint8_t)readRegister(outXlow);
return aux;
}
/*
* getY (void) - checks accelerometer's acceleration on OY
*
* returns the combined contents of data registers outYhigh and outYlow as an
* integer according to ADC's configuration
*
* since it calls readRegister, getY won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
int16_t WaspACC::getY(void)
{
int16_t aux = ((int8_t)readRegister(outYhigh)*256) + (uint8_t)readRegister(outYlow);
return aux;
}
/*
* getZ (void) - checks accelerometer's acceleration on OZ
*
* returns the combined contents of data registers outZhigh and outZlow as an
* integer according to ADC's configuration
*
* since it calls readRegister, getZ won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
int16_t WaspACC::getZ(void)
{
int16_t aux = ((int8_t)readRegister(outZhigh)*256) + (uint8_t)readRegister(outZlow);
return aux;
}
/*******************************************************************************
* HANDLE ACCELEROMETER'S WORK MODES *
*******************************************************************************/
/*
* getMode (void) - checks accelerometer's work mode
*
* returns the value for the accelerometer's work mode, the possibilites are:
* - ACC_INT: wake up the processor on preprogammed interrupt (free fall or deviation)
* - ACC_CONTINUOUS: read/send at a constant pace upon request
* - ACC_CUSTOM: user defined work mode
*
* It doesn't call any other functions and therefore it won't activate any flags
*/
uint8_t WaspACC::getMode()
{
return accMode;
}
/*
* setMode (uint8_t) - sets accelerometer's work mode
*
* configures the accelerometer to a new work mode, the possibilites are:
* - ACC_HIBERNATE: go on the lowest power mode possible. This mode has no interrupt
* calls and therefore won't disturb the processor if anything happened
* - ACC_ON: read/send at a constant pace upon request
* - ACC_CUSTOM: user defined work mode, should be programmed in here
*
* since it calls writeRegister, setAccMode won't activate any flags by itself,
* but the other functions will activate ACC_COMM_ERROR in case there
* was an error communicating to the register
*/
uint8_t WaspACC::setMode(uint8_t mode)
{
accMode = mode;
if (mode == ACC_HIBERNATE)
{
writeRegister(ctrlReg2,B00000000); // de-activate RDY
writeRegister(ctrlReg1,B00000111); // turn power off
isON = 0;
}
if (mode == ACC_ON)
{
writeRegister(ctrlReg2, B00000000);
writeRegister(ctrlReg1, B01000111); // turn power ON
writeRegister(ctrlReg3, B00001000);
isON = 1;
}
if (mode == ACC_CUSTOM)
{
// here the custom mode has to be defined by expert users
}
// go out with no error, leaves room to implement an error function
return 0;
}
/*******************************************************************************
* SPECIFIC WASP FUNCTIONS TO HANDLE EVENTS
*******************************************************************************/
/*
* setFF (void) - sets the Free Fall interrupt
*/
uint8_t WaspACC::setFF(void)
{
// clear the FF interrupt if active
unsetFF();
// configure the different registers to
// handle acceleration detection on the X, Y, or Z axis
ACC.writeRegister(ctrlReg1, 0xC7);
ACC.writeRegister(ctrlReg2, 0x08);
ACC.writeRegister(ctrlReg3, 0x08);
// here we have to double-check if we
// are in 12 or 16bit data modes. The 12
// bit data mode is giving away the 4LSBs
// therefore the register needs to be written
// according to that. 0x3C00 is just below 1g
// but the acc will give 0x03C0, beware!
writeRegister(FF_WU_THS_L, FF_WU_THS_L_val); // threshold L
writeRegister(FF_WU_THS_H, FF_WU_THS_H_val); // threshold H
writeRegister(FF_WU_DURATION, FF_WU_DURATION_val); // event duration
// readRegister(HP_FILTER_RESET); // config the acc. to get current acceleration as initial val
writeRegister(FF_WU_CFG, FF_WU_CFG_val); // config accelerometer to wake up
// assign the ACC_FREE_FALL mode
AccEventMode |= ACC_FREE_FALL;
// attach the hardware interrupt to the pin
attachInt();
return flag;
}
/*
* unsetFF (void) - clears and unsets the Free Fall interrupt
*/
uint8_t WaspACC::unsetFF(void)
{
writeRegister(FF_WU_CFG, 0x00);
readRegister(FF_WU_ACK); // clear the interrupt flag
// detach the event if there are no flags active
AccEventMode &= ~(ACC_FREE_FALL);
if (!AccEventMode) detachInt();
return flag;
}
/*
* setDD (uint8_t) - sets the Direction Change interrupt
*/
uint8_t WaspACC::setDD(uint8_t directions)
{
// make sure it gets configured for whatever direction
// people choose like e.g. XHIE or ZLIE
directions |= (IEND | LIR);
// clear the DD interrupt if active
unsetDD();
// configure the different registers to
// handle acceleration detection on the X, Y, or Z axis
writeRegister(ctrlReg1, 0xC7);
writeRegister(ctrlReg2, 0x08);
writeRegister(ctrlReg3, 0x4B);
// here we have to double-check if we
// are in 12 or 16bit data modes. The 12
// bit data mode is giving away the 4LSBs
// therefore the register needs to be written
// according to that. 0x3C00 is just below 1g
// but the acc will give 0x03C0, beware!
writeRegister(DD_THSI_L, DD_THSI_L_val); // threshold L internal
writeRegister(DD_THSI_H, DD_THSI_H_val); // threshold H internal
writeRegister(DD_THSE_L, DD_THSE_L_val); // threshold L external
writeRegister(DD_THSE_H, DD_THSE_H_val); // threshold H external
readRegister(HP_FILTER_RESET); // config the acc. to get current acceleration as initial val
writeRegister(DD_CFG, directions); // config accelerometer to wake up
// assign the ACC_FREE_FALL mode
AccEventMode |= ACC_DIRECTION;
// attach the hardware interrupt to the pin
attachInt();
return flag;
}
/*
* unsetDD (void) - clears and unsets the Direction Change interrupt
*/
uint8_t WaspACC::unsetDD(void)
{
writeRegister(DD_CFG, 0x00);
readRegister(DD_ACK); // clear the interrupt flag
// detach the event if there are no flags active
AccEventMode &= ~(ACC_DIRECTION);
if (!AccEventMode) detachInt();
return flag;
}
/*
* getAccEvent (void) - returns the event type on the accelerometer
*
* will be zero if there are no values set, bigger otherwise
*
* It doesn't call any other functions and therefore it won't activate any flags
*/
uint8_t WaspACC::getAccEvent(void)
{
return AccEventMode;
}
/*
* setAccEvent (mode) - sets the event type on the accelerometer
*
* It will set up the type of event, they are non exclusive and could be:
*
* - ACC_NONE
* - ACC_FREE_FALL
* - ACC_DIRECTION
* - ACC_THRESHOLD
*/
uint8_t WaspACC::setAccEvent(uint8_t mode)
{
AccEventMode = mode;
if (mode & ACC_DIRECTION)
{
}
if (mode == ACC_FREE_FALL)
{
}
if (mode == ACC_NONE)
{
}
// go out with no error, leaves room to implement an error function
return 0;
}
/*******************************************************************************
* HANDLING HARDWARE INTERRUPTS
*******************************************************************************/
/*
* attachInterrupt(void) - configure the specific hardware interrupt for the acc
*
* the default interrupt functions are defined inside WInterrupts.c
*/
void WaspACC::attachInt(void)
{
enableInterrupts(ACC_INT);
}
/*
* detachInterrupt(void) - unset the specific hardware interrupt for the acc
*/
void WaspACC::detachInt(void)
{
disableInterrupts(ACC_INT);
}
/*
* clearAlarmFlag() - clears the Accelerometer's alarm flag
*/
void WaspACC::clearAlarmFlag(void)
{
writeRegister(FF_WU_CFG, 0x00);
readRegister(FF_WU_ACK); // clear the interrupt flag
writeRegister(DD_CFG, 0x00);
readRegister(DD_ACK); // clear the interrupt flag
}
/*
void attachInterrupt();
void detachInterrupt();
*/
/*******************************************************************************
* LOW LEVEL READ AND WRITE REGISTERS
*******************************************************************************/
// reads a register from the accelerometer
// returns its value or -1 if error
int16_t WaspACC::readRegister(uint8_t regNum)
{
// reset the flag
flag &= ~(ACC_ERROR_READING);
uint8_t aux = 0;
Wire.beginTransmission(i2cID);
Wire.send(regNum);
Wire.endTransmission();
Wire.requestFrom(i2cID, 1);
if(Wire.available())
{
aux = Wire.receive();
return aux;
}
// error, activate the reading flag
flag |= ACC_ERROR_READING;
return -1;
}
// writes a byte to a register in the accelerometer
// returns 0 or -1 if error
int16_t WaspACC::writeRegister(uint8_t address, uint8_t val)
{
// reset the flag
flag &= ~(ACC_ERROR_WRITING);
Wire.beginTransmission(i2cID);
Wire.send(address);
Wire.send(val);
Wire.endTransmission();
if (readRegister(address) != val)
{
// error, activate the reading flag
flag |= ACC_ERROR_WRITING;
return -1;
}
// exit with no error
return 0;
}
// Private Methods /////////////////////////////////////////////////////////////
// Preinstantiate Objects //////////////////////////////////////////////////////
WaspACC ACC = WaspACC();