max31855: add sensor and documentation on creation of a UPM sensor
authorBrendan Le Foll <brendan.le.foll@intel.com>
Fri, 13 Jun 2014 15:44:48 +0000 (16:44 +0100)
committerBrendan Le Foll <brendan.le.foll@intel.com>
Fri, 13 Jun 2014 15:45:55 +0000 (16:45 +0100)
Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
Doxyfile.in
docs/max31855.md [new file with mode: 0644]
docs/porting.md
examples/CMakeLists.txt
examples/max31855.cxx [new file with mode: 0644]
src/max31855/CMakeLists.txt [new file with mode: 0644]
src/max31855/jsupm_max31855.i [new file with mode: 0644]
src/max31855/max31855.cxx [new file with mode: 0644]
src/max31855/max31855.h [new file with mode: 0644]
src/max31855/pyupm_max31855.i [new file with mode: 0644]

index 501b0c4..a8ff968 100644 (file)
@@ -865,7 +865,8 @@ EXCLUDE_SYMBOLS        =
 # command).
 
 EXAMPLE_PATH           = @CMAKE_CURRENT_SOURCE_DIR@/examples/ \
-                         @CMAKE_CURRENT_SOURCE_DIR@/docs/
+                         @CMAKE_CURRENT_SOURCE_DIR@/docs/ \
+                        @CMAKE_CURRENT_SOURCE_DIR@/src/max31855/
 
 # If the value of the EXAMPLE_PATH tag contains directories, you can use the
 # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
diff --git a/docs/max31855.md b/docs/max31855.md
new file mode 100644 (file)
index 0000000..dabb1ea
--- /dev/null
@@ -0,0 +1,96 @@
+Making a UPM module for MAX31855                         {#max31855}
+================================
+
+The Maxim Integrated MAX31855 is a thermocouple amplifier allowing you to read
+from a K type themocouple. My board comes from the Pmod kit form Maxim
+(MAX31855PMB1) but you can get this from many different sources. The adafruit
+people made arduino code already so we'll use that as a
+[reference](https://github.com/adafruit/Adafruit-MAX31855-library/blob/master/Adafruit_MAX31855.cpp).
+
+### Basics
+
+This is a spi module so we will use the maa spi functions to build our module.
+First thing to do is to create a tree structure like this in upm/src/max31855:
+
+* max31855.cxx
+* max31855.h
+* jsupm_max31855.i
+* pyupm_max31855.i
+* CMakeLists.txt
+
+And then an example file to use & test our lib with in upm/examples/max31855.cxx.
+
+### Swig
+
+The .i files are used by swig, there is one for each python & javascript. They
+contain essentially the same thing and are very simple. The only thing to
+change between the javascript & node.js one is the argument to %module.
+
+@snippet jsupm_max31855.i Interesting
+
+The %include parameter defines which functions will be available to the
+node/python module created, Whilst the headers inside %{} will be explicitly
+required during compilation. Typically only the top level header is required in
+either of those args.
+
+### API
+
+Then we create the header (max31855.h) , a very simple header in our case we
+will have only a very basic api. We provide a getTemp() function which will
+return the same type as in the arduino library, a double.
+
+@snippet max31855.h Interesting
+
+Note that the header contains both the io that we will use, the gpio is in this
+case used as the chip select pin.
+
+### Implementing our API
+
+In the adafruit library the read function (our chip is a 3pin SPI so only read
+is possible), the spiread32() does all the work. It starts by setting up the io
+so we will do the same in our constructor.
+
+Note unlike on Arduino, we'll just set a 2Mhz clock and let the chip do the
+work.
+
+@snippet src/max31855/max31855.cxx Constructor
+
+Then we also need to implement a nice cleanup in our destructor.
+
+@snippet src/max31855/max31855.cxx Destructor
+
+Then to read data, we will use spi_write_buf which will allow us to write a
+whole uint32_t in order to get one back, which is what the arduino code does in
+spiread32. Obviously we set our chip select to low first. Here is the start of
+the implementation of MAX31855::getTemp()
+
+@snippet src/max31855/max31855.cxx spi
+
+Then using the arduino code as reference we simply reconstruct form the 4
+uint8_t values a 32bit int value and select only the valuable parts of
+information from that. The MAX31855 datahseet explains exactly which bits are
+useful, we will just do the same as the adafruit code, first checking the error
+bit and then scrapping everything but the 14bit of thermocouple data that are
+useful to us and converting it to a double.
+
+@snippet src/max31855/max31855.cxx conversion
+
+### Finalizing
+
+Our final example, very easy to use api!
+
+@snippet examples/max31855.cxx Interesting
+
+### Building
+
+The we need to add it to the examples/CMakeLists.txt. Only three lines are required
+
+~~~~~~~~~~~
+add_executable (max31855-example max31855.cxx)
+include_directories (${PROJECT_SOURCE_DIR}/src/max31855)
+target_link_libraries (max31855-example max31855 ${CMAKE_THREAD_LIBS_INIT})
+~~~~~~~~~~~
+
+Note you dont have to rebuild everything, cmake keeps target lists so if you
+named your example target <modulename>-example you can simply do make
+max31855-example and both the library & example will build.
index ea8416b..4a9e5f9 100644 (file)
@@ -3,7 +3,8 @@ Porting a module from Arduino                         {#porting}
 
 Porting arduino libraries to libmaa as UPM libraries is usually fairly easy.
 The issues typically come from misunderstanding of how a non real time OS deals
-with interupts and timers. It also highly depends on the sensor.
+with interupts and timers. It also highly depends on the sensor. A concrete
+example is explained in detail on @ref max31855
 
 ### Adding a new module to UPM
 
index 98d3be6..7dc24fd 100644 (file)
@@ -15,6 +15,7 @@ add_executable (oled-1327 oled-1327.cxx)
 add_executable (proximity max44000.cxx)
 add_executable (accelerometer mma7455.cxx)
 add_executable (lcd st7735.cxx)
+add_executable (max31855-example max31855.cxx)
 
 include_directories (${PROJECT_SOURCE_DIR}/src/hmc5883l)
 include_directories (${PROJECT_SOURCE_DIR}/src/grove)
@@ -28,6 +29,7 @@ include_directories (${PROJECT_SOURCE_DIR}/src/hcsr04)
 include_directories (${PROJECT_SOURCE_DIR}/src/max44000)
 include_directories (${PROJECT_SOURCE_DIR}/src/mma7455)
 include_directories (${PROJECT_SOURCE_DIR}/src/st7735)
+include_directories (${PROJECT_SOURCE_DIR}/src/max31855)
 
 target_link_libraries (compass hmc5883l ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries (groveled grove ${CMAKE_THREAD_LIBS_INIT})
@@ -46,3 +48,4 @@ target_link_libraries (oled-1327 i2clcd ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries (proximity max44000 ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries (accelerometer mma7455 ${CMAKE_THREAD_LIBS_INIT})
 target_link_libraries (lcd st7735 ${CMAKE_THREAD_LIBS_INIT})
+target_link_libraries (max31855-example max31855 ${CMAKE_THREAD_LIBS_INIT})
diff --git a/examples/max31855.cxx b/examples/max31855.cxx
new file mode 100644 (file)
index 0000000..2390d93
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Author: Brendan Le Foll <brendan.le.foll@intel.com>
+ * Copyright (c) 2014 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <unistd.h>
+#include <iostream>
+#include <signal.h>
+
+//! [Interesting]
+#include "max31855.h"
+
+int
+main(int argc, char **argv)
+{
+    upm::MAX31855 *temp = new upm::MAX31855(0, 8);
+
+    std::cout << temp->getTemp() << std::endl;
+
+    return 0;
+}
+//! [Interesting]
diff --git a/src/max31855/CMakeLists.txt b/src/max31855/CMakeLists.txt
new file mode 100644 (file)
index 0000000..b2ff5df
--- /dev/null
@@ -0,0 +1,5 @@
+set (libname "max31855")
+set (libdescription "K type thermistor amplifier")
+set (module_src ${libname}.cxx)
+set (module_h ${libname}.h)
+upm_module_init()
diff --git a/src/max31855/jsupm_max31855.i b/src/max31855/jsupm_max31855.i
new file mode 100644 (file)
index 0000000..a136948
--- /dev/null
@@ -0,0 +1,9 @@
+//! [Interesting]
+%module jsupm_max31855
+
+%{
+    #include "max31855.h"
+%}
+
+%include "max31855.h"
+//! [Interesting]
diff --git a/src/max31855/max31855.cxx b/src/max31855/max31855.cxx
new file mode 100644 (file)
index 0000000..f772b19
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Author: Brendan Le Foll <brendan.le.foll@intel.com>
+ * Copyright (c) 2014 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <iostream>
+#include <unistd.h>
+#include <stdlib.h>
+#include <functional>
+#include <string.h>
+
+#include "max31855.h"
+
+using namespace upm;
+
+//! [Constructor]
+MAX31855::MAX31855(int bus, int cs)
+{
+    // initialise chip select as a normal gpio
+    m_gpio = maa_gpio_init(cs);
+    maa_gpio_dir(m_gpio, MAA_GPIO_OUT);
+
+    // initialise the spi bus with a 2Mhz clock
+    m_sensor = maa_spi_init(bus);
+    maa_spi_frequency(m_sensor, 2000000);
+}
+//! [Constructor]
+
+//! [Destructor]
+MAX31855::~MAX31855()
+{
+    // close both m_sensor & m_gpio cleanly
+    maa_result_t error;
+    error = maa_spi_stop(m_sensor);
+    if (error != MAA_SUCCESS) {
+        maa_result_print(error);
+    }
+    error = maa_gpio_close(m_gpio);
+    if (error != MAA_SUCCESS) {
+        maa_result_print(error);
+    }
+}
+//! [Destructor]
+
+double
+MAX31855::getTemp()
+{
+//! [spi]
+    // set chip select low
+    maa_gpio_write(m_gpio, 0);
+
+    uint8_t buf[4];
+
+    // set our input buffer to 0, this is clean but not required
+    memset(buf, 0, sizeof(uint8_t)*4);
+
+    // Write buffer to the spi slave
+    uint8_t* x = maa_spi_write_buf(m_sensor, buf, 4);
+//! [spi]
+
+//! [conversion]
+    // Endian correct way of making our char array into an 32bit int
+    int32_t temp = (x[0] << 24) | (x[1] << 16) | (x[2] << 8) | x[3];;
+
+    // maa_spi_write_buf does not free the return buffer
+    free(x);
+
+    if (temp & 0x7) {
+        std::cerr << "Something went very wrong!" << std::endl;
+    }
+
+    // scrap all the data we dont care about
+    temp >>= 18;
+
+    // LSB = 0.25 degrees C
+    double c = (double) temp;
+    c *= 0.25;
+//! [conversion]
+
+    // set chip select high
+    maa_gpio_write(m_gpio, 1);
+
+    return c;
+}
diff --git a/src/max31855/max31855.h b/src/max31855/max31855.h
new file mode 100644 (file)
index 0000000..3b77c1d
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ * Author: Brendan Le Foll <brendan.le.foll@intel.com>
+ * Copyright (c) 2014 Intel Corporation.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+#pragma once
+
+#include <string>
+#include <maa/spi.h>
+#include <maa/gpio.h>
+
+namespace upm {
+
+/**
+ * @brief C++ API for MAX31855
+ *
+ * This file defines the max31855 SPI sensor
+ *
+ * @snippet examples/max31855.cxx Interesting
+ *
+ */
+ //! [Interesting]
+class MAX31855 {
+    public:
+        /**
+         * Instanciates a MAX31855 object
+         *
+         * @param bus The spi bus to use
+         * @param cs The chip select pin
+         */
+        MAX31855(int bus, int cs);
+
+        /**
+         * MAX31855 object destructor
+         */
+        ~MAX31855();
+
+        /**
+         * Get the distance from the sensor
+         *
+         * @return value in degrees celcius
+         */
+        double getTemp();
+
+    private:
+        maa_spi_context m_sensor;
+        maa_gpio_context m_gpio;
+};
+//! [Interesting]
+
+}
diff --git a/src/max31855/pyupm_max31855.i b/src/max31855/pyupm_max31855.i
new file mode 100644 (file)
index 0000000..a0fe90d
--- /dev/null
@@ -0,0 +1,10 @@
+%module pyupm_max31855
+
+%include "stdint.i"
+
+%feature("autodoc", "3");
+
+%include "max31855.h"
+%{
+    #include "max31855.h"
+%}