📄 spi.sgml
字号:
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
<paramdef>cyg_bool <parameter>polled</parameter></paramdef>
<paramdef>cyg_uint32 <parameter>count</parameter></paramdef>
<paramdef>const cyg_uint8* <parameter>tx_data</parameter></paramdef>
<paramdef>cyg_uint8* <parameter>rx_data</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>cyg_spi_tick</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
<paramdef>cyg_bool <parameter>polled</parameter></paramdef>
<paramdef>cyg_uint32 <parameter>count</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>cyg_spi_get_config</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
<paramdef>cyg_uint32 <parameter>key</parameter></paramdef>
<paramdef>void* <parameter>buf</parameter></paramdef>
<paramdef>cyg_uint32* <parameter>len</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>cyg_spi_set_config</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
<paramdef>cyg_uint32 <parameter>key</parameter></paramdef>
<paramdef>const void* <parameter>buf</parameter></paramdef>
<paramdef>cyg_uint32* <parameter>len</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>cyg_spi_transaction_begin</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>cyg_bool <function>cyg_spi_transaction_begin_nb</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>cyg_spi_transaction_transfer</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
<paramdef>cyg_bool <parameter>polled</parameter></paramdef>
<paramdef>cyg_uint32 <parameter>count</parameter></paramdef>
<paramdef>const cyg_uint8* <parameter>tx_data</parameter></paramdef>
<paramdef>cyg_uint8* <parameter>rx_data</parameter></paramdef>
<paramdef>cyg_bool <parameter>drop_cs</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>cyg_spi_transaction_tick</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
<paramdef>cyg_bool <parameter>polled</parameter></paramdef>
<paramdef>cyg_uint32 <parameter>count</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>void <function>cyg_spi_transaction_end</function></funcdef>
<paramdef>cyg_spi_device* <parameter>device</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1 id="spi-api-description"><title>Description</title>
<para>
All SPI functions take a pointer to a
<structname>cyg_spi_device</structname> structure as their first
argument. This is an opaque data structure, usually provided by the
platform HAL. It contains the information needed by the SPI bus driver
to interact with the device, for example the required clock rate and
polarity.
</para>
<para>
An SPI transfer involves the following stages:
</para>
<orderedlist>
<listitem><para>
Perform thread-level locking on the bus. Only one thread at a time is
allowed to access an SPI bus. This eliminates the need to worry about
locking at the bus driver level. If a platform involves multiple SPI
buses then each one will have its own lock. Prepare the bus for
transfers to the specified device, for example by making sure it will
tick at the right clock rate.
</para></listitem>
<listitem><para>
Assert the chip select on the specified device, then transfer data to
and from the device. There may be a single data transfer or a
sequence. It may or may not be necessary to keep the chip select
asserted throughout a sequence.
</para></listitem>
<listitem><para>
Optionally generate some number of clock ticks without asserting a
chip select, for those devices which need this to complete an
operation.
</para></listitem>
<listitem><para>
Return the bus to a quiescent state. Then unlock the bus, allowing
other threads to perform SPI operations on devices attached to this
bus.
</para></listitem>
</orderedlist>
<para>
The simple functions <function>cyg_spi_transfer</function> and
<function>cyg_spi_tick</function> perform all these steps in a single
call. These are suitable for simple I/O operations. The alternative
transaction-oriented functions each perform just one of these steps.
This makes it possible to perform multiple transfers while only
locking and unlocking the bus once, as required for more complicated
devices.
</para>
<para>
With the exception of
<function>cyg_spi_transaction_begin_nb</function> all the functions
will block until completion. There are no error conditions. An SPI
transfer will always take a predictable amount of time, depending on
the transfer size and the clock rate. The SPI bus does not receive any
feedback from a device about possible errors, instead those have to be
handled by software at a higher level. If a thread cannot afford the
time it will take to perform a complete large transfer then a number
of smaller transfers can be used instead.
</para>
<para>
SPI operations should always be performed at thread-level or during
system initialization, and not inside an ISR or DSR. This greatly
simplifies locking. Also a typical ISR or DSR should not perform a
blocking operation such as an SPI transfer.
</para>
<para>
SPI transfers can happen in either polled or interrupt-driven mode.
Typically polled mode should be used during system initialization,
before the scheduler has been started and interrupts have been
enabled. Polled mode should also be used in single-threaded
applications such as RedBoot. A typical multi-threaded application
should normally use interrupt-driven mode because this allows for more
efficient use of cpu cycles. Polled mode may be used in a
multi-threaded application but this is generally undesirable: the cpu
will spin while waiting for a transfer to complete, wasting cycles;
also the current thread may get preempted or timesliced, making the
timing of an SPI transfer much less predictable. On some hardware
interrupt-driven mode is impossible or would be very inefficient. In
such cases the bus drivers will only support polled mode and will
ignore the <varname>polled</varname> argument.
</para>
</refsect1>
<refsect1 id="spi-api-transfer"><title>Simple Transfers</title>
<para>
<function>cyg_spi_transfer</function> can be used for SPI operations
to simple devices. It takes the following arguments:
</para>
<variablelist>
<varlistentry>
<term><type>cyg_spi_device*</type> <varname>device</varname></term>
<listitem><para>
This identifies the SPI device that should be used.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_bool</type> <varname>polled</varname></term>
<listitem><para>
Polled mode should be used during system initialization and in a
single-threaded application. Interrupt-driven mode should normally be
used in a multi-threaded application.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint32</type> <varname>count</varname></term>
<listitem><para>
This identifies the number of data items to be transferred. Usually
each data item is a single byte, but some devices use a larger size up
to 16 bits.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>const cyg_uint8*</type> <varname>tx_data</varname></term>
<listitem><para>
The data to be transferred to the device. If the device will only
output data and ignore its input then a null pointer can be used.
Otherwise the array should contain <varname>count</varname> data
items, usually bytes. For devices where each data item is larger than
one byte the argument will be interpreted as an array of shorts
instead, and should be aligned to a 2-byte boundary. The bottom n bits
of each short will be sent to the device. The buffer need not be
aligned to a cache-line boundary, even for SPI devices which use DMA
transfers, but some bus drivers may provide better performance if the
buffer is suitably aligned. The buffer will not be modified by the
transfer.
</para></listitem>
</varlistentry>
<varlistentry>
<term><type>cyg_uint8*</type> <varname>rx_data</varname></term>
<listitem><para>
A buffer for the data to be received from the device. If the device
does not generate any output then a null pointer can be used.
The same size and alignment rules apply as for <varname>tx_data</varname>.
</para></listitem>
</varlistentry>
</variablelist>
<para>
<function>cyg_spi_transfer</function> performs all the stages of an
SPI transfer: locking the bus; setting it up correctly for the
specified device; asserting the chip select and transferring the data;
dropping the chip select at the end of the transfer; returning the bus
to a quiescent state; and unlocking the bus.
</para>
</refsect1>
<refsect1 id="spi-api-tick"><title>Additional Clock Ticks</title>
<para>
Some devices require a number of clock ticks on the SPI bus between
transfers so that they can complete some internal processing. These
ticks must happen at the appropriate clock rate but no chip select
should be asserted and no data transfer will happen.
<function>cyg_spi_tick</function> provides this functionality.
The <varname>device</varname> argument identifies the SPI bus, the
required clock rate and the size of each data item. The
<varname>polled</varname> argument has the usual meaning. The
<varname>count</varname> argument specifies the number of data items
that would be transferred, which in conjunction with the size of each
data item determines the number of clock ticks.
</para>
</refsect1>
<refsect1 id="spi-api-transaction"><title>Transactions</title>
<para>
A transaction-oriented API is available for interacting with more
complicated devices. This provides separate functions for each of the
steps in an SPI transfer.
</para>
<para>
<function>cyg_spi_transaction_begin</function> must be used at the
start of a transaction. This performs thread-level locking on the bus,
blocking if it is currently in use by another thread. Then it prepares
the bus for transfers to the specified device, for example by making
sure it will tick at the right clock rate.
</para>
<para>
<function>cyg_spi_transaction_begin_nb</function> is a non-blocking
variant, useful for threads which cannot afford to block for an
indefinite period. If the bus is currently locked the function returns
false immediately. If the bus is not locked then it acts as
<filename>cyg_spi_transaction_begin</filename> and returns true.
</para>
<para>
Once the bus has been locked it is possible to perform one or more
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -