Microchip MCP342x ADC library
mcp342x.cpp@4:9480edf3926d, 2018-09-10 (annotated)
- Committer:
- SomeRandomBloke
- Date:
- Mon Sep 10 17:02:22 2018 +0000
- Revision:
- 4:9480edf3926d
- Parent:
- 3:03911aa07029
- Child:
- 5:0ca445d2d2bc
Updates to add end of conversion checking
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
antoniogonzalez | 0:7dbf7356da6b | 1 | #include "mcp342x.h" |
antoniogonzalez | 0:7dbf7356da6b | 2 | |
antoniogonzalez | 0:7dbf7356da6b | 3 | #define LEN_ONE_BYTE 1 |
SomeRandomBloke | 4:9480edf3926d | 4 | extern Serial pc; |
antoniogonzalez | 0:7dbf7356da6b | 5 | |
antoniogonzalez | 0:7dbf7356da6b | 6 | MCP342x::MCP342x(I2C *i2c, uint8_t device_address) |
antoniogonzalez | 0:7dbf7356da6b | 7 | { |
antoniogonzalez | 1:c4da9889ff85 | 8 | _i2c = i2c; |
antoniogonzalez | 1:c4da9889ff85 | 9 | |
antoniogonzalez | 0:7dbf7356da6b | 10 | // The address byte is the device code (4 bits, hardcoded in |
antoniogonzalez | 0:7dbf7356da6b | 11 | // factory) and the device address (3 bits). These are shifted one |
antoniogonzalez | 0:7dbf7356da6b | 12 | // bit to the left because mbed uses 8-bit addresses. |
antoniogonzalez | 0:7dbf7356da6b | 13 | _address = (_device_code << 4) | (device_address << 1); |
antoniogonzalez | 1:c4da9889ff85 | 14 | |
antoniogonzalez | 1:c4da9889ff85 | 15 | // Initialise to default settings: channel 1, gain 1x, 12 bits. |
antoniogonzalez | 1:c4da9889ff85 | 16 | // It is necessary to do this to ensure that the variables |
antoniogonzalez | 1:c4da9889ff85 | 17 | // _resolution and _pga are properly set. |
SomeRandomBloke | 4:9480edf3926d | 18 | _configuration = 0x10; // Continuous mode |
antoniogonzalez | 0:7dbf7356da6b | 19 | set_channel(CHANNEL_1); |
antoniogonzalez | 0:7dbf7356da6b | 20 | set_resolution(RESOLUTION_12); |
antoniogonzalez | 0:7dbf7356da6b | 21 | set_pga(PGA_1); |
antoniogonzalez | 0:7dbf7356da6b | 22 | } |
antoniogonzalez | 0:7dbf7356da6b | 23 | |
antoniogonzalez | 0:7dbf7356da6b | 24 | void MCP342x::set_channel(mcp342x_channel_t channel) |
antoniogonzalez | 0:7dbf7356da6b | 25 | { |
antoniogonzalez | 1:c4da9889ff85 | 26 | _configuration &= REG_CHANNEL_Clear; |
antoniogonzalez | 1:c4da9889ff85 | 27 | _configuration |= channel << REG_CHANNEL_Pos; |
antoniogonzalez | 0:7dbf7356da6b | 28 | _write_configuration(); |
antoniogonzalez | 0:7dbf7356da6b | 29 | } |
antoniogonzalez | 0:7dbf7356da6b | 30 | |
antoniogonzalez | 0:7dbf7356da6b | 31 | void MCP342x::set_conversion_mode(mcp342x_conversion_mode_t mode) |
antoniogonzalez | 0:7dbf7356da6b | 32 | { |
antoniogonzalez | 1:c4da9889ff85 | 33 | _configuration &= REG_MODE_Clear; |
antoniogonzalez | 1:c4da9889ff85 | 34 | _configuration |= mode << REG_MODE_Pos; |
antoniogonzalez | 0:7dbf7356da6b | 35 | _write_configuration(); |
antoniogonzalez | 0:7dbf7356da6b | 36 | } |
antoniogonzalez | 0:7dbf7356da6b | 37 | |
antoniogonzalez | 0:7dbf7356da6b | 38 | void MCP342x::set_resolution(mcp342x_resolution_t resolution) |
antoniogonzalez | 0:7dbf7356da6b | 39 | { |
antoniogonzalez | 1:c4da9889ff85 | 40 | _resolution = resolution; |
antoniogonzalez | 1:c4da9889ff85 | 41 | |
antoniogonzalez | 1:c4da9889ff85 | 42 | // _lsb and _max_code are variables required for converting the ADC |
antoniogonzalez | 1:c4da9889ff85 | 43 | // data into volts; see Section 4.9 of the MCP342x datasheet. Their |
antoniogonzalez | 1:c4da9889ff85 | 44 | // value depends on the resolution chosen, so it is useful to |
antoniogonzalez | 1:c4da9889ff85 | 45 | // calculate these values here, whenever the resolution setting is |
antoniogonzalez | 1:c4da9889ff85 | 46 | // changed. |
antoniogonzalez | 1:c4da9889ff85 | 47 | // |
antoniogonzalez | 1:c4da9889ff85 | 48 | // _lsb is the magnitude (in volts) of the last significant byte, |
antoniogonzalez | 1:c4da9889ff85 | 49 | // and it is calculated as 2 * 2.048 / (2^N), where N is the |
antoniogonzalez | 1:c4da9889ff85 | 50 | // resolution (datasheet Eq. 4-3). |
antoniogonzalez | 1:c4da9889ff85 | 51 | // |
antoniogonzalez | 1:c4da9889ff85 | 52 | // _max_code is the maximum output code, and it is equal to |
antoniogonzalez | 1:c4da9889ff85 | 53 | // 2^(N-1) - 1 (datasheet Table 4-3). |
SomeRandomBloke | 4:9480edf3926d | 54 | switch(_resolution) { |
antoniogonzalez | 0:7dbf7356da6b | 55 | case RESOLUTION_12: |
antoniogonzalez | 1:c4da9889ff85 | 56 | _lsb = 2 * 2.048 / 4096; |
antoniogonzalez | 1:c4da9889ff85 | 57 | _max_code = 2047; |
antoniogonzalez | 0:7dbf7356da6b | 58 | break; |
antoniogonzalez | 0:7dbf7356da6b | 59 | case RESOLUTION_14: |
antoniogonzalez | 1:c4da9889ff85 | 60 | _lsb = 2 * 2.048 / 16384; |
antoniogonzalez | 1:c4da9889ff85 | 61 | _max_code = 8191; |
antoniogonzalez | 0:7dbf7356da6b | 62 | break; |
antoniogonzalez | 0:7dbf7356da6b | 63 | case RESOLUTION_16: |
antoniogonzalez | 1:c4da9889ff85 | 64 | _lsb = 2 * 2.048 / 65536; |
antoniogonzalez | 1:c4da9889ff85 | 65 | _max_code = 32767; |
antoniogonzalez | 0:7dbf7356da6b | 66 | break; |
antoniogonzalez | 0:7dbf7356da6b | 67 | case RESOLUTION_18: |
antoniogonzalez | 1:c4da9889ff85 | 68 | _lsb = 2 * 2.048 / 262144; |
antoniogonzalez | 1:c4da9889ff85 | 69 | _max_code = 131071; |
antoniogonzalez | 0:7dbf7356da6b | 70 | break; |
antoniogonzalez | 1:c4da9889ff85 | 71 | } |
antoniogonzalez | 1:c4da9889ff85 | 72 | |
antoniogonzalez | 1:c4da9889ff85 | 73 | _configuration &= REG_RESOLUTION_Clear; |
antoniogonzalez | 1:c4da9889ff85 | 74 | _configuration |= _resolution << REG_RESOLUTION_Pos; |
antoniogonzalez | 0:7dbf7356da6b | 75 | _write_configuration(); |
antoniogonzalez | 0:7dbf7356da6b | 76 | } |
antoniogonzalez | 0:7dbf7356da6b | 77 | |
antoniogonzalez | 0:7dbf7356da6b | 78 | void MCP342x::set_pga(mcp342x_pga_t pga) |
antoniogonzalez | 0:7dbf7356da6b | 79 | { |
antoniogonzalez | 1:c4da9889ff85 | 80 | // The gain value (1, 2, 4 or 8) is required for converting digital |
antoniogonzalez | 1:c4da9889ff85 | 81 | // output codes to voltage. For this purpose the actual PGA value is |
antoniogonzalez | 1:c4da9889ff85 | 82 | // kept in the variable _pga, instead of keeping the *position* in |
antoniogonzalez | 1:c4da9889ff85 | 83 | // the register of PGA, which is what the variable type |
antoniogonzalez | 1:c4da9889ff85 | 84 | // mcp342x_pga_t represents. |
antoniogonzalez | 1:c4da9889ff85 | 85 | switch (pga) { |
antoniogonzalez | 0:7dbf7356da6b | 86 | case PGA_1: |
antoniogonzalez | 0:7dbf7356da6b | 87 | _pga = 1; |
antoniogonzalez | 0:7dbf7356da6b | 88 | break; |
antoniogonzalez | 0:7dbf7356da6b | 89 | case PGA_2: |
antoniogonzalez | 0:7dbf7356da6b | 90 | _pga = 2; |
antoniogonzalez | 0:7dbf7356da6b | 91 | break; |
antoniogonzalez | 0:7dbf7356da6b | 92 | case PGA_4: |
antoniogonzalez | 0:7dbf7356da6b | 93 | _pga = 4; |
antoniogonzalez | 0:7dbf7356da6b | 94 | break; |
antoniogonzalez | 0:7dbf7356da6b | 95 | case PGA_8: |
antoniogonzalez | 0:7dbf7356da6b | 96 | _pga = 8; |
antoniogonzalez | 0:7dbf7356da6b | 97 | break; |
antoniogonzalez | 1:c4da9889ff85 | 98 | } |
antoniogonzalez | 1:c4da9889ff85 | 99 | |
antoniogonzalez | 1:c4da9889ff85 | 100 | _configuration &= REG_PGA_Clear; |
antoniogonzalez | 1:c4da9889ff85 | 101 | _configuration |= pga << REG_PGA_Pos; |
antoniogonzalez | 0:7dbf7356da6b | 102 | _write_configuration(); |
antoniogonzalez | 0:7dbf7356da6b | 103 | } |
antoniogonzalez | 0:7dbf7356da6b | 104 | |
antoniogonzalez | 0:7dbf7356da6b | 105 | void MCP342x::_write_configuration() |
antoniogonzalez | 0:7dbf7356da6b | 106 | { |
SomeRandomBloke | 4:9480edf3926d | 107 | // pc.printf("MCP3424 config %0X\r\n", _configuration ); |
antoniogonzalez | 1:c4da9889ff85 | 108 | _i2c_command[0] = _configuration; |
antoniogonzalez | 1:c4da9889ff85 | 109 | _i2c->write(_address, _i2c_command, LEN_ONE_BYTE); |
antoniogonzalez | 0:7dbf7356da6b | 110 | } |
antoniogonzalez | 0:7dbf7356da6b | 111 | |
SomeRandomBloke | 4:9480edf3926d | 112 | uint8_t MCP342x::read_configuration() |
SomeRandomBloke | 4:9480edf3926d | 113 | { |
SomeRandomBloke | 4:9480edf3926d | 114 | // pc.printf("MCP3424 config %0X\r\n", _configuration ); |
SomeRandomBloke | 4:9480edf3926d | 115 | _i2c_command[0] = _configuration; |
SomeRandomBloke | 4:9480edf3926d | 116 | _i2c->read(_address, _i2c_command, LEN_ONE_BYTE); |
SomeRandomBloke | 4:9480edf3926d | 117 | return _i2c_command[0]; |
SomeRandomBloke | 4:9480edf3926d | 118 | } |
SomeRandomBloke | 4:9480edf3926d | 119 | |
SomeRandomBloke | 4:9480edf3926d | 120 | void MCP342x::_startRead() |
SomeRandomBloke | 4:9480edf3926d | 121 | { |
SomeRandomBloke | 4:9480edf3926d | 122 | _i2c_command[0] = _configuration | 0x80; |
SomeRandomBloke | 4:9480edf3926d | 123 | _i2c->write(_address, _i2c_command, LEN_ONE_BYTE); |
SomeRandomBloke | 4:9480edf3926d | 124 | } |
SomeRandomBloke | 4:9480edf3926d | 125 | |
antoniogonzalez | 1:c4da9889ff85 | 126 | uint32_t MCP342x::read() |
antoniogonzalez | 0:7dbf7356da6b | 127 | { |
antoniogonzalez | 1:c4da9889ff85 | 128 | uint32_t adc_value = 0; |
SomeRandomBloke | 4:9480edf3926d | 129 | uint8_t readConfig = 0; |
SomeRandomBloke | 4:9480edf3926d | 130 | int byteNum = 3; |
SomeRandomBloke | 4:9480edf3926d | 131 | |
SomeRandomBloke | 4:9480edf3926d | 132 | if( (_configuration & 0x10) == 0 ) |
SomeRandomBloke | 4:9480edf3926d | 133 | _startRead(); |
SomeRandomBloke | 4:9480edf3926d | 134 | |
SomeRandomBloke | 4:9480edf3926d | 135 | // Read config register |
SomeRandomBloke | 4:9480edf3926d | 136 | if (_resolution == RESOLUTION_18 ) { |
SomeRandomBloke | 4:9480edf3926d | 137 | byteNum = 4; |
SomeRandomBloke | 4:9480edf3926d | 138 | } |
SomeRandomBloke | 4:9480edf3926d | 139 | |
SomeRandomBloke | 4:9480edf3926d | 140 | _i2c->read(_address, _i2c_command, byteNum); |
SomeRandomBloke | 4:9480edf3926d | 141 | |
SomeRandomBloke | 4:9480edf3926d | 142 | while( (_i2c_command[byteNum-1] & 0x80) == 0x80 ) { |
SomeRandomBloke | 4:9480edf3926d | 143 | wait_ms(10); |
SomeRandomBloke | 4:9480edf3926d | 144 | // pc.printf("MCP3424 config %0X %0X %0X %0X\r\n", _i2c_command[0],_i2c_command[1],_i2c_command[2],_i2c_command[3] ); |
SomeRandomBloke | 4:9480edf3926d | 145 | _i2c->read(_address, _i2c_command, byteNum); |
SomeRandomBloke | 4:9480edf3926d | 146 | } |
SomeRandomBloke | 4:9480edf3926d | 147 | |
antoniogonzalez | 0:7dbf7356da6b | 148 | |
antoniogonzalez | 0:7dbf7356da6b | 149 | switch (_resolution) { |
antoniogonzalez | 1:c4da9889ff85 | 150 | case RESOLUTION_12: |
antoniogonzalez | 1:c4da9889ff85 | 151 | adc_value = (_i2c_command[0] << 8) | _i2c_command[1]; |
antoniogonzalez | 0:7dbf7356da6b | 152 | adc_value &= 0xfff; |
antoniogonzalez | 0:7dbf7356da6b | 153 | break; |
antoniogonzalez | 0:7dbf7356da6b | 154 | |
antoniogonzalez | 1:c4da9889ff85 | 155 | case RESOLUTION_14: |
antoniogonzalez | 1:c4da9889ff85 | 156 | adc_value = (_i2c_command[0] << 8) | _i2c_command[1]; |
antoniogonzalez | 0:7dbf7356da6b | 157 | adc_value &= 0x3fff; |
antoniogonzalez | 0:7dbf7356da6b | 158 | break; |
antoniogonzalez | 0:7dbf7356da6b | 159 | |
antoniogonzalez | 1:c4da9889ff85 | 160 | case RESOLUTION_16: |
antoniogonzalez | 1:c4da9889ff85 | 161 | adc_value = (_i2c_command[0] << 8) | _i2c_command[1]; |
antoniogonzalez | 0:7dbf7356da6b | 162 | adc_value &= 0xffff; |
antoniogonzalez | 0:7dbf7356da6b | 163 | break; |
antoniogonzalez | 0:7dbf7356da6b | 164 | |
antoniogonzalez | 1:c4da9889ff85 | 165 | case RESOLUTION_18: |
antoniogonzalez | 1:c4da9889ff85 | 166 | adc_value = (_i2c_command[0] << 16) | |
SomeRandomBloke | 4:9480edf3926d | 167 | (_i2c_command[1] << 8) | _i2c_command[2]; |
antoniogonzalez | 0:7dbf7356da6b | 168 | adc_value &= 0x3ffff; |
antoniogonzalez | 0:7dbf7356da6b | 169 | break; |
antoniogonzalez | 0:7dbf7356da6b | 170 | } |
antoniogonzalez | 0:7dbf7356da6b | 171 | return adc_value; |
antoniogonzalez | 0:7dbf7356da6b | 172 | } |
antoniogonzalez | 1:c4da9889ff85 | 173 | |
SomeRandomBloke | 4:9480edf3926d | 174 | float MCP342x::read_volts() |
SomeRandomBloke | 4:9480edf3926d | 175 | { |
antoniogonzalez | 1:c4da9889ff85 | 176 | float volts = 0.0; |
antoniogonzalez | 1:c4da9889ff85 | 177 | uint32_t adc_value = read(); |
antoniogonzalez | 1:c4da9889ff85 | 178 | |
antoniogonzalez | 1:c4da9889ff85 | 179 | // The digital output of the MCP342x is in two's complement format; |
antoniogonzalez | 1:c4da9889ff85 | 180 | // see datasheet Section 4.9. This 'if... else' construction |
antoniogonzalez | 1:c4da9889ff85 | 181 | // determines whether the digital code is negative or positive; if |
antoniogonzalez | 3:03911aa07029 | 182 | // it is the former, its two's complement is calculated. |
antoniogonzalez | 1:c4da9889ff85 | 183 | if (adc_value > _max_code) { |
antoniogonzalez | 1:c4da9889ff85 | 184 | // if the output code is negative... |
antoniogonzalez | 1:c4da9889ff85 | 185 | volts = (~adc_value & _max_code) + 1; |
antoniogonzalez | 1:c4da9889ff85 | 186 | volts *= -1; |
antoniogonzalez | 1:c4da9889ff85 | 187 | } else { |
antoniogonzalez | 1:c4da9889ff85 | 188 | // if the output code is positive... |
antoniogonzalez | 1:c4da9889ff85 | 189 | volts = (float)adc_value; |
antoniogonzalez | 1:c4da9889ff85 | 190 | } |
antoniogonzalez | 1:c4da9889ff85 | 191 | |
antoniogonzalez | 1:c4da9889ff85 | 192 | // The actual voltage is proportional to the resolution and PGA |
antoniogonzalez | 1:c4da9889ff85 | 193 | // settings. This equation corresponds to Equation 4-4 in the |
antoniogonzalez | 1:c4da9889ff85 | 194 | // datasheet. The variables _lsb and _pga are calculated whenever |
antoniogonzalez | 1:c4da9889ff85 | 195 | // the user changes the resolution or PGA parameters. |
antoniogonzalez | 1:c4da9889ff85 | 196 | return volts * _lsb / _pga; |
antoniogonzalez | 1:c4da9889ff85 | 197 | } |