Electronics > Microcontrollers

PIC16F1946 - Hardware SPI timing issues?

(1/10) > >>

nexus:
Hi all,

I am working on a board I designed using a PIC16F1946 in the QFN-64 package as my main mcu. This is not my first PIC16 project, but it is the first where I am implementing SPI with PIC.
I have been reading and studying the datasheet and online examples regarding hardware SPI using the MSSP peripheral.
I would like to use typical 4-wire SPI to interface with a MAX 31865 RTD temp sensor interface IC. Please see attached schematic for pinout and connection info.

I began with writing some code to initialize and read/write using hardware SPI on MSSP1. I am developing in MPLAB IDE X v6.05 using the free XC8 v2.40 compiler.

As far as I can tell, the setup code I wrote follows the SPI configuration as per the datasheet. However, I am seeing this strange behavior on my hardware: the clock (CLK) and serial data out (SDI) are transitioning at the same time, on the same edge. This is not how SPI should operate, as data is shifted in on the clock transition... i.e. the clock should transition while the data remains constant. For some reason, they are transitioning on the same edge which will not allow SPI to work.

My main.c is as follows:

--- Code: ---/*
 * 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"

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<<5); //clear bit 5, disable serial port
    SSP1CON1 = (0<<4) | (0<<3) | (0<<2) | (0<<1) | (0<<0); // 4: (CKP), 3-0:(SSPM = 0000; Master mode , Fosc/4)
    SSP1STAT = (0<<7) | (0<<6); //6: (CKE) transmit on clock transition to active
    SSP1ADD = 0;
   
    //LATCbits.LATC6 = 1;  //CS high
    //LATCbits.LATC6 = 0;  //CS low
   
    SSP1CON1 = (1<<5); //set bit 5, enable serial port
}

uint8_t spi_read(uint8_t buf)
{
    SSP1BUF = buf;
    while(!PIR1bits.SSP1IF);
    PIR1bits.SSP1IF = 0;
    return SSP1BUF;
}

uint8_t spi_read2(uint8_t buf)
{
    SSP1BUF = 0xAA; // Writes dummy byte
while(!PIR1bits.SSP1IF); // Wait for transfer to complete
return SSP1BUF; // Returns received byte
}

void spi_write(uint8_t *buf)
{
    SSP1BUF = *buf;
    while(!PIR1bits.SSP1IF);
    PIR1bits.SSP1IF = 0;
}

void spi_write2(uint8_t buf)
{
uint8_t rxtmp;
SSP1BUF = buf; // Write to SPI
while(!PIR1bits.SSP1IF); // Wait for transfer to complete
rxtmp = SSP1BUF; // Dummy read
}

void main(void) {
    spi_init();
   
    unsigned char i;
   
    while(1){
        for( i = 0; i < 255; i++ ) {
            spi_write2(i);
        }
    }
}
--- End code ---

Any idea or explanations as to if I am doing something incorrectly in software to initialize and write to the SPI buffer?

Attached a screenshot from my scope showing what happens when this code runs. The labels (CS, CLK, SDI, SDO) are as viewed from the MAX chip, so SDI here would be the same net as SDO on the PIC.

nexus:
My code is a bit sloppy as of now as I have been scatterbrained trying to figure this out as of now, and I am by no means a pro software engineer.
Attaching datasheet for PIC16F1946 for convenience.

DavidAlfa:
Your problem is CKE. You must set it to 1.
But your code isn't doing that:

--- Code: ---SSP1STAT = (0<<7) | (0<<6); //6: (CKE) transmit on clock transition to active

--- End code ---

Fix:

--- Code: ---SSP1STAT = (0<<7) | (1<<6); //6: (CKE) transmit on clock transition to active

--- End code ---

No need to upload the datasheet (Wasting forum storage), just link it from microchip: datasheet

Edit:
For dummy read:

--- Code: ---void spi_write2(uint8_t buf)
{
uint8_t rxtmp;
SSP1BUF = buf;            // Write to SPI
while(!PIR1bits.SSP1IF);  // Wait for transfer to complete
rxtmp = SSP1BUF;          // Dummy read
}

--- End code ---

This is enough, and faster:

--- Code: ---void spi_write2(uint8_t buf)
{
SSP1BUF = buf;            // Write to SPI
while(!PIR1bits.SSP1IF);  // Wait for transfer to complete
SSP1BUF;           // Dummy read
}

--- End code ---

jpanhalt:
I use similar chips (e.g., 16F18xx and 16F17xx).  I also code in Assembly, so my code probably won't help you.  The two variables I worry about are mode and system oscillator frequency.  Usually mode is pretty clear, but I wrote a routine for all four modes.  If I have a problem, I drop the fosc to something very reasonable, like 4 MHz or 8Mhz, then try each mode.  Once that is working, I go to 16 MHz or 32 MHz to be sure they also work.  In my present project, for example, with two peripherals on the same SPI, only one mode worked with both, and I needed to keep fosc at 16 MHz or below. 

Have you tried different modes at a low frequency?

Benta:
There are four modes of SPI transfers depending on clock phase and clock polarity.
It looks to me like you have your clock polarity wrong.

Navigation

[0] Message Index

[#] Next page

There was an error while thanking
Thanking...
Go to full version
Powered by SMFPacks Advanced Attachments Uploader Mod