From the first 'scope plot, your clock has the wrong polarity/phase. You should have positive going pulse when transferring data.
uint8_t max31865_interface_spi_init(void)
{
SSP1CON1 = (0<<5); //clear bit 5, disable serial port
TRISC = (0<<3) | (1<<4) | (0<<5) | (0<<6); //clear RC3, RC5, RC6 (output: SCK1, SDO, CS) and set RC4 (input: SDI)
SSP1CON1 = (1<<4) | (0<<3) | (0<<2) | (0<<1) | (0<<0); // 4: (CKP), 3-0:(SSPM = 0000; Master mode , Fosc/4)
SSP1STAT = (0<<7) | (0<<6); //7: (SMP) 1-end, 0-middle, 6: (CKE) transmit on clock transition to active
SSP1ADD = 0;
SSP1CON1 = (1<<5); //set bit 5, enable serial port
return 0;
}
SSP1CON1 = (1<<5); //set bit 5, enable serial port
SSP1CON1 = 0x20; //set bit 5, enable serial port
SSP1CON1 |= (1<<5); //set bit 5, enable serial port
SSP1CON1bits.SSPEN = 1; //set bit 5, enable serial port
void max31865_interface_spi_init(void)
{
TRISC = 1<<4; // Clear RC3, RC5, RC6 (output: SCK1, SDO, CS) and set RC4 (input: SDI)
SSP1CON1 = 0;
SSP1STAT = 0;
SSP1ADD = 0;
CKE1 = 1; // Transmit from idle to active transition
SSPEN1 = 1; // Enable serial port
}
void max31865_interface_spi_deinit(void)
{
SSPEN1=0; // Disable serial port
}
uint8_t max31865_interface_spi_readwrite(uint8_t reg, uint8_t data)
{
LATC6 = 0; // CS low
NOP(); // Small delay
SSP1BUF = reg; // Send address
while(!SSP1IF); // Wait
SSP1BUF = data; // Send data (Or dummy byte in read mode)
SSP1IF = 0; // Clear flag
while(!SSP1IF);SSP1IF=0; // Wait, clear flag
LATC6 = 1; // CS high
return SSP1BUF; // Return received data if any (Ignore in write mode)
}
max31865_interface_spi_readwrite(0x99,0xAA);
SDO (also called MOSI) is driven by the PIC. SDI (MISO) is driven by Max. Check your connections. Do you have anything else connected to these pins.
Also, whewn you write this:Code: [Select]SSP1CON1 = (1<<5); //set bit 5, enable serial port
you overwrite all the bits of the register. It's the same as if you wrote
Your code is overcomplicated.
The MAX31865 only reads/write one byte for each register, so there's little sense on using a pointer to the buffer and data length.
Also the two sepparate read/write functions are 99% redundant, that's why I showed how to unify them, the result will be the same.
Why are you setting CKE low? You've been warned about the errata, also CKP=0,CKE=1 is the most common SPI mode.
Why so many functions always returning 0 when there're no checks of any kind, or anything else to return? Just make them void.
The delay_ms function is redundant, simply use __delay_ms();
Remember for the delay to work correctly, _XTAL_FREQ must be defined somewhere, matching the crystal frequency in Hz.
You're defining it as 1MHz, is that correct? Seems too low?
I did change it to CKP = 0 and CKE = 1 to avoid the errata; thank you for pointing this out (again). I also consolidated everything to the single read/write duplex function as you suggested. The "return 0" was a part of the max31865 library I was attempting to use. I discarded the library as you will see below and I'm trying to make my code as simple as possible so I can first understand what is (or isn't) working.
I am running the Fosc at 1MHz, so CLK is 250 kHz (Fosc/4). I don't think running on the slower side should somehow "break" SPI?
/*
* File: max_test_1.c
* Author: kev
*
* Created on November 6, 2022, 1:05 PM
*/
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include "configs.h"
#define _XTAL_FREQ 1000000
void spi_init(){
SSP1CON1 = (0<<5); //clear bit 5, disable serial port
TRISC = (0<<3) | (1<<4) | (0<<5) | (0<<6); //clear RC3, RC5, RC6 (output: SCK1, SDO, CS) and set RC4 (input: SDI)
SSP1CON1 = (0<<4) | (0<<3) | (0<<2) | (0<<1) | (0<<0); // 4: (CKP), 3-0:(SSPM = 0000; Master mode , Fosc/4)
SSP1STAT = (0<<7) | (1<<6); //6: (CKE) transmit on clock transition to active
SSP1ADD = 0;
SSP1CON1bits.SSPEN = 1; //set bit 5, enable serial port
}
uint8_t max31865_interface_spi_readwrite(uint8_t reg, uint8_t data)
{
LATCbits.LATC6 = 0; // CS low
NOP(); // Small delay
SSP1BUF = reg; // Send address
while(!SSP1IF); // Wait
SSP1BUF = data; // Send data (Or dummy byte in read mode)
PIR1bits.SSP1IF = 0; // Clear flag
while(!SSP1IF);SSP1IF=0; // Wait, clear flag
LATCbits.LATC6 = 1; // CS low
return SSP1BUF; // Return received data if any (Ignore in write mode)
}
void main(void) {
spi_init();
OSCCONbits.IRCF = 0x0B; //set internal osc to 1mhz
OSCCONbits.SCS = 0x00; //system clock setup
max31865_interface_spi_readwrite(0x00,0x62);
__delay_ms(100);
while (1){
max31865_interface_spi_readwrite(0x01,0x00); //read RTD MSBs
max31865_interface_spi_readwrite(0x02,0x00); //read RTD LSBs
// max31865_interface_spi_readwrite(0x03,0x00); //read high fault threshold status
// max31865_interface_spi_readwrite(0x04,0x00); //read low fault threshold status
// max31865_interface_spi_readwrite(0x05,0x00); //read low fault threshold MSB
// max31865_interface_spi_readwrite(0x06,0x00); //read low fault threshold LSB
// max31865_interface_spi_readwrite(0x07,0x00); //read fault status
__delay_ms(1000);
}
}
Coming back to this after another exhausting week.
In your communications, everything appears to be shifted by 1 bit. You're reading register 0x04 instead of 0x02, hence you get all ones. The response is shifted right by 1 bit too - 0x7f instead of 0xff. So, your SPI mode is wrong. Looking at their pictures in the datasheet, you need CKE = 0. The datasheet claims CKP doesn't matter (see Fig. 5). You have CKP = 0, CKE = 1.
Doesn't look shifted to me, I clearly see how SDO changes on the previous falling edge, sending 1 & 2.
The MAX31865 automatically accommodates either clock polarity by sampling SCLK when CS becomes active to determine the polarity of the inactive clock
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include "configs.h"
#define _XTAL_FREQ 1000000
void spi_init(){
SSP1CON1 = (0<<5); //clear bit 5, disable serial port
TRISC = (0<<3) | (1<<4) | (0<<5) | (0<<6)| (0<<6); //clear RC3, RC5, RC6 (output: SCK1, SDO, CS) and set RC4, RC7 (input: SDI, MAX RDY)
SSP1CON1 = (1<<4) | (0<<3) | (0<<2) | (0<<1) | (0<<0); // 4: (CKP), 3-0:(SSPM = 0000; Master mode , Fosc/4)
SSP1STAT = (0<<7) | (0<<6); //7 (SPI Master mode), 0 = Input data sampled at middle of data output time, 6: (CKE) transmit on clock transition to active
SSP1ADD = 0;
SSP1CON1bits.SSPEN = 1; //set bit 5, enable serial port
}
uint8_t max31865_interface_spi_readwrite(uint8_t reg, uint8_t data)
{
LATCbits.LATC6 = 0; // CS low
NOP(); // Small delay
SSP1BUF = reg; // Send address
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
SSP1BUF = data; // Send dummy byte / data
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
SSP1BUF = data; // Send dummy byte / data
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
LATCbits.LATC6 = 1; // CS high
return SSP1BUF; // Return received data
}
void main(void) {
spi_init();
OSCCONbits.IRCF = 0x0B; //set internal osc to 1mhz
OSCCONbits.SCS = 0x00; //system clock setup
max31865_interface_spi_readwrite(0x80,0xA0); //config register write addr: 0x80. set config register bits 1000000 = 0x80
__delay_ms(100);
while (1){
max31865_interface_spi_readwrite(0x80,0xA8); //set 1-shot bit to trigger conversion (D5)
max31865_interface_spi_readwrite(0x01,0x00); //read RTD MSBs
// max31865_interface_spi_readwrite(0x02,0x00); //read RTD LSBs
max31865_interface_spi_readwrite(0x80,0xA0); //clear 1-shot bit (D5)
// max31865_interface_spi_readwrite(0x03,0x00); //read high fault threshold status
// max31865_interface_spi_readwrite(0x04,0x00); //read low fault threshold status
// max31865_interface_spi_readwrite(0x05,0x00); //read low fault threshold MSB
// max31865_interface_spi_readwrite(0x06,0x00); //read low fault threshold LSB
// max31865_interface_spi_readwrite(0x07,0x00); //read fault status
__delay_ms(1000);
}
}
uint8_t max31865_interface_spi_readwrite(uint8_t reg, uint8_t data)
{
LATCbits.LATC6 = 0; // CS low
NOP(); // Small delay
SSP1BUF = reg; // Send address
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
SSP1BUF = data; // Send dummy byte / data
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
SSP1BUF = data; // Send dummy byte / data <<--------- ?????
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
LATCbits.LATC6 = 1; // CS high
return SSP1BUF; // Return received data
}
uint8_t max31865_interface_spi_readwrite(uint8_t reg, uint8_t data)
{
LATCbits.LATC6 = 0; // CS low
NOP(); // Small delay
SSP1BUF = reg; // Send address
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
SSP1BUF = data; // Send dummy byte / data
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
LATCbits.LATC6 = 1; // CS high
return SSP1BUF; // Return received data
}
uint16_t read_rtd(void)
{
uint16_t rtd = max31865_interface_spi_readwrite(0x01,0x00); //read RTD MSBs
rtd = rtd<<8 | max31865_interface_spi_readwrite(0x02,0x00); //read RTD LSBs
return rtd;
}
Another thing I realized is that I need to have 24 clock cycles to do a complete read of the RTD registers; 8 to write the register address, and 16 for the full 16 bits of data in the MSB temperature measurement register.
uint16_t max31865_interface_spi_read16(uint8_t reg)
{
uint8_t temp;
LATCbits.LATC6 = 0; // CS low
NOP(); // Small delay
SSP1BUF = reg; // Send address
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
SSP1BUF = 0; // Send dummy byte
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
temp = SSP1BUF;
SSP1BUF = 0; // Send dummy byte
while(!PIR1bits.SSP1IF); // Wait
PIR1bits.SSP1IF = 0;
LATCbits.LATC6 = 1; // CS high
return (SSP1BUF << 8) | temp; // Return received data
}
Memory Summary:
Program space used 1FC4h ( 8132) of 2000h words ( 99.3%)
Data space used 1D3h ( 467) of 200h bytes ( 91.2%)
EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)
Configuration bits used 2h ( 2) of 2h words (100.0%)
ID Location space used 4h ( 4) of 4h bytes (100.0%)
Ensure to enable optimizations, O2 is free and will reduce the memory usage a lot.
Memory Summary:
Program space used 1D7Ch ( 7548) of 2000h words ( 92.1%)
Data space used 1D3h ( 467) of 200h bytes ( 91.2%)
EEPROM space used 0h ( 0) of 100h bytes ( 0.0%)
Configuration bits used 2h ( 2) of 2h words (100.0%)
ID Location space used 4h ( 4) of 4h bytes (100.0%)
Finally, I think I've reached the finish line on this project.