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

cross mob
pblemel
Level 4
Level 4
25 replies posted 25 sign-ins First like received

Hi everyone,

I'm trying to understand how to initiate a read from the SPI.  I have an SPI master block on my design/schematic. I am reading from a slave that transmits over MISO beginning when CS is asserted and the clock toggles. I call SPI_SetActiveSlaveSelect() and see it go low, but need to clock in the data.

Digging down through SPI_Read() I get to Cy_SCB_SPI_Read(), which has a comment:

* This function only reads data available in the RX FIFO. It does not initiate an SPI transfer.

but the next comment says

* When in the master mode, this function writes data into the TX FIFO and waits until the transfer is completed before reading data from the RX FIFO.

Which would seem to imply that it initiates an SPI transfer by writing something into the TX FIFO.  

How do I initiate a read from MISO into the RX buffer?

Thanks

 

0 Likes
1 Solution

pblemel,

It appears that sending a "dummy" Tx 16-bits provides a non-zero and non 0xFFFF response from the MAX6675 slave IC.

According to the datasheet, bit 15 and bit 0 should equal '0' in both cases.  Is this the case?   If not this might be a clue.

What is the state of bit 2?  If set to '1' this indicates a open thermocouple connection.  If '1', this could be a reason for the constant value returned.

According to the MAX6675 datasheet, this should be the settings of the SPI Master for the PSoC.

Len_CONSULTRON_0-1665487138038.png

Len
"Engineering is an Art. The Art of Compromise."

View solution in original post

0 Likes
11 Replies
Len_CONSULTRON
Level 9
Level 9
Beta tester 500 solutions authored 1000 replies posted

pblemel,

Can you provide what SPI slave device you are talking to with your SPI master?

Normally in a SPI protocol at a higher-level, the SPI master needs to issue a SPI "command" which may include an address in the command or may be included in a second byte following the command.

Once this command (and possibly an additional address) byte is issued, the SPI slave responds in the next SPI byte sequence.  To achieve this, you need the SPI master to transfer a "dummy" byte.  This is commonly 0x00.  Usually it doesn't matter what this byte is.  In SPI full-duplex mode, it is ignored by the slave.  In SPI half-duplex, it is not seen by the slave.

In SPI full-duplex mode, the Rx FIFO at this point will contain "dummy" byte(s) for the command (and, if sent, the address byte).  The last byte in the Rx FIFO will be the expected answer from the SPI slave after the SPI master Tx "dummy" byte was sent.

In SPI half-duplex mode, the last byte in the Rx FIFO will be the expected answer from the SPI slave after the SPI master Tx "dummy" byte was sent.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Thanks for replying,

The chip is a MAX6675 thermocouple. It does not have a MOSI, so it isn't commanded. Instead, the data sheet says that when CS is not asserted the device does conversions.  When CS is asserted, the device stops converting and shifts out the most recent 16bit measurement (on SCK). 

I checked in the Arduino library code just to see what it does, which is pretty straightforward as expected;  Assert CS, shift in 16 bits toggling SCK, de-assert CS. 

Based on your comment about full-duplex, I added a "dummy write" of 16 bits (I set the SPI block to 16 bits in Creator).  While I don't get "nothing read' (0XFFFF) from the RX buffers any more, I also don't get anything that makes sense. It's a constant result even if I heat up the thermocouple. 

So, I must have set  something wrong in the block or in the way I am initiating the read. This device sends 16 bits, so I have set the block to 16 bits in Creator. Creator will not let send width = 8 if recv width = 16, so I have send = recv = 16.  I'll play around with it some more, but am open to suggestions on getting the dummy write correct.

Thanks

 

0 Likes

pblemel,

It appears that sending a "dummy" Tx 16-bits provides a non-zero and non 0xFFFF response from the MAX6675 slave IC.

According to the datasheet, bit 15 and bit 0 should equal '0' in both cases.  Is this the case?   If not this might be a clue.

What is the state of bit 2?  If set to '1' this indicates a open thermocouple connection.  If '1', this could be a reason for the constant value returned.

According to the MAX6675 datasheet, this should be the settings of the SPI Master for the PSoC.

Len_CONSULTRON_0-1665487138038.png

Len
"Engineering is an Art. The Art of Compromise."
0 Likes
pblemel
Level 4
Level 4
25 replies posted 25 sign-ins First like received

Len,

Thanks. I am new to using PSoC Creator (and SPI), and may not be doing things "right". Your configuration dialog is a little different than mine.

pblemel_0-1665510739277.png

Dialog differences aside, I had CPHA=0, CPOL=1. With that corrected, things are working :). Thanks!

I suspected (as a newb) that my code might be the problem, so I rewrote it borrowing code from another project that checks things more rigorously.  Is this code considered the "right way" to accomplish this?  Is there an API call that will accomplish the same thing?

 

In main_cm4.c:

SPI_Start();

Code to read from the TC:

uint8_t tx[2], rx[2];

/* Write dummy to initiate read */
Cy_SCB_SPI_WriteArrayBlocking(SCB1, tx, 2);

uint32_t masterStatus;
uint32_t timeOut = 1000UL;  /* Timeout 1 sec (one unit is 1 milli) */

/* Wait until master completes transfer or time out has occurred. */
do {
    masterStatus = Cy_SCB_SPI_GetSlaveMasterStatus(SCB1);
    Cy_SysLib_Delay(CY_SCB_WAIT_1_UNIT);
    timeOut--;
} while (masterStatus != CY_SCB_SPI_MASTER_DONE && timeOut > 0UL);

/* If time out occured handle the error. */
if (masterStatus != CY_SCB_SPI_MASTER_DONE)
     HandleError("SPI TX status != CY_SCB_SPI_MASTER_DONE");

/* Check number of bytes in Rx FIFO and set the status. */
if (2 != Cy_SCB_SPI_GetNumInRxFifo(SCB1))
HandleError("SPI RX NumInRxFifo != 2");

/* Read data from Rx FIFO. */
Cy_SCB_SPI_ReadArray(SCB1, rx, size);

/* Clear Master status and Tx FIFO status. */
Cy_SCB_SPI_ClearSlaveMasterStatus(SCB1, Cy_SCB_SPI_GetSlaveMasterStatus(SCB1));
Cy_SCB_SPI_ClearTxFifoStatus(SCB1, CY_SCB_SPI_TX_INTR_MASK );
Cy_SCB_SPI_ClearTxFifo(SCB1);

/* Clear Rx FIFO status.
*/
Cy_SCB_SPI_ClearRxFifoStatus(SCB1, CY_SCB_SPI_RX_INTR_MASK);
Cy_SCB_SPI_ClearRxFifo(SCB1);

 

0 Likes

pblemel,

I'm glad it's working.

I'm assuming the issue was you were sampling on the rising edge of SCLK instead of the falling edge as the MAX6675 requires.  This might be the major reason for the constant value you were receiving.

It is common to use working code from examples to begin a project.  I do this all the time especially if I'm not that familiar with the underlying HW or SW I need to work with.  Once I get the example working, I tailor it to my specific needs.

The code you included in your post seems overly complicated for this specific task.

In theory your code flow should be pretty simple:

  1. Send 16-bit dummy to SPI.
  2. Read 16-bit response from SPI
  3. Wait some minor amount of time for MAX6675 to convert.  (Probably at least 1ms).
  4. Repeat 1.

In theory, you do need to perform rigorous status checks especially if the return result is within expected range.   

Normally what I do is add the "simple" form of accessing the data.   This is allows me to get meaningful results quickly at closer to maximum performance.

I then enhance it later with more sophisticated diagnostics as needed to improve the reliability of the project and provide run-time diagnostic output which comes in handy if something goes wrong.

If you want me to code a "simple" example, give me a day.  

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Len,

Thanks for the offer. The previous author was commanding a different chip and, judging from the code, wanted to make sure that the write/read completes prior to copying from the RX buffers. The only other example I've found uses a different set of API calls. If you have the time and inclination, I'd like to know what a more efficient way using the higher-level API looks like.  I have another chip to work with next, and wouldn't mind contributing it as an example.  We could put it in a GitHub project for the next person who needs it. 

Thanks

0 Likes

pblemel,

I forgot to ask:  Are you using PSoC Creator or ModusToolbox for your IDE?

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

I am using Creator 4.4 and these pins, for what it's worth.

pblemel_0-1665608196884.png

Thanks,
Peter  

0 Likes

Peter,

I've taken a 'stab' at writing simpler SPI code for your application.

This is taking longer than I expected.  I usually work with the PSoC5LP and it is much simpler and straightforward to achieve this level of coding.

With the SPI coded in PDL-style, there is a level of sophistication that I have to get used to.

Len
"Engineering is an Art. The Art of Compromise."
0 Likes

Hi Len,

Sorry for the delay in getting back to this. I came down with COVID and then had to spend time catching up on other things.  Do you have any other thoughts on how to simplify reading from the SPI?  The code I posted works, so I do have a working solution. Just wondering if there's a better way.

Thanks

0 Likes

Peter,

The code you are using is from a project where the SPI data to the slave device is a multi-byte packet.  Therefore, the code has checking to see when the entire multi-byte packet is sent before checking the response from the slave.

I code I propose is much simpler.  In your case, you just need to send ONE dummy byte (of any value) and the slave returns the temperature conversion value. 

#define SPIM_DUMMY_TX_DATA 0xFFFF   /* 16-bit dummy byte for Tx */
#define CMD_TO_CMD_DELAY   100u     /* delay in msecs */
main(void)
{
uint16 rx_data = 0;
/* Initialization same as the code you already have */
   ...

   for(;;)
   {
...
      Cy_SCB_SPI_Write(mSPI_HW, SPIM_DUMMY_TX_DATA);  /* Send the dummy data for force a response from MAX6675 */
      CySysLib_Delay(CMD_TO_CMD_DELAY);

      while((Cy_SCB_SPI_GetSlaveMasterStatus(mSPI_HW) & CY_SCB_SPI_MASTER_DONE) == 0) {} /* wait until Tx done */
      rx_data = Cy_SCB_SPI_Read(mSPI_HW);   /* MAX6675 data ready to be read from SPI */
...

   }
Len
"Engineering is an Art. The Art of Compromise."
0 Likes