Yann Garcia / MCP320x_SPI

Dependents:   MCP320xApp

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers MCP320x_SPI.cpp Source File

MCP320x_SPI.cpp

00001 /* mbed simplified access to Microchip 12 bits ADC devices (SPI)
00002  * Copyright (c) 2013 ygarcia, MIT License
00003  *
00004  * Permission is hereby granted, free of charge, to any person obtaining a copy of this software 
00005  * and associated documentation files (the "Software"), to deal in the Software without restriction, 
00006  * including without limitation the rights to use, copy, modify, merge, publish, distribute, 
00007  * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 
00008  * furnished to do so, subject to the following conditions:
00009  *
00010  * The above copyright notice and this permission notice shall be included in all copies or 
00011  * substantial portions of the Software.
00012  *
00013  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 
00014  * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 
00015  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 
00016  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 
00017  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
00018  */
00019 
00020 #include "MCP320x_SPI.h"
00021 
00022 namespace MCP320x_SPI {
00023 
00024     unsigned char CMCP320x_SPI::SPIModuleRefCounter = 0;
00025 
00026     CMCP320x_SPI::CMCP320x_SPI(const PinName p_mosi, const PinName p_miso, const PinName p_sclk, const PinName p_cs, const Mcp320xFamilly p_familly, const unsigned int p_frequency) : _internalId("") {
00027         DEBUG_ENTER("CMCP320x_SPI")
00028         
00029         CMCP320x_SPI::SPIModuleRefCounter += 1;
00030         if (CMCP320x_SPI::SPIModuleRefCounter > 1) {
00031             //FIXME Check that SPI settings are identical. Otherwise it should failed
00032             return;
00033         }
00034 
00035         _familly = p_familly;
00036         switch (_familly) {
00037             case _3201:
00038                 _channelsNum = 1;
00039                 break;
00040             case _3204:
00041                 _channelsNum = 4;
00042                 break;
00043             default: // _3208
00044                 _channelsNum = 8;
00045         } // End of 'switch' statement
00046         _settings = 0x02; // SGL/DIFF bit set to 1 = See DS21298E-page 19 TABLE 5-1: CONFIGURATION BITS FOR THE MCP3204/TABLE 5-2: CONFIGURATION BITS FOR THE MCP3208
00047         DEBUG("CMCP320x_SPI: familly:%d - #channels:%d", _familly, _channelsNum)
00048         _spiInstance = new SPI(p_mosi, p_miso, p_sclk);
00049         _spiInstance->frequency(p_frequency); // Set the frequency of the SPI interface
00050         _spiInstance->format(8, 3);
00051         DEBUG_ENTER("CMCP320x_SPI: refCounter=%d", CMCP320x_SPI::SPIModuleRefCounter)
00052 
00053         if (p_cs != NC) {
00054             DEBUG("CMCP320x_SPI: /CS managed");
00055             _cs = new DigitalOut(p_cs);
00056             _cs->write(1); // Disable chip
00057         } else {
00058             DEBUG("CMCP320x_SPI: /CS not managed");
00059             _cs = NULL; // Not used
00060         }
00061     
00062    
00063         DEBUG_LEAVE("CMCP320x_SPI")
00064     }
00065     
00066     CMCP320x_SPI::~CMCP320x_SPI() {
00067         DEBUG_ENTER("~CMCP320x_SPI")
00068     
00069         // Release I2C instance
00070         DEBUG_ENTER("~CMCP320x_SPI: refCounter=%d", CMCP320x_SPI::SPIModuleRefCounter)
00071         CMCP320x_SPI::SPIModuleRefCounter -= 1;
00072         if (CMCP320x_SPI::SPIModuleRefCounter == 0) {
00073             delete _spiInstance;
00074             _spiInstance = NULL;
00075         }
00076         // Release _reset if required
00077         if (_cs != NULL) {
00078             _cs->write(1);
00079             delete _cs;
00080         }
00081    
00082         DEBUG_LEAVE("~CMCP320x_SPI")
00083     }
00084 
00085     float CMCP320x_SPI::Read(const Mcp320xChannels p_channels) {
00086         DEBUG_ENTER("CMCP320x_SPI::Read: %d", (unsigned char)p_channels)
00087         
00088         // Read a sample
00089         _sample.value = 0x00;
00090         switch (_familly) {
00091             case _3204:
00092                 // No break;
00093             case _3208:
00094                 Read_320x(p_channels);
00095                 break;
00096             default: // _3201
00097                 Read_3201();
00098                 break;
00099         } // End of 'switch' statement 
00100         DEBUG("CMCP320x_SPI::Read: 0x%02x - 0x%02x", _sample.bytes[0], _sample.bytes[1])
00101         // Convert it
00102         float temp;
00103         _sample.value >>= 1; // Adjust composite integer for 12 valid bits
00104         _sample.value &= 0x0FFF; // Mask out upper nibble of integer
00105         temp = (_sample.value * 0.001225585);
00106         
00107         DEBUG_LEAVE("CMCP320x_SPI::Read: %f", temp)
00108         return temp;        
00109     }
00110     
00111     void CMCP320x_SPI::SetConfig(const bool p_settings) {
00112         DEBUG_LEAVE("CMCP320x_SPI::SetConfig: %x", (unsigned char)p_settings)
00113         
00114         if (_settings) {
00115             _settings = 0x02;
00116         } else {
00117             _settings = 0x00;
00118         }
00119     }
00120     
00121     bool CMCP320x_SPI::Shutdown(const bool p_shutdown) {
00122         // Sanity check
00123         if (_cs == NULL) {
00124             return false;
00125         }
00126         
00127         _cs->write(p_shutdown == false ? 0 : 1);
00128         
00129         return true;
00130     }
00131     
00132     void CMCP320x_SPI::Read_3201() {
00133         if (_cs != NULL) {
00134             _cs->write(0);
00135             wait_us(1);
00136         }
00137         _sample.bytes[1] = _spiInstance->write(0);
00138         _sample.bytes[0] = _spiInstance->write(0);
00139         if (_cs != NULL) {
00140             _cs->write(1);
00141         }    
00142     }
00143 
00144     void CMCP320x_SPI::Read_320x(const Mcp320xChannels p_channels) {
00145         DEBUG_ENTER("CMCP320x_SPI::Read_320x: %d", (unsigned char)p_channels)
00146         
00147         unsigned char _channels = (unsigned char)p_channels % _channelsNum;
00148         // Set start bit 
00149         unsigned char mask = 0x04 | _settings; // Start bit set to 1 - See DS21298E-page 19 Clause 5.0 SERIAL COMMUNICATIONS
00150         // Set channel address
00151         unsigned char cmd0;
00152         unsigned char cmd1;
00153         if (_familly == _3204) {
00154             cmd0 = mask;
00155             cmd1 = _channels << 6; // MCP3204 has 4 channels in single-ended mode
00156         } else { // MCP3208
00157             cmd0 = mask | ((_channels & 0x04) >> 2); // Extract D2 bit - See DS21298E-page 19 Clause 5.0 SERIAL COMMUNICATIONS
00158             cmd1 = _channels << 6; // MCP3204 has 8 channels in single-ended mode
00159         }
00160         DEBUG("CMCP320x_SPI::Read_320x: cmd0:%02x - cmd1:%02x", cmd0, cmd1)
00161         if (_cs != NULL) {
00162             _cs->write(0);
00163             wait_us(1);
00164         }
00165         _spiInstance->write(cmd0); // Don't care of the result - See DS21298E-page 21 Clause 6.1 Using the MCP3204/3208 with Microcontroller (MCU) SPI Ports
00166         _sample.bytes[1] = _spiInstance->write(cmd1); // DS21298E-page 21 See FIGURE 6-1: SPI Communication using 8-bit segments (Mode 0,0: SCLK idles low)
00167         _sample.bytes[0] = _spiInstance->write(0);
00168         if (_cs != NULL) {
00169             _cs->write(1);
00170         }
00171             
00172         DEBUG_LEAVE("CMCP320x_SPI::Read_320x")
00173     }
00174     
00175 } // End of namespace MCP320x_SPI