Skip to content

Commit

Permalink
SPI refactor.
Browse files Browse the repository at this point in the history
Still a polling driver, but the libmaple proper interface exposes
enough that users enable the various interrupts and define their own
IRQ handlers if they feel like it.

Wirish HardwareSPI interface was largely redone; it's more like the
Arduino implementation now, although there are some differences when I
didn't like their API.  The old methods are still there, but are
deprecated and slated for deletion in 0.1.0.

New board-specific values: BOARD_NR_SPI, BOARD_SPIx_NSS_PIN,
BOARD_SPIx_MOSI_PIN, BOARD_SPIx_MISO_PIN, and BOARD_SPIx_SCK_PIN, for
x from 1 to BOARD_NR_SPI.

Documentation was updated appropriately.
  • Loading branch information
Marti Bolivar committed Apr 28, 2011
1 parent c9da002 commit 77f707d
Show file tree
Hide file tree
Showing 12 changed files with 1,389 additions and 426 deletions.
215 changes: 108 additions & 107 deletions docs/source/lang/api/hardwarespi.rst
Expand Up @@ -5,160 +5,161 @@
HardwareSPI
===========

This class is used for creating objects to manage the Maple's built-in
SPI ports. The Maple has two SPI ports. The relevant pins
corresponding to each port's logic signals are documented in the
following table (and on the Maple silkscreen):
This page describes how to use the built-in SPI ports. It does not
describe the SPI protocol itself. For more information about SPI, see
the :ref:`SPI reference <spi>`.

.. _lang-hardwarespi-pinout:
.. contents:: Contents
:local:

.. list-table::
:header-rows: 1
Getting Started
---------------

* - Port number
- NSS
- MOSI
- MISO
- SCK
.. TODO [0.1.0] Add a note about calling disableDebugPorts() when
.. using SPI3 on Maple Native
* - 1
- 10
- 11
- 12
- 13
In order to get started, you'll first need to define a ``HardwareSPI``
variable, which you'll use to control the SPI port. Do this by
putting the line "``HardwareSPI spi(number);``" with your variables,
where ``number`` is the SPI port's number.

* - 2
- 31
- 32
- 33
- 34
Here's an example (we'll fill in :ref:`setup() <lang-setup>` and
:ref:`loop() <lang-loop>` later)::

If you use a SPI port, you cannot simultaneously use its associated
pins for other purposes.
// Use SPI port number 1
HardwareSPI spi(1);

Library Documentation
---------------------
void setup() {
// Your setup code
}

void loop() {
// Do stuff with SPI
}

Using the SPI Class
^^^^^^^^^^^^^^^^^^^
Turning the SPI Port On
-----------------------

You can declare that you want to use SPI in your sketch by putting
``HardwareSPI Spi(number);`` with your variables, where ``number`` is
1 or 2, depending on which SPI you want to use. Then you can use the
functions described in the next section. For example::
Now it's time to turn your SPI port on. Do this with the ``begin()``
function (an example is given below).

// Use SPI 1
HardwareSpi Spi(1);
.. FIXME [0.0.10] Breathe doesn't include the class; fix & submit pull req
.. doxygenfunction:: HardwareSPI::begin

The speed at which the SPI port communicates is configured using a
``SPIFrequency`` value:

.. FIXME [0.1.0] Breathe's enum output is enormous; shrink & submit pull req
.. doxygenenum:: SPIFrequency

.. note:: Due to hardware issues, you can't use the frequency
``SPI_140_625KHz`` with SPI port 1.

You'll need to determine the correct values for ``frequency``,
``bitOrder``, and ``mode`` yourself, by consulting the datasheet for
the device you're communicating with. Continuing our example from
before, we'll add a call to ``begin()`` to our ``setup()``::

// Use SPI port number 1
HardwareSPI spi(1);

void setup() {
Spi.begin(SPI_18MHZ);
// Turn on the SPI port
spi.begin(SPI_18MHZ, MSBFIRST, 0);
}

void loop() {
// Get the next byte from the peripheral
uint8 byte = Spi.recv();
// Do stuff with SPI
}

HardwareSPI Class Reference
^^^^^^^^^^^^^^^^^^^^^^^^^^^
If you call ``begin()`` with no arguments (as in "``spi.begin();``"),
it's the same as if you wrote "``spi.begin(SPI_1_125MHZ, MSBFIRST,
0);``".

.. cpp:class:: HardwareSPI
Communicating Over SPI
----------------------

Class for interacting with SPI.
Now that you've got your SPI port set up, it's time to start
communicating. You can send data using ``HardwareSPI::write()``,
receive data using ``HardwareSPI::read()``, and do both using
``HardwareSPI::transfer()``.

.. cpp:function:: HardwareSPI::HardwareSPI(uint32 spi_num)
.. cpp:function:: void HardwareSPI::write(byte data)

Construct an object for managing a SPI peripheral. ``spi_num``
must be 1 or 2; see the :ref:`table above
<lang-hardwarespi-pinout>` for pinout information.
Send a single byte of data.

.. cpp:function:: void HardwareSPI::begin(SPIFrequency freq, uint32 endianness, uint32 mode)
**Parameters**:

Configure the baudrate of the given SPI port and set up the header
pins appropriately.
- ``data``: Byte to send

Parameters:
.. cpp:function:: byte HardwareSPI::read()

- ``freq``: one of the ``SPIFrequency`` values, given :ref:`below
<lang-hardwarespi-spifrequency>`.
Get the next available, unread byte. If there aren't any unread
bytes, this function will wait until one is received.

- ``endianness``: either ``LSBFIRST`` (little-endian) or
``MSBFIRST`` (big-endian).
.. cpp:function:: byte HardwareSPI::transmit(byte data)

- ``mode``: one of 0, 1, 2, or 3, and specifies which SPI mode is
used. The mode number determines a combination of polarity and
phase according to the following table:
Send a byte, then return the next byte received.

.. list-table::
:header-rows: 1
**Parameters:**

* - Mode
- Polarity
- Phase
- ``data``: Byte to send

* - 0
- 0
- 0
**Returns:** Next unread byte

* - 1
- 0
- 1
Continuing our example from before, let's send a number over SPI and
print out whatever we get back over :ref:`lang-serialusb`::

* - 2
- 1
- 0
// Use SPI port number 1
HardwareSPI spi(1);

* - 3
- 1
- 1
void setup() {
// Turn on the SPI port
spi.begin(SPI_18MHZ, MSBFIRST, 0);
}

For more information on polarity and phase, see the
:ref:`external references, below <lang-hardwarespi-seealso>`.
void loop() {
// Send 245 over SPI, and wait for a response.
spi.write(245);
byte response = spi.read();
// Print out the response received.
SerialUSB.print("response: ");
SerialUSB.println(response, DEC);
}

HardwareSPI Class Reference
---------------------------

There are a number of other things you can accomplish with your
``spi`` object. A full function listing follows.

.. cpp:function:: void HardwareSPI::begin()
.. doxygenclass:: HardwareSPI
:members: HardwareSPI, begin, beginSlave, end, read, write, transfer

A convenience ``begin()``, equivalent to ``begin(SPI_1_125MHZ,
MSBFIRST, 0)``.
Deprecated Functions
--------------------

.. cpp:function:: uint8 HardwareSpi::send(uint8 *data, uint32 length)
The following functions are defined for now, but they have been
deprecated, and will be removed in a future Maple IDE release. You
shouldn't use them in new programs, and you should change any of your
programs which do use them to the up-to-date functions discussed
above.

.. cpp:function:: uint8 HardwareSPI::send(uint8 *data, uint32 length)

Writes ``data`` into the port buffer to be transmitted as soon as
possible, where ``length`` is the number of bytes to send from
``data``. Returns the last byte shifted back from slave.

.. cpp:function:: uint8 HardwareSpi::send(uint8 data)
.. cpp:function:: uint8 HardwareSPI::send(uint8 data)

Writes the single byte ``data`` into the port buffer to be
transmitted as soon as possible. Returns the data byte shifted
back from the slave.

.. cpp:function:: uint8 HardwareSpi::recv()
.. cpp:function:: uint8 HardwareSPI::recv()

Reads a byte from the peripheral. Returns the next byte in the
buffer.

SPI Speeds
^^^^^^^^^^

.. _lang-hardwarespi-spifrequency:

The possible SPI speeds are configured using the ``SPIFrequency`` enum:

.. doxygenenum:: SPIFrequency

.. _lang-hardwarespi-seealso:

See Also
--------

* `Wikipedia Article on Serial Peripheral Interface Bus (SPI)
<http://en.wikipedia.org/wiki/Serial_Peripheral_Interface_Bus>`_
* `Arduino reference on SPI
<http://www.arduino.cc/playground/Code/Spi>`_
* `Hardcore SPI on Arduino <http://klk64.com/arduino-spi/>`_ by kik64
* STMicro documentation for STM32F103RB microcontroller:

* `Datasheet <http://www.st.com/stonline/products/literature/ds/13587.pdf>`_ (pdf)
* `Reference Manual <http://www.st.com/stonline/products/literature/rm/13902.pdf>`_ (pdf)


6 changes: 1 addition & 5 deletions docs/source/spi.rst
Expand Up @@ -8,12 +8,8 @@ The Serial Peripheral Interface Bus (SPI) is a serial data transfer
protocol useful for interacting with a wide variety of hardware
peripherals.

The Maple has two SPI ports. The first has NSS on D10, MOSI on
D11, MISO on D12, and SCK on D13. The second has NSS on D31, SCK on
D32, MISO on D33, and MOSI on D34.

The public libmaple API for managing the SPI ports is the
:ref:`HardwareSpi <lang-hardwarespi>` class.
:ref:`HardwareSPI <lang-hardwarespi>` class.

Recommended Reading
-------------------
Expand Down

0 comments on commit 77f707d

Please sign in to comment.