Library for NXP (Philips) PCF8591 I2C 4 Channel, 8bit Analog to Digital converter and a 1 Channel, 8bit Digital to Analog converter.

Dependents:   812_hello PCF8591_test_LAAS

Committer:
wim
Date:
Sat Sep 21 19:25:09 2013 +0000
Revision:
0:1116b0d151fc
Extended functionality to include mbed type AnalogIn and AnalogOut; Fixed issue related to LPC812 I2C bug

Who changed what in which revision?

UserRevisionLine numberNew contents of line
wim 0:1116b0d151fc 1 /* PCF8591 - I2C 8 bit 4 channel A/D and 8 bit 1 channel D/A converter
wim 0:1116b0d151fc 2 * Copyright (c) 2013 Wim Huiskamp
wim 0:1116b0d151fc 3 *
wim 0:1116b0d151fc 4 * Released under the MIT License: http://mbed.org/license/mit
wim 0:1116b0d151fc 5 *
wim 0:1116b0d151fc 6 * version 0.2 Initial Release
wim 0:1116b0d151fc 7 */
wim 0:1116b0d151fc 8 #include "mbed.h"
wim 0:1116b0d151fc 9 #include "PCF8591.h"
wim 0:1116b0d151fc 10
wim 0:1116b0d151fc 11
wim 0:1116b0d151fc 12 /** Create a PCF8591 AD and DA object using a specified I2C bus and slaveaddress
wim 0:1116b0d151fc 13 *
wim 0:1116b0d151fc 14 * @param I2C &i2c the I2C port to connect to
wim 0:1116b0d151fc 15 * @param char deviceAddress the address of the PCF8591
wim 0:1116b0d151fc 16 */
wim 0:1116b0d151fc 17 PCF8591::PCF8591(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) {
wim 0:1116b0d151fc 18
wim 0:1116b0d151fc 19 _slaveAddress = deviceAddress;
wim 0:1116b0d151fc 20 _init();
wim 0:1116b0d151fc 21 }
wim 0:1116b0d151fc 22
wim 0:1116b0d151fc 23
wim 0:1116b0d151fc 24 #if(0)
wim 0:1116b0d151fc 25 //These methods are disabled since they interfere with normal expected behaviour for mbed type Analog I/O
wim 0:1116b0d151fc 26 //
wim 0:1116b0d151fc 27
wim 0:1116b0d151fc 28 /** Set ADC mode
wim 0:1116b0d151fc 29 *
wim 0:1116b0d151fc 30 * @param adc_mode ADC Channel mode, valid Range (PCF8591_4S, PCF8591_3D, PCF8591_2S_1D, PCF8591_2D)
wim 0:1116b0d151fc 31 */
wim 0:1116b0d151fc 32 void PCF8591::setADCMode(uint8_t mode){
wim 0:1116b0d151fc 33 uint8_t data[6];
wim 0:1116b0d151fc 34
wim 0:1116b0d151fc 35 _mode = _mode & ~PCF8591_2D; // Clear ADC mode bits
wim 0:1116b0d151fc 36
wim 0:1116b0d151fc 37 switch (mode) {
wim 0:1116b0d151fc 38 case PCF8591_4S:
wim 0:1116b0d151fc 39 _mode = _mode | PCF8591_4S;
wim 0:1116b0d151fc 40 break;
wim 0:1116b0d151fc 41 case PCF8591_3D:
wim 0:1116b0d151fc 42 _mode = _mode | PCF8591_3D;
wim 0:1116b0d151fc 43 break;
wim 0:1116b0d151fc 44 case PCF8591_2S_1D:
wim 0:1116b0d151fc 45 _mode = _mode | PCF8591_2S_1D;
wim 0:1116b0d151fc 46 break;
wim 0:1116b0d151fc 47 case PCF8591_2D:
wim 0:1116b0d151fc 48 _mode = _mode | PCF8591_2D;
wim 0:1116b0d151fc 49 break;
wim 0:1116b0d151fc 50 default:
wim 0:1116b0d151fc 51 _mode = _mode | PCF8591_4S;
wim 0:1116b0d151fc 52 break;
wim 0:1116b0d151fc 53 }
wim 0:1116b0d151fc 54
wim 0:1116b0d151fc 55 data[0] = _mode; // Control Reg
wim 0:1116b0d151fc 56
wim 0:1116b0d151fc 57 // write data to the device
wim 0:1116b0d151fc 58 _i2c->write(_slaveAddress, (char*) data, 1);
wim 0:1116b0d151fc 59
wim 0:1116b0d151fc 60 };
wim 0:1116b0d151fc 61
wim 0:1116b0d151fc 62 /** Set DAC mode
wim 0:1116b0d151fc 63 *
wim 0:1116b0d151fc 64 * @param dac_mode DAC Channel mode, valid Range (false=disable, true=enable)
wim 0:1116b0d151fc 65 */
wim 0:1116b0d151fc 66 void PCF8591::setDACMode(bool mode) {
wim 0:1116b0d151fc 67 uint8_t data[6];
wim 0:1116b0d151fc 68
wim 0:1116b0d151fc 69 if (mode)
wim 0:1116b0d151fc 70 _mode = _mode | PCF8591_AOUT; // Enable DAC output
wim 0:1116b0d151fc 71 else
wim 0:1116b0d151fc 72 _mode = _mode & ~PCF8591_AOUT; // Disable DAC output
wim 0:1116b0d151fc 73
wim 0:1116b0d151fc 74 data[0] = _mode; // Control Reg
wim 0:1116b0d151fc 75
wim 0:1116b0d151fc 76 // write data to the device
wim 0:1116b0d151fc 77 _i2c->write(_slaveAddress, (char*) data, 1);
wim 0:1116b0d151fc 78
wim 0:1116b0d151fc 79 };
wim 0:1116b0d151fc 80 #endif
wim 0:1116b0d151fc 81
wim 0:1116b0d151fc 82
wim 0:1116b0d151fc 83 /** Write Analog Output
wim 0:1116b0d151fc 84 *
wim 0:1116b0d151fc 85 * @param analogOut output value (0..255)
wim 0:1116b0d151fc 86 */
wim 0:1116b0d151fc 87 void PCF8591::write(uint8_t analogOut) {
wim 0:1116b0d151fc 88 uint8_t data[6];
wim 0:1116b0d151fc 89
wim 0:1116b0d151fc 90 data[0] = _mode; // Control Reg
wim 0:1116b0d151fc 91 data[1] = analogOut; // DAC Channel
wim 0:1116b0d151fc 92
wim 0:1116b0d151fc 93 // write data to the device
wim 0:1116b0d151fc 94 _i2c->write(_slaveAddress, (char*) data, 2);
wim 0:1116b0d151fc 95 };
wim 0:1116b0d151fc 96
wim 0:1116b0d151fc 97 /** Read Analog Channel
wim 0:1116b0d151fc 98 *
wim 0:1116b0d151fc 99 * @param Channel ADC channel, valid range PCF8591_ADC0, PCF8591_ADC1, PCF8591_ADC2 or PCF8591_ADC3
wim 0:1116b0d151fc 100 * @return value uint8_t AD converted value (0..255, representing 0V..Vcc)
wim 0:1116b0d151fc 101 */
wim 0:1116b0d151fc 102 #if(0)
wim 0:1116b0d151fc 103 // I2C block operations test
wim 0:1116b0d151fc 104 // Causes problems with Ticker and printf on LPC812. No issues found on LPC1768
wim 0:1116b0d151fc 105 uint8_t PCF8591::read(uint8_t channel) {
wim 0:1116b0d151fc 106 // uint8_t data[6];
wim 0:1116b0d151fc 107 uint8_t data[6] = {123,123,123,123,123,123}; //test to check failed read
wim 0:1116b0d151fc 108
wim 0:1116b0d151fc 109 _mode = _mode & ~PCF8591_CHMSK; // Clear ADC Channel bits
wim 0:1116b0d151fc 110 _mode = _mode | (channel & PCF8591_CHMSK); // Set ADC Channel bits
wim 0:1116b0d151fc 111
wim 0:1116b0d151fc 112 data[0] = _mode; // Init Control Reg
wim 0:1116b0d151fc 113
wim 0:1116b0d151fc 114 // write data to the device to select the ADC channel
wim 0:1116b0d151fc 115 _i2c->write(_slaveAddress, (char*) data, 1);
wim 0:1116b0d151fc 116
wim 0:1116b0d151fc 117 // read selected ADC channel
wim 0:1116b0d151fc 118 // note that first byte is a 'dummy' and should be ignored
wim 0:1116b0d151fc 119 _i2c->read(_slaveAddress, (char*) data, 2);
wim 0:1116b0d151fc 120 return data[1];
wim 0:1116b0d151fc 121 };
wim 0:1116b0d151fc 122
wim 0:1116b0d151fc 123 #else
wim 0:1116b0d151fc 124 // I2C single byte operations test
wim 0:1116b0d151fc 125 // No issues found on LPC812
wim 0:1116b0d151fc 126 uint8_t PCF8591::read(uint8_t channel) {
wim 0:1116b0d151fc 127 uint8_t data[6];
wim 0:1116b0d151fc 128 // uint8_t data[6] = {123,123,123,123,123,123}; //test to check failed read
wim 0:1116b0d151fc 129
wim 0:1116b0d151fc 130 _mode = _mode & ~PCF8591_CHMSK; // Clear ADC Channel bits
wim 0:1116b0d151fc 131 _mode = _mode | (channel & PCF8591_CHMSK); // Set ADC Channel bits
wim 0:1116b0d151fc 132
wim 0:1116b0d151fc 133 data[0] = _mode; // Init Control Reg
wim 0:1116b0d151fc 134
wim 0:1116b0d151fc 135 // write data to the device to select the ADC channel
wim 0:1116b0d151fc 136 _i2c->start();
wim 0:1116b0d151fc 137 _i2c->write(_slaveAddress); // Slave write address
wim 0:1116b0d151fc 138 _i2c->write(data[0]);
wim 0:1116b0d151fc 139 _i2c->stop();
wim 0:1116b0d151fc 140
wim 0:1116b0d151fc 141 // read selected ADC channel
wim 0:1116b0d151fc 142 // note that first byte is a 'dummy' and should be ignored
wim 0:1116b0d151fc 143 _i2c->start();
wim 0:1116b0d151fc 144 _i2c->write(_slaveAddress | 0x01); // Slave read address
wim 0:1116b0d151fc 145 data[0]=_i2c->read(1); //ack
wim 0:1116b0d151fc 146 data[1]=_i2c->read(0); //nack
wim 0:1116b0d151fc 147 _i2c->stop();
wim 0:1116b0d151fc 148
wim 0:1116b0d151fc 149 return data[1];
wim 0:1116b0d151fc 150 };
wim 0:1116b0d151fc 151
wim 0:1116b0d151fc 152 #endif
wim 0:1116b0d151fc 153
wim 0:1116b0d151fc 154
wim 0:1116b0d151fc 155 /** Initialise AD and DA driver
wim 0:1116b0d151fc 156 *
wim 0:1116b0d151fc 157 */
wim 0:1116b0d151fc 158 void PCF8591::_init() {
wim 0:1116b0d151fc 159 uint8_t data[6];
wim 0:1116b0d151fc 160
wim 0:1116b0d151fc 161 _mode = PCF8591_CTRL_DEF; // Init mode
wim 0:1116b0d151fc 162
wim 0:1116b0d151fc 163 data[0] = _mode; // Init Control Reg
wim 0:1116b0d151fc 164 data[1] = 0x00; // Init DAC Channel to 0
wim 0:1116b0d151fc 165
wim 0:1116b0d151fc 166 // write data to the device
wim 0:1116b0d151fc 167 _i2c->write(_slaveAddress, (char*) data, 2);
wim 0:1116b0d151fc 168 };
wim 0:1116b0d151fc 169
wim 0:1116b0d151fc 170
wim 0:1116b0d151fc 171
wim 0:1116b0d151fc 172
wim 0:1116b0d151fc 173
wim 0:1116b0d151fc 174 /** Create a PCF8591 AnalogOut object connected to the specified I2C bus and deviceAddress
wim 0:1116b0d151fc 175 *
wim 0:1116b0d151fc 176 */
wim 0:1116b0d151fc 177 PCF8591_AnalogOut::PCF8591_AnalogOut(I2C *i2c, uint8_t deviceAddress) : _i2c(i2c) {
wim 0:1116b0d151fc 178
wim 0:1116b0d151fc 179 _slaveAddress = deviceAddress;
wim 0:1116b0d151fc 180 _init();
wim 0:1116b0d151fc 181 }
wim 0:1116b0d151fc 182
wim 0:1116b0d151fc 183
wim 0:1116b0d151fc 184 /** Write Analog Output
wim 0:1116b0d151fc 185 *
wim 0:1116b0d151fc 186 * @param analogOut value (0 .. 1.0)
wim 0:1116b0d151fc 187 */
wim 0:1116b0d151fc 188 void PCF8591_AnalogOut::write(float analogOut) {
wim 0:1116b0d151fc 189 uint8_t data[6];
wim 0:1116b0d151fc 190
wim 0:1116b0d151fc 191 data[0] = _mode; // Control Reg
wim 0:1116b0d151fc 192
wim 0:1116b0d151fc 193 // DAC Channel
wim 0:1116b0d151fc 194 if (analogOut < 0.0) data[1] = 0;
wim 0:1116b0d151fc 195 else if (analogOut >= 1.0) data[1] = 255;
wim 0:1116b0d151fc 196 else data[1] = uint8_t (analogOut * 255.0);
wim 0:1116b0d151fc 197
wim 0:1116b0d151fc 198 // write data to the device
wim 0:1116b0d151fc 199 _i2c->write(_slaveAddress, (char*) data, 2);
wim 0:1116b0d151fc 200 };
wim 0:1116b0d151fc 201
wim 0:1116b0d151fc 202 /** Operator = Analog Output
wim 0:1116b0d151fc 203 *
wim 0:1116b0d151fc 204 * @param analogOut value (0.0f .. 1.0f)
wim 0:1116b0d151fc 205 */
wim 0:1116b0d151fc 206 PCF8591_AnalogOut& PCF8591_AnalogOut::operator= (float value){
wim 0:1116b0d151fc 207 write(value);
wim 0:1116b0d151fc 208 return *this;
wim 0:1116b0d151fc 209 }
wim 0:1116b0d151fc 210
wim 0:1116b0d151fc 211
wim 0:1116b0d151fc 212 /** Initialise DAC driver
wim 0:1116b0d151fc 213 *
wim 0:1116b0d151fc 214 */
wim 0:1116b0d151fc 215 void PCF8591_AnalogOut::_init() {
wim 0:1116b0d151fc 216 uint8_t data[6];
wim 0:1116b0d151fc 217
wim 0:1116b0d151fc 218 _mode = PCF8591_CTRL_DEF; // Init mode
wim 0:1116b0d151fc 219
wim 0:1116b0d151fc 220 data[0] = _mode; // Init Control Reg
wim 0:1116b0d151fc 221 data[1] = 0x00; // Init DAC Channel to 0
wim 0:1116b0d151fc 222
wim 0:1116b0d151fc 223 // write data to the device
wim 0:1116b0d151fc 224 _i2c->write(_slaveAddress, (char*) data, 2);
wim 0:1116b0d151fc 225 };
wim 0:1116b0d151fc 226
wim 0:1116b0d151fc 227
wim 0:1116b0d151fc 228
wim 0:1116b0d151fc 229 /** Create a PCF8591 AnalogIn object connected to the specified I2C bus and deviceAddress
wim 0:1116b0d151fc 230 *
wim 0:1116b0d151fc 231 */
wim 0:1116b0d151fc 232 PCF8591_AnalogIn::PCF8591_AnalogIn(I2C *i2c, uint8_t channel, uint8_t deviceAddress) : _i2c(i2c) {
wim 0:1116b0d151fc 233
wim 0:1116b0d151fc 234 _slaveAddress = deviceAddress;
wim 0:1116b0d151fc 235 _channel = channel;
wim 0:1116b0d151fc 236 _init();
wim 0:1116b0d151fc 237 }
wim 0:1116b0d151fc 238
wim 0:1116b0d151fc 239
wim 0:1116b0d151fc 240 /** Read Analog input
wim 0:1116b0d151fc 241 *
wim 0:1116b0d151fc 242 * @return analogIn value (0 .. 1.0)
wim 0:1116b0d151fc 243 */
wim 0:1116b0d151fc 244 float PCF8591_AnalogIn::read() {
wim 0:1116b0d151fc 245 uint8_t data[6];
wim 0:1116b0d151fc 246
wim 0:1116b0d151fc 247 data[0] = _mode; // Init Control Reg
wim 0:1116b0d151fc 248
wim 0:1116b0d151fc 249 // write data to the device to select the ADC channel
wim 0:1116b0d151fc 250 _i2c->start();
wim 0:1116b0d151fc 251 _i2c->write(_slaveAddress); // Slave write address
wim 0:1116b0d151fc 252 _i2c->write(data[0]);
wim 0:1116b0d151fc 253 _i2c->stop();
wim 0:1116b0d151fc 254
wim 0:1116b0d151fc 255 // read selected ADC channel
wim 0:1116b0d151fc 256 // note that first byte is a 'dummy' and should be ignored
wim 0:1116b0d151fc 257 _i2c->start();
wim 0:1116b0d151fc 258 _i2c->write(_slaveAddress | 0x01); // Slave read address
wim 0:1116b0d151fc 259 data[0]=_i2c->read(1); //ack
wim 0:1116b0d151fc 260 data[1]=_i2c->read(0); //nack
wim 0:1116b0d151fc 261 _i2c->stop();
wim 0:1116b0d151fc 262
wim 0:1116b0d151fc 263
wim 0:1116b0d151fc 264 // ADC Channel
wim 0:1116b0d151fc 265 return ((float) data[1] / 255.0);
wim 0:1116b0d151fc 266
wim 0:1116b0d151fc 267 };
wim 0:1116b0d151fc 268
wim 0:1116b0d151fc 269
wim 0:1116b0d151fc 270 /** Operator float Analog Input
wim 0:1116b0d151fc 271 *
wim 0:1116b0d151fc 272 * @return analogIn value (0 .. 1.0)
wim 0:1116b0d151fc 273 */
wim 0:1116b0d151fc 274 PCF8591_AnalogIn::operator float(){
wim 0:1116b0d151fc 275 return (read());
wim 0:1116b0d151fc 276 }
wim 0:1116b0d151fc 277
wim 0:1116b0d151fc 278
wim 0:1116b0d151fc 279 /** Initialise ADC driver
wim 0:1116b0d151fc 280 *
wim 0:1116b0d151fc 281 */
wim 0:1116b0d151fc 282 void PCF8591_AnalogIn::_init() {
wim 0:1116b0d151fc 283 uint8_t data[6];
wim 0:1116b0d151fc 284
wim 0:1116b0d151fc 285 _mode = PCF8591_CTRL_DEF; // Init mode
wim 0:1116b0d151fc 286 _mode = _mode & ~PCF8591_CHMSK; // Clear ADC Channel bits
wim 0:1116b0d151fc 287 _mode = _mode | (_channel & PCF8591_CHMSK); // Set ADC Channel bits
wim 0:1116b0d151fc 288
wim 0:1116b0d151fc 289 data[0] = _mode; // Init Control Reg
wim 0:1116b0d151fc 290
wim 0:1116b0d151fc 291 // write data to the device
wim 0:1116b0d151fc 292 _i2c->write(_slaveAddress, (char*) data, 1);
wim 0:1116b0d151fc 293 };