Hi Karl,

On 28-04-16 10:58, Karl Palsson wrote:
> Comments inline...
>> 2/
>> Concider a scenario where you need to write two bytes over SPI.
>> Then the following code looks logical:
>> --- cut here --- cut here --- cut here ---
>> gpio_clear(nss_gpioport,nss_gpios);
>> spi_send(SPI0, data1);
>> spi_send(SPI0, data2);
>> spi_read(SPI0); // wait for SPI transaction to finish
>> gpio_set(nss_gpioport,nss_gpios);
>> --- cut here --- cut here --- cut here ---

>> However, this does NOT work neither.
>> The reason is that the "read" will just check if data is
>> available in the SPI RX-register and if/when that is, return
>> it.
>> The problem here is that the first spi_send has also returned
>> data, and -as you have not yet read it- that data is returned.
>> Again, the NSS is set up again to early.

> toggle CS
> dont_care = spi_xfer(data1)
> data = spi_xfer(data2)
> toggle CS

OK, that is correct, but that is not the point.

People who write (or port) libraries like the MFRC522 library are not 
interested in the underlying platform. They have a problem to solve (in 
this case, interact with a RFID chip) and the SPI-interface is just a 
tool for that.

Look at this this way,
According the API documentation, there is a "send" (and a "write"), but 
in reality, these are just "queue-data-to-TX-FIFO", not the functional 
equivalent of what mbed or wiring see as "write".

I understand that xfer is the command to use, but there is nothing in 
the API documentation that mentions this.

>> Now, from the point of view of somebody writing/porting a
>> library, isn't it logical that there are certain things we can
>> assume to be correct for all processors?
>> I think in this case, this would be:
>> - a standard SPI transaction (read or write) will always wait for the
>> transaction to terminate.

> No, not at all. This means the cpu is busy waiting, burning
> power, doing nothing.

I understand that, but that's not the point. If you have a function that 
just does "queue-data-to-TX-buffer", please call it so. :-)

>> - a SPI-read should always return the data of the last spi-transaction.

> isn't it already doing that? I mean, spi_read is just returning
> the data register right?

Sure, but it does not garantee that this is the data of the latest spi 
If the user does a "send" and then a "xfer", he will get a result of the 
"send", not of the "xfer".

There is nothing in the API documentation that says this and therefor 
very confusing for the people porting code.

>> So here is what I propose for the "spi_send":

>> - At the end, add a "wait for data-available-in-RX-buffer" flag (which
>> also signals the end of a transaction)

> absolutely not. what's wrong with spi_xfer for this case? If
> you're talking about other apis, it's very often that you only
> have one api, spi_xfer, and "write" and "read" are just whether
> you send garbage or ignore the reply with the spi_xfer style
> method.

OK, but for somebody porting applications that's irrelevant.

99% of the code out-there is written for either mbed or arduino/wiring, 
so porting goes in that direction.

>> - at the beginning, do a check if there is data in the SPI RX-buffer. If
>> there is, read it (invalidating it)

> spi_xfer will effectively already do this?

As mention, if you have done a "send" and then a "xfer", it will not.
spi_xfer does not invalidate any data that might still be in the RX buffer.

It might be me, but people thinking "ok, I only need to write data so I 
can use spi_send" does not look that far-fetched to me.

>> I think it is more logical to assume that -once you start a
>> SPI_write- you are no longer interested in data return by
>> previous transactions.

> so... use spi_xfer? If you want simple mbed arduino apis, use
> spi_xfer. The others are if you want to have more control and
> write your own non-blocking code. The spi_common_all.c file could
> probably use documentation updates to make this clearer maybe.

Well, one of the things I missed is a good simple example of how to do 
SPI-transaction in a real application talking to a chip.

I looked inthe example-code for stm32/f1.

The spi.c example just is a simple loopback between MISO and MOSI. It 
does not deal with the chip-select pin, the fact that the "write" is 
asyncronous, talking to a chip in blocks of multiple SPI-transactions.
It even just uses "send" and "read", not the xfer-function.

The other example is code for DMA (not needed for what I needed to do 
and to processor-specific) and the 3th example actually implemented its 
own functions instead of using generic calls.

Now, don't get me wrong.

I wrote this message for two reasons:

- to have this documented so -hopefully- people who have the same issue 
in the future might find this information.
(I hope the internet search-machines do scan this mailing-list archive :-) )

- But also to show what this looks like from people who want to port 
code to libopencm3.

If cost me almost a full day debugging with a logic-analyser and zipping 
through the source-code and datasheets to find out that the "spi_send" 
is in fact "spi_queue-to-TXbuffer" and not what its name implies and 
what that meant for porting this library.

Now, it might have been an interesting day learning the ins and outs of 
SPI and the STM32F1, but would I rather would have spend this time on 
the application-level code. :-)

So, please, if you want to see more libraries for libopencm3 -like for 
mbed and arduino-, do not make things more confusing then needed.

> Cheers,
> Karl P
Cheerio! Kr. Bonne.

Find and fix application performance issues faster with Applications Manager
Applications Manager provides deep performance insights into multiple tiers of
your business applications. It resolves application problems quickly and
reduces your MTTR. Get your free trial!
libopencm3-devel mailing list

Reply via email to