summaryrefslogtreecommitdiff
path: root/ucoo/hal
diff options
context:
space:
mode:
authorNicolas Schodet2015-05-26 11:12:25 +0200
committerNicolas Schodet2019-10-07 00:44:50 +0200
commit751a7d2ba7a0fbb9c6dae2d91891f0cc74897a2a (patch)
treee9661160c9257d918984b04625c8e8b5a5b78753 /ucoo/hal
parent09ed558608a3aacfe394e9b3046d7fa856969416 (diff)
ucoo/hal/spi: add hardware SPI on STM32
Diffstat (limited to 'ucoo/hal')
-rw-r--r--ucoo/hal/spi/Module2
-rw-r--r--ucoo/hal/spi/spi.hh33
-rw-r--r--ucoo/hal/spi/spi_hard.stm32.cc156
-rw-r--r--ucoo/hal/spi/spi_hard.stm32.hh57
-rw-r--r--ucoo/hal/spi/test/test_spi.cc42
5 files changed, 277 insertions, 13 deletions
diff --git a/ucoo/hal/spi/Module b/ucoo/hal/spi/Module
index a6df136..fe9737f 100644
--- a/ucoo/hal/spi/Module
+++ b/ucoo/hal/spi/Module
@@ -1 +1 @@
-hal_spi_SOURCES := spi_soft.cc
+hal_spi_SOURCES := spi_soft.cc spi_hard.stm32.cc
diff --git a/ucoo/hal/spi/spi.hh b/ucoo/hal/spi/spi.hh
new file mode 100644
index 0000000..a7ca4a9
--- /dev/null
+++ b/ucoo/hal/spi/spi.hh
@@ -0,0 +1,33 @@
+#ifndef ucoo_hal_spi_spi_hh
+#define ucoo_hal_spi_spi_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2015 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+
+#if defined (TARGET_stm32)
+# include "spi_hard.stm32.hh"
+#else
+# error "not implemented for this target"
+#endif
+
+#endif // ucoo_hal_spi_spi_hh
diff --git a/ucoo/hal/spi/spi_hard.stm32.cc b/ucoo/hal/spi/spi_hard.stm32.cc
new file mode 100644
index 0000000..264647d
--- /dev/null
+++ b/ucoo/hal/spi/spi_hard.stm32.cc
@@ -0,0 +1,156 @@
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2015 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/hal/spi/spi_hard.stm32.hh"
+
+#include <libopencm3/stm32/spi.h>
+#include <libopencm3/stm32/rcc.h>
+
+#include "ucoo/common.hh"
+
+namespace ucoo {
+
+/// Information on SPI hardware.
+struct spi_hardware_t
+{
+ /// SPI base address.
+ uint32_t base;
+ /// APB number.
+ int apb;
+ /// Clock enable identifier.
+ enum rcc_periph_clken clken;
+};
+
+/// Information on SPI hardware array, this is zero indexed.
+static const spi_hardware_t spi_hardware[] =
+{
+ { SPI1, 2, RCC_SPI1 },
+ { SPI2, 1, RCC_SPI2 },
+ { SPI3, 1, RCC_SPI3 },
+#ifdef SPI4_BASE
+ { SPI4, 2, RCC_SPI4 },
+#endif
+#ifdef SPI5_BASE
+ { SPI5, 2, RCC_SPI5 },
+#endif
+#ifdef SPI6_BASE
+ { SPI6, 2, RCC_SPI6 },
+#endif
+};
+
+SpiHardMaster::SpiHardMaster (int n)
+ : n_ (n), enabled_ (false)
+{
+ assert (n < lengthof (spi_hardware));
+}
+
+SpiHardMaster::~SpiHardMaster ()
+{
+ disable ();
+}
+
+void
+SpiHardMaster::enable (int speed_hz, SpiMode mode)
+{
+ enabled_ = true;
+ uint32_t base = spi_hardware[n_].base;
+ // Turn on.
+ rcc_periph_clock_enable (spi_hardware[n_].clken);
+ // Compute speed, rounded down.
+ int apb_freq = spi_hardware[n_].apb == 1 ? rcc_apb1_frequency
+ : rcc_apb2_frequency;
+ int freq = apb_freq / 2;
+ int br = 0;
+ while (freq > speed_hz)
+ {
+ freq = freq / 2;
+ br++;
+ assert (br <= SPI_CR1_BR_FPCLK_DIV_256);
+ }
+ // Set parameters and enable.
+ SPI_CR2 (base) = 0;
+ SPI_CR1 (base) = SPI_CR1_SSM | SPI_CR1_SSI | SPI_CR1_SPE | (br << 3)
+ | SPI_CR1_MSTR | mode;
+}
+
+void
+SpiHardMaster::disable ()
+{
+ if (enabled_)
+ {
+ enabled_ = false;
+ uint32_t base = spi_hardware[n_].base;
+ // Stop SPI.
+ SPI_CR1 (base) = 0;
+ // Turn off.
+ rcc_periph_clock_disable (spi_hardware[n_].clken);
+ }
+}
+
+void
+SpiHardMaster::send_and_recv (const char *tx_buf, char *rx_buf, int count)
+{
+ assert (enabled_);
+ uint32_t base = spi_hardware[n_].base;
+ while (count--)
+ {
+ SPI_DR (base) = *tx_buf++;
+ while (!(SPI_SR (base) & SPI_SR_RXNE))
+ ;
+ *rx_buf++ = SPI_DR (base);
+ }
+}
+
+void
+SpiHardMaster::send (const char *tx_buf, int count)
+{
+ assert (enabled_);
+ uint32_t base = spi_hardware[n_].base;
+ while (count--)
+ {
+ SPI_DR (base) = *tx_buf++;
+ while (!(SPI_SR (base) & SPI_SR_TXE))
+ ;
+ }
+ // Wait for end of transfer.
+ while (SPI_SR (base) & SPI_SR_BSY)
+ ;
+ // Clear RXNE.
+ (void) SPI_DR (base);
+}
+
+void
+SpiHardMaster::recv (char *rx_buf, int count)
+{
+ assert (enabled_);
+ uint32_t base = spi_hardware[n_].base;
+ while (count--)
+ {
+ SPI_DR (base) = 0;
+ while (!(SPI_SR (base) & SPI_SR_RXNE))
+ ;
+ *rx_buf++ = SPI_DR (base);
+ }
+}
+
+} // namespace ucoo
diff --git a/ucoo/hal/spi/spi_hard.stm32.hh b/ucoo/hal/spi/spi_hard.stm32.hh
new file mode 100644
index 0000000..7576be5
--- /dev/null
+++ b/ucoo/hal/spi/spi_hard.stm32.hh
@@ -0,0 +1,57 @@
+#ifndef ucoo_hal_spi_spi_hard_stm32_hh
+#define ucoo_hal_spi_spi_hard_stm32_hh
+// ucoolib - Microcontroller object oriented library. {{{
+//
+// Copyright (C) 2015 Nicolas Schodet
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the "Software"),
+// to deal in the Software without restriction, including without limitation
+// the rights to use, copy, modify, merge, publish, distribute, sublicense,
+// and/or sell copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+//
+// }}}
+#include "ucoo/intf/spi_master.hh"
+
+namespace ucoo {
+
+/// SPI master on STM32, using dedicated hardware.
+class SpiHardMaster : public SpiMaster
+{
+ public:
+ /// Constructor for the Nth SPI.
+ SpiHardMaster (int n);
+ /// Destructor, disable.
+ ~SpiHardMaster ();
+ /// See SpiMaster::enable.
+ void enable (int speed_hz, SpiMode mode = SPI_MODE_0);
+ /// See SpiMaster::disable.
+ void disable ();
+ /// See SpiMaster::send_and_recv.
+ void send_and_recv (const char *tx_buf, char *rx_buf, int count);
+ /// See SpiMaster::send.
+ void send (const char *tx_buf, int count);
+ /// See SpiMaster::recv.
+ void recv (char *rx_buf, int count);
+ private:
+ /// SPI number.
+ int n_;
+ /// Is it enabled?
+ bool enabled_;
+};
+
+} // namespace ucoo
+
+#endif // ucoo_hal_spi_spi_hard_stm32_hh
diff --git a/ucoo/hal/spi/test/test_spi.cc b/ucoo/hal/spi/test/test_spi.cc
index f115c83..de155b7 100644
--- a/ucoo/hal/spi/test/test_spi.cc
+++ b/ucoo/hal/spi/test/test_spi.cc
@@ -21,6 +21,7 @@
// DEALINGS IN THE SOFTWARE.
//
// }}}
+#include "ucoo/hal/spi/spi.hh"
#include "ucoo/hal/spi/spi_soft.hh"
#include "ucoo/hal/gpio/gpio.hh"
#include "ucoo/utils/delay.hh"
@@ -46,8 +47,10 @@ main (int argc, const char **argv)
ss.set ();
ss.output ();
ucoo::Gpio sck (GPIOA, 5), mosi (GPIOA, 7), miso (GPIOA, 6);
- ucoo::SpiSoftMaster spi (sck, mosi, miso);
- spi.enable (1000000, ucoo::SPI_MODE_3);
+ ucoo::SpiSoftMaster spis (sck, mosi, miso);
+ spis.enable (1000000, ucoo::SPI_MODE_3);
+ ucoo::SpiHardMaster spih (0);
+ ucoo::SpiMaster *spi = &spis;
// Loop with simple IU.
char buf[64];
unsigned int r;
@@ -57,12 +60,12 @@ main (int argc, const char **argv)
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 ();
+ 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);
@@ -79,15 +82,17 @@ main (int argc, const char **argv)
"\n? - help\n"
"w - who am I\n"
"o - turn on\n"
- "f - turn off\n";
+ "f - turn off\n"
+ "h - use hardware SPI\n"
+ "s - use software SPI\n";
ts.write (help, sizeof (help));
break;
case 'w':
{
// Read Who am I register.
ss.reset ();
- spi.send (0x8f);
- char rsp = spi.recv ();
+ spi->send (0x8f);
+ char rsp = spi->recv ();
ss.set ();
ucoo::delay_ns (100);
// Report result.
@@ -102,11 +107,24 @@ main (int argc, const char **argv)
{
char cmd[] = { 0x20, (char) (c == 'o' ? 0x47 : 0x07) };
ss.reset ();
- spi.send (cmd, sizeof (cmd));
+ spi->send (cmd, sizeof (cmd));
ss.set ();
ucoo::delay_ns (100);
}
break;
+ case 'h':
+ spi->disable ();
+ spi = &spih;
+ gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE,
+ GPIO5 | GPIO6 | GPIO7);
+ gpio_set_af (GPIOA, GPIO_AF5, GPIO5 | GPIO6 | GPIO7);
+ spi->enable (1000000, ucoo::SPI_MODE_3);
+ break;
+ case 's':
+ spi->disable ();
+ spi = &spis;
+ spi->enable (1000000, ucoo::SPI_MODE_3);
+ break;
}
}
}