SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help

Tip / Sign in to post questions, reply, level up, and achieve exciting badges. Know more

cross mob
user_4203386
Level 1
Level 1

Hello,

I would like some help to set up or correct my SPI communication.

I've been looking for two days now and trying to make changes in vain and I don't know if the problem is in the pin configuration or in the SPI functions.

Here is a summary of my situation:

I use a PIC16LF18446 (running at 8Mhz = 32Mhz/4) and a CY15B104Q-LHXI memory purchased from Mouser. I try to read the device ID but I only get 0 or F depending on whether the pin RC2 = SDI1 is in analog or digital mode. I also tried to write a value to an address and read it but this is not conclusive. Notation : nXX = XX_bar for the XX with the bar above.

Nevertheless, my pin configuration is as follows:

Memory <= 400kHz => PIC



Configuration (* = requested in the documentation of the PIC)
SO <=> SDI1 = RC2 as Input*, digital, weak pull-up disable, open-drain
nCS <=> nSS1 = RB4 as Input*, digital, weak pull-up disable, push-pull
SI <=> SDO1 = RB5as Output*, digital, weak pull-up disable, push-pull
SCK <=> SCK1 = RB6 as Output*, digital, weak pull-up disable, push-pull

Is this sounds correct?

Then, the SPI modes described in the PIC do not match those in the memory. With the information from both sides, I deduced that:

PIC-Mode
0123
CKP0011
CKE1010
Memory-Mode03
CPOL

01
CPHA01

I set myself in the PIC-mode 1 configuration in order to be in Memory-mode 0 and I force the SCK to be at zero to detect mode 0 when nSS1 is set to LOW. This is converted to :

SSP1STAT = 0b 0000 0000 ; // Mode 0 with sampled at the middle

SSP1CON1 = 0x2A

SSP1CON2 = 0x00

Is this configuration sounds correct?

Now, here is my code:

In the file main.c

En-tête 1

#include <xc.h>

#include "./mcc.h"

#include <string.h>

// Prototype -----------------------

void print_bytes(void *ptr, int size);

void main(void)

{

                PMD_Initialize();

PIN_MANAGER_Initialize();

   

    printf("\n=== SPI 25.04 TEST ===\n\n");

__delay_ms(2000);  

               

    // Write at 0x012345 the value 0xAB, then read this latter

    uint8_t     ReadBuffer = 0x01;

    uint8_t     WriteBuffer = 0xAB;

    uint8_t     DummyBuffer = 0x00;

    long        addresse = 0x00012345;

    uint8_t     add_0 = (uint8_t)(addresse>>0);

    uint8_t     add_1 = (uint8_t)(addresse>>8);

    uint8_t     add_2 = (uint8_t)(addresse>>16);

    uint8_t     add_3 = (uint8_t)(addresse>>24);

    spi1_Initialize();

    __delay_ms(2000);

    printf("\n\n=== WRITING ===\n\n");

    printf("Step 1: Send WREN \n");

    SS1_bar_SetLow();   // nCS à 0

    DummyBuffer = spi1_exchangeByte(SPI_WREN);

    SS1_bar_SetHigh();  // nCS à 1

    printf("Step 2: Send WRITE \n");

    DummyBuffer = spi1_exchangeByte(SPI_WRITE);

    printf("Step 3: Send the addresse\n");

    DummyBuffer = spi1_exchangeByte(add_2);

    DummyBuffer = spi1_exchangeByte(add_1);

    DummyBuffer = spi1_exchangeByte(add_0);

    printf("Step 4: Write the value\n");

    DummyBuffer = spi1_exchangeByte(WriteBuffer);

    SS1_bar_SetHigh();  // nCS à 1

    printf("\n=== WRITING DONE ===\n");

    printf("\n\n=== READING ===\n\n");

    printf("Step 2: Send READ \n");

    SS1_bar_SetLow();   // nCS à 0

    DummyBuffer = spi1_exchangeByte(SPI_READ);

    printf("Step 3: Send the address\n");

    DummyBuffer = spi1_exchangeByte(add_2);

    DummyBuffer = spi1_exchangeByte(add_1);

    DummyBuffer = spi1_exchangeByte(add_0);

    printf("Step 4: Read the value\n");

    ReadBuffer = spi1_exchangeByte(DummyBuffer);

    SS1_bar_SetHigh();   // nCS à 1

    printf("\n=== READING DONE ===\n");

    printf("RB=%2X\n",ReadBuffer);

    print_bytes(&ReadBuffer, 1);

} // End of main

void print_bytes(void *ptr, int size)

{

    unsigned char *p = ptr;

    int i;

    for (i=0; i<size; i++) {

        printf("%02hhX ", p);

    }

    printf("\n");

}

In the file spi.c (generated with the help of the MCC of MPLAB IDE and with my modifications):

En-tête 1

#include <xc.h>

#include "pin_manager.h"

#include "spi_MCC.h"

#pragma warning disable 520    

uint8_t dummy = 0;

void SPI_Read_Device_ID(uint8_t *data)

{

    dummy = SSP1BUF; // Clear Tx buffer

   

    // RDID opcode

                //SS1_bar_SetLow();   // nCS à 0

    dummy = spi1_exchangeByte(SPI_RDID);

    // Take only the fisrt byte of the device ID

                data[0] = spi1_exchangeByte(dummy);

   

    // To read the device ID

    //spi1_exchangeBlock(data, SPI_DEV_ID_LENGTH);

           

    SS1_bar_SetHigh(); // nCS à 1

}

void spi1_close(void)

{

    SSP1CON1bits.SSPEN = 0;

}

//Setup SPI

void spi1_Initialize(void)

{

        //setup SPI

        //SSP1STAT = 0x80; // Mode 0(PIC) = Mode 0(Mem), sample at the END

        //SSP1STAT = 0x00; // Mode 0(PIC) = Mode 0(Mem), sample at the MIDDLE

        //SSP1STAT = 0xC0; // Mode 1(PIC) = Mode 0(Mem), sample at the END

        SSP1STAT = 0x40; // Mode 1(PIC) = Mode 0(Mem), sample at the MIDDLE

        // SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD;

        SSP1CON1 = 0x2A;

       

        SSP1CON2 = 0x00;

        //SSP1CON3 = 0x00;

       

        // Divider of the clock => 400 kHz

        SSP1ADD = 0x04;

        // Fix the SCK at 0, so when nCS is LOW, it will detect the mode 0, p.5 last §

        TRISBbits.TRISB6 = 0x00;

}

// Full Duplex SPI Functions

uint8_t spi1_exchangeByte(uint8_t b)

{

    // Clear the Write Collision flag, to allow writing

    SSP1CON1bits.WCOL = 0;

   

    SSP1BUF = b;

    while(!PIR3bits.SSP1IF);

    PIR3bits.SSP1IF = 0;

    return SSP1BUF;

}

void spi1_exchangeBlock(void *block, size_t blockSize)

{

    uint8_t *data = block;

    while(blockSize--)

    {

        *data = spi1_exchangeByte(*data);

        data++;

    }

}

// Half Duplex SPI Functions

void spi1_writeBlock(void *block, size_t blockSize)

{

    uint8_t *data = block;

    while(blockSize--)

    {

        spi1_exchangeByte(*data++);

    }

}

void spi1_readBlock(void *block, size_t blockSize)

{

    uint8_t *data = block;

    while(blockSize--)

    {

        *data++ = spi1_exchangeByte(0);

    }

}

Thank you in advance if you have taken the time to read all the way and help me.

I remain at your disposal for further information.

Have a good day.

Best regards,

Michael

0 Likes
1 Solution
SudheeshK
Moderator
Moderator
Moderator
250 sign-ins First question asked 750 replies posted

Hi Michael,

We found out that, the chip select pin is configured as an input. It should be configured as an output pin in the controller similar to SI and SCK pins. Could you please test after configuring chip select pin as an output?


Thanks and Regards,Sudheesh

View solution in original post

0 Likes
7 Replies
SudheeshK
Moderator
Moderator
Moderator
250 sign-ins First question asked 750 replies posted

Hi Michael,

Thank you for providing the details about the issue. Could you please attach SPI waveform (SO, SI, SCK and CS# signals) for "read device ID" operation also?

Thanks and Regards,

Sudheesh

0 Likes

Dear Sudheesh,

I unfortunately don't have an oscillator on hand....

Best regards,

Michael

0 Likes

Hi Michael,

I checked SPI mode waveform in datasheet of PIC16LF18446 (http://ww1.microchip.com/downloads/en/DeviceDoc/Microchip-8-bit-PIC-MCU-PIC16(L)F18426_46-Datasheet-... , page 508). Our device changes the data on SO signal along with falling edge of the clock, so that the master can sample it along with the rising edge. So, can you change the bit SMP to 1 in SSP1STAT register and check?

Thanks and Regards,

Sudheesh

0 Likes

Hi Sudheesh,

I tried what you suggested as SPP1STAT = 0xC0 = 0b 1100 0000 and it doesn't work either.

EDIT : I tried all these modes with the same result.

        //setup SPI => MODE 0 and 1 of PIC

        SSP1STAT = 0xC0; // Mode 0(PIC) = Mode 0(Mem), sample at the END           1100

        // NO SSP1STAT = 0x40; // Mode 0(PIC) = Mode 0(Mem), sample at the MIDDLE  0100

        // NO SSP1STAT = 0x80; // Mode 1(PIC) = Mode 0(Mem), sample at the END     1000

        // NO SSP1STAT = 0x00; // Mode 1(PIC) = Mode 0(Mem), sample at the MIDDLE  0000

       

        // SSPEN enabled; CKP Idle:Low, Active:High; SSPM FOSC/4_SSPxADD;

        SSP1CON1 = 0x2A;

       

        // === OR ===

       

        //setup SPI => MODE 2 and 3 of PIC

        // NO SSP1STAT = 0xC0; // Mode 2(PIC) = Mode 1(Mem), sample at the END      1100

        // NO SSP1STAT = 0x40; // Mode 2(PIC) = Mode 1(Mem), sample at the MIDDLE   0100

        // NO SSP1STAT = 0x80; // Mode 3(PIC) = Mode 1(Mem), sample at the END      1000

        // NO SSP1STAT = 0x00; // Mode 3(PIC) = Mode 1(Mem), sample at the MIDDLE   0000

       

        // SSPEN enabled; CKP Idle:High, Active:High; SSPM FOSC/4_SSPxADD;

        //SSP1CON1 = 0x3A;

Is there any way to ensure that the memory loads its BUFFER register with the right data? For example, in the case of an RDID, it should load the first byte which is 0x7F.

Are there any particularities in the use of the component? I put nHOLD to Vdd, Vdd to ground through a capacity of 100nF, Vss to GND and nWP to Vdd.

Best regards,

Michael

0 Likes

Hi Sudheesh,

I'm still stuck. However, I was able to verify that the memory was working by using a USB key with a small software that reads and writes on it.

However, my code still doesn't allow me to write or read in this memory. I kept searching and searching everywhere on the internet but I couldn't get SPI communication to work.

You really have no idea how to help me?

Best regards,

Michael

0 Likes

Hi Michael,

My sincere apologies for the delay in getting back to you.

I reviewed your program that you provided earlier and found that the function call to make CS# signal LOW before SPI operations are missing before RDID (commented the function call "SS1_bar_SetLow();") command and WRITE command. Please call "SS1_bar_SetLow();" before RDID and WRITE operations.

Thanks and Regards,

Sudheesh

0 Likes
SudheeshK
Moderator
Moderator
Moderator
250 sign-ins First question asked 750 replies posted

Hi Michael,

We found out that, the chip select pin is configured as an input. It should be configured as an output pin in the controller similar to SI and SCK pins. Could you please test after configuring chip select pin as an output?


Thanks and Regards,Sudheesh

0 Likes