sensor_max6675: add library for MAX6675 k-type thermocouple reader

This commit is contained in:
King Kévin 2020-12-19 00:16:37 +01:00
parent 952d947c1b
commit e50cd35728
2 changed files with 94 additions and 0 deletions

75
lib/sensor_max6675.c Normal file
View File

@ -0,0 +1,75 @@
/** library to communication with Maxim MAX6675 K-type thermocouple to digital temperature sensor using SPI
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2020
* @note peripherals used: SPI @ref sensor_max6675_spi
*/
/* standard libraries */
#include <stdint.h> // standard integer types
#include <stdlib.h> // general utilities
#include <stdbool.h> // boolean utilities
#include <math.h> // math utilities
/* STM32 (including CM3) libraries */
#include <libopencmsis/core_cm3.h> // Cortex M3 utilities
#include <libopencm3/stm32/rcc.h> // real-time control clock library
#include <libopencm3/stm32/gpio.h> // general purpose input output library
#include <libopencm3/stm32/spi.h> // SPI library
/* own library */
#include "global.h" // common definitions
#include "sensor_max6675.h" // own definitions
/** @defgroup sensor_max6675_spi SPI peripheral used to communicate with the AS3935
* @note SCK, MISO, and NSS pins are used
*/
#define SENSOR_MAX6675_SPI 1 /**< SPI peripheral */
void sensor_max6675_setup(void)
{
// setup SPI
rcc_periph_clock_enable(RCC_SPI_SCK_PORT(SENSOR_MAX6675_SPI)); // enable clock for GPIO peripheral for clock signal
gpio_set_mode(SPI_SCK_PORT(SENSOR_MAX6675_SPI), GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, SPI_SCK_PIN(SENSOR_MAX6675_SPI)); // set SCK as output (clock speed will be negotiated later)
rcc_periph_clock_enable(RCC_SPI_MISO_PORT(SENSOR_MAX6675_SPI)); // enable clock for GPIO peripheral for MISO signal
gpio_set_mode(SPI_MISO_PORT(SENSOR_MAX6675_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_PULL_UPDOWN, SPI_MISO_PIN(SENSOR_MAX6675_SPI)); // set MISO as input
rcc_periph_clock_enable(RCC_SPI_NSS_PORT(SENSOR_MAX6675_SPI)); // enable clock for GPIO peripheral for NSS (CS) signal
gpio_set_mode(SPI_NSS_PORT(SENSOR_MAX6675_SPI), GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL, SPI_NSS_PIN(SENSOR_MAX6675_SPI)); // set NSS (CS) as output
rcc_periph_clock_enable(RCC_AFIO); // enable clock for SPI alternate function
rcc_periph_clock_enable(RCC_SPI(SENSOR_MAX6675_SPI)); // enable clock for SPI peripheral
spi_reset(SPI(SENSOR_MAX6675_SPI)); // clear SPI values to default
spi_init_master(SPI(SENSOR_MAX6675_SPI), SPI_CR1_BAUDRATE_FPCLK_DIV_32, SPI_CR1_CPOL_CLK_TO_0_WHEN_IDLE, SPI_CR1_CPHA_CLK_TRANSITION_2, SPI_CR1_DFF_16BIT, SPI_CR1_MSBFIRST); // initialise SPI as master, divide clock by 64 (72E6/32=2250 kHz, max AS3935 SCK is 4.3, maximum SPI PCLK clock is 72 Mhz, depending on which SPI is used), set clock polarity to idle low (not that important), set clock phase to do bit change on falling edge (polarity depends on clock phase), use 16 bits frames , use MSb first
spi_set_unidirectional_mode(SPI(SENSOR_MAX6675_SPI)); // set simplex mode (only two wires used)
// do not set as receive only to trigger transfer (read) using write
//spi_set_receive_only_mode(SPI(SENSOR_MAX6675_SPI)); // we will only receive data
spi_enable_software_slave_management(SPI(SENSOR_MAX6675_SPI)); // control NSS (CS) manually
spi_set_nss_high(SPI(SENSOR_MAX6675_SPI)); // set NSS high (internally) so we can get input
spi_disable_ss_output(SPI(SENSOR_MAX6675_SPI)); // disable NSS output since we control CS manually
gpio_set(SPI_NSS_PORT(SENSOR_MAX6675_SPI), SPI_NSS_PIN(SENSOR_MAX6675_SPI)); // set CS high to unselect device
spi_enable(SPI(SENSOR_MAX6675_SPI)); // enable SPI
}
void sensor_max6675_release(void)
{
spi_reset(SPI(SENSOR_MAX6675_SPI));
spi_disable(SPI(SENSOR_MAX6675_SPI));
rcc_periph_clock_disable(RCC_SPI(SENSOR_MAX6675_SPI));
gpio_set_mode(SPI_NSS_PORT(SENSOR_MAX6675_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_NSS_PIN(SENSOR_MAX6675_SPI));
gpio_set_mode(SPI_MISO_PORT(SENSOR_MAX6675_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_MISO_PIN(SENSOR_MAX6675_SPI));
gpio_set_mode(SPI_SCK_PORT(SENSOR_MAX6675_SPI), GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, SPI_SCK_PIN(SENSOR_MAX6675_SPI));
}
float sensor_max6675_read(void)
{
(void)SPI_DR(SPI(SENSOR_MAX6675_SPI)); // clear RXNE flag (by reading previously received data (not done by spi_read or spi_xref)
gpio_clear(SPI_NSS_PORT(SENSOR_MAX6675_SPI), SPI_NSS_PIN(SENSOR_MAX6675_SPI)); // set CS low to select device
const uint16_t temp = spi_xfer(SPI(SENSOR_MAX6675_SPI), 0); // read data
gpio_set(SPI_NSS_PORT(SENSOR_MAX6675_SPI), SPI_NSS_PIN(SENSOR_MAX6675_SPI)); // set CS high to unselect device
if (temp & 0x8002) { // sign and device ID bits should not be set
return NAN;
}
if (temp & 0x0004) { // thermocouple is open
return INFINITY;
}
return (temp >> 3) / 4.0; // return temperature value
}

19
lib/sensor_max6675.h Normal file
View File

@ -0,0 +1,19 @@
/** library to communication with Maxim MAX6675 K-type thermocouple to digital temperature sensor using SPI
* @file
* @author King Kévin <kingkevin@cuvoodoo.info>
* @copyright SPDX-License-Identifier: GPL-3.0-or-later
* @date 2020
* @note peripherals used: SPI @ref sensor_max6675_spi
*/
#pragma once
/** setup communication to MAX6675 sensor */
void sensor_max6675_setup(void);
/** release peripherals used to communicate with MAX6675 sensor */
void sensor_max6675_release(void);
/** read temperature from MAX6675 sensor
* @return temperature (in °C) measured by sensor (infinity if K-thermocouple is missing, nan on error)
* @note resolution is in 0.25 °C
* @note wait 0.22 s between readings (max. time needed for a conversion)
*/
float sensor_max6675_read(void);