summaryrefslogtreecommitdiffhomepage
path: root/digital/ucoolib/ucoolib/hal/spi/spi_soft.cc
diff options
context:
space:
mode:
authorNicolas Schodet2013-01-12 09:00:19 +0100
committerNicolas Schodet2013-01-12 18:28:49 +0100
commitd3702da4a90890010e3a3b1dc2eb6d1eb3a3d1c9 (patch)
tree0991ebc9a39fd3b72fbd0d3c238273f5519e853c /digital/ucoolib/ucoolib/hal/spi/spi_soft.cc
parentd2ad7231c09c16d94d5f85096caf2332fc9fc291 (diff)
digital/ucoolib/ucoolib/hal/spi: new spi module
Diffstat (limited to 'digital/ucoolib/ucoolib/hal/spi/spi_soft.cc')
-rw-r--r--digital/ucoolib/ucoolib/hal/spi/spi_soft.cc125
1 files changed, 125 insertions, 0 deletions
diff --git a/digital/ucoolib/ucoolib/hal/spi/spi_soft.cc b/digital/ucoolib/ucoolib/hal/spi/spi_soft.cc
new file mode 100644
index 00000000..af5ac124
--- /dev/null
+++ b/digital/ucoolib/ucoolib/hal/spi/spi_soft.cc
@@ -0,0 +1,125 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2013 Nicolas Schodet
+//
+// APBTeam:
+// Web: http://apbteam.org/
+// Email: team AT apbteam DOT org
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// }}}
+#include "spi_soft.hh"
+
+#include "ucoolib/utils/delay.hh"
+#include "ucoolib/common.hh"
+
+namespace ucoo {
+
+SpiSoftMaster::SpiSoftMaster (Io &sck, Io &mosi, Io &miso, int speed,
+ SpiMode mode)
+ : sck_ (sck), mosi_ (mosi), miso_ (miso)
+{
+ setup (speed, mode);
+}
+
+SpiSoftMaster::~SpiSoftMaster ()
+{
+ setup (0);
+}
+
+void
+SpiSoftMaster::setup (int speed, SpiMode mode)
+{
+ if (speed)
+ {
+ // Take pins ownership, set SCK according to CPOL.
+ sck_.set (mode >= SPI_MODE_2);
+ sck_.output ();
+ mosi_.reset ();
+ mosi_.output ();
+ miso_.input ();
+ // Set clock period and clock phase.
+ half_period_ns_ = 1000 * 1000 * 1000 / 2 / speed;
+ cpha_ = mode & 1;
+ }
+ else
+ {
+ // Release pins.
+ sck_.input ();
+ sck_.reset ();
+ mosi_.input ();
+ }
+}
+
+void
+SpiSoftMaster::send_and_recv (const char *tx_buf, char *rx_buf, int count)
+{
+ while (count--)
+ *rx_buf++ = send_and_recv (*tx_buf++);
+}
+
+char
+SpiSoftMaster::send_and_recv (char tx)
+{
+ uint8_t i, rx = 0;
+ // Depending on clock phase, sample is done on first transition or second
+ // transition.
+ for (i = 0x80; i; i >>= 1)
+ {
+ // Setup stage.
+ if (cpha_)
+ sck_.toggle ();
+ mosi_.set (tx & i);
+ delay_ns (half_period_ns_);
+ // Sample stage.
+ sck_.toggle ();
+ if (miso_.get ())
+ rx |= i;
+ delay_ns (half_period_ns_);
+ // SCK toggle for next setup stage.
+ if (!cpha_)
+ sck_.toggle ();
+ }
+ return rx;
+}
+
+void
+SpiSoftMaster::send (const char *tx_buf, int count)
+{
+ while (count--)
+ send (*tx_buf++);
+}
+
+void
+SpiSoftMaster::send (char tx)
+{
+ send_and_recv (tx);
+}
+
+void
+SpiSoftMaster::recv (char *rx_buf, int count)
+{
+ while (count--)
+ *rx_buf++ = recv ();
+}
+
+char
+SpiSoftMaster::recv ()
+{
+ return send_and_recv (0);
+}
+
+} // namespace ucoo