SSP in SPI slave mode: SSPx status register reports FIFO empty, but data lags 8 bytes behind

cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

SSP in SPI slave mode: SSPx status register reports FIFO empty, but data lags 8 bytes behind

1,309 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MindBender on Thu Jul 30 05:24:36 MST 2015
I am using the SSP0 peripheral as a SPI slave, and I am experiencing a rather weird problem: When I write a byte of data to the Data Register and the SPI master is clocking the bus, the data byte comes out as the 9th byte on the bus.

When freshly started, the preceding 8 bytes all have a value of 0. When restarting in with the debugger, these 8 bytes have values of the not-yet-shown 8 bytes of the previous session. During the problem, the Status Register has a value of 0x00000003 all the time, indicating that the TX FIFO is empty.

My test is really simple: Write a single byte to the data register and have the SPI master read it. The first 8 times I read zeroes on the master and my scope, the 9th time I read the 1st data byte. If in that state the master reads again without writing an new data byte to the Data Register, the master reads de 1st data byte again. It is as if transmitted bytes always have to travel through the whole FIFO, regardless of it's filling grade.

This problem only occurs at SPI clock frequencies of 250kHz and higher. If I have the master clock the bus at 30kHz or 125kHz, data bytes come out immediately.

The manual writes that Clock Prescaler Register contents are irrelevant for SPI in slave mode. It Does not say something similar about the SCR field in Control Register 0, but those two are determining the SPI bit rate. However, configuring both for 8MHz SPI doesn't change anything in the situation; Neither 250kHz or 8MHz work properly.

Any ideas? Anybody had something similar? Or anybody has a working SPI slave @>=250kHz?
Labels (1)
0 Kudos
5 Replies

962 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by firmwear on Tue Jan 26 01:13:40 MST 2016
"There's no bug here!!!"

LOL, that guy must be hourly.
0 Kudos

962 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MindBender on Tue Aug 04 00:29:15 MST 2015
I have found the cause of the problem. The NXP manual specifies in section 21.6.1 the contents of the CR0 register. The CPOL bit functionality is described as follows:
      Clock Out Polarity. This bit is only used in SPI mode.
0 SSP controller maintains the bus clock low between frames.
1 SSP controller maintains the bus clock high between frames.


The NXP example code uses a configuration struct to set the bus configuration:
typedef struct {
uint32_t Databit; /** Databit number, should be SSP_DATABIT_x,
where x is in range from 4 - 16 */
uint32_t CPHA;/** Clock phase, should be:
- SSP_CPHA_FIRST: first clock edge
- SSP_CPHA_SECOND: second clock edge */
uint32_t CPOL;/** Clock polarity, should be:
- SSP_CPOL_HI: high level
- SSP_CPOL_LO: low level */
uint32_t Mode;/** SSP mode, should be:
- SSP_MASTER_MODE: Master mode
- SSP_SLAVE_MODE: Slave mode */
uint32_t FrameFormat;/** Frame Format:
- SSP_FRAME_SPI: Motorola SPI frame format
- SSP_FRAME_TI: TI frame format
- SSP_FRAME_MICROWIRE: National Microwire frame format */
uint32_t ClockRate;/** Clock rate,in Hz */
} SSP_CFG_Type;

This struct also contains a CPOL parameter (and it really beat me why this is a uint32_t and not an unsigned char), with a very non-discriptive comment behind it.

However, the programmer deemed it a good idea to reverse the polarity of this parameter in his implementation from what it is in the documentation. He even insists, with no less than 3 exclamation marks, that this is not a bug (making it even worse, in my opinion).
/** Clock polarity control bit */
/* There's no bug here!!!
 * - If bit[6] in SSPnCR0 is 0: SSP controller maintains the bus clock low between frames.
 * That means the active clock is in HI state.
 * - If bit[6] in SSPnCR0 is 1 (SSP_CR0_CPOL_HI): SSP controller maintains the bus clock
 * high between frames. That means the active clock is in LO state.
 */
#define SSP_CPOL_HI((uint32_t)(0))
#define SSP_CPOL_LOSSP_CR0_CPOL_HI

The very leas the guy should have done, is being equally explicit about the parameter being reversed in the comments at defininig SSP_CFG_Type. It wasn't until I started dumping raw register contents until I noticed, and even then I overlooked it at first, but at least the problem's solved now.
0 Kudos

962 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MindBender on Mon Aug 03 00:48:27 MST 2015

Quote: rocketdawg
Leaving MISO disabled for the addr and cmd would make the master clock in Hi-z bits.  We assume the master is not interested in this return data anyway.

True. But a remarkable side-effect of disabling MISO is that during this period, the slave is not dequeueing data from the TX FIFO.


Quote: rocketdawg
Might be better to leave MISO active and just prime the slave FIFO with 2 bytes of dummy data to send out.
That data is placed in the FIFO (at init, and) when CS goes high, so it is ready to send when CS goes low.

Would be better indeed, but not necessary because of the property above.

And we can't leave MISO active on our bus: The first byte is an address byte, addressing one of multiple slaves sharing a single CS line... Yeah, I know what you're thinking.

For a test, I have left MISO enabled all the time, to rule out that shenanigan being the cause of the problem, but it's not.


Quote: rocketdawg
what I do not see is the master sending out a dummy byte so it can clock in the rply from the slave.  Or is that just missing from the ascii art?

Well, it's a synchronous bus, so as long as there's a clock, there's data. Perhaps not valid data, but still data. In the ASCII art I have drawn don't-care data as an asterisk. And the clock is drawn as hashes. It may not be very clear, because I drew it on a byte level, not a bit level.


Quote: rocketdawg
I see the clock, but that should only occur if there is master data being sent, so I assume it is being sent.

I'm sure we mean the same: Either read, write or read/write transactions require a clock. You can just read or write, but one doesn't go without the other, so there will be don't-care data.


Quote: rocketdawg
the problem is, that the master has no way of telling when the slave will have the data ready for the response, so it does not know when to send the dummy.
I assume it takes some time for the slave to calculate the response from the addr/cmd, and I bet that time is something like 1/120kHz.
you might want to rethink this protocol or have a sufficient delay time so that the slave is always ready.

That's why the reply byte is delayed a bit; It will give the slave time to prepare data.

I'm afraid I don't have the luxury to rethink this protocol. It's not mine; I just need to develop a slave to work with this protocol in existing equipment. Personally I would not have went with SPI in the first place, because the slave not being able to tell the master there's no data yet, is a problem I have encountered many times before. I2C is superior in that way (clock stretching) and many more ways.
0 Kudos

962 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by rocketdawg on Fri Jul 31 09:56:01 MST 2015
SPI is a shift register.  The master shifts out a bit on MOSI and the slave shifts out a bit on MISO.
Leaving MISO disabled for the addr and cmd would make the master clock in Hi-z bits.  We assume the master is not interested in this return data anyway.
Might be better to leave MISO active and just prime the slave FIFO with 2 bytes of dummy data to send out.
That data is placed in the FIFO (at init, and) when CS goes high, so it is ready to send when CS goes low.


what I do not see is the master sending out a dummy byte so it can clock in the rply from the slave.  Or is that just missing from the ascii art?
I see the clock, but that should only occur if there is master data being sent, so I assume it is being sent.
the problem is, that the master has no way of telling when the slave will have the data ready for the response, so it does not know when to send the dummy.
I assume it takes some time for the slave to calculate the response from the addr/cmd, and I bet that time is something like 1/120kHz.
you might want to rethink this protocol or have a sufficient delay time so that the slave is always ready.

of course, I could totally be missing the point.  There are master slave examples in LPCOpen source code.
0 Kudos

962 Views
lpcware
NXP Employee
NXP Employee
Content originally posted in LPCWare by MindBender on Fri Jul 31 00:29:27 MST 2015
My test scenario is the following:
      ___                                              ___
         \                                            /
SSEL      \                                          /
           \________________________________________/

               ####   ####                      ####
Clk            ####   ####                      ####
      _________####___####______________________####______
      ______   ____   ____   _____________________________
            \ /    \ /    \ /
MOSI      *  X addr X cmd  X  *
      ______/ \____/ \____/ \_____________________________
      ___________________                       ____   ___
                         \                     /    \ /
MISO      Hi-Z            \                   X rply X  *
      _____________________\_________________/ \____/ \___
                    ^      ^                    ^
                    |      |                    |
                    t1     t2                   t3
The SPI master selects us and sends us an address byte. At t1 we have recognized our address and upon that we enable our slave output by clearing the SOD bit in CR1 (note 1). Immediately after, the SPI master sends us a command. The time MISO actually becomes active lags a little behind, but all timings have been verified with an oscilloscope (a real one, not a USB piece of cr*p) and the illustration above is pretty accurate. At t2 we have recognized the command and we write our reply to the Data register.

At t1 and t2, SR has a value of 0x00000013. Briefly after t2, after writing to the Data register, it is 0x00000012.

At first I thought the enabling and disabling MISO was interfering, but keeping MISO enabled did not cure the problem. The time between t2 and t3 isn't of much influence either. Extending it did not cure the problem.

What does cure the problem, is lowering the SPI master's clock to 120kHz, but that's completely useless to us. And if I write a data byte to the Data register outside of SSEL being active, it comes out at t3 the next command. This suggests that the problem may occur when writing to the Data register while BSY in SR is active. But the manual doesn't say that's not allowed. And the description of BSY being active is far from exact (and/or).

Note 1: The manual says the SOD bit in CR1 'blocks the SSP controller from driving MISO'. In fact it does a little more than tri-stating this output: It also stops clocking data out of the TX FIFO. This vital information would be a valuable addition to the manual.

@nxp: I could really use your help right now. I'm starting to regret to have selected this chip
0 Kudos