8 Replies Latest reply on Jan 10, 2017 2:19 AM by user_1377889

    Configured as a SPI Master to talk to a device

    jdowd

      I have the PSoC 4 BLE system connected via SPI to a device. That device has a "Who Am I" register at 0x0f that will reply with the value 0x6a if read correctly.

         

      I have used a SCB dialog to create a SPI master, Sub mode: Motorola  CLK CPHA=1, CPOL=1

         

      Data Rate: 1Mbps

         

      Rx & Tx data bits 16

         

      Transfer Separation: Separated

         

      Rx & Tx Buffer Size: 8

         

      No Interrupts

         

      I have written the code to just query that register to prove that the SPI bus works. When the register is read correctly a LED connected to Pin 2 is turned on.

         

      What I found was that I had to put a while loop to continuously read the SPI bus to get the correct value. In fact I had to read the bus 9 times first and then on the 10th time the value returned was correct.

         

      Here is the code:

         

      static uint8_t readTheRegByUart(uint8_t theRegAddr) {
        uint8_t theRegValue = 0;
        uint16_t theReadCmd = 0x8000;
        
        /* read the register */
        theReadCmd |= (uint16_t)((uint16_t)theRegAddr << 8);
        SPI_SpiUartWriteTxData(theReadCmd);
        
        while(SPI_SpiUartGetRxBufferSize() > 0) {
          theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff);
        }
        
        return theRegValue;
      }

         

      int main(void) {
        uint8_t theValue;
        
          CyGlobalIntEnable; /* Enable global interrupts. */
          SPI_Start();
          while((theValue = readTheRegByUart(0x0f)) != 0x6a);
          Pin_2_Write(0);

         

          for (;;)
          {
              ;
          }
      }

         

      Am I running into a buffering issue from the Rx FIFO in the SPI implementation? Is using the "Uart" version of the SPI code wrong?

         

      Any insights would be helpful.

         

      Cheers!!

        • 1. Re: Configured as a SPI Master to talk to a device
          user_1377889

          Between these lines

             

            SPI_SpiUartWriteTxData(theReadCmd);
            
            while(SPI_SpiUartGetRxBufferSize() > 0) {
          you should wait for SPI write is completed.

             

          For every bit (byte) the SPI interface gets, one bit (byte) is returned immediately. When the very first byte is sent, the interface does not "know" yet what to answer, so a dummy byte is returned which should be skipped.
          SPI has no read command, so you must send dummy bytes to retrieve the information wanted.
          A pitfall is the select line, which is automatically taken low when a byte is sent. When the buffer is empty it is taken high again. This can lead to interface errors when the byte sequence is not provided fast enough resulting in ss-line glitches.

             

           

             

          Bob

          • 2. Re: Configured as a SPI Master to talk to a device
            jdowd

            Bob,

               

            Thanks for replying. I stuck this line in as you suggested:

               

            while(SPI_SpiUartGetTxBufferSize() > 0);

               

            However no joy. 

               

            If I'm sending "0x8f00" I'm assuming I should get something like 0x??6a" back. Where the 0x8f is the slave devices read command of it's ID register. What would be read back is "0x6a" (Slaves ID register contents) not so? In other words I send 2 bytes I immediately receive 2 bytes of data that are the effect of the sent 2 bytes which are commands to the slave device.

               

            Cheers!!

            • 3. Re: Configured as a SPI Master to talk to a device
              user_78878863

              Instead of

                 

              while(SPI_SpiUartGetTxBufferSize() == 0);

                 

              look at the SPI status / status register / bits. The SPI component thells you when a transfer is in progress. Even when the TX FIFO is empty it might take a (little) while until the data is available in the RX FIFO.

              • 4. Re: Configured as a SPI Master to talk to a device
                jdowd

                Hli,

                   

                In fact "SPI_SpiUartGetTxBufferSize()" is a call to the following code:

                   

                #define SPI_GET_TX_FIFO_ENTRIES    (SPI_TX_FIFO_STATUS_REG & \
                                                                 SPI_TX_FIFO_STATUS_USED_MASK)

                   

                So it does what you are describing.

                   

                Cheers!!

                • 5. Re: Configured as a SPI Master to talk to a device
                  jdowd

                  Me again...

                     

                  Perhaps I've solved this myself but I hate the solution...

                     

                   

                     

                  Essentially I just added a wait until I saw that data was received...

                     

                    uint8_t theRegValue = 0;
                    uint16_t theReadCmd = 0x8000;

                     

                    SPI_SpiUartClearRxBuffer();

                     

                    /* read the register */
                    theReadCmd |= (uint16_t)((uint16_t)theRegister << 8);
                    SPI_SpiUartWriteTxData(theReadCmd);

                     

                    while(SPI_SpiUartGetTxBufferSize() > 0);

                     

                    while(SPI_SpiUartGetRxBufferSize() == 0);
                    while(SPI_SpiUartGetRxBufferSize() > 0) {
                      theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff);
                    }
                    return theRegValue;

                     

                  I don't like having a blocking read in the code but I'm wondering if this is a typical solution to using SPI in this environment?

                     

                  Cheers!!

                  • 6. Re: Configured as a SPI Master to talk to a device
                    user_1377889

                      SPI_SpiUartWriteTxData(theReadCmd);

                       

                      while(SPI_SpiUartGetTxBufferSize() > 0); // Not needed

                       

                      while(SPI_SpiUartGetRxBufferSize() == 0); // needed to blocking wait for char ready
                      while(SPI_SpiUartGetRxBufferSize() > 0) // Not needed{
                        theRegValue = (uint8_t) (SPI_SpiUartReadRxData() & 0x000000ff); // This is what you want...

                       

                     

                       

                    Bob

                    • 7. Re: Configured as a SPI Master to talk to a device
                      jdowd

                      Thanks Bob.

                         

                      that works.

                         

                      Have a great New Year!!

                      • 8. Re: Configured as a SPI Master to talk to a device
                        user_1377889

                        Thanks, I'll do my very best ;-)

                           

                         

                           

                        Bob