max31855: add sensor and documentation on creation of a UPM sensor

Signed-off-by: Brendan Le Foll <brendan.le.foll@intel.com>
This commit is contained in:
Brendan Le Foll 2014-06-13 16:44:48 +01:00
parent 3e12ed6719
commit 2c1baf66b5
10 changed files with 340 additions and 2 deletions

View File

@ -865,7 +865,8 @@ EXCLUDE_SYMBOLS =
# command). # command).
EXAMPLE_PATH = @CMAKE_CURRENT_SOURCE_DIR@/examples/ \ 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 # 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 # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and

96
docs/max31855.md Normal file
View File

@ -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.

View File

@ -3,7 +3,8 @@ Porting a module from Arduino {#porting}
Porting arduino libraries to libmaa as UPM libraries is usually fairly easy. 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 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 ### Adding a new module to UPM

View File

@ -15,6 +15,7 @@ add_executable (oled-1327 oled-1327.cxx)
add_executable (proximity max44000.cxx) add_executable (proximity max44000.cxx)
add_executable (accelerometer mma7455.cxx) add_executable (accelerometer mma7455.cxx)
add_executable (lcd st7735.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/hmc5883l)
include_directories (${PROJECT_SOURCE_DIR}/src/grove) 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/max44000)
include_directories (${PROJECT_SOURCE_DIR}/src/mma7455) include_directories (${PROJECT_SOURCE_DIR}/src/mma7455)
include_directories (${PROJECT_SOURCE_DIR}/src/st7735) 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 (compass hmc5883l ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (groveled grove ${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 (proximity max44000 ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (accelerometer mma7455 ${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 (lcd st7735 ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries (max31855-example max31855 ${CMAKE_THREAD_LIBS_INIT})

41
examples/max31855.cxx Normal file
View File

@ -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]

View File

@ -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()

View File

@ -0,0 +1,9 @@
//! [Interesting]
%module jsupm_max31855
%{
#include "max31855.h"
%}
%include "max31855.h"
//! [Interesting]

103
src/max31855/max31855.cxx Normal file
View File

@ -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;
}

69
src/max31855/max31855.h Normal file
View File

@ -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]
}

View File

@ -0,0 +1,10 @@
%module pyupm_max31855
%include "stdint.i"
%feature("autodoc", "3");
%include "max31855.h"
%{
#include "max31855.h"
%}