cancel
Showing results for 
Search instead for 
Did you mean: 

Problem with SPI communication with MAX31855K from STM8S103F3

Junaid PV
Associate II

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

4 REPLIES 4
CPhei.1
Associate

Hi, did you come right with this?

I'm also having issues with MAX31855

Thanks

Junaid PV
Associate II

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
Associate II

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

CPhei.1
Associate

Thank you!