5 Replies Latest reply on Apr 30, 2019 12:34 AM by MichaelP.

    SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help

    MichaelP.

      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[i]);

          }

          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

        • 1. Re: SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help
          SudheeshK_26

          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

          • 2. Re: SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help
            MichaelP.

            Dear Sudheesh,

             

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

             

            Best regards,

            Michael

            • 3. Re: SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help
              SudheeshK_26

              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-40001985A.pdf , 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

              • 4. Re: SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help
                MichaelP.

                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

                • 5. Re: SPI communication between CY15B104Q-LHXI and PIC16LF18446 - Need help
                  MichaelP.

                  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