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