ADS1115 error messages

by Luv2Solder on Mon Feb 04, 2013 8:36 pm

I purchased the ADS1115 16-bit ADC and downloaded the code for it but these errors appear while I attempt to upload the file:

singleended:4: error: 'Adafruit_ADS1015' does not name a type
singleended.ino: In function 'void setup()':
singleended:13: error: 'ads1015' was not declared in this scope
singleended.ino: In function 'void loop()':
singleended:20: error: 'ads1015' was not declared in this scope

I am using the following files:
1. singleended.pde
2. Adafruit_ADS1015.h
3. Adafruit_ADS1015.cpp

singleended.pde

Code: Select all
#include <Wire.h>
#include <Adafruit_ADS1015.h>

Adafruit_ADS1015 ads1015;

void setup(void)
{
  Serial.begin(9600);
  Serial.println("Hello!");
 
  Serial.println("Getting single-ended readings from AIN0..3");
  Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV)");
  ads1015.begin();
}

void loop(void)
{
  int16_t adc0, adc1, adc2, adc3;

  adc0 = ads1015.readADC_SingleEnded(0);
  adc1 = ads1015.readADC_SingleEnded(1);
  adc2 = ads1015.readADC_SingleEnded(2);
  adc3 = ads1015.readADC_SingleEnded(3);
  Serial.print("AIN0: "); Serial.println(adc0);
  Serial.print("AIN1: "); Serial.println(adc1);
  Serial.print("AIN2: "); Serial.println(adc2);
  Serial.print("AIN3: "); Serial.println(adc3);
  Serial.println(" ");
 
  delay(1000);
}


Adafruit_ADS1015.h

Code: Select all
/**************************************************************************/
/*!
@file Adafruit_ADS1015.h
@author K. Townsend (Adafruit Industries)
@license BSD (see license.txt)

This is a library for the Adafruit ADS1015 breakout board
----> https://www.adafruit.com/products/???

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

@section HISTORY

v1.0 - First release
v1.1 - Added ADS1115 support - W. Earl
*/
/**************************************************************************/

#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include <Wire.h>

/*=========================================================================
I2C ADDRESS/BITS
-----------------------------------------------------------------------*/
    #define ADS1015_ADDRESS (0x48) // 1001 000 (ADDR = GND)
/*=========================================================================*/

/*=========================================================================
CONVERSION DELAY (in mS)
-----------------------------------------------------------------------*/
    #define ADS1015_CONVERSIONDELAY (1)
    #define ADS1115_CONVERSIONDELAY (8)
/*=========================================================================*/

/*=========================================================================
POINTER REGISTER
-----------------------------------------------------------------------*/
    #define ADS1015_REG_POINTER_MASK (0x03)
    #define ADS1015_REG_POINTER_CONVERT (0x00)
    #define ADS1015_REG_POINTER_CONFIG (0x01)
    #define ADS1015_REG_POINTER_LOWTHRESH (0x02)
    #define ADS1015_REG_POINTER_HITHRESH (0x03)
/*=========================================================================*/

/*=========================================================================
CONFIG REGISTER
-----------------------------------------------------------------------*/
    #define ADS1015_REG_CONFIG_OS_MASK (0x8000)
    #define ADS1015_REG_CONFIG_OS_SINGLE (0x8000) // Write: Set to start a single-conversion
    #define ADS1015_REG_CONFIG_OS_BUSY (0x0000) // Read: Bit = 0 when conversion is in progress
    #define ADS1015_REG_CONFIG_OS_NOTBUSY (0x8000) // Read: Bit = 1 when device is not performing a conversion

    #define ADS1015_REG_CONFIG_MUX_MASK (0x7000)
    #define ADS1015_REG_CONFIG_MUX_DIFF_0_1 (0x0000) // Differential P = AIN0, N = AIN1 (default)
    #define ADS1015_REG_CONFIG_MUX_DIFF_0_3 (0x1000) // Differential P = AIN0, N = AIN3
    #define ADS1015_REG_CONFIG_MUX_DIFF_1_3 (0x2000) // Differential P = AIN1, N = AIN3
    #define ADS1015_REG_CONFIG_MUX_DIFF_2_3 (0x3000) // Differential P = AIN2, N = AIN3
    #define ADS1015_REG_CONFIG_MUX_SINGLE_0 (0x4000) // Single-ended AIN0
    #define ADS1015_REG_CONFIG_MUX_SINGLE_1 (0x5000) // Single-ended AIN1
    #define ADS1015_REG_CONFIG_MUX_SINGLE_2 (0x6000) // Single-ended AIN2
    #define ADS1015_REG_CONFIG_MUX_SINGLE_3 (0x7000) // Single-ended AIN3

    #define ADS1015_REG_CONFIG_PGA_MASK (0x0E00)
    #define ADS1015_REG_CONFIG_PGA_6_144V (0x0000) // +/-6.144V range
    #define ADS1015_REG_CONFIG_PGA_4_096V (0x0200) // +/-4.096V range
    #define ADS1015_REG_CONFIG_PGA_2_048V (0x0400) // +/-2.048V range (default)
    #define ADS1015_REG_CONFIG_PGA_1_024V (0x0600) // +/-1.024V range
    #define ADS1015_REG_CONFIG_PGA_0_512V (0x0800) // +/-0.512V range
    #define ADS1015_REG_CONFIG_PGA_0_256V (0x0A00) // +/-0.256V range

    #define ADS1015_REG_CONFIG_MODE_MASK (0x0100)
    #define ADS1015_REG_CONFIG_MODE_CONTIN (0x0000) // Continuous conversion mode
    #define ADS1015_REG_CONFIG_MODE_SINGLE (0x0100) // Power-down single-shot mode (default)

    #define ADS1015_REG_CONFIG_DR_MASK (0x00E0)
    #define ADS1015_REG_CONFIG_DR_128SPS (0x0000) // 128 samples per second
    #define ADS1015_REG_CONFIG_DR_250SPS (0x0020) // 250 samples per second
    #define ADS1015_REG_CONFIG_DR_490SPS (0x0040) // 490 samples per second
    #define ADS1015_REG_CONFIG_DR_920SPS (0x0050) // 920 samples per second
    #define ADS1015_REG_CONFIG_DR_1600SPS (0x0080) // 1600 samples per second (default)
    #define ADS1015_REG_CONFIG_DR_2400SPS (0x00A0) // 2400 samples per second
    #define ADS1015_REG_CONFIG_DR_3300SPS (0x00C0) // 3300 samples per second

    #define ADS1015_REG_CONFIG_CMODE_MASK (0x0010)
    #define ADS1015_REG_CONFIG_CMODE_TRAD (0x0000) // Traditional comparator with hysteresis (default)
    #define ADS1015_REG_CONFIG_CMODE_WINDOW (0x0010) // Window comparator

    #define ADS1015_REG_CONFIG_CPOL_MASK (0x0008)
    #define ADS1015_REG_CONFIG_CPOL_ACTVLOW (0x0000) // ALERT/RDY pin is low when active (default)
    #define ADS1015_REG_CONFIG_CPOL_ACTVHI (0x0008) // ALERT/RDY pin is high when active

    #define ADS1015_REG_CONFIG_CLAT_MASK (0x0004) // Determines if ALERT/RDY pin latches once asserted
    #define ADS1015_REG_CONFIG_CLAT_NONLAT (0x0000) // Non-latching comparator (default)
    #define ADS1015_REG_CONFIG_CLAT_LATCH (0x0004) // Latching comparator

    #define ADS1015_REG_CONFIG_CQUE_MASK (0x0003)
    #define ADS1015_REG_CONFIG_CQUE_1CONV (0x0000) // Assert ALERT/RDY after one conversions
    #define ADS1015_REG_CONFIG_CQUE_2CONV (0x0001) // Assert ALERT/RDY after two conversions
    #define ADS1015_REG_CONFIG_CQUE_4CONV (0x0002) // Assert ALERT/RDY after four conversions
    #define ADS1015_REG_CONFIG_CQUE_NONE (0x0003) // Disable the comparator and put ALERT/RDY in high state (default)
/*=========================================================================*/

class Adafruit_ADS1015
{
protected:
   // Instance-specific properties
   uint8_t m_i2cAddress;
   uint8_t m_conversionDelay;
   uint8_t m_bitShift;

 public:
  Adafruit_ADS1015(uint8_t i2cAddress = ADS1015_ADDRESS);
  void begin(void);
  uint16_t readADC_SingleEnded(uint8_t channel);
  int16_t readADC_Differential_0_1(void);
  int16_t readADC_Differential_2_3(void);
  void startComparator_SingleEnded(uint8_t channel, int16_t threshold);
  int16_t getLastConversionResults();

 private:
};

// Derive from ADS1105 & override construction to set properties
class Adafruit_ADS1115 : public Adafruit_ADS1015
{
 public:
  Adafruit_ADS1115(uint8_t i2cAddress = ADS1015_ADDRESS);

 private:
};


Adafruit_ADS1015.cpp

Code: Select all
/**************************************************************************/
/*!
@file Adafruit_ADS1015.cpp
@author K.Townsend (Adafruit Industries)
@license BSD (see license.txt)

Driver for the ADS1015/ADS1115 ADC

This is a library for the Adafruit MPL115A2 breakout
----> https://www.adafruit.com/products/???

Adafruit invests time and resources providing this open source code,
please support Adafruit and open-source hardware by purchasing
products from Adafruit!

@section HISTORY

v1.0 - First release
*/
/**************************************************************************/
#if ARDUINO >= 100
 #include "Arduino.h"
#else
 #include "WProgram.h"
#endif

#include <Wire.h>

#include "Adafruit_ADS1015.h"

/**************************************************************************/
/*!
@brief Abstract away platform differences in Arduino wire library
*/
/**************************************************************************/
static uint8_t i2cread(void) {
  #if ARDUINO >= 100
  return Wire.read();
  #else
  return Wire.receive();
  #endif
}

/**************************************************************************/
/*!
@brief Abstract away platform differences in Arduino wire library
*/
/**************************************************************************/
static void i2cwrite(uint8_t x) {
  #if ARDUINO >= 100
  Wire.write((uint8_t)x);
  #else
  Wire.send(x);
  #endif
}

/**************************************************************************/
/*!
@brief Writes 16-bits to the specified destination register
*/
/**************************************************************************/
static void writeRegister(uint8_t i2cAddress, uint8_t reg, uint16_t value) {
  Wire.beginTransmission(i2cAddress);
  i2cwrite((uint8_t)reg);
  i2cwrite((uint8_t)(value>>8));
  i2cwrite((uint8_t)(value & 0xFF));
  Wire.endTransmission();
}

/**************************************************************************/
/*!
@brief Writes 16-bits to the specified destination register
*/
/**************************************************************************/
static uint16_t readRegister(uint8_t i2cAddress, uint8_t reg) {
  Wire.beginTransmission(i2cAddress);
  i2cwrite(ADS1015_REG_POINTER_CONVERT);
  Wire.endTransmission();
  Wire.requestFrom(i2cAddress, (uint8_t)2);
  return ((i2cread() << 8) | i2cread());
}

/**************************************************************************/
/*!
@brief Instantiates a new ADS1015 class w/appropriate properties
*/
/**************************************************************************/
Adafruit_ADS1015::Adafruit_ADS1015(uint8_t i2cAddress)
{
   m_i2cAddress = i2cAddress;
   m_conversionDelay = ADS1015_CONVERSIONDELAY;
   m_bitShift = 4;
}


/**************************************************************************/
/*!
@brief Instantiates a new ADS1115 class w/appropriate properties
*/
/**************************************************************************/
Adafruit_ADS1115::Adafruit_ADS1115(uint8_t i2cAddress)
{
   m_i2cAddress = i2cAddress;
   m_conversionDelay = ADS1115_CONVERSIONDELAY;
   m_bitShift = 0;
}

/**************************************************************************/
/*!
@brief Setups the HW (reads coefficients values, etc.)
*/
/**************************************************************************/
void Adafruit_ADS1015::begin() {
  Wire.begin();
}

/**************************************************************************/
/*!
@brief Gets a single-ended ADC reading from the specified channel
*/
/**************************************************************************/
uint16_t Adafruit_ADS1015::readADC_SingleEnded(uint8_t channel) {
  if (channel > 3)
  {
    return 0;
  }
 
  // Start with default values
  uint16_t config = ADS1015_REG_CONFIG_CQUE_NONE | // Disable the comparator (default val)
                    ADS1015_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val)
                    ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low (default val)
                    ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator (default val)
                    ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second (default)
                    ADS1015_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default)

  // Set PGA/voltage range
  config |= ADS1015_REG_CONFIG_PGA_6_144V; // +/- 6.144V range (limited to VDD +0.3V max!)

  // Set single-ended input channel
  switch (channel)
  {
    case (0):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_0;
      break;
    case (1):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_1;
      break;
    case (2):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_2;
      break;
    case (3):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_3;
      break;
  }

  // Set 'start single-conversion' bit
  config |= ADS1015_REG_CONFIG_OS_SINGLE;

  // Write config register to the ADC
  writeRegister(m_i2cAddress, ADS1015_REG_POINTER_CONFIG, config);

  // Wait for the conversion to complete
  delay(m_conversionDelay);

  // Read the conversion results
  // Shift 12-bit results right 4 bits for the ADS1015
  return readRegister(m_i2cAddress, ADS1015_REG_POINTER_CONVERT) >> m_bitShift;
}

/**************************************************************************/
/*!
@brief Reads the conversion results, measuring the voltage
difference between the P (AIN0) and N (AIN1) input. Generates
a signed value since the difference can be either
positive or negative.
*/
/**************************************************************************/
int16_t Adafruit_ADS1015::readADC_Differential_0_1() {
  // Start with default values
  uint16_t config = ADS1015_REG_CONFIG_CQUE_NONE | // Disable the comparator (default val)
                    ADS1015_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val)
                    ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low (default val)
                    ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator (default val)
                    ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second (default)
                    ADS1015_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default)

  // Set PGA/voltage range
  config |= ADS1015_REG_CONFIG_PGA_6_144V; // +/- 6.144V range (limited to VDD +0.3V max!)

  // Set channels
  config |= ADS1015_REG_CONFIG_MUX_DIFF_0_1; // AIN0 = P, AIN1 = N

  // Set 'start single-conversion' bit
  config |= ADS1015_REG_CONFIG_OS_SINGLE;

  // Write config register to the ADC
  writeRegister(m_i2cAddress, ADS1015_REG_POINTER_CONFIG, config);

  // Wait for the conversion to complete
  delay(m_conversionDelay);

  // Read the conversion results
  // Shift 12-bit results right 4 bits for the ADS1015
  return (int16_t)(readRegister(m_i2cAddress, ADS1015_REG_POINTER_CONVERT) >> m_bitShift);
}

/**************************************************************************/
/*!
@brief Reads the conversion results, measuring the voltage
difference between the P (AIN2) and N (AIN3) input. Generates
a signed value since the difference can be either
positive or negative.
*/
/**************************************************************************/
int16_t Adafruit_ADS1015::readADC_Differential_2_3() {
  // Start with default values
  uint16_t config = ADS1015_REG_CONFIG_CQUE_NONE | // Disable the comparator (default val)
                    ADS1015_REG_CONFIG_CLAT_NONLAT | // Non-latching (default val)
                    ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low (default val)
                    ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator (default val)
                    ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second (default)
                    ADS1015_REG_CONFIG_MODE_SINGLE; // Single-shot mode (default)

  // Set PGA/voltage range
  config |= ADS1015_REG_CONFIG_PGA_6_144V; // +/- 6.144V range (limited to VDD +0.3V max!)

  // Set channels
  config |= ADS1015_REG_CONFIG_MUX_DIFF_2_3; // AIN2 = P, AIN3 = N

  // Set 'start single-conversion' bit
  config |= ADS1015_REG_CONFIG_OS_SINGLE;

  // Write config register to the ADC
  writeRegister(m_i2cAddress, ADS1015_REG_POINTER_CONFIG, config);

  // Wait for the conversion to complete
  delay(m_conversionDelay);

  // Shift 12-bit results right 4 bits for the ADS1015
  return (int16_t)(readRegister(m_i2cAddress, ADS1015_REG_POINTER_CONVERT) >> m_bitShift);
}

/**************************************************************************/
/*!
@brief Sets up the comparator to operate in basic mode, causing the
ALERT/RDY pin to assert (go from high to low) when the ADC
value exceeds the specified threshold.

This will also set the ADC in continuous conversion mode.
*/
/**************************************************************************/
void Adafruit_ADS1015::startComparator_SingleEnded(uint8_t channel, int16_t threshold)
{
  uint16_t value;

  // Start with default values
  uint16_t config = ADS1015_REG_CONFIG_CQUE_1CONV | // Comparator enabled and asserts on 1 match
                    ADS1015_REG_CONFIG_CLAT_LATCH | // Latching mode
                    ADS1015_REG_CONFIG_CPOL_ACTVLOW | // Alert/Rdy active low (default val)
                    ADS1015_REG_CONFIG_CMODE_TRAD | // Traditional comparator (default val)
                    ADS1015_REG_CONFIG_DR_1600SPS | // 1600 samples per second (default)
                    ADS1015_REG_CONFIG_MODE_CONTIN | // Continuous conversion mode
                    ADS1015_REG_CONFIG_PGA_6_144V | // +/- 6.144V range (limited to VDD +0.3V max!)
                    ADS1015_REG_CONFIG_MODE_CONTIN; // Continuous conversion mode

  // Set single-ended input channel
  switch (channel)
  {
    case (0):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_0;
      break;
    case (1):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_1;
      break;
    case (2):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_2;
      break;
    case (3):
      config |= ADS1015_REG_CONFIG_MUX_SINGLE_3;
      break;
  }

  // Set the high threshold register
  // Shift 12-bit results left 4 bits for the ADS1015
  writeRegister(m_i2cAddress, ADS1015_REG_POINTER_HITHRESH, threshold << m_bitShift);

  // Write config register to the ADC
  writeRegister(m_i2cAddress, ADS1015_REG_POINTER_CONFIG, config);
}

/**************************************************************************/
/*!
@brief In order to clear the comparator, we need to read the
conversion results. This function reads the last conversion
results without changing the config value.
*/
/**************************************************************************/
int16_t Adafruit_ADS1015::getLastConversionResults()
{
  // Wait for the conversion to complete
  delay(m_conversionDelay);

  // Read the conversion results
  // Shift 12-bit results right 4 bits for the ADS1015
  return (int16_t)(readRegister(m_i2cAddress, ADS1015_REG_POINTER_CONVERT) >> m_bitShift);
}


What changes would correct those errors? Thank you!
Luv2Solder
 
Posts: 33
Joined: Tue Jun 21, 2011 3:15 pm

Re: ADS1115 error messages

by adafruit_support_bill on Mon Feb 04, 2013 9:48 pm

It looks like you don't have the library installed in the correct location.

Follow the instructions here to install the library: http://learn.adafruit.com/arduino-tips- ... -libraries
User avatar
adafruit_support_bill
 
Posts: 25404
Joined: Sat Feb 07, 2009 9:11 am

Re: ADS1115 error messages

by Luv2Solder on Mon Feb 04, 2013 10:46 pm

That solved that problem, but others occurred:

1. The serial monitor reports AIN0, AIN1, AIN2, and AIN3 are always the same whether I have a voltage going into AIN0 only (and the others with no inputs) or a variable voltage (from rotating a potentiometer used as a voltage divider) going into AIN0, with AIN1, AIN2, and AIN3 tied to Vdd or ground. Shouldn't I receive 4 different readings depending on what is input into AIN0, AIN1, AIN2, and AIN3?

2. When I input 0.6 mV into AIN0, the serial monitor reads 0 (for all: AIN0, AIN1, AIN2, and AIN3). However, if I reduce the voltage slightly (to 0.0 V), it reads 4095 (again, for all: AIN0, AIN1, AIN2, and AIN3). Inputting 4.93 V to AIN0 gives a reading of 1648 for all. Why would reducing the input voltage to AIN0 cause the reading to jump from 0 to 4095?

3. With the apparently valid range spanning from 0 to 1648, how can I get 16 bits of precision from this ADC?
Luv2Solder
 
Posts: 33
Joined: Tue Jun 21, 2011 3:15 pm

Re: ADS1115 error messages

by Luv2Solder on Mon Feb 04, 2013 10:57 pm

Some more info regarding my last posting: In the valid range, the response seems very linear:
Inputting 1.018 V (into AIN0) gives a reading of 339.
Inputting 2.024 V (into AIN0) gives a reading of 675.
Inputting 3.160 V (into AIN0) gives a reading of 1056.
Inputting 4.210 V (into AIN0) gives a reading of 1408.
Luv2Solder
 
Posts: 33
Joined: Tue Jun 21, 2011 3:15 pm

Re: ADS1115 error messages

by adafruit_support_bill on Tue Feb 05, 2013 6:26 am

The example defaults to the 12-bit ADS1015. You need to change it to use the ADS1115.

Also, to get a full 16 bits from the ADS1115, you need to use differential readings. In single-ended mode, you lose the sign-bit. And the ADC max-scale is a little higher than the reference voltage, so you will never get a full-scale reading. The designers sacrificed a little bit of resolution in exchange for better accuracy over the measurable range.
User avatar
adafruit_support_bill
 
Posts: 25404
Joined: Sat Feb 07, 2009 9:11 am

Re: ADS1115 error messages

by Luv2Solder on Tue Feb 05, 2013 9:54 am

The example defaults to the 12-bit ADS1015. You need to change it to use the ADS1115.


How do I do that? Exactly what do I need to change in singleended.pde, Adafruit_ADS1015.h, and Adafruit_ADS1015.cpp?
Luv2Solder
 
Posts: 33
Joined: Tue Jun 21, 2011 3:15 pm

Re: ADS1115 error messages

by adafruit_support_bill on Tue Feb 05, 2013 10:07 am

It can be as simple as just changing the declaration:
Code: Select all
Adafruit_ADS1015 ads1015;

To:
Code: Select all
Adafruit_ADS1115 ads1015;

Of course, that leaves you with a bunch of references to an ADS1115 called ADS1015. To really clean it up, just change all occurrences of "1015" to "1115". (except for the library #include).

Code: Select all
#include <Wire.h>
#include <Adafruit_ADS1015.h>

Adafruit_ADS1115 ads1115;

void setup(void)
{
  Serial.begin(9600);
  Serial.println("Hello!");
 
  Serial.println("Getting differential reading from AIN0 (P) and AIN1 (N)");
  Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV)");
  ads1115.begin();
}

void loop(void)
{
  int16_t results;

  results = ads1115.readADC_Differential_0_1(); 
  Serial.print("Differential: "); Serial.print(results); Serial.print("("); Serial.print(results * 3); Serial.println("mV)");

  delay(1000);
}
User avatar
adafruit_support_bill
 
Posts: 25404
Joined: Sat Feb 07, 2009 9:11 am

Re: ADS1115 error messages

by Luv2Solder on Tue Feb 05, 2013 12:51 pm

It worked very well. I graphed the results, which are EXCELLENT -- straight as an arrow linear.

Thank you. You really are national treasure! :D
Luv2Solder
 
Posts: 33
Joined: Tue Jun 21, 2011 3:15 pm