SPI + MAX31855: SPI_Read(0) not working? - SOLVED!

General discussion on mikroC PRO for PIC.
Post Reply
Author
Message
jzk
Posts: 83
Joined: 04 Aug 2010 11:48
Location: west yorkshire, U.K

SPI + MAX31855: SPI_Read(0) not working? - SOLVED!

#1 Post by jzk » 29 Aug 2022 23:20

Hi. I'm trying to get a PIC18F45K22 reading a MAX31855 via easypic7 board.
I'm not using a thermo-click, but the adafruit break out board.
It has connections for D0, CS and CLK i have connected it as follows:
DO -> RC4(SDI1)
CS -> RE0
CLK -> RC3(SCK)

The code i've built up from examples obtained plucking out the parts i considered correct to build up the code.
I'm not getting any response, no values and no discernible read/comms with the MAX?
i.e. the code should pick up errors, open-cct, short-cct etc.
but i get nothing even with no k-type connected.

I may well have a faulty/damaged break out board, but i have no confidence the SPI is setup correctly in the first place.
it seems such a simple thing, but beyond me?
if i can get advice, confirmation the SPI is setup correctly, then i can go from there.

code i'm using as follows.

Code: Select all

/*PIC18F45K22, internal osc 8MHz, PLL enabled
CONFIG1H : $300001 : 0x0038
CONFIG2L : $300002 : 0x001F
CONFIG2H : $300003 : 0x003C
CONFIG3H : $300005 : 0x00BF
CONFIG4L : $300006 : 0x0081
CONFIG5L : $300008 : 0x000F
CONFIG5H : $300009 : 0x00C0
CONFIG6L : $30000A : 0x000F
CONFIG6H : $30000B : 0x00E0
CONFIG7L : $30000C : 0x000F
CONFIG7H : $30000D : 0x0040
*/
// Lcd module connections
sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End Lcd module connections

sbit THERMO_CS     at LATE0_bit;//chip-select
sbit THERMO_CS_Dir at TRISE0_bit;

int tmp2, intTemp, remTemp;
float temperature, tempInternal;
char s_temp[15], s_tempInternal[15];

unsigned short temp_byte[4] = {0, 0, 0, 0};

void MAX31855_Read() {
  THERMO_CS = 0;
  Delay_ms(350);
  temp_byte[0] = SPI_Read(0);
  temp_byte[1] = SPI_Read(0);
  temp_byte[2] = SPI_Read(0);
  temp_byte[3] = SPI_Read(0);
  THERMO_CS = 1;
}

void Compute_Temp_Value() {

  tmp2 = temp_byte[0];
  tmp2 = tmp2 << 8;
  tmp2 = tmp2 | temp_byte[1];
  remTemp = tmp2 >> 2;
  remTemp = remTemp & 0x03;// Decimal part of temperature value
  temperature = remTemp * 0.25;
  intTemp = tmp2 >> 4;// Intiger part of temperature value
  temperature += intTemp;// Temperature value

  FloatToStr(temperature, s_temp);

}

// NOTE FOR NOW DO NOT HANDLE NEGATIVE VALUES
void Compute_InternalTemp_Value() {

  //temp_byte[2] = 0b00011001;
  //temp_byte[3] = 0b00000000;

  tmp2 = temp_byte[2];
  tmp2 = tmp2 << 8;
  tmp2 = tmp2 | temp_byte[3];
  remTemp = tmp2 >> 4;
  tempInternal = remTemp * 0.0625;

  FloatToStr(tempInternal, s_tempInternal);

}
void main() {

    THERMO_CS_Dir = 0;
    THERMO_CS = 1;
    TRISC5_bit = 0;// output for SDO1
    TRISC4_bit = 1;// input for SDI1
    TRISC3_bit = 0;// output for SCK1
    
    Lcd_Init();
    Lcd_Cmd(_LCD_CLEAR);               // Clear display
    Lcd_Cmd(_LCD_CURSOR_OFF);
    Delay_ms(100);
    
    //SPI1_Init();
    SPI1_Init_Advanced(
    _SPI_MASTER_OSC_DIV16,
    _SPI_DATA_SAMPLE_MIDDLE,
    _SPI_CLK_IDLE_LOW,
    _SPI_LOW_2_HIGH
    );  // Initialize SPI communication*/
    SPI_Set_Active(&SPI1_Read, &SPI1_Write);// Sets the SPI1 module active
    Delay_ms(100);

    while (1) {

    Delay_ms(100);

    MAX31855_Read();

    ///*
    if((temp_byte[1] & 0x01) == 0x01){// Fault detection
        Lcd_Out(1,1,"ERROR");
        if((temp_byte[3] & 0x01) == 0x01){// Open circuit fault?
            Lcd_Out(2,1,"Open circuit");
            Delay_ms(1000);
          }
          //
        if((temp_byte[3] & 0x02) == 0x02){// Short to GND fault?
            Lcd_Out(2,1,"Short to GND");
            Delay_ms(1000);
          }
          //
          if((temp_byte[3] & 0x04) == 0x04){// Short to Vcc fault?
             Lcd_Out(2,1,"Short to Vcc");
             Delay_ms(1000);
          }
    }
    else{
        Compute_Temp_Value();
        Lcd_Out(1,1,"TempTC: ");
        Lcd_Out(1,8,s_temp);

        Compute_InternalTemp_Value();
        Lcd_Out(2,1,"TempInt:");
        Lcd_Out(2,9,s_tempInternal);
    }
    //*/
       Delay_ms(500);
   }

}
TIA.
Last edited by jzk on 01 Sep 2022 23:36, edited 2 times in total.

jzk
Posts: 83
Joined: 04 Aug 2010 11:48
Location: west yorkshire, U.K

Re: SPI + MAX31855: SPI_Read(0) not working

#2 Post by jzk » 30 Aug 2022 19:55

looked into this a little more.
i put a scope on the data-out (DO) and clock pins and got the following.

Image

top trace is the data, i assume DO on the break out board, connected to RC4 SDI/MISO
lower trace is the clock as coming from RC3 SCK.
each clock pulse is about 7.5us, period of one clock cycle is about 15us
so there appears to be some kind of coherent exchange?
This data is with no thermocouple connected, so should be the no connection message?
data does change when i connected a TC and changed further still when the tip was held to heat it whilst capturing data.

still lost on this, it's like the data isn't being captured? i'd expect something on the LCD display even if it was garbage, no?
do i need interrupts?
all the spi max31855 examples out there seem to be quite simple

I'll rig up the USB-UART and see what i get on the USART terminal.
i'm going to try and slow it down too. i'm clutching straws here?
Any help/advice gladly welcome.
Last edited by jzk on 01 Sep 2022 12:26, edited 1 time in total.

jzk
Posts: 83
Joined: 04 Aug 2010 11:48
Location: west yorkshire, U.K

Re: SPI + MAX31855: SPI_Read(0) not working?

#3 Post by jzk » 31 Aug 2022 20:57

more work on this. so close and yet so far!
i have the MAX31855 working properly now with regards to output data.
I had SW4 on the dev-board setup incorrectly: SW4.7 & SW4.8 were in the 'ON' position, selecting RC3 and RC4, as i thought. But that infact selects EEPROM SCL/SDA.
changing them to the 'OFF' position, as i thought selecting SCL & SDA actually selects RC3 and RC4. Dickhead!

So the previous somewhat arbitrary data return is now correct. and tallys up with the data sheet.

Image

the scope image above shows data-set for a fault condition of no thermocouple connected.
D0 is correct (1), D16 is correct (1), D30-D18 is correct (All 1s) and D31 sign-bit is correct (0)
I have connected a thermocouple and it changes correctly, i.e. no fault and D30-D18, TC data changes during heating tip.
so i'm 100% confident the MAX31855 is working and the SPI operation almost there.

now the clock cycles are forcing the data out, but it doesn't appear to capturing the bytes during the read?
the RC4 is configured as Input with TRISC, the storage for the bytes seems reasonable, unsigned short temp_byte[4]?
all the bytes are zero as put out by the UART?

Image

any help as to why the read is not picking up the data?

i played around with clock frequency, oscillator etc.
i got some odd responses, it seemed the faster i set the clock the slower the code took between reads, bizarre?
most, if not all the code examples i've seen just use <storage variable> = SPI_Read(dummy data for clock)?
as i have, but without success?
code used as follows....
TIA.

Code: Select all

/* 18F45K22, Int Osc, 1MHz.
CONFIG1H : $300001 : 0x0028
CONFIG2L : $300002 : 0x001F
CONFIG2H : $300003 : 0x003C
CONFIG3H : $300005 : 0x00BF
CONFIG4L : $300006 : 0x0081
CONFIG5L : $300008 : 0x000F
CONFIG5H : $300009 : 0x00C0
CONFIG6L : $30000A : 0x000F
CONFIG6H : $30000B : 0x00E0
CONFIG7L : $30000C : 0x000F
CONFIG7H : $30000D : 0x0040
*/
sbit THERMO_CS     at LATE0_bit;
sbit THERMO_CS_Dir at TRISE0_bit;

int tmp2, intTemp, remTemp;
float temperature, tempInternal;
char s_temp[15], s_tempInternal[15];
unsigned short temp_byte[4] = {0, 0, 0, 0};

void MAX31855_Read() {
  THERMO_CS = 0;//enables device
  Delay_ms(100);
  temp_byte[0] = SPI_Read(0);//read command initiates clock
  temp_byte[1] = SPI_Read(0);//each read gives x8 clock pulses
  temp_byte[2] = SPI_Read(0);//obtaining x1 byte from slave
  temp_byte[3] = SPI_Read(0);//next byte received by following read(s)
  THERMO_CS = 1;//disables device
}

void Compute_Temp_Value() {
  tmp2 = temp_byte[0];
  tmp2 = tmp2 << 8;
  tmp2 = tmp2 | temp_byte[1];
  remTemp = tmp2 >> 2;
  remTemp = remTemp & 0x03;// Decimal part of temperature value
  temperature = remTemp * 0.25;
  intTemp = tmp2 >> 4;// Intiger part of temperature value
  temperature += intTemp;// Temperature value
  FloatToStr(temperature, s_temp);
}
// NOTE FOR NOW DO NOT HANDLE NEGATIVE VALUES
void Compute_InternalTemp_Value() {
  //temp_byte[2] = 0b00011001;
  //temp_byte[3] = 0b00000000;
  tmp2 = temp_byte[2];
  tmp2 = tmp2 << 8;
  tmp2 = tmp2 | temp_byte[3];
  remTemp = tmp2 >> 4;
  tempInternal = remTemp * 0.0625;
  FloatToStr(tempInternal, s_tempInternal);
}
void main() {
    THERMO_CS_Dir = 0;// output for CS
    THERMO_CS = 1;
    TRISC4_bit = 1;// input for PIC MISO/RC4
    TRISC3_bit = 0;// output for PIC SCK1/RCC3
    
    UART1_Init(9600);               // Initialize UART module at 9600 bps
    Delay_ms(100);                  // Wait for UART module to stabilize

    SPI1_Init_Advanced(
    _SPI_MASTER_OSC_DIV64,
    _SPI_DATA_SAMPLE_MIDDLE,
    _SPI_CLK_IDLE_LOW,
    _SPI_LOW_2_HIGH
    );  // Initialize SPI communication*/
    SPI_Set_Active(&SPI1_Read, &SPI1_Write);// Sets the SPI1 module active

    while (1) {
    Delay_ms(100);
    MAX31855_Read();
        UART1_Write(temp_byte[0]);
        UART1_Write(temp_byte[1]);
        UART1_Write(temp_byte[2]);
        UART1_Write(temp_byte[3]);
        UART1_Write(13);
       Delay_ms(1000);
   }

}

jzk
Posts: 83
Joined: 04 Aug 2010 11:48
Location: west yorkshire, U.K

Re: SPI + MAX31855: SPI_Read(0) not working?

#4 Post by jzk » 01 Sep 2022 20:53

Again, got nowhere with this, this evening?
thinking it was timing related, i've tried various clock speeds, divisions everything from as slow as possible to, too fast to work?
i managed to get some bianry values returned, but conclude it was garbage, a lot of repeated values, plus it was returning x7 bytes and not 4.
so why, oh, why does my

temp_byte [n] = SPI_Read(0)

not work, when everyone seems to use it without issue???????

jzk
Posts: 83
Joined: 04 Aug 2010 11:48
Location: west yorkshire, U.K

Re: SPI + MAX31855: SPI_Read(0) not working? - SOLVED!

#5 Post by jzk » 01 Sep 2022 23:43

took a break from staring at the code and went back to the 45K22 data sheet.
thought SSP1EN might have been culpable, but no.
then went onto SPI pin data direction assignments.

Though I had TRISC for the SPI pin assignments, inputs and outputs.
i didn't have ANSELC = 0, I thought this might have been digital as default?
Anyway, i added ANSELC = 0 and it sprang to life.

jzk
Posts: 83
Joined: 04 Aug 2010 11:48
Location: west yorkshire, U.K

Re: SPI + MAX31855: SPI_Read(0) not working? - SOLVED!

#6 Post by jzk » 02 Sep 2022 21:13

sorted out some issues with the temperature conversion.
it gave some erroneous values during reasonable rate of temperature change?
i.e. it would give a small negative value like -1.3 or -6.7 when holding the TC between finger tips.
It would then settle at ~32C, same cooling it down and with the CJC temp.
So it appears to be all sorted now.
measurement with TC placed inside fridge down to ~5C, then out into room temp, ~1sec interval between measurements.

Image

following is full code if someone intends messing with one of these MAX31855 chips.

Code: Select all

/* EasyPIC7, 18F45K22, XT Osc, 8MHz.
CONFIG1H : $300001 : 0x0023
CONFIG2L : $300002 : 0x001F
CONFIG2H : $300003 : 0x003C
CONFIG3H : $300005 : 0x00BF
CONFIG4L : $300006 : 0x0081
CONFIG5L : $300008 : 0x000F
CONFIG5H : $300009 : 0x00C0
CONFIG6L : $30000A : 0x000F
CONFIG6H : $30000B : 0x00E0
CONFIG7L : $30000C : 0x000F
CONFIG7H : $30000D : 0x0040
*/

// Lcd module connections
sbit LCD_RS at LATB4_bit;
sbit LCD_EN at LATB5_bit;
sbit LCD_D4 at LATB0_bit;
sbit LCD_D5 at LATB1_bit;
sbit LCD_D6 at LATB2_bit;
sbit LCD_D7 at LATB3_bit;

sbit LCD_RS_Direction at TRISB4_bit;
sbit LCD_EN_Direction at TRISB5_bit;
sbit LCD_D4_Direction at TRISB0_bit;
sbit LCD_D5_Direction at TRISB1_bit;
sbit LCD_D6_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB3_bit;
// End Lcd module connections

//SPI Declarations
sbit MAX_CS at LATE0_bit;
sbit SPI_CLK at LATC3_bit;
sbit SPI_MISO at LATC4_bit;
sbit MAX_CS_Dir at TRISE0_bit;
sbit SPI_CLK_Dir at TRISC3_bit;
sbit SPI_MISO_Dir at TRISC4_bit;

int temp, temp1, temp2;
float tempTC, tempCJC;
char s_tempTC[15], s_tempCJC[15];
short temp_byte[4] = {0, 0, 0, 0};

void MAX31855_Read() {
  MAX_CS = 0;//enables device
  Delay_ms(10);
  temp_byte[0] = SPI_Read(0);//read command initiates clock
  temp_byte[1] = SPI_Read(0);//each read gives x8 clock pulses
  temp_byte[2] = SPI_Read(0);//obtaining x1 byte from slave
  temp_byte[3] = SPI_Read(0);//next byte received by following read(s)
  MAX_CS = 1;//disables device
}
// NOTE: NOT HANDLE NEGATIVE VALUES
void temperatureTC()
{
  temp = (temp_byte[1] & 0xff) >> 2;//Ignore the first 2 bits
  temp1 = (temp_byte[0] & 0xff) << 6;//Sets of the second byte position, to form the 14-bit.
  temp2 = temp | temp1;//Converts the 2 bytes to 16-bit variable.
  tempTC = temp2 * 0.25;//times bit resolution
  sprintf(s_tempTC,"%4.2f°C",tempTC);// Convert temperature value to string
}
void temperatureCJC() {
  temp = (temp_byte[3] & 0xff) >> 4;//Ignore the first 4 bits
  temp1 = (temp_byte[2] & 0xff) << 4;//Sets of the second byte position, to form the 12-bit.
  temp2 = temp | temp1;// Converts the 2 bytes to 16-bit variable.
  tempCJC = temp2 * 0.0625;// times bit resolution
  sprintf(s_tempCJC,"%4.2f°C",tempCJC);// Convert temperature value to string

}
void main() {
    ANSELC = 0;//will not read correctly without this
    MAX_CS_Dir = 0;// output for CS
    MAX_CS = 1;
    SPI_CLK_Dir = 0;//output for PIC SCK1 on RC3 
    SPI_MISO_Dir = 1;// input for PIC MISO1 on RC4
    
    Lcd_Init();// Initialize Lcd
    Delay_ms(100);
    Lcd_Cmd(_LCD_CLEAR);// Clear display
    Lcd_Cmd(_LCD_CURSOR_OFF);// Cursor off

    UART1_Init(9600);// Initialize UART module at 9600 bps
    Delay_ms(100);// Wait for UART module to stabilize
    
    SPI1_Init_Advanced(//initialise SPI
    _SPI_MASTER_OSC_DIV64,
    _SPI_DATA_SAMPLE_MIDDLE,
    _SPI_CLK_IDLE_LOW,
    _SPI_LOW_2_HIGH
    );
    SPI_Set_Active(&SPI1_Read, &SPI1_Write);//SPI1 active

    while (1) {
    MAX31855_Read();
    if((temp_byte[1] & 0x01) == 0x01){          // Fault detection
        Lcd_Out(1,1,"     ERROR      ");
        UART1_Write_Text("ERROR");         //  Send message on connection
        UART1_Write(0x20);//space
        UART1_Write(0x20);

      if((temp_byte[3] & 0x01) == 0x01){        // Open circuit fault?
         Lcd_Out(2,1,"  Open circuit  ");           // Write text in first row
         UART1_Write_Text("Open circuit");         //  Send message on connection
         UART1_Write(13);
         Delay_ms(1000);
      }
      //
      if((temp_byte[3] & 0x02) == 0x02){        // Short to GND fault?
        Lcd_Out(2,1,"  Short to GND  ");           // Write text in first row
        UART1_Write_Text("Short to GND");         //  Send message on connection
        UART1_Write(13);
         Delay_ms(1000);
      }
      //
      if((temp_byte[3] & 0x04) == 0x04){        // Short to Vcc fault?
        Lcd_Out(2,1,"  Short to Vcc  ");           // Write text in first row
        UART1_Write_Text("Short to Vcc");         //  Send message on connection
        UART1_Write(13);
         Delay_ms(1000);
      }
    }
    else{
        temperatureTC();
        Lcd_Out(1,1,"TempTC:         ");
        Lcd_Out(1,10,s_tempTC);
        UART1_Write_Text("TempTC: ");
        UART1_Write_Text(s_tempTC);
        UART1_Write(0x20);//space
        UART1_Write(0x20);
        //
        temperatureCJC();
        Lcd_Out(2,1,"TempCJC:        ");
        Lcd_Out(2,10,s_tempCJC);
        UART1_Write_Text("TempCJC: ");
        UART1_Write_Text(s_tempCJC);
        UART1_Write(13);
    }
    Delay_ms(1000);
   }//ends while(1)

}//ends main

Post Reply

Return to “mikroC PRO for PIC General”