RT1050 LPSPI last bit not completing in continuous mode

cancel
Showing results for 
Search instead for 
Did you mean: 

RT1050 LPSPI last bit not completing in continuous mode

Jump to solution
1,870 Views
drodgers
Senior Contributor I

TL;DR - On the RT1050 LPSPI peripheral, when continuous mode is active (TCR.CONT == 1), the last SCK edge of a transfer does not complete, which means the last byte does not arrive in the RX FIFO, which means that when implementing a SPI driver API, nothing can continue after a read transfer, because the read request cannot be closed out without sending at least one more byte into the FIFO, and clearing CONT would de-assert PCSx and terminate the transfer.

So, I've been writing my own C++ LPSPI driver, using the FSL driver and other code as examples.  The base class for my SPI driver consists of two methods:

  • Begin(cs) -- Establishes what chip select is being driven and sets up the transfer.
  • Xfer(txdata, rxdata, length, is_final) -- Transmits and/or receives X number of bytes, marking whether this is the final transfer before PCSx is deasserted.

Xfer() can be called multiple times, for instance when doing a write-then-read as is typical of most SPI devices.  E.g.

/* Select PCS0. */
lpspi.Begin(0);
 /* Send command buffer, keep PCS0 active. */
lpspi.Xfer(cmd_buffer, nullptr, cmd_length, false);
/* Read data buffer, deassert PCS0 when done. */
lpspi.Xfer(nullptr, data_buffer, data_length, true);
‍‍‍‍‍‍

Now, while it's not typical, there should be no reason why one could not do two or more consecutive reads, perhaps because of a limited buffer size or other considerations.  Like this:

lpspi.Begin(0);
 lpspi.Xfer(cmd_buffer, nullptr, cmd_length, false);
int cycle_count = 4;
for (int i = 0; i < cycle_count; ++i) {
 lpspi.Xfer(nullptr, data_buffer, data_length, (i == (cycle_count - 1)));
 /* Process the data buffer. */
}‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

However, THIS IS NOT POSSIBLE with the NXP LPSPI peripheral, based on my own testing and one other forum post on this exact topic involving a Kinetis KL28 LPSPI.  Here's a screencap of a 20-byte transfer, with CONT == 0:

lpspi_cont_is_0.png

CONT == 0 obviously won't work for a SPI device access, with PCSx de-asserting between every byte.  But here's the same transfer with CONT == 1 (the only change made in the code):

lpspi_cont_is_1.png

You can see that the last half-clock doesn't appear on SCK; the clock stays high, and PCSx stays asserted because I haven't written to TCR yet.  This results in the last (zero) byte not arriving in the RX FIFO, which causes my driver to stall because the expected 20 bytes are never fully received.  If I write TCR with both CONT and CONTC set to 1, this doesn't change (I tried it, SCK remains stuck in the middle of the final bit).  And if I write TCR with CONTC set to 0, then yes, the lask SCK edge appears and the last byte arrives in the RX FIFO, but this also de-asserts PCSx and terminates the transfer.

I consider this to be a bug/erratum in the LPSPI peripheral, because it unnecessarily constrains the behavior of the software using it.  My SPI driver cannot perform another transfer following a read while keeping PCSx asserted; performing a read requires that it be the last transfer before de-asserting PCSx.  I've worked around this in my driver by doing two things:

  • Rather than always trying to receive N bytes from the RX FIFO after sending N bytes, I keep a "garbage byte" counter that goes up each time a byte is written with no read expected; the counter is decremented each time a byte is read from the RX FIFO, but the counter is not required to go to zero if the write is not a final transfer; the garbage count carries over to the subsequent transfer.
  • If the application requests a read (i.e. rxdata != nullptr) and is_final is false, the LPSPI driver returns an error because it cannot complete the request.

It's a crummy workaround, but it at least allows me to maintain a consistent API for my drivers.  Unless NXP has a proper workaround that allows me to get that last byte into the RX FIFO without terminating the transfer or shoving an extra byte into the TX FIFO, then I guess this isn't really a question post, more of an "engineer beware" post.  Thanks for reading.

Labels (1)
1 Solution
768 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi David,

Sorry for the delay reply.

I got the confirmation from product team: LPSPI IP designer confirm that issue and will fix it at next version IP.

As a workaround so far, customer can clear LPSPI Transmit Command Register (TCR) [CONT] bit after required bytes had been transmitted.

Sorry for that may bring any inconvenience to you.

best regards,

Mike

View solution in original post

12 Replies
768 Views
drodgers
Senior Contributor I

Alternately, I realize I could set the TCR.RXMSK bit instead of counting "garbage" bytes when doing a pure write; that would only require that I write TCR before each new block of data, with CONTC set.  But that still doesn't solve the core issue of getting every last byte/word into the RX FIFO when actually doing a read, so that it could be followed by another continuous operation.

0 Kudos
768 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi David,

I did a test with MCUXpresso SDK V2.5.1 lpspi driver demo [\interrupt_b2b\master] with IMXRT1050-EVKB board.

When I set Transmit Command Register (TCR) [CONT] bit to enable continuous transfer, I could regenerate your mentioned issue:

pastedImage_1.png

pastedImage_2.png

Then I add clear Transmit Command Register (TCR) [CONT] bit code at IRQHandler function, which could fix the issue:

pastedImage_6.png

pastedImage_4.png

From RT1050 reference manual, the LPSPI command word in master mode [CONT] bit can be modified during transfer.

If clear LPSPI Transmit Command Register (TCR) [CONT] bit during LPSPI communication processing, Then the chip select will exit continuous mode during transfer.

pastedImage_7.png

So far, customer can clear LPSPI Transmit Command Register (TCR) [CONT] bit after required bytes had been transmitted.

I need to check with i.MXRT product team about LPSPI module behavior with CONT bit set.

I will update this thread when there with any feedback.

Thanks for the patience.


Have a great day,
Mike

-------------------------------------------------------------------------------
Note:
- If this post answers your question, please click the "Mark Correct" button. Thank you!

- We are following threads for 7 weeks after the last post, later replies are ignored
Please open a new thread and refer to the closed one, if you have a related question at a later point in time.
-------------------------------------------------------------------------------

0 Kudos
768 Views
drodgers
Senior Contributor I

Hi Mike,

I appreciate your taking the time to reproduce my issue.  You've also confirmed my diagnosis, that to get the last clock to appear and get the last byte to appear in the RX FIFO, you have to write TCR with either CONT or CONTC set to 0, which terminates the transfer.  That's the core issue; I can't write a driver for LPSPI that allows multiple reads within the same transfer, because the previous read can't be completed without pushing more data into the TX FIFO or terminating the transfer.  The following hypothetical code snippet is an example of what I can't do with LPSPI, that I can do with most any other SPI peripheral (e.g. Kinetis DSPI):

/* Last parameter:
 * false = continue transfer
 * true = end transfer */
lpspi.Begin(0);  // use PCS0
lpspi.Send(cmd_buffer, cmd_length, false);
lpspi.Read(data_buffer_1, data_length_1, false);
lpspi.Read(data_buffer_2, data_length_2, false);
lpspi.Read(data_buffer_3, data_length_3, false);
lpspi.Read(data_buffer_4, data_length_4, true);‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍‍

The first call to lpspi.Read() can't complete because the last byte will not enter the RX FIFO without 1) writing the next dummy byte to the TX FIFO or 2) writing TCR with CONT or CONTC set to 0, which also terminates the transfer.  The driver's hands are completely tied; writing an extra dummy byte is out of the question (there's no way to know what's supposed to come next), and terminating the transfer is also not an option.  My only workaround is to restrict the driver and generate an error if lpspi.Read() is called with "terminate transfer" set to false.

This really looks like a defect in the LPSPI peripheral; there's no good reason for SCK to freeze in the active state on the last bit of a transfer and withhold the last byte from the RX FIFO until either the next byte is written or the transfer is terminated.  I do now have a working C++ driver for LPSPI, with the aforementioned restriction that any read operation must also terminate the transfer, which is probably fine for most SPI device drivers.  It's just frustrating that NXP hasn't noticed or addressed this before now.  As I mentioned, someone had this exact same issue two years ago with a KL28 LPSPI, and you gave the same advice, which was to write TCR with CONT and CONTC clear to terminate the transfer and get the last byte into the RX FIFO.  But if you don't want to terminate the transfer at that point, you have no other option.

768 Views
brucemckenney
Contributor III

This also happens on the RT1011. This isn't too surprising (probably the same Verilog), just a data point.

My workaround was to configure PCS0 as a GPIO and wiggle it myself (the way we did it in the Ancient Days).

768 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi Bruce

Thanks for the info.

I don't know the process for develop/update the new LPSPI IP and be applied with new product.

RT1011 product project start define quite early. There exists the gap. 

I hope the new IP could be applied with new RT product soon.

best regards,

Mike

0 Kudos
769 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi David,

Sorry for the delay reply.

I got the confirmation from product team: LPSPI IP designer confirm that issue and will fix it at next version IP.

As a workaround so far, customer can clear LPSPI Transmit Command Register (TCR) [CONT] bit after required bytes had been transmitted.

Sorry for that may bring any inconvenience to you.

best regards,

Mike

View solution in original post

768 Views
drodgers
Senior Contributor I

I appreciate you looking into this issue and determining that there is in fact a silicon bug present.  It's a shame that this wasn't identified two years ago so that it might have been fixed prior to broad release of the i.MX RT series.  Thank you for your attention to this.

David R.

768 Views
liangliangma
Contributor II

I should have argued more so they would have not simply ignored this.

768 Views
drodgers
Senior Contributor I

I do think it's NXP's fault for ignoring what looked to me like an obvious erratum.

0 Kudos
768 Views
TomE
Specialist I

I can't find mention of this problem in either of the latest  IMXRT1050 or IMXRT1060 Errata documents.

Could you please consider adding this to both the IMXRT1050 and IMXRT1060 (if applicable) Errata Documents?

Tom

768 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi David,

Just let you know, I am still checking with product team about this issue.

There has no feedback so far.

Thanks for the patience.

best regards,

Mike

768 Views
Hui_Ma
NXP TechSupport
NXP TechSupport

Hi David,

Thanks for the info.

I am checking with product team and wish it could draw a conclusion this time.

I will update this thread when there with any feedback.

best regards,

Mike