stm32f1/lib/sensor_max6675.c

76 lines
4.5 KiB
C

/** 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
}