Skip to main content
Junaid PV
Associate II
October 6, 2018
Question

Problem with SPI communication with MAX31855K from STM8S103F3

  • October 6, 2018
  • 4 replies
  • 3494 views

Hi all,

I am trying to read temperature data from MAX31855K over SPI, using STM8S103F3 on a breakout board.

Development set up is STVD, STVP and Consmic compiler. And using STM8S Standard Peripheral library.

Here is my max31855.h:

#ifndef MAX31855_H
#define MAX31855_H
 
#define MAX31855_SPI_GPIO_PORT GPIOC
#define MAX31855_SPI_SCK_PIN GPIO_PIN_5
#define MAX31855_SPI_MISO_PIN GPIO_PIN_7
#define MAX31855_NCS_GPIO_PORT GPIOA /* Chip Select I/O definition */
#define MAX31855_NCS_PIN GPIO_PIN_3
 
 
#ifdef USE_Delay
#include "main.h"
 
 #define _delay_ Delay /* !< User can provide more timing precise _delay_
 function (with at least 1ms time base), using
 Timer for example */
#else
 #define _delay_ delay /* !< Default _delay_ function with less precise timing */
#endif
 
 
#define MAX31855_CONVERSION_POWER_UP_TIME 200 //in milliseconds
 
#define MAX31855_SELECT() GPIO_WriteLow(MAX31855_NCS_GPIO_PORT, MAX31855_NCS_PIN)
#define MAX31855_DESELECT() GPIO_WriteHigh(MAX31855_NCS_GPIO_PORT, MAX31855_NCS_PIN)
 
void MAX31855_Init(void);
uint8_t MAX31855_ReceiveData(void);
// uint32_t MAX31855_spiread32(void);
void MAX31855_spiread32(struct max_data* data);
int16_t MAX31855_readCelsius(void);
 
static void delay(__IO uint32_t nCount);
 
#endif /* MAX31855_H */

here is the max31855.c

#include "stm8s_gpio.h"
#include "max31855.h"
#include "stdio.h"
 
static void delay(__IO uint32_t nCount);
 
struct max_data {
	uint16_t high;
	uint16_t low;
};
 
#define check_bit(var,pos) ((var) & (1<<(pos)))
 
/**
 * @brief SPI connection with MAX31855
 * @param None
 * @retval None
 */
void MAX31855_Init(void)
{
 /* Enable SPI clock */
 CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
 
 /* Configure SPI pins: SCK and MISO */
 GPIO_Init(MAX31855_SPI_GPIO_PORT, (GPIO_Pin_TypeDef)(MAX31855_SPI_SCK_PIN | MAX31855_SPI_MISO_PIN), GPIO_MODE_OUT_PP_LOW_FAST);
 
 /* Configure MAX31855 ChipSelect pin (NCS) in Output push-pull mode */
 GPIO_Init(MAX31855_NCS_GPIO_PORT, MAX31855_NCS_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
 
 /* Initialize SPI */
 /* TODO: Not sure about SPI_NSS_SOFT and 0x07 */
 SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_64, SPI_MODE_MASTER,
 SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_1LINE_RX,
 SPI_NSS_SOFT, 0x07);
 SPI_Cmd(ENABLE);
 
 
 
 /* Required to ensure proper MAX31855 display when the board is powered-on ... */
 _delay_(0x4000 * MAX31855_CONVERSION_POWER_UP_TIME); /* 0x4000 = 1ms _delay_ using Fcpu = 16Mhz*/
}
 
uint8_t MAX31855_ReceiveData(void) {
 while (SPI_GetFlagStatus(SPI_FLAG_RXNE) == RESET); // wait for a byte to come in; checks if the Receive register is not empty
 return SPI_ReceiveData();
}
 
void MAX31855_spiread32(struct max_data* data) {
 // uint32_t d = 0;
 data->high = 0;
 data->low = 0;
 
 MAX31855_SELECT();
 _delay_(0x4000); // 1ms
 
 //SPI.beginTransaction(SPISettings(4000000, MSBFIRST, SPI_MODE0));
 // SPI_Cmd(ENABLE);
 
 data->high = MAX31855_ReceiveData();
 data->high <<= 8;
 data->high |= MAX31855_ReceiveData();
 // d <<= 8;
 data->low |= MAX31855_ReceiveData();
 data->low <<= 8;
 data->low |= MAX31855_ReceiveData();
 
 // SPI.endTransaction();
 // SPI_Cmd(DISABLE);
 
 MAX31855_DESELECT();
 
 // return d;
}
 
int16_t MAX31855_readCelsius(void) {
 struct max_data data;
 // float centigrade = v;
 int16_t internal;
 
 MAX31855_spiread32(&data);
 printf("high: %d low: %d\n\r", data.high, data.low);
 
 // Bit 3 of low is always supposed to be 0.
	if (check_bit( data.low , 3)) {
		printf("Bit 3 is set. WRONG!\r\n");
	}
 
	// Bit 1 (17th bit of SPI data) of high is always supposed to be 0.
	if (check_bit(data.high, 1)) {
		printf("Bit 17 is set. WRONG!\r\n");
 return 0;
	}
 
	if (check_bit(data.low, 0)) {
		printf("Thermocouple is open. No connection.\r\n");
 return 0;
	}
	if (check_bit(data.low, 1)) {
		printf("Thermocouple is short circuited to ground.\r\n");
 return 0;
	}
	if (check_bit(data.low, 2)) {
		printf("Thermocouple is short circuited to VCC.\r\n");
 return 0;
	}
 
 internal = (data.low >> 4) / 16;
 printf("Internal: %d\n\r", internal);
 
 return (data.high >> 2) / 4;
}
 
#ifndef USE_Delay
/**
 * @brief Inserts a delay time.
 * The delay function implemented in this driver is not a precise one,
 * however it allows the insertion of 1ms delay when Fcpu is 16Mhz if
 * the passed parameter is 0x4000.
 * Any change in system clock frequency will impact this delay duration.
 *
 * User is given the possibility to develop a customized and accurate
 * delay function by the mean of timers for example.
 * Uncommenting " #define USE_Delay" line in the stm8s_eval_lcd.h file
 * will allow the consideration of the new function by this driver.
 *
 * @param nCount: specifies the _delay_ time length.
 * @retval None
 */
static void delay(__IO uint32_t nCount)
{
 /* Decrement nCount value */
 while (nCount != 0)
 {
 nCount--;
 }
}
#endif /* USE_Delay*/

And here is the main function:

It already contains several printf() calls as debugging purpose.

I mostly suspect MAX31855_Init() function which initialize the SPI. I coded it for receive-only mode, however not sure if used correct values for the parameters I used for SPI_Init() function call.

Somewhere I read calling SPI_ReceiveData() is not enough and we have to check status of SPI_FLAG_RXNE flag. So created MAX31855_ReceiveData().

Here is the connection from STM8S103 => MAX31855

PC7 (SPI_MISO) => DO

PA3 (SPI_NSS) => CS

PC5 (SPI_SCK) => CLK

I also set AFR1 bit of option byte OPT2 to 1 as per datasheet. Hope i did it correct.

Overall it outputs non consistent garbage values. Thus SPI communication is not happening right.

Could somebody help me to fix the issue over SPI communication with MAX31855K?

I would be happy to hear if somebody already have code for working with MAX31855.

Thanks in advance!

Junaid

This topic has been closed for replies.

4 replies

CPhei.1
Visitor II
July 19, 2020

Hi, did you come right with this?

I'm also having issues with MAX31855

Thanks

Junaid PV
Junaid PVAuthor
Associate II
July 22, 2020

Yes, I had got that working.

These are my update max31855.h and max31855.c:

max31855.h:

// @author: Junaid PV (http://junix.in)
 
#ifndef MAX31855_H
#define MAX31855_H
 
#define check_bit(var,pos) ((var) & (1<<(pos)))
 
#define MAX31855_SPI_GPIO_PORT GPIOC
#define MAX31855_SPI_SCK_PIN GPIO_PIN_5
#define MAX31855_SPI_MISO_PIN GPIO_PIN_7
#define MAX31855_NCS_GPIO_PORT GPIOA /* Chip Select I/O definition */
#define MAX31855_NCS_PIN GPIO_PIN_3
 
struct max_data {
	uint16_t high;
	uint16_t low;
};
 
#define MAX31855_CONVERSION_POWER_UP_TIME 200 //in milliseconds
 
#define MAX31855_SELECT() GPIO_WriteLow(MAX31855_NCS_GPIO_PORT, MAX31855_NCS_PIN)
#define MAX31855_DESELECT() GPIO_WriteHigh(MAX31855_NCS_GPIO_PORT, MAX31855_NCS_PIN)
 
void MAX31855_Init(void);
uint8_t MAX31855_ReceiveData(void);
// uint32_t MAX31855_spiread32(void);
void MAX31855_spiread32(struct max_data* data);
uint8_t max31855_print_error(struct max_data* data);
int16_t MAX31855_get_internal_temperature(struct max_data* data);
int16_t MAX31855_get_junction_temperature(struct max_data* data);
 
#endif /* MAX31855_H */

max31855.c:

// @author: Junaid PV (http://junix.in)
 
#include "stm8s_gpio.h"
#include "max31855.h"
#include "stdio.h"
#include "delay.h"
 
/**
 * @brief SPI connection with MAX31855
 * @param None
 * @retval None
 */
void MAX31855_Init(void)
{
 /* Enable SPI clock */
 CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, ENABLE);
 
 /* Configure MAX31855 ChipSelect pin (NCS) in Output push-pull mode */
 GPIO_Init(MAX31855_NCS_GPIO_PORT, MAX31855_NCS_PIN, GPIO_MODE_OUT_PP_LOW_FAST);
 
 /* Initialize SPI */
 /* TODO: Not sure about SPI_NSS_SOFT and 0x07 */
 SPI_Init(SPI_FIRSTBIT_MSB, SPI_BAUDRATEPRESCALER_8, SPI_MODE_MASTER,
 SPI_CLOCKPOLARITY_LOW, SPI_CLOCKPHASE_1EDGE, SPI_DATADIRECTION_2LINES_FULLDUPLEX,
 SPI_NSS_SOFT, 0x07);
 SPI_Cmd(ENABLE);
 
	// Ensure MAX31855 is not selected by default.
	MAX31855_DESELECT();
}
 
uint8_t MAX31855_ReceiveData(void) {
	// Need to send dummy byte to get data in read buffer.
	// In fact we send nothing since MAX31855 is read only device,
	// but this line is required otherwise we will wait indefinitely for the SPI_FLAG_RXNE flag.
	SPI_SendData(0x00);
 while (SPI_GetFlagStatus(SPI_FLAG_RXNE) == RESET); // wait for a byte to come in; checks if the Receive register is not empty
 return SPI_ReceiveData();
}
 
void MAX31855_spiread32(struct max_data* data) {
 data->high = 0;
 data->low = 0;
 
 MAX31855_SELECT();
	// Wait for 1 millisecond to allow MAX31855 to prepare the data.
 _delay_ms(1);
 
	// Read MSBytes
 data->high = MAX31855_ReceiveData();
 data->high <<= 8;
 data->high |= MAX31855_ReceiveData();
	// Read LSBytes
 data->low |= MAX31855_ReceiveData();
 data->low <<= 8;
 data->low |= MAX31855_ReceiveData();
 
 MAX31855_DESELECT();
}
 
uint8_t max31855_print_error(struct max_data* data) {
 // Bits 0, 1, 2 and 3 should not be 1s
	// Bit 3 of low is always supposed to be 0.
 // Bit 1 of high (17th bit of SPI data) of high is always supposed to be 0.
	return (data->low & 0b0000000000001111) || (data->high & 0b0000000000000001);
}
 
int16_t MAX31855_get_internal_temperature(struct max_data* data) {
	int16_t temp = data->low;
 
	// ignore bottom 4 bits - they're just thermocouple data
	temp >>= 4;
 
	// check sign bit!
	if (temp & 0x800) {
		// Convert to negative value by extending sign and casting to signed type.
		temp = 0xF800 | (temp & 0x7FF);
	}
	else {
		// pull the bottom 11 bits off
		temp = temp & 0x7FF;
	}
 
	return temp / 16;
}
 
int16_t MAX31855_get_junction_temperature(struct max_data* data) {
	int16_t temp = data->high;
 
	if (check_bit(temp, 15)) {
		// Negative value, drop the lower 18 bits and explicitly extend sign bits.
		temp = 0xFFFFC000 | ((temp >> 2) & 0x00003FFFF);
	}
	else {
		// Positive value, just drop the lower 2 bits.
		temp >>= 2;
	}
 
 return temp / 4;
}

As far as I remember, the important change was to send a byte to MAX31855 before reading data from it, see function MAX31855_ReceiveData().

Then, in my main function has something like this:

int16_t temp;
struct max_data data;
char szTemp[8];
 
MAX31855_Init();
 
while (1) {
 MAX31855_spiread32(&data);
 if (!max31855_print_error(&data)) {
 temp = MAX31855_get_junction_temperature(&data);
 sprintf(szTemp, "%04d", temp);
 }
}

Hope it helps.

Regards,

Junaid

Junaid PV
Junaid PVAuthor
Associate II
July 22, 2020

Please note that I had switched to SDCC compiler. So, code may require minor changes if you are with a different compiler.

CPhei.1
Visitor II
July 22, 2020

Thank you!