3 Replies Latest reply on Mar 16, 2018 6:42 AM by svoz

    SPI Slave Simple Echo

    ufuk.onder_2438846

      Hi,

       

      I am trying to build a simple SPI slave communication protocol for an existing master. The master device is an Atmega microcontroller, with an SPI clock approximately 40Kbps.

       

      There are two types of messages: first one is master write messages, and second one is master read messages. And I want to implement all protocol logic in interrupt handler...

      The problem is; I cant simply use buffered mode, since master write packets should echo the incoming packet (with one or two bytes exception) immediately.

       

      SCB is configured in SPI slave mode, with 0 software buffer size (RX and TX buffer sizes are 8). Interrupt is configured as Internal, and the only interrupt source selected is "RX FIFO Not Empty".

      Code is written with following naming notations...

      Every thing starting with cy are cypress conponents, and everything starting with comm are related with my communication routines.

      the following code is my custom SPI ISR function.

       

      //WRITE MESSAGE FORMAT:

      // <WriteSlaveCommand><TotalSize><PayloadSize><...PAYLOAD...><MasterMagic><CRC>

      // Response should be an echo (only change MasterMagic with SlaveMagic, and update CRC accordingly)

      //READ MESSAGE FORMAT:

      // <WriteSlaveCommand><TotalSize><PayloadSize><...0xFF's...><MasterMagic><CRC>

      //Response should be populated accordingly

      void _commParsePacket(void)

      {

          //store received byte

          _commRxByte = cySPI_RX_FIFO_RD_REG;

          while(0u != cySPI_GET_RX_FIFO_ENTRIES);

          cySPI_ClearRxInterruptSource(cySPI_INTR_RX_NOT_EMPTY);

         

          //if software buffer enabled

          //cySPI_rxBufferHead = 0;

          //cySPI_rxBufferTail = 0;   

         

          switch(_parseIndex)

          {

              //wait for Write or Read command

              case 0:

                  commRxCrcReset();

                  commPacket.command = _commRxByte;

       

                 //Clear/Invalidate TX buffer

                  cySPI_TX_FIFO_CTRL_REG |= 0x00010000;

                  cySPI_TX_FIFO_CTRL_REG &= 0xFFFEFFFF;

                 

                  if ((commPacket.command == WriteSlaveCommand) || (commPacket.command == ReadSlaveCommand))

                  {

                      commStartedCount++;

                      commTxCrcReset();

                      _commTxByte = commPacket.command;

       

       

                      if (commPacket.command == WriteSlaveCommand)

                      {

                          commPacket.payload = (unsigned char*)&commMosiPacket; //if command is a write command, fill this structure

                      }

                      else

                      {

                          commPacket.payload = (unsigned char*)&commDummyPacket; //if command is a read command, fill a dummy/temporary structure

                                                                                                                                 //note: already populates MisoPacket is going to be transferred

                      }

                     

                      _parseIndex++;

                  }

                  commRxCrcUpdate(_commRxByte);

                  break;

       

              // wait for total size

              case 1:

                  commPacket.totalSize = _commRxByte;

       

       

                  _commTxByte = commPacket.totalSize;

                 

                  commRxCrcUpdate(commPacket.totalSize);

                 

                  _parseIndex++;

                  break;

       

              //wait for payload size           

              case 2:

                  commPacket.payloadSize = _commRxByte;

                  commRxCrcUpdate(commPacket.payloadSize);

       

                  //check for payload sizes... return to parseIndex=0 to avoid a possible data overflow

                  if( ((commPacket.command == ReadSlaveCommand) && (commPacket.payloadSize ==  5)) ||

                      ((commPacket.command == WriteSlaveCommand) && (commPacket.payloadSize == 17)) )

                  {

                      _commTxByte = commPacket.payloadSize;

                     

                      _parsePacketIndex = 0;

                      _parseIndex++;

                  }

                  else

                  {

                      _parseIndex = 0;

                  }

                  break;

       

              //fill payloads

              case 3:

                  if (_parsePacketIndex < commPacket.payloadSize)

                  {

                      commPacket.payload[_parsePacketIndex] = _commRxByte;

       

       

                      if (commPacket.command == ReadSlaveCommand)

                      {

                          _commTxByte = ((unsigned char*)(&commMisoPacket))[_parsePacketIndex];

                      }

                      else

                      {

                          _commTxByte = ((unsigned char*)(&commMosiPacket))[_parsePacketIndex];

                      }

                      commRxCrcUpdate(_commRxByte);           

                      _parsePacketIndex++;

                  }

                  if (_parsePacketIndex == commPacket.payloadSize)

                  {

                      _parseIndex++;

                  }

                  break;

       

              //replace magic numbers

              case 4:

                  commPacket.magicNumber = _commRxByte;

                  _commTxByte = SlaveMagic;

                 

                  commRxCrcUpdate(commPacket.magicNumber);

                  _parseIndex++;

                  break;

       

              //wait and check for CRC's

              case 5:

                  commPacket.crc = _commRxByte;

                  _commTxByte = commTxCrcGet();

                  _parseIndex++;

                  if (commPacket.crc == commRxCrcGet())

                  {

                      if (commPacket.command == WriteSlaveCommand)

                          _commSuccess = 0x00;

                  }

                  break;

       

              //wait for my CRC to be send...

              default:

                  _parseIndex = 0;

                  //_commResetTXBuff();

                  //return;

                  break;

          }  

         

          //transmit

          cySPI_TX_FIFO_WR_REG = _commTxByte;

          commTxCrcUpdate(_commTxByte);

             

          //if software buffer enabled

          //cySPI_txBufferHead = 1;

          //cySPI_txBufferTail = 0;

         

          return;

      }

       

      I am using Psoc Creator 4.1, and my device is CY8C4124...

      Also note that "Slave Select" is always selected.

       

      Problem is;

      1 - It seems nearly 1/2 of the time, they just communicate ok.

      2 - If I read failed packets, I see data is late 1 or 2 bytes...

       

       

       

      Thanks...