From d3702da4a90890010e3a3b1dc2eb6d1eb3a3d1c9 Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Sat, 12 Jan 2013 09:00:19 +0100 Subject: digital/ucoolib/ucoolib/hal/spi: new spi module --- digital/ucoolib/ucoolib/hal/spi/Module | 1 + digital/ucoolib/ucoolib/hal/spi/spi_soft.cc | 125 +++++++++++++++++++++++ digital/ucoolib/ucoolib/hal/spi/spi_soft.hh | 62 +++++++++++ digital/ucoolib/ucoolib/hal/spi/test/Makefile | 9 ++ digital/ucoolib/ucoolib/hal/spi/test/test_spi.cc | 111 ++++++++++++++++++++ digital/ucoolib/ucoolib/intf/spi_master.cc | 48 +++++++++ digital/ucoolib/ucoolib/intf/spi_master.hh | 70 +++++++++++++ 7 files changed, 426 insertions(+) create mode 100644 digital/ucoolib/ucoolib/hal/spi/Module create mode 100644 digital/ucoolib/ucoolib/hal/spi/spi_soft.cc create mode 100644 digital/ucoolib/ucoolib/hal/spi/spi_soft.hh create mode 100644 digital/ucoolib/ucoolib/hal/spi/test/Makefile create mode 100644 digital/ucoolib/ucoolib/hal/spi/test/test_spi.cc create mode 100644 digital/ucoolib/ucoolib/intf/spi_master.cc create mode 100644 digital/ucoolib/ucoolib/intf/spi_master.hh diff --git a/digital/ucoolib/ucoolib/hal/spi/Module b/digital/ucoolib/ucoolib/hal/spi/Module new file mode 100644 index 00000000..a6df136f --- /dev/null +++ b/digital/ucoolib/ucoolib/hal/spi/Module @@ -0,0 +1 @@ +hal_spi_SOURCES := spi_soft.cc 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 diff --git a/digital/ucoolib/ucoolib/hal/spi/spi_soft.hh b/digital/ucoolib/ucoolib/hal/spi/spi_soft.hh new file mode 100644 index 00000000..dcf0441d --- /dev/null +++ b/digital/ucoolib/ucoolib/hal/spi/spi_soft.hh @@ -0,0 +1,62 @@ +#ifndef ucoolib_hal_spi_spi_soft_hh +#define ucoolib_hal_spi_spi_soft_hh +// 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 "ucoolib/intf/spi_master.hh" +#include "ucoolib/intf/io.hh" + +namespace ucoo { + +/// Software implementation of a SPI master. +class SpiSoftMaster : public SpiMaster +{ + public: + /// Constructor, need all SPI pins. Speed is given in Hz. + SpiSoftMaster (Io &sck, Io &mosi, Io &miso, int speed = 0, + SpiMode mode = SPI_MODE_0); + /// Destructor, release SPI pins. + ~SpiSoftMaster (); + /// Change settings, use speed 0 to stop. + void setup (int speed, SpiMode mode = SPI_MODE_0); + /// See SpiMaster::send_and_recv. + void send_and_recv (const char *tx_buf, char *rx_buf, int count); + /// Send and receive one byte. + char send_and_recv (char tx); + /// See SpiMaster::send. + void send (const char *tx_buf, int count); + /// Send one byte. + void send (char tx); + /// See SpiMaster::recv. + void recv (char *rx_buf, int count); + /// Receive one byte. + char recv (); + private: + Io &sck_, &mosi_, &miso_; + int half_period_ns_; + bool cpha_; +}; + +} // namespace ucoo + +#endif // ucoolib_hal_spi_spi_soft_hh diff --git a/digital/ucoolib/ucoolib/hal/spi/test/Makefile b/digital/ucoolib/ucoolib/hal/spi/test/Makefile new file mode 100644 index 00000000..76b82304 --- /dev/null +++ b/digital/ucoolib/ucoolib/hal/spi/test/Makefile @@ -0,0 +1,9 @@ +BASE = ../../../.. + +TARGETS = stm32f4 +PROGS = test_spi +test_spi_SOURCES = test_spi.cc + +MODULES = hal/spi hal/gpio utils base/test hal/usb + +include $(BASE)/build/top.mk diff --git a/digital/ucoolib/ucoolib/hal/spi/test/test_spi.cc b/digital/ucoolib/ucoolib/hal/spi/test/test_spi.cc new file mode 100644 index 00000000..4814f921 --- /dev/null +++ b/digital/ucoolib/ucoolib/hal/spi/test/test_spi.cc @@ -0,0 +1,111 @@ +// 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 "ucoolib/hal/spi/spi_soft.hh" +#include "ucoolib/hal/gpio/gpio.hh" +#include "ucoolib/utils/delay.hh" + +#include "ucoolib/arch/arch.hh" +#include "ucoolib/base/test/test.hh" + +#include + +#include +#include + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::Stream &ts = ucoo::test_stream (); + // Use connection to LIS302DL device on discovery board. + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN + | RCC_AHB1ENR_IOPEEN); + ucoo::Gpio ss (GPIOE, 3); + ss.set (); + gpio_mode_setup (GPIOE, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO3); + ucoo::Gpio sck (GPIOA, 5), mosi (GPIOA, 7), miso (GPIOA, 6); + ucoo::SpiSoftMaster spi (sck, mosi, miso, 1000000, ucoo::SPI_MODE_3); + // Loop with simple IU. + char buf[64]; + unsigned int r; + int8_t x, y, z; + while (1) + { + ucoo::delay_ms (200); + // Read X, Y, Z. + ss.reset (); + spi.send (0xe9); + x = spi.recv (); + spi.recv (); + y = spi.recv (); + spi.recv (); + z = spi.recv (); + ss.set (); + ucoo::delay_ns (100); + r = snprintf (buf, sizeof (buf), "x: %4d, y: %4d, z: %4d\r", x, y, z); + r = std::min (sizeof (buf) - 1, r); + ts.write (buf, r); + // Simple UI. + while (ts.poll ()) + { + char c = ts.getc (); + switch (c) + { + case '?': + static const char help[] = + "\n? - help\n" + "w - who am I\n" + "o - turn on\n" + "f - turn off\n"; + ts.write (help, sizeof (help)); + break; + case 'w': + { + // Read Who am I register. + ss.reset (); + spi.send (0x8f); + char rsp = spi.recv (); + ss.set (); + ucoo::delay_ns (100); + // Report result. + r = snprintf (buf, sizeof (buf), "\nI am 0x%02x\n", + static_cast (rsp)); + r = std::min (sizeof (buf) - 1, r); + ts.write (buf, r); + } + break; + case 'o': + case 'f': + { + char cmd[] = { 0x20, c == 'o' ? 0x47 : 0x07 }; + ss.reset (); + spi.send (cmd, sizeof (cmd)); + ss.set (); + ucoo::delay_ns (100); + } + break; + } + } + } +} diff --git a/digital/ucoolib/ucoolib/intf/spi_master.cc b/digital/ucoolib/ucoolib/intf/spi_master.cc new file mode 100644 index 00000000..cec1231b --- /dev/null +++ b/digital/ucoolib/ucoolib/intf/spi_master.cc @@ -0,0 +1,48 @@ +// 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_master.hh" + +namespace ucoo { + +char +SpiMaster::send_and_recv (char tx) +{ + char rx; + send_and_recv (&tx, &rx, 1); + return rx; +} + +void +SpiMaster::send (char tx) +{ + send_and_recv (tx); +} + +char +SpiMaster::recv () +{ + return send_and_recv (0); +} + +} // namespace ucoo diff --git a/digital/ucoolib/ucoolib/intf/spi_master.hh b/digital/ucoolib/ucoolib/intf/spi_master.hh new file mode 100644 index 00000000..63e0b95c --- /dev/null +++ b/digital/ucoolib/ucoolib/intf/spi_master.hh @@ -0,0 +1,70 @@ +#ifndef ucoolib_intf_spi_master_hh +#define ucoolib_intf_spi_master_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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. +// +// }}} + +namespace ucoo { + +/// SPI clock polarity and phase modes. +enum SpiMode +{ + /// Mode 0, sample on rising edge, setup on falling edge. + SPI_MODE_0, + /// Mode 1, setup on rising edge, sample on falling edge. + SPI_MODE_1, + /// Mode 2, sample on falling edge, setup on rising edge. + SPI_MODE_2, + /// Mode 3, setup on falling edge, sample on rising edge. + SPI_MODE_3, +}; + +/// Interface to the master side of an SPI bus. Do not handle slave select, +/// this should be done with a regular IO. +class SpiMaster +{ + public: + /// Send and receive COUNT bytes of data. Send data from TX_BUF, store + /// received data in RX_BUF. TX_BUF and RX_BUF can be the same memory. + virtual void send_and_recv (const char *tx_buf, char *rx_buf, int count) + = 0; + /// Send and receive one byte, shortcut. + virtual char send_and_recv (char tx); + /// Send, and ignore received data. Same as send_and_recv, but received + /// data is discarded. + virtual void send (const char *tx_buf, int count) = 0; + /// Send one byte, shortcut. + virtual void send (char tx); + /// Send zeros, and receive data. Same as send_and_recv, but transmit + /// zeros. + virtual void recv (char *rx_buf, int count) = 0; + /// Receive one byte, shortcut. + virtual char recv (); + protected: + /// Default constructor. + SpiMaster () { } +}; + +} // namespace ucoo + +#endif // ucoolib_intf_spi_master_hh -- cgit v1.2.3