From 574480980dcffbfa7cd6dbe71e88253eb4c9feba Mon Sep 17 00:00:00 2001 From: Nicolas Schodet Date: Wed, 3 Jun 2015 13:46:44 +0200 Subject: Rename ucoolib modules directory from ucoolib to ucoo --- ucoo/hal/adc/Module | 1 + ucoo/hal/adc/adc.hh | 35 +++ ucoo/hal/adc/adc.host.cc | 92 ++++++++ ucoo/hal/adc/adc.host.hh | 52 +++++ ucoo/hal/adc/adc_hard.stm32f4.cc | 69 ++++++ ucoo/hal/adc/adc_hard.stm32f4.hh | 73 +++++++ ucoo/hal/adc/test/Makefile | 9 + ucoo/hal/adc/test/test_adc.cc | 51 +++++ ucoo/hal/gpio/Module | 1 + ucoo/hal/gpio/gpio.hh | 35 +++ ucoo/hal/gpio/gpio.host.cc | 181 ++++++++++++++++ ucoo/hal/gpio/gpio.host.hh | 69 ++++++ ucoo/hal/gpio/gpio.stm32f4.cc | 105 +++++++++ ucoo/hal/gpio/gpio.stm32f4.hh | 85 ++++++++ ucoo/hal/gpio/test/Makefile | 9 + ucoo/hal/gpio/test/test_gpio.cc | 71 ++++++ ucoo/hal/i2c/Config | 5 + ucoo/hal/i2c/Module | 1 + ucoo/hal/i2c/i2c.hh | 36 ++++ ucoo/hal/i2c/i2c.host.cc | 213 ++++++++++++++++++ ucoo/hal/i2c/i2c.host.hh | 66 ++++++ ucoo/hal/i2c/i2c_hard.stm32.cc | 396 ++++++++++++++++++++++++++++++++++ ucoo/hal/i2c/i2c_hard.stm32.hh | 91 ++++++++ ucoo/hal/i2c/i2c_slave_data_buffer.cc | 80 +++++++ ucoo/hal/i2c/i2c_slave_data_buffer.hh | 71 ++++++ ucoo/hal/i2c/test/Makefile | 9 + ucoo/hal/i2c/test/hub.py | 6 + ucoo/hal/i2c/test/test_i2c.cc | 226 +++++++++++++++++++ ucoo/hal/spi/Module | 1 + ucoo/hal/spi/spi_soft.cc | 125 +++++++++++ ucoo/hal/spi/spi_soft.hh | 64 ++++++ ucoo/hal/spi/test/Makefile | 9 + ucoo/hal/spi/test/test_spi.cc | 112 ++++++++++ ucoo/hal/uart/Config | 6 + ucoo/hal/uart/Module | 1 + ucoo/hal/uart/test/Config | 4 + ucoo/hal/uart/test/Makefile | 12 ++ ucoo/hal/uart/test/test_uart.cc | 70 ++++++ ucoo/hal/uart/test/test_uart_disc.cc | 128 +++++++++++ ucoo/hal/uart/uart.hh | 36 ++++ ucoo/hal/uart/uart.stm32.cc | 221 +++++++++++++++++++ ucoo/hal/uart/uart.stm32.hh | 78 +++++++ ucoo/hal/usb/Config | 12 ++ ucoo/hal/usb/Module | 1 + ucoo/hal/usb/test/Config | 2 + ucoo/hal/usb/test/Makefile | 9 + ucoo/hal/usb/test/test_usb.cc | 73 +++++++ ucoo/hal/usb/usb.hh | 33 +++ ucoo/hal/usb/usb.stm32.cc | 160 ++++++++++++++ ucoo/hal/usb/usb.stm32.hh | 98 +++++++++ ucoo/hal/usb/usb_desc.stm32.c | 193 +++++++++++++++++ ucoo/hal/usb/usb_desc.stm32.h | 33 +++ 52 files changed, 3619 insertions(+) create mode 100644 ucoo/hal/adc/Module create mode 100644 ucoo/hal/adc/adc.hh create mode 100644 ucoo/hal/adc/adc.host.cc create mode 100644 ucoo/hal/adc/adc.host.hh create mode 100644 ucoo/hal/adc/adc_hard.stm32f4.cc create mode 100644 ucoo/hal/adc/adc_hard.stm32f4.hh create mode 100644 ucoo/hal/adc/test/Makefile create mode 100644 ucoo/hal/adc/test/test_adc.cc create mode 100644 ucoo/hal/gpio/Module create mode 100644 ucoo/hal/gpio/gpio.hh create mode 100644 ucoo/hal/gpio/gpio.host.cc create mode 100644 ucoo/hal/gpio/gpio.host.hh create mode 100644 ucoo/hal/gpio/gpio.stm32f4.cc create mode 100644 ucoo/hal/gpio/gpio.stm32f4.hh create mode 100644 ucoo/hal/gpio/test/Makefile create mode 100644 ucoo/hal/gpio/test/test_gpio.cc create mode 100644 ucoo/hal/i2c/Config create mode 100644 ucoo/hal/i2c/Module create mode 100644 ucoo/hal/i2c/i2c.hh create mode 100644 ucoo/hal/i2c/i2c.host.cc create mode 100644 ucoo/hal/i2c/i2c.host.hh create mode 100644 ucoo/hal/i2c/i2c_hard.stm32.cc create mode 100644 ucoo/hal/i2c/i2c_hard.stm32.hh create mode 100644 ucoo/hal/i2c/i2c_slave_data_buffer.cc create mode 100644 ucoo/hal/i2c/i2c_slave_data_buffer.hh create mode 100644 ucoo/hal/i2c/test/Makefile create mode 100644 ucoo/hal/i2c/test/hub.py create mode 100644 ucoo/hal/i2c/test/test_i2c.cc create mode 100644 ucoo/hal/spi/Module create mode 100644 ucoo/hal/spi/spi_soft.cc create mode 100644 ucoo/hal/spi/spi_soft.hh create mode 100644 ucoo/hal/spi/test/Makefile create mode 100644 ucoo/hal/spi/test/test_spi.cc create mode 100644 ucoo/hal/uart/Config create mode 100644 ucoo/hal/uart/Module create mode 100644 ucoo/hal/uart/test/Config create mode 100644 ucoo/hal/uart/test/Makefile create mode 100644 ucoo/hal/uart/test/test_uart.cc create mode 100644 ucoo/hal/uart/test/test_uart_disc.cc create mode 100644 ucoo/hal/uart/uart.hh create mode 100644 ucoo/hal/uart/uart.stm32.cc create mode 100644 ucoo/hal/uart/uart.stm32.hh create mode 100644 ucoo/hal/usb/Config create mode 100644 ucoo/hal/usb/Module create mode 100644 ucoo/hal/usb/test/Config create mode 100644 ucoo/hal/usb/test/Makefile create mode 100644 ucoo/hal/usb/test/test_usb.cc create mode 100644 ucoo/hal/usb/usb.hh create mode 100644 ucoo/hal/usb/usb.stm32.cc create mode 100644 ucoo/hal/usb/usb.stm32.hh create mode 100644 ucoo/hal/usb/usb_desc.stm32.c create mode 100644 ucoo/hal/usb/usb_desc.stm32.h (limited to 'ucoo/hal') diff --git a/ucoo/hal/adc/Module b/ucoo/hal/adc/Module new file mode 100644 index 0000000..f633ffd --- /dev/null +++ b/ucoo/hal/adc/Module @@ -0,0 +1 @@ +hal_adc_SOURCES = adc.host.cc adc_hard.stm32f4.cc diff --git a/ucoo/hal/adc/adc.hh b/ucoo/hal/adc/adc.hh new file mode 100644 index 0000000..b7832c3 --- /dev/null +++ b/ucoo/hal/adc/adc.hh @@ -0,0 +1,35 @@ +#ifndef ucoo_hal_adc_adc_hh +#define ucoo_hal_adc_adc_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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_host) +# include "adc.host.hh" +#elif defined (TARGET_stm32f4) +# include "adc_hard.stm32f4.hh" +#else +# error "not implemented for this target" +#endif + +#endif // ucoo_hal_adc_adc_hh diff --git a/ucoo/hal/adc/adc.host.cc b/ucoo/hal/adc/adc.host.cc new file mode 100644 index 0000000..0dfc01d --- /dev/null +++ b/ucoo/hal/adc/adc.host.cc @@ -0,0 +1,92 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "adc.host.hh" + +#include + +namespace ucoo { + +/// Shared context between instances. +class AdcHostShared +{ + public: + /// Constructor, connect to mex node. + AdcHostShared (Host &host); + /// Register a new instance. + void register_instance (Host &host, AdcHost &instance, const char *name); + private: + /// Handle value from Mex. + void handle_adc_channel (mex::Msg &msg); + private: + Host &host_; + typedef std::map Instances; + Instances instances_; +}; + +AdcHostShared::AdcHostShared (Host &host) + : host_ (host) +{ + std::string instance = host_.get_instance (); + mex::Node &node = host_.get_node (); + mex::mtype_t mtype = node.reserve (instance + ":adc_channel"); + node.handler_register (mtype, *this, &AdcHostShared::handle_adc_channel); +} + +void +AdcHostShared::register_instance (Host &host, AdcHost &instance, + const char *name) +{ + assert (&host == &host_); + std::pair r = + instances_.insert (Instances::value_type (name, &instance)); + assert (r.second); +} + +void +AdcHostShared::handle_adc_channel (mex::Msg &msg) +{ + int ivalue, namelen; + msg.pop ("l") >> ivalue; + namelen = msg.len (); + std::string name (msg.pop (namelen), namelen); + Instances::iterator i = instances_.find (name); + assert (i != instances_.end ()); + double fvalue = ivalue / (double) (1u << 31); + i->second->value_ = fvalue * i->second->resolution_; +} + +AdcHostShared *AdcHost::shared_; + +AdcHost::AdcHost (Host &host, const char *name, int resolution) + : resolution_ (resolution), value_ (0) +{ + if (!shared_) + { + static AdcHostShared shared (host); + shared_ = &shared; + } + shared_->register_instance (host, *this, name); +} + +} // namespace ucoo diff --git a/ucoo/hal/adc/adc.host.hh b/ucoo/hal/adc/adc.host.hh new file mode 100644 index 0000000..02b7cc9 --- /dev/null +++ b/ucoo/hal/adc/adc.host.hh @@ -0,0 +1,52 @@ +#ifndef ucoo_hal_adc_adc_host_hh +#define ucoo_hal_adc_adc_host_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/adc.hh" +#include "ucoo/arch/host/host.hh" + +namespace ucoo { + +class AdcHostShared; + +/// Host ADC channel. +class AdcHost : public Adc +{ + public: + /// Constructor. + AdcHost (Host &host, const char *name, int resolution); + /// See Adc::read. + int read () { return value_; } + /// See Adc::get_resolution. + int get_resolution () const { return resolution_; } + private: + int resolution_; + int value_; + static AdcHostShared *shared_; + friend class AdcHostShared; +}; + +} // namespace ucoo + +#endif // ucoo_hal_adc_adc_host_hh diff --git a/ucoo/hal/adc/adc_hard.stm32f4.cc b/ucoo/hal/adc/adc_hard.stm32f4.cc new file mode 100644 index 0000000..38661e3 --- /dev/null +++ b/ucoo/hal/adc/adc_hard.stm32f4.cc @@ -0,0 +1,69 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "adc_hard.stm32f4.hh" + +#include +#include + +namespace ucoo { + +AdcHard::AdcHard (int n) + : n_ (n) +{ + static const uint32_t bases[] = { ADC1, ADC2, ADC3 }; + assert (n < (int) lengthof (bases)); + base_ = bases[n]; +} + +AdcHard::~AdcHard () +{ + disable (); +} + +void +AdcHard::enable () +{ + rcc_peripheral_enable_clock (&RCC_APB2ENR, RCC_APB2ENR_ADC1EN << n_); + ADC_CR2 (base_) = ADC_CR2_ADON; +} + +void +AdcHard::disable () +{ + ADC_CR2 (base_) = 0; + rcc_peripheral_disable_clock (&RCC_APB2ENR, RCC_APB2ENR_ADC1EN << n_); +} + +int +AdcHard::read (int channel) +{ + ADC_SQR3 (base_) = channel; + ADC_CR2 (base_) |= ADC_CR2_SWSTART; + while (!(ADC_SR (base_) & ADC_SR_EOC)) + yield (); + ADC_SR (base_) = ~ADC_SR_EOC; + return ADC_DR (base_); +} + +} // namespace ucoo diff --git a/ucoo/hal/adc/adc_hard.stm32f4.hh b/ucoo/hal/adc/adc_hard.stm32f4.hh new file mode 100644 index 0000000..7ab0d7f --- /dev/null +++ b/ucoo/hal/adc/adc_hard.stm32f4.hh @@ -0,0 +1,73 @@ +#ifndef ucoo_hal_adc_adc_hard_stm32f4_hh +#define ucoo_hal_adc_adc_hard_stm32f4_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/adc.hh" +#include "ucoo/common.hh" + +namespace ucoo { + +/// ADC interface. This control a full ADC, use AdcHardChannel for a single +/// channel. +class AdcHard +{ + public: + static const int resolution = 1 << 12; + public: + /// Constructor for the Nth ADC. + AdcHard (int n); + /// Shutdown. + ~AdcHard (); + /// Enable, power on. + void enable (); + /// Disable. + void disable (); + /// Make a single measure. + int read (int channel); + private: + /// ADC index. + int n_; + /// ADC base address. + uint32_t base_; +}; + +/// Single ADC channel. +class AdcHardChannel : public Adc +{ + public: + /// Constructor. + AdcHardChannel (AdcHard &adc, int channel) + : adc_ (adc), channel_ (channel) { } + /// See Adc::read. + int read () { return adc_.read (channel_); } + /// See Adc::get_resolution. + int get_resolution () const { return AdcHard::resolution; } + private: + AdcHard &adc_; + int channel_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_adc_adc_hard_stm32f4_hh diff --git a/ucoo/hal/adc/test/Makefile b/ucoo/hal/adc/test/Makefile new file mode 100644 index 0000000..fc46e0d --- /dev/null +++ b/ucoo/hal/adc/test/Makefile @@ -0,0 +1,9 @@ +BASE = ../../../.. + +TARGETS = stm32f4 +stm32f4_PROGS = test_adc +test_adc_SOURCES = test_adc.cc + +MODULES = hal/adc base/test hal/usb utils + +include $(BASE)/build/top.mk diff --git a/ucoo/hal/adc/test/test_adc.cc b/ucoo/hal/adc/test/test_adc.cc new file mode 100644 index 0000000..eaaf44e --- /dev/null +++ b/ucoo/hal/adc/test/test_adc.cc @@ -0,0 +1,51 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/adc/adc.hh" + +#include "ucoo/arch/arch.hh" +#include "ucoo/base/test/test.hh" +#include "ucoo/utils/delay.hh" + +#include +#include "ucoo/hal/gpio/gpio.hh" + +#include + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::test_stream_setup (); + // Have fun with temperature sensor. + ucoo::AdcHard adc (0); + adc.enable (); + ADC_CCR = ADC_CCR_TSVREFE; + ucoo::AdcHardChannel c (adc, 16); + while (1) + { + int r = c.read (); + std::printf ("ADC = %d\n", r); + ucoo::delay (0.5); + } +} diff --git a/ucoo/hal/gpio/Module b/ucoo/hal/gpio/Module new file mode 100644 index 0000000..8f2ba40 --- /dev/null +++ b/ucoo/hal/gpio/Module @@ -0,0 +1 @@ +hal_gpio_SOURCES = gpio.host.cc gpio.stm32f4.cc diff --git a/ucoo/hal/gpio/gpio.hh b/ucoo/hal/gpio/gpio.hh new file mode 100644 index 0000000..86a6c91 --- /dev/null +++ b/ucoo/hal/gpio/gpio.hh @@ -0,0 +1,35 @@ +#ifndef ucoo_hal_gpio_gpio_hh +#define ucoo_hal_gpio_gpio_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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_host) +# include "gpio.host.hh" +#elif defined TARGET_stm32f4 +# include "gpio.stm32f4.hh" +#else +# error "not implemented for this target" +#endif + +#endif // ucoo_hal_gpio_gpio_hh diff --git a/ucoo/hal/gpio/gpio.host.cc b/ucoo/hal/gpio/gpio.host.cc new file mode 100644 index 0000000..ca9065b --- /dev/null +++ b/ucoo/hal/gpio/gpio.host.cc @@ -0,0 +1,181 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "gpio.host.hh" + +#include + +namespace ucoo { + +/// Shared context between instances. +class GpioShared +{ + public: + /// Constructor, connect to mex node. + GpioShared (Host &host); + /// Register a new GPIO. + void register_instance (Host &host, Gpio &instance); + /// Set output state. + void set (Gpio &instance, bool state); + /// Set direction. + void output (Gpio &instance, bool output); + private: + /// Send state change message. + void send (Gpio &instance); + /// Handle input value from Mex. + void handle_gpio_input (mex::Msg &msg); + private: + Host &host_; + mex::Node &node_; + mex::mtype_t gpio_output_mtype_, gpio_input_mtype_; + typedef std::map Instances; + Instances instances_; +}; + +GpioShared::GpioShared (Host &host) + : host_ (host), node_ (host.get_node ()) +{ + std::string instance = host_.get_instance (); + gpio_output_mtype_ = node_.reserve (instance + ":gpio_out"); + gpio_input_mtype_ = node_.reserve (instance + ":gpio_in"); + node_.handler_register (gpio_input_mtype_, *this, + &GpioShared::handle_gpio_input); +} + +void +GpioShared::register_instance (Host &host, Gpio &instance) +{ + assert (&host == &host_); + std::pair r = + instances_.insert (Instances::value_type (instance.name_, &instance)); + assert (r.second); +} + +void +GpioShared::set (Gpio &instance, bool state) +{ + if (state != instance.output_) + { + instance.output_ = state; + send (instance); + } +} + +void +GpioShared::output (Gpio &instance, bool output) +{ + if (output != instance.direction_output_) + { + instance.direction_output_ = output; + send (instance); + } +} + +void +GpioShared::send (Gpio &instance) +{ + mex::Msg msg (gpio_output_mtype_); + msg.push ("BB") << instance.direction_output_ << instance.output_; + msg.push (instance.name_, std::strlen (instance.name_)); + node_.send (msg); +} + +void +GpioShared::handle_gpio_input (mex::Msg &msg) +{ + int input, namelen; + msg.pop ("B") >> input; + namelen = msg.len (); + std::string name (msg.pop (namelen), namelen); + Instances::iterator i = instances_.find (name); + assert (i != instances_.end ()); + i->second->input_ = input; +} + +GpioShared *Gpio::shared_; + +Gpio::Gpio (Host &host, const char *name) + : name_ (name), input_ (false), output_ (false), direction_output_ (false) +{ + if (!shared_) + { + static GpioShared shared (host); + shared_ = &shared; + } + shared_->register_instance (host, *this); +} + +Gpio::Gpio () + : name_ (0), input_ (false), output_ (false), direction_output_ (false) +{ +} + +void +Gpio::set () +{ + if (name_) + shared_->set (*this, true); +} + +void +Gpio::reset () +{ + if (name_) + shared_->set (*this, false); +} + +void +Gpio::set (bool state) +{ + if (name_) + shared_->set (*this, state); +} + +void +Gpio::toggle () +{ + if (name_) + shared_->set (*this, !output_); +} + +bool +Gpio::get () const +{ + return input_; +} + +void +Gpio::input () +{ + if (name_) + shared_->output (*this, false); +} + +void +Gpio::output () +{ + if (name_) + shared_->output (*this, true); +} + +} // namespace ucoo diff --git a/ucoo/hal/gpio/gpio.host.hh b/ucoo/hal/gpio/gpio.host.hh new file mode 100644 index 0000000..fcd0cbf --- /dev/null +++ b/ucoo/hal/gpio/gpio.host.hh @@ -0,0 +1,69 @@ +#ifndef ucoo_hal_gpio_gpio_host_hh +#define ucoo_hal_gpio_gpio_host_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/io.hh" +#include "ucoo/arch/host/host.hh" + +namespace ucoo { + +class GpioShared; + +/// General purpose input/output on host. +class Gpio : public Io +{ + public: + /// Initialise GPIO. + Gpio (Host &host, const char *name); + /// Initialise GPIO, with no mex support. + Gpio (); + /// See Io::set. + void set (); + /// See Io::reset. + void reset (); + /// See Io::set. + void set (bool state); + /// See Io::toggle. + void toggle (); + /// See Io::get. + bool get () const; + /// See Io::input. + void input (); + /// See Io::output. + void output (); + private: + /// Name. + const char *name_; + /// Current input/output states. + bool input_, output_; + /// Current direction, true for output. + bool direction_output_; + /// Shared context. + static GpioShared *shared_; + friend class GpioShared; +}; + +} // namespace ucoo + +#endif // ucoo_hal_gpio_gpio_host_hh diff --git a/ucoo/hal/gpio/gpio.stm32f4.cc b/ucoo/hal/gpio/gpio.stm32f4.cc new file mode 100644 index 0000000..1b46fd5 --- /dev/null +++ b/ucoo/hal/gpio/gpio.stm32f4.cc @@ -0,0 +1,105 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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 "gpio.stm32f4.hh" + +namespace ucoo { + +void +Gpio::set () +{ + GPIO_BSRR (port_) = mask_; +} + +void +Gpio::reset () +{ + GPIO_BSRR (port_) = mask_ << 16; +} + +/// Helper to avoid virtual dance. +static inline void +Gpio_set (uint32_t port, uint16_t mask, bool state) +{ + if (state) + GPIO_BSRR (port) = mask; + else + GPIO_BSRR (port) = mask << 16; +} + +void +Gpio::set (bool state) +{ + Gpio_set (port_, mask_, state); +} + +void +Gpio::toggle () +{ + // Avoid read/modify/write ODR, to achieve atomic operation. + Gpio_set (port_, mask_, !(GPIO_ODR (port_) & mask_)); +} + +bool +Gpio::get () const +{ + return GPIO_IDR (port_) & mask_; +} + +/// Set two bits in a register for the corresponding one-bit mask. +static uint32_t +dmask_set (uint32_t mask, uint32_t reg, uint32_t bits) +{ + uint32_t dmask = mask * mask; + reg &= ~(dmask | dmask << 1); + reg |= bits * dmask; + return reg; +} + +void +Gpio::input () +{ + GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_), + GPIO_MODE_INPUT); +} + +void +Gpio::output () +{ + GPIO_MODER (port_) = dmask_set (mask_, GPIO_MODER (port_), + GPIO_MODE_OUTPUT); +} + +void +Gpio::pull (Pull dir) +{ + GPIO_PUPDR (port_) = dmask_set (mask_, GPIO_PUPDR (port_), dir); +} + +void +Gpio::speed (Speed s) +{ + GPIO_OSPEEDR (port_) = dmask_set (mask_, GPIO_OSPEEDR (port_), s); +} + +} // namespace ucoo diff --git a/ucoo/hal/gpio/gpio.stm32f4.hh b/ucoo/hal/gpio/gpio.stm32f4.hh new file mode 100644 index 0000000..b2dfb16 --- /dev/null +++ b/ucoo/hal/gpio/gpio.stm32f4.hh @@ -0,0 +1,85 @@ +#ifndef ucoo_hal_gpio_gpio_stm32f4_hh +#define ucoo_hal_gpio_gpio_stm32f4_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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/io.hh" + +#include + +namespace ucoo { + +/// General purpose input/output on STM32F4. +class Gpio : public Io +{ + public: + enum Pull + { + PULL_NONE = GPIO_PUPD_NONE, + PULL_UP = GPIO_PUPD_PULLUP, + PULL_DOWN = GPIO_PUPD_PULLDOWN, + }; + enum Speed + { + SPEED_2MHZ = GPIO_OSPEED_2MHZ, + SPEED_25MHZ = GPIO_OSPEED_25MHZ, + SPEED_50MHZ = GPIO_OSPEED_50MHZ, + SPEED_100MHZ = GPIO_OSPEED_100MHZ, + }; + public: + /// Constructor, take the PORT base address, and pin BIT number. + Gpio (uint32_t port, int bit); + /// See Io::set. + void set (); + /// See Io::reset. + void reset (); + /// See Io::set. + void set (bool state); + /// See Io::toggle. + void toggle (); + /// See Io::get. + bool get () const; + /// See Io::input. + void input (); + /// See Io::output. + void output (); + /// Set pull-up or pull-down. + void pull (Pull dir); + /// Set output speed. + void speed (Speed s); + private: + /// Port register base address. + const uint32_t port_; + /// IO bitmask. + const uint16_t mask_; +}; + +inline +Gpio::Gpio (uint32_t port, int bit) + : port_ (port), mask_ (1u << bit) +{ +} + +} // namespace ucoo + +#endif // ucoo_hal_gpio_gpio_stm32f4_hh diff --git a/ucoo/hal/gpio/test/Makefile b/ucoo/hal/gpio/test/Makefile new file mode 100644 index 0000000..e2f7692 --- /dev/null +++ b/ucoo/hal/gpio/test/Makefile @@ -0,0 +1,9 @@ +BASE = ../../../.. + +TARGETS = stm32f4 +stm32f4_PROGS = test_gpio +test_gpio_SOURCES = test_gpio.cc + +MODULES = hal/gpio utils + +include $(BASE)/build/top.mk diff --git a/ucoo/hal/gpio/test/test_gpio.cc b/ucoo/hal/gpio/test/test_gpio.cc new file mode 100644 index 0000000..a953505 --- /dev/null +++ b/ucoo/hal/gpio/test/test_gpio.cc @@ -0,0 +1,71 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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/arch/arch.hh" +#include "ucoo/hal/gpio/gpio.hh" +#include "ucoo/utils/delay.hh" + +#include + +void +test (ucoo::Io &loop_out, ucoo::Io &loop_in, ucoo::Io &led3, ucoo::Io &led4, + ucoo::Io &led5, ucoo::Io &led6) +{ + loop_in.input (); + loop_out.output (); + led3.output (); + led4.output (); + led5.output (); + led6.output (); + led3.set (); + led6.reset (); + bool state = false; + while (1) + { + led3.toggle (); + led4.set (state); + led5.set (loop_in.get ()); + led6.toggle (); + state = !state; + loop_out.set (state); + ucoo::delay (1); + } +} + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN + | RCC_AHB1ENR_IOPDEN); + // For this test, shorten B6 & B7 to have loopback. + gpio_mode_setup (GPIOB, GPIO_MODE_INPUT, GPIO_PUPD_PULLUP, GPIO7); + ucoo::Gpio loop_out (GPIOB, 6); + ucoo::Gpio loop_in (GPIOB, 7); + ucoo::Gpio led3 (GPIOD, 13); + ucoo::Gpio led4 (GPIOD, 12); + ucoo::Gpio led5 (GPIOD, 14); + ucoo::Gpio led6 (GPIOD, 15); + test (loop_out, loop_in, led3, led4, led5, led6); + return 0; +} diff --git a/ucoo/hal/i2c/Config b/ucoo/hal/i2c/Config new file mode 100644 index 0000000..3871f5c --- /dev/null +++ b/ucoo/hal/i2c/Config @@ -0,0 +1,5 @@ +[hal/i2c] +# Size of slave buffer, used for both reception and transmission. +slave_buffer_size = 64 +# Activate debug trace. +trace = false diff --git a/ucoo/hal/i2c/Module b/ucoo/hal/i2c/Module new file mode 100644 index 0000000..ae93f22 --- /dev/null +++ b/ucoo/hal/i2c/Module @@ -0,0 +1 @@ +hal_i2c_SOURCES := i2c.host.cc i2c_slave_data_buffer.cc i2c_hard.stm32.cc diff --git a/ucoo/hal/i2c/i2c.hh b/ucoo/hal/i2c/i2c.hh new file mode 100644 index 0000000..2c06085 --- /dev/null +++ b/ucoo/hal/i2c/i2c.hh @@ -0,0 +1,36 @@ +#ifndef ucoo_hal_i2c_i2c_hh +#define ucoo_hal_i2c_i2c_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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_host) +# include "i2c.host.hh" +#elif defined (TARGET_stm32) +# include "i2c_hard.stm32.hh" +#else +# error "not implemented for this target" +#endif +#include "i2c_slave_data_buffer.hh" + +#endif // ucoo_hal_i2c_i2c_hh diff --git a/ucoo/hal/i2c/i2c.host.cc b/ucoo/hal/i2c/i2c.host.cc new file mode 100644 index 0000000..4a2553b --- /dev/null +++ b/ucoo/hal/i2c/i2c.host.cc @@ -0,0 +1,213 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "i2c.host.hh" + +#include "config/hal/i2c.hh" + +namespace ucoo { + +/// Shared context between instances. +class I2cHostShared +{ + public: + /// Constructor, connect to mex node. + I2cHostShared (Host &host); + /// Register a new driver instance. + void register_instance (Host &host, I2cHost &instance); + /// Send message, return new master status. + int send (uint8_t addr, const char *buf, int count); + /// Receive message, return new master status. + int recv (uint8_t addr, char *buf, int count); + /// Handle read requests from master. + void handle_read (mex::Msg &msg); + /// Handle write requests from master. + void handle_write (mex::Msg &msg); + private: + Host &host_; + mex::Node &node_; + mex::mtype_t read_mtype_, write_mtype_; + typedef std::list Instances; + Instances instances_; +}; + +I2cHostShared::I2cHostShared (Host &host) + : host_ (host), node_ (host.get_node ()) +{ + std::string instance = host_.get_instance (1); + read_mtype_ = node_.reserve (instance + ":read"); + write_mtype_ = node_.reserve (instance + ":write"); + node_.handler_register (read_mtype_, *this, &I2cHostShared::handle_read); + node_.handler_register (write_mtype_, *this, &I2cHostShared::handle_write); +} + +void +I2cHostShared::register_instance (Host &host, I2cHost &instance) +{ + assert (&host == &host_); + instances_.push_back (&instance); +} + +int +I2cHostShared::send (uint8_t addr, const char *buf, int count) +{ + // Test for this slave in the same program. + for (Instances::const_iterator i = instances_.begin (); + i != instances_.end (); ++i) + { + if (addr == (*i)->slave_addr_) + { + assert (count <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE); + (*i)->slave_data_handler_->to_recv (buf, count); + return count; + } + } + // Else, send message. + mex::Msg msg (write_mtype_); + msg.push ("B") << addr; + msg.push (buf, count); + node_.send (msg); + return count; +} + +int +I2cHostShared::recv (uint8_t addr, char *buf, int count) +{ + // Test for this slave in the same program. + for (Instances::const_iterator i = instances_.begin (); + i != instances_.end (); ++i) + { + if (addr == (*i)->slave_addr_) + { + assert (count <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE); + return (*i)->slave_data_handler_->to_send (buf, count); + } + } + // Else, send request and wait for response. + mex::Msg msg (read_mtype_); + msg.push ("BB") << addr << count; + std::auto_ptr rsp = node_.request (msg); + int rcount = rsp->len (); + assert (rcount <= count); + const char *rbuf = rsp->pop (rcount); + std::copy (rbuf, rbuf + rcount, buf); + return rcount; +} + +void +I2cHostShared::handle_read (mex::Msg &msg) +{ + uint8_t addr; + int size; + msg.pop ("BB") >> addr >> size; + for (Instances::const_iterator i = instances_.begin (); + i != instances_.end (); ++i) + { + if (addr == (*i)->slave_addr_) + { + assert (size <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE); + char buf[size]; + int n = (*i)->slave_data_handler_->to_send (buf, size); + mex::Msg rsp (read_mtype_); + rsp.push (buf, n); + node_.response (rsp); + break; + } + } +} + +void +I2cHostShared::handle_write (mex::Msg &msg) +{ + uint8_t addr; + msg.pop ("B") >> addr; + for (Instances::const_iterator i = instances_.begin (); + i != instances_.end (); ++i) + { + if (addr == (*i)->slave_addr_) + { + int size = msg.len (); + assert (size <= UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE); + (*i)->slave_data_handler_->to_recv (msg.pop (size), size); + break; + } + } +} + +I2cHostShared *I2cHost::shared_; + +I2cHost::I2cHost (Host &host, int n) + : n_ (n), slave_addr_ (0), slave_data_handler_ (0), + master_status_ (STATUS_ERROR) +{ + if (!shared_) + { + static I2cHostShared shared (host); + shared_ = &shared; + } + shared_->register_instance (host, *this); + // n is not used, there is no support for several buses in the MEX + // messages at the moment. +} + +void +I2cHost::send (uint8_t addr, const char *buf, int count) +{ + // Update status, there is no background task. + master_status_ = shared_->send (addr, buf, count); + // If needed, call callback. + if (finished_handler_) + finished_handler_->finished (master_status_); +} + +void +I2cHost::recv (uint8_t addr, char *buf, int count) +{ + // Update status, there is no background task. + master_status_ = shared_->recv (addr, buf, count); + // If needed, call callback. + if (finished_handler_) + finished_handler_->finished (master_status_); +} + +int +I2cHost::status () +{ + return master_status_; +} + +int +I2cHost::wait () +{ + // Transfers are immediate. + return status (); +} + +void +I2cHost::register_data (uint8_t addr, DataHandler &data_handler) +{ + slave_addr_ = addr; + slave_data_handler_ = &data_handler; +} + +} // namespace ucoo diff --git a/ucoo/hal/i2c/i2c.host.hh b/ucoo/hal/i2c/i2c.host.hh new file mode 100644 index 0000000..c0bb7f9 --- /dev/null +++ b/ucoo/hal/i2c/i2c.host.hh @@ -0,0 +1,66 @@ +#ifndef ucoo_hal_i2c_i2c_host_hh +#define ucoo_hal_i2c_i2c_host_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/i2c.hh" +#include "ucoo/arch/host/host.hh" + +namespace ucoo { + +class I2cHostShared; + +/// I2C interface, host version. +class I2cHost : public I2c +{ + public: + /// Initialise the Nth I2C. + I2cHost (Host &host, int n); + /// See I2cMaster::send. + void send (uint8_t addr, const char *buf, int count); + /// See I2cMaster::recv. + void recv (uint8_t addr, char *buf, int count); + /// See I2cMaster::status. + int status (); + /// See I2cMaster::wait. + int wait (); + /// See I2cSlave::register_data. + void register_data (uint8_t addr, DataHandler &data_handler); + private: + /// I2C number. + int n_; + /// Slave address. + uint8_t slave_addr_; + /// Handler called to source or sink data for slave exchanges. + DataHandler *slave_data_handler_; + /// Current master transfer status. + int master_status_; + /// Shared context. + static I2cHostShared *shared_; + friend class I2cHostShared; +}; + +} // namespace ucoo + + +#endif // ucoo_hal_i2c_i2c_host_hh diff --git a/ucoo/hal/i2c/i2c_hard.stm32.cc b/ucoo/hal/i2c/i2c_hard.stm32.cc new file mode 100644 index 0000000..8122d15 --- /dev/null +++ b/ucoo/hal/i2c/i2c_hard.stm32.cc @@ -0,0 +1,396 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "i2c_hard.stm32.hh" + +#include +#include +#include + +#include "ucoo/utils/trace.hh" + +namespace ucoo { + +/// Local trace. +static Trace i2c_trace; + +static const int i2c_nb = 3; + +/// Information on I2C hardware structure. +struct i2c_hardware_t +{ + /// I2C base address. + uint32_t base; + /// RCC enable bit. + uint32_t rcc_en; + /// Corresponding event IRQ (error IRQ is next one). + int ev_irq; +}; + +/// Information on I2C hardware array, this is zero indexed, I2C1 is at index +/// 0. +static const i2c_hardware_t i2c_hardware[i2c_nb] = +{ + { I2C1_BASE, RCC_APB1ENR_I2C1EN, NVIC_I2C1_EV_IRQ }, + { I2C2_BASE, RCC_APB1ENR_I2C2EN, NVIC_I2C2_EV_IRQ }, + { I2C3_BASE, RCC_APB1ENR_I2C3EN, NVIC_I2C3_EV_IRQ }, +}; + +static I2cHard *i2c_instances[i2c_nb]; + +} // namespace ucoo + +extern "C" { + +void i2c1_ev_isr () { ucoo::I2cHard::ev_isr (0); } + +void i2c1_er_isr () { ucoo::I2cHard::er_isr (0); } + +void i2c2_ev_isr () { ucoo::I2cHard::ev_isr (1); } + +void i2c2_er_isr () { ucoo::I2cHard::er_isr (1); } + +void i2c3_ev_isr () { ucoo::I2cHard::ev_isr (2); } + +void i2c3_er_isr () { ucoo::I2cHard::er_isr (2); } + +} + +namespace ucoo { + +I2cHard::I2cHard (int n) + : n_ (n), enabled_ (false), slave_addr_ (0), slave_data_handler_ (0), + master_ (false), master_status_ (STATUS_ERROR), master_buf_ (0) +{ + assert (n < i2c_nb); + assert (!i2c_instances[n]); + i2c_instances[n] = this; +} + +I2cHard::~I2cHard () +{ + disable (); + i2c_instances[n_] = 0; +} + +void +I2cHard::enable (int speed) +{ + enabled_ = true; + uint32_t base = i2c_hardware[n_].base; + // Turn on. + rcc_peripheral_enable_clock (&RCC_APB1ENR, i2c_hardware[n_].rcc_en); + // Reset. + I2C_CR1 (base) = I2C_CR1_SWRST; + // TODO: make sure the bus is free!!! How! + I2C_CR1 (base) = 0; + // Compute clock parameters. + int pclk = rcc_ppre1_frequency; + int pclk_mhz = pclk / 1000000; + uint16_t ccr, tris; + if (speed <= 100000) + { + ccr = pclk / speed / 2; + tris = pclk_mhz + 1; + } + else + { + assert (speed <= 400000); + ccr = I2C_CCR_FS | I2C_CCR_DUTY | (pclk / speed / 25); + tris = pclk_mhz * 3 / 10 + 1; + } + // Set all parameters. + I2C_CCR (base) = ccr; + I2C_TRISE (base) = tris; + I2C_OAR1 (base) = slave_addr_ | (1 << 14); + I2C_OAR2 (base) = 0; + I2C_CR2 (base) = I2C_CR2_ITEVTEN | I2C_CR2_ITERREN | pclk_mhz; + // Enable. + nvic_enable_irq (i2c_hardware[n_].ev_irq); + nvic_enable_irq (i2c_hardware[n_].ev_irq + 1); + I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_PE; + +} + +void +I2cHard::disable () +{ + if (enabled_) + { + enabled_ = false; + uint32_t base = i2c_hardware[n_].base; + // TODO: wait for end of transfer? + // Disable. + nvic_disable_irq (i2c_hardware[n_].ev_irq); + nvic_disable_irq (i2c_hardware[n_].ev_irq + 1); + I2C_CR1 (base) = 0; + // Turn off. + rcc_peripheral_disable_clock (&RCC_APB1ENR, + i2c_hardware[n_].rcc_en); + } +} + +void +I2cHard::transfer (uint8_t addr, char *buf, int count) +{ + assert (enabled_ && count); + // No need to lock, master is not busy. + assert (master_status_ != STATUS_BUSY); + uint32_t base = i2c_hardware[n_].base; + // Wait until STOP condition terminated, polling is the only way. + while (I2C_CR1 (base) & I2C_CR1_STOP) + barrier (); + // Now, program next transfer. + master_status_ = STATUS_BUSY; + master_slave_addr_ = addr; + master_buf_ = buf; + master_count_ = count; + // TODO: multimaster: about ACK, may have to lock IRQ for multimaster. + I2C_CR1 (base) |= I2C_CR1_START; +} + +void +I2cHard::send (uint8_t addr, const char *buf, int count) +{ + transfer (addr, const_cast (buf), count); +} + +void +I2cHard::recv (uint8_t addr, char *buf, int count) +{ + assert (count >= 2); // TODO: count = 1 not supported, there is no IT! + // LSB = 1 for receiver mode. + transfer (addr | 1, buf, count); +} + +int +I2cHard::status () +{ + return master_status_; +} + +int +I2cHard::wait () +{ + while (master_status_ == STATUS_BUSY) + barrier (); + return master_status_; +} + +void +I2cHard::register_data (uint8_t addr, DataHandler &data_handler) +{ + assert ((addr & 1) == 0); + slave_addr_ = addr; + slave_data_handler_ = &data_handler; + if (enabled_) + { + uint32_t base = i2c_hardware[n_].base; + // Just in case a transfer is triggered right now. + barrier (); + // According to datasheet, bit 14 should be 1! + I2C_OAR1 (base) = addr | (1 << 14); + } +} + +void +I2cHard::ev_isr (int n) +{ + uint32_t base = i2c_hardware[n].base; + assert (i2c_instances[n]); + I2cHard &i2c = *i2c_instances[n]; + i2c_trace ("<%d> event isr", n); + while (1) + { + uint16_t sr1 = I2C_SR1 (base); + i2c_trace ("<%d> sr1=%04x", n, sr1); + // Can not read SR2 because doing so would clear the ADDR bit. + if (i2c.master_) + { + if (sr1 & I2C_SR1_ADDR) + { + uint16_t sr2; + // If only one or two bytes should be received, disable ACK + // before reading SR2, and STOP after... Crappy hardware! + if ((i2c.master_slave_addr_ & 1) && i2c.buf_count_ == 1) + { + I2C_CR1 (base) = I2C_CR1_PE; + sr2 = I2C_SR2 (base); + I2C_CR1 (base) = I2C_CR1_STOP | I2C_CR1_PE; + // TODO: what to wait now? Unsupported for now. + } + else if ((i2c.master_slave_addr_ & 1) && i2c.buf_count_ == 2) + { + I2C_CR1 (base) = I2C_CR1_POS | I2C_CR1_PE; + sr2 = I2C_SR2 (base); + // Wait for BTF. + } + else + { + sr2 = I2C_SR2 (base); + I2C_CR2 (base) |= I2C_CR2_ITBUFEN; + } + i2c_trace ("<%d> master sr2=%04x", n, sr2); + } + else if (sr1 & I2C_SR1_TxE + && i2c.buf_index_ < i2c.buf_count_) + { + i2c_trace ("<%d> master tx index=%d", n, i2c.buf_index_); + // Send next byte. + I2C_DR (base) = i2c.master_buf_[i2c.buf_index_++]; + // Wait for BTF if last one. + if (i2c.buf_index_ == i2c.buf_count_) + I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN; + } + else if (sr1 & I2C_SR1_RxNE + && i2c.buf_count_ - i2c.buf_index_ > 3) + { + i2c_trace ("<%d> master rx index=%d", n, i2c.buf_index_); + i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base); + if (i2c.buf_count_ - i2c.buf_index_ == 3) + // Wait for BTF. + I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN; + } + else if (sr1 & I2C_SR1_BTF) + { + i2c_trace ("<%d> master btf index=%d", n, i2c.buf_index_); + if (!(i2c.master_slave_addr_ & 1)) + { + // End of transmission. + I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE; + i2c.master_ = false; + i2c.master_status_ = i2c.buf_index_; + if (i2c.finished_handler_) + i2c.finished_handler_->finished (i2c.master_status_); + } + else if (i2c.buf_count_ - i2c.buf_index_ == 3) + { + // Near end of reception. + I2C_CR1 (base) = I2C_CR1_PE; + i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base); + // Wait for BTF. + } + else + { + // End of reception. + I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE; + if (i2c.buf_count_ - i2c.buf_index_ == 2) + i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base); + i2c.master_buf_[i2c.buf_index_++] = I2C_DR (base); + i2c.master_ = false; + i2c.master_status_ = i2c.buf_index_; + if (i2c.finished_handler_) + i2c.finished_handler_->finished (i2c.master_status_); + } + } + else + break; + } + else + { + if (sr1 & I2C_SR1_ADDR) + { + uint16_t sr2 = I2C_SR2 (base); + i2c_trace ("<%d> slave sr2=%04x", n, sr2); + // Initiate new slave transfer. + if (sr2 & I2C_SR2_TRA) + { + i2c.buf_count_ = i2c.slave_data_handler_->to_send + (i2c.slave_buf_, sizeof (i2c.slave_buf_)); + } + else + i2c.buf_count_ = sizeof (i2c.slave_buf_); + i2c.buf_index_ = 0; + I2C_CR2 (base) |= I2C_CR2_ITBUFEN; + } + else if (sr1 & I2C_SR1_TxE) + { + i2c_trace ("<%d> slave tx index=%d", n, i2c.buf_index_); + uint8_t b = 0xff; + if (i2c.buf_index_ < i2c.buf_count_) + b = i2c.slave_buf_[i2c.buf_index_++]; + I2C_DR (base) = b; + } + else if (sr1 & I2C_SR1_RxNE) + { + i2c_trace ("<%d> slave rx index=%d", n, i2c.buf_index_); + uint8_t b = I2C_DR (base); + if (i2c.buf_index_ < i2c.buf_count_) + i2c.slave_buf_[i2c.buf_index_++] = b; + } + else if (sr1 & I2C_SR1_STOPF) + { + i2c_trace ("<%d> slave stop", n); + i2c.slave_data_handler_->to_recv (i2c.slave_buf_, i2c.buf_index_); + // TODO: multimaster: there is no way to write in this + // register if a START was requested to switch to master mode! + I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_PE; + I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN; + } + else if (sr1 & I2C_SR1_SB) + { + i2c_trace ("<%d> master start", n); + // Starting master mode. + I2C_DR (base) = i2c.master_slave_addr_; + i2c.master_ = true; + i2c.buf_count_ = i2c.master_count_; + i2c.buf_index_ = 0; + } + else + break; + } + + } +} + +void +I2cHard::er_isr (int n) +{ + uint32_t base = i2c_hardware[n].base; + assert (i2c_instances[n]); + I2cHard &i2c = *i2c_instances[n]; + uint16_t sr1 = I2C_SR1 (base); + I2C_SR1 (base) = 0; + i2c_trace ("<%d> error isr sr1=%04x", n, sr1); + if (i2c.master_) + { + if (sr1 & I2C_SR1_ARLO) + { + // Try again. + I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_START | I2C_CR1_PE; + i2c.master_ = false; + } + else if (sr1 & I2C_SR1_AF) + { + I2C_CR1 (base) = I2C_CR1_ACK | I2C_CR1_STOP | I2C_CR1_PE; + i2c.master_ = false; + i2c.master_status_ = i2c.buf_index_; + if (i2c.finished_handler_) + i2c.finished_handler_->finished (i2c.master_status_); + } + } + I2C_CR2 (base) &= ~I2C_CR2_ITBUFEN; + // TODO: handle misplaced STOP errata. +} + +} // namespace ucoo diff --git a/ucoo/hal/i2c/i2c_hard.stm32.hh b/ucoo/hal/i2c/i2c_hard.stm32.hh new file mode 100644 index 0000000..94e4259 --- /dev/null +++ b/ucoo/hal/i2c/i2c_hard.stm32.hh @@ -0,0 +1,91 @@ +#ifndef ucoo_hal_i2c_i2c_hard_stm32_hh +#define ucoo_hal_i2c_i2c_hard_stm32_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/i2c.hh" + +#include "config/hal/i2c.hh" + +namespace ucoo { + +/// I2C interface, using dedicated hardware. +class I2cHard : public I2c +{ + public: + /// Constructor for the Nth I2C. + I2cHard (int n); + /// Shutdown. + ~I2cHard (); + /// Enable and setup + void enable (int speed = 100000); + /// Disable. + void disable (); + /// See I2cMaster::send. + void send (uint8_t addr, const char *buf, int count); + /// See I2cMaster::recv. + void recv (uint8_t addr, char *buf, int count); + /// See I2cMaster::status. + int status (); + /// See I2cMaster::wait. + int wait (); + /// See I2cSlave::register_data. + void register_data (uint8_t addr, DataHandler &data_handler); + /// Event ISR. + static void ev_isr (int n); + /// Error ISR. + static void er_isr (int n); + private: + /// Start a master transfer, send or recv, depending on addr LSB. + void transfer (uint8_t addr, char *buf, int count); + private: + /// I2C number. + int n_; + /// Is it enabled? + bool enabled_; + /// Slave address. + uint8_t slave_addr_; + /// Handler called to source or sink data for slave exchanges. + DataHandler *slave_data_handler_; + /// Slave buffer. + char slave_buf_[UCOO_CONFIG_HAL_I2C_SLAVE_BUFFER_SIZE]; + /// Current buffer count (bytes to send), or buffer size (available room). + int buf_count_; + /// Current buffer index (position to read byte to send or write received + /// byte). + int buf_index_; + /// Master access granted. + bool master_; + /// Current master transfer status. + int master_status_; + /// Current master transfer buffer. + char *master_buf_; + /// Current master transfer size, copied to buf_count_ when active. + int master_count_; + /// Current master transfer slave address, LSB is set for receiver mode. + uint8_t master_slave_addr_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_i2c_i2c_hard_stm32_hh diff --git a/ucoo/hal/i2c/i2c_slave_data_buffer.cc b/ucoo/hal/i2c/i2c_slave_data_buffer.cc new file mode 100644 index 0000000..1ba3a3a --- /dev/null +++ b/ucoo/hal/i2c/i2c_slave_data_buffer.cc @@ -0,0 +1,80 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "i2c_slave_data_buffer.hh" + +#include + +namespace ucoo { + +I2cSlaveDataBuffer::I2cSlaveDataBuffer (char *send_buf, int send_size, + char *recv_buf, int recv_size) + : send_buf_ (send_buf), send_size_ (send_size), send_count_ (0), + recv_buf_ (recv_buf), recv_size_ (recv_size), recv_count_ (0) +{ +} + +void +I2cSlaveDataBuffer::update (const char *buf, int count) +{ + int r = std::min (count, send_size_); + irq_flags_t flags = irq_lock (); + std::copy (buf, buf + r, send_buf_); + send_count_ = r; + irq_restore (flags); +} + +int +I2cSlaveDataBuffer::poll (char *buf, int count) +{ + // Test to avoid superfluous irq lock. This is not a problem if + // condition become false before irq is locked. + if (recv_count_) + { + irq_flags_t flags = irq_lock (); + int r = std::min (count, recv_count_); + recv_count_ = 0; + std::copy (recv_buf_, recv_buf_ + r, buf); + irq_restore (flags); + return r; + } + else return 0; +} + +int +I2cSlaveDataBuffer::to_send (char *buf, int count) +{ + int r = std::min (count, send_count_); + std::copy (send_buf_, send_buf_ + r, buf); + return r; +} + +void +I2cSlaveDataBuffer::to_recv (const char *buf, int count) +{ + int r = std::min (count, recv_size_); + std::copy (buf, buf + r, recv_buf_); + recv_count_ = r; +} + +} // namespace ucoo diff --git a/ucoo/hal/i2c/i2c_slave_data_buffer.hh b/ucoo/hal/i2c/i2c_slave_data_buffer.hh new file mode 100644 index 0000000..eae45ae --- /dev/null +++ b/ucoo/hal/i2c/i2c_slave_data_buffer.hh @@ -0,0 +1,71 @@ +#ifndef ucoo_hal_i2c_i2c_slave_data_buffer_hh +#define ucoo_hal_i2c_i2c_slave_data_buffer_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/i2c.hh" + +namespace ucoo { + +/// Data sink and source for I2C slave. Store any received data and data to +/// send in buffers. +class I2cSlaveDataBuffer : public I2cSlave::DataHandler +{ + public: + /// Constructor, take buffers. + I2cSlaveDataBuffer (char *send_buf, int send_size, + char *recv_buf, int recv_size); + /// Update slave internal buffer, will be sent to master on request. + void update (const char *buf, int count); + /// If data has been received, copy it to provided buffer and return its + /// size. Else, return 0. + int poll (char *buf, int count); + /// See I2cSlave::DataHandler::to_send. + int to_send (char *buf, int count); + /// See I2cSlave::DataHandler::to_recv. + void to_recv (const char *buf, int count); + private: + char *send_buf_; + int send_size_, send_count_; + char *recv_buf_; + int recv_size_, recv_count_; +}; + +/// Same as I2cSlaveDataBuffer, but include buffers. +template +class I2cSlaveDataBufferSize : public I2cSlaveDataBuffer +{ + public: + /// Default constructor. + I2cSlaveDataBufferSize () + : I2cSlaveDataBuffer (send_array_, sizeof (send_array_), + recv_array_, sizeof (recv_array_)) + { } + private: + char send_array_[send_size]; + char recv_array_[recv_size]; +}; + +} // namespace ucoo + +#endif // ucoo_hal_i2c_i2c_slave_data_buffer_hh diff --git a/ucoo/hal/i2c/test/Makefile b/ucoo/hal/i2c/test/Makefile new file mode 100644 index 0000000..5046862 --- /dev/null +++ b/ucoo/hal/i2c/test/Makefile @@ -0,0 +1,9 @@ +BASE = ../../../.. + +TARGETS = host stm32f4 +PROGS = test_i2c +test_i2c_SOURCES = test_i2c.cc + +MODULES = hal/i2c utils base/test hal/usb + +include $(BASE)/build/top.mk diff --git a/ucoo/hal/i2c/test/hub.py b/ucoo/hal/i2c/test/hub.py new file mode 100644 index 0000000..c6c77f7 --- /dev/null +++ b/ucoo/hal/i2c/test/hub.py @@ -0,0 +1,6 @@ +# Hub for test. +from mex.hub import Hub +def log (x): + print x +h = Hub (min_clients = 1, log = log) +h.wait () diff --git a/ucoo/hal/i2c/test/test_i2c.cc b/ucoo/hal/i2c/test/test_i2c.cc new file mode 100644 index 0000000..7fc7772 --- /dev/null +++ b/ucoo/hal/i2c/test/test_i2c.cc @@ -0,0 +1,226 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/i2c/i2c.hh" + +#include "ucoo/arch/arch.hh" +#include "ucoo/base/test/test.hh" + +#ifdef TARGET_stm32 +# include +# include "ucoo/hal/gpio/gpio.hh" +#endif + +#ifdef TARGET_host +# define TEST_NOT_THERE 0 +#else +# define TEST_NOT_THERE 1 +#endif + +#include "ucoo/utils/delay.hh" + +#include +#include + +static const int buffer_size = 16; +static const int margin = 5; +static const uint8_t a1 = 0x2c, a2 = 0x2e, a3 = 0x42; + +void +test_basic (ucoo::TestSuite &tsuite, ucoo::I2cMaster &m, + ucoo::I2cSlaveDataBuffer &d, uint8_t addr) +{ + tsuite.group ("basic"); + { + ucoo::Test test (tsuite, "recv"); + const char *hello = "Hello world!"; + char buf[buffer_size + margin]; + d.update (hello, std::strlen (hello) + 1); + char ref[buffer_size + margin]; + int ref_size = std::strlen (hello) + 1; + std::copy (hello, hello + ref_size, ref); +#ifdef TARGET_stm32 + // Slave is not able to signal its buffer end. Extra bytes will be + // read as 0xff. + std::fill (ref + ref_size, ref + sizeof (ref), 0xff); + ref_size = sizeof (ref); +#endif + for (int len = 2; len < (int) sizeof (buf); len++) + { + std::fill (buf, buf + sizeof (buf), 42); + m.recv (addr, buf, len); + int r = m.wait (); + int rexp = std::min (len, ref_size); + test_fail_break_unless (test, r == rexp); + test_fail_break_unless (test, std::equal (buf, buf + rexp, ref)); + test_fail_break_unless (test, std::count (buf, buf + sizeof (buf), 42) + == (int) sizeof (buf) - rexp); + } + } + { + ucoo::Test test (tsuite, "send"); + // Slave is supposed to signal when it received enough data, but this + // is not implemented. + char buf[buffer_size + margin]; + for (int len = 1; len < (int) sizeof (buf); len++) + { + int r; + // Before transfer, no data. + r = d.poll (buf, sizeof (buf)); + test_fail_break_unless (test, r == 0); + // Send data. + char c = '0' + len % 10; + std::fill (buf, buf + len, c); + m.send (addr, buf, len); + r = m.wait (); + test_fail_break_unless (test, r == len); + // Let some time for slave to finish reception. + ucoo::delay_ms (1); + // Check what is received. + r = d.poll (buf, sizeof (buf)); + test_fail_break_unless (test, r == std::min (len, buffer_size)); + test_fail_break_unless (test, std::count (buf, buf + r, c) == r); + } + } + do { + ucoo::Test test (tsuite, "callback"); + // Callback object will start a reception, then a transmission of what + // was received. + class TestCallback : public ucoo::I2cMaster::FinishedHandler + { + ucoo::I2cMaster &m_; + uint8_t addr_; + int step_; + char buf_[buffer_size]; + public: + bool failed; + public: + TestCallback (ucoo::I2cMaster &m, uint8_t addr) + : m_ (m), addr_ (addr), step_ (0), failed (false) { } + void finished (int status) + { + if (status != buffer_size) + failed = true; + else + { + switch (step_) + { + case 0: + step_++; + m_.recv (addr_, buf_, buffer_size); + break; + case 1: + step_++; + m_.send (addr_, buf_, buffer_size); + break; + case 2: + // Nothing, stop. + break; + } + } + } + }; + TestCallback callback (m, addr); + m.register_finished (callback); + // Set slave data. + char buf[buffer_size]; + std::fill (buf, buf + sizeof (buf), 42); + d.update (buf, sizeof (buf)); + // Start transfers. + std::fill (buf, buf + sizeof (buf), 21); + m.send (addr, buf, sizeof (buf)); + // Will only return after the last transfer. + m.wait (); + m.unregister_finished (); + test_fail_break_unless (test, !callback.failed); + // Let some time for slave to finish reception. + ucoo::delay_ms (1); + // Check what is received by slave (master should have read 42 from + // slave and send it back). + int r = d.poll (buf, sizeof (buf)); + test_fail_break_unless (test, r == buffer_size); + test_fail_break_unless (test, std::count (buf, buf + r, 42) == r); + } while (0); +} + +void +test_not_there (ucoo::TestSuite &tsuite, ucoo::I2cMaster &m, uint8_t addr) +{ + tsuite.group ("not there"); + do { + ucoo::Test test (tsuite, "recv"); + char buf[buffer_size]; + m.recv (addr, buf, buffer_size); + int r = m.wait (); + test_fail_break_unless (test, r == ucoo::I2cMaster::STATUS_ERROR); + } while (0); + do { + ucoo::Test test (tsuite, "send"); + char buf[buffer_size]; + std::fill (buf, buf + buffer_size, 42); + m.send (addr, buf, buffer_size); + int r = m.wait (); + test_fail_break_unless (test, r == ucoo::I2cMaster::STATUS_ERROR); + } while (0); +} + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::TestSuite tsuite ("i2c"); +#if defined (TARGET_host) + ucoo::Host host ("test_i2c"); + host.parse_options (); + ucoo::I2cHost i2c1 (host, 0); + ucoo::I2cHost i2c2 (host, 1); +#elif defined (TARGET_stm32) + // I2C1: B6: SCL, B9: SDA + // I2C3: A8: SCL, C9: SDA + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN); + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN); + gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO6 | GPIO9); + gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO8); + gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO9); + gpio_set_output_options (GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO6 | GPIO9); + gpio_set_output_options (GPIOA, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO8); + gpio_set_output_options (GPIOC, GPIO_OTYPE_OD, GPIO_OSPEED_2MHZ, GPIO9); + gpio_set_af (GPIOB, GPIO_AF4, GPIO6 | GPIO9); + gpio_set_af (GPIOA, GPIO_AF4, GPIO8); + gpio_set_af (GPIOC, GPIO_AF4, GPIO9); + ucoo::I2cHard i2c1 (0); + ucoo::I2cHard i2c2 (2); + i2c1.enable (); + i2c2.enable (); +#endif + ucoo::I2cSlaveDataBufferSize<16, 16> data1, data2; + i2c1.register_data (a1, data1); + i2c2.register_data (a2, data2); + // Run tests. + test_basic (tsuite, i2c1, data2, a2); + if (TEST_NOT_THERE) + test_not_there (tsuite, i2c1, a3); + test_basic (tsuite, i2c2, data1, a1); + return tsuite.report () ? 0 : 1; +} diff --git a/ucoo/hal/spi/Module b/ucoo/hal/spi/Module new file mode 100644 index 0000000..a6df136 --- /dev/null +++ b/ucoo/hal/spi/Module @@ -0,0 +1 @@ +hal_spi_SOURCES := spi_soft.cc diff --git a/ucoo/hal/spi/spi_soft.cc b/ucoo/hal/spi/spi_soft.cc new file mode 100644 index 0000000..3bcc0d5 --- /dev/null +++ b/ucoo/hal/spi/spi_soft.cc @@ -0,0 +1,125 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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 "spi_soft.hh" + +#include "ucoo/utils/delay.hh" +#include "ucoo/common.hh" + +namespace ucoo { + +SpiSoftMaster::SpiSoftMaster (Io &sck, Io &mosi, Io &miso) + : sck_ (sck), mosi_ (mosi), miso_ (miso), enabled_ (false) +{ +} + +SpiSoftMaster::~SpiSoftMaster () +{ + disable (); +} + +void +SpiSoftMaster::enable (int speed, SpiMode mode) +{ + enabled_ = true; + // 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; +} + +void +SpiSoftMaster::disable () +{ + enabled_ = false; + // 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) +{ + assert (enabled_); + 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/ucoo/hal/spi/spi_soft.hh b/ucoo/hal/spi/spi_soft.hh new file mode 100644 index 0000000..2dc1a64 --- /dev/null +++ b/ucoo/hal/spi/spi_soft.hh @@ -0,0 +1,64 @@ +#ifndef ucoo_hal_spi_spi_soft_hh +#define ucoo_hal_spi_spi_soft_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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" +#include "ucoo/intf/io.hh" + +namespace ucoo { + +/// Software implementation of a SPI master. +class SpiSoftMaster : public SpiMaster +{ + public: + /// Constructor, need all SPI pins. + SpiSoftMaster (Io &sck, Io &mosi, Io &miso); + /// Destructor, disable. + ~SpiSoftMaster (); + /// Enable and setup. + void enable (int speed_hz, SpiMode mode = SPI_MODE_0); + /// Disable. + void disable (); + /// 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_; + bool enabled_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_spi_spi_soft_hh diff --git a/ucoo/hal/spi/test/Makefile b/ucoo/hal/spi/test/Makefile new file mode 100644 index 0000000..76b8230 --- /dev/null +++ b/ucoo/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/ucoo/hal/spi/test/test_spi.cc b/ucoo/hal/spi/test/test_spi.cc new file mode 100644 index 0000000..fa26abc --- /dev/null +++ b/ucoo/hal/spi/test/test_spi.cc @@ -0,0 +1,112 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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_soft.hh" +#include "ucoo/hal/gpio/gpio.hh" +#include "ucoo/utils/delay.hh" + +#include "ucoo/arch/arch.hh" +#include "ucoo/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 (); + 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); + // 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, (char) (c == 'o' ? 0x47 : 0x07) }; + ss.reset (); + spi.send (cmd, sizeof (cmd)); + ss.set (); + ucoo::delay_ns (100); + } + break; + } + } + } +} diff --git a/ucoo/hal/uart/Config b/ucoo/hal/uart/Config new file mode 100644 index 0000000..0a67d63 --- /dev/null +++ b/ucoo/hal/uart/Config @@ -0,0 +1,6 @@ +[hal/uart] +# Size of reception buffer. +rx_buffer = 32 +# Size of transmission buffer. +tx_buffer = 32 + diff --git a/ucoo/hal/uart/Module b/ucoo/hal/uart/Module new file mode 100644 index 0000000..a9d185e --- /dev/null +++ b/ucoo/hal/uart/Module @@ -0,0 +1 @@ +hal_uart_SOURCES = uart.stm32.cc diff --git a/ucoo/hal/uart/test/Config b/ucoo/hal/uart/test/Config new file mode 100644 index 0000000..4fd7571 --- /dev/null +++ b/ucoo/hal/uart/test/Config @@ -0,0 +1,4 @@ +[hal/uart] +rx_buffer = 32 +tx_buffer = 8 + diff --git a/ucoo/hal/uart/test/Makefile b/ucoo/hal/uart/test/Makefile new file mode 100644 index 0000000..6989dd2 --- /dev/null +++ b/ucoo/hal/uart/test/Makefile @@ -0,0 +1,12 @@ +BASE = ../../../.. + +TARGETS = host stm32f4 +PROGS = test_uart +stm32f4_PROGS = test_uart_disc +test_uart_SOURCES = test_uart.cc +test_uart_disc_SOURCES = test_uart_disc.cc + +MODULES = hal/uart +test_uart_disc_MODULES = $(MODULES) base/test hal/usb + +include $(BASE)/build/top.mk diff --git a/ucoo/hal/uart/test/test_uart.cc b/ucoo/hal/uart/test/test_uart.cc new file mode 100644 index 0000000..c1b111c --- /dev/null +++ b/ucoo/hal/uart/test/test_uart.cc @@ -0,0 +1,70 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2013 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/uart/uart.hh" + +#include "ucoo/arch/arch.hh" + +#if defined (TARGET_stm32) +# include +# include "ucoo/hal/gpio/gpio.hh" +#endif + +#include "ucoo/common.hh" + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); +#if defined (TARGET_host) + ucoo::Uart u0, u1 ("uart1"); +#elif defined (TARGET_stm32) + // D8, D9: UART3 + // C12, D2: UART5 + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPCEN); + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPDEN); + gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO12); + gpio_mode_setup (GPIOD, GPIO_MODE_AF, GPIO_PUPD_NONE, GPIO2 | GPIO8 | GPIO9); + gpio_set_af (GPIOC, GPIO_AF8, GPIO12); + gpio_set_af (GPIOD, GPIO_AF8, GPIO2); + gpio_set_af (GPIOD, GPIO_AF7, GPIO8 | GPIO9); + ucoo::Uart u0 (2), u1 (4); + u0.enable (38400, ucoo::Uart::EVEN, 1); + u1.enable (38400, ucoo::Uart::EVEN, 1); +#endif + ucoo::Uart *u[] = { &u0, &u1 }; + char buf[64]; + while (1) + { + for (int i = 0; i < (int) lengthof (u); i++) + { + if (u[i]->poll ()) + { + int len = u[i]->read (buf, sizeof (buf)); + u[i]->write (buf, len); + } + } + ucoo::yield (); + } +} + diff --git a/ucoo/hal/uart/test/test_uart_disc.cc b/ucoo/hal/uart/test/test_uart_disc.cc new file mode 100644 index 0000000..e2d307a --- /dev/null +++ b/ucoo/hal/uart/test/test_uart_disc.cc @@ -0,0 +1,128 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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/uart/uart.hh" + +#include "ucoo/arch/arch.hh" +#include "ucoo/hal/gpio/gpio.hh" +#include "ucoo/base/test/test.hh" + +#include + +static void +check_act (ucoo::Stream &ts, ucoo::Stream &u, char n) +{ + char buf[3 + 16 + 1]; + if (!u.poll ()) + return; + int r = u.read (buf + 3, 16); + if (r <= 0) + { + buf[3] = '#'; + r = 1; + } + buf[0] = '<'; + buf[1] = n; + buf[2] = ':'; + buf[3 + r] = '>'; + ts.write (buf, 3 + r + 1); +} + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::Stream &ts = ucoo::test_stream (); + ucoo::Uart u1 (0); + ucoo::Uart u3 (2); + ucoo::Uart u4 (3); + u1.enable (38400, ucoo::Uart::EVEN, 1); + u3.enable (38400, ucoo::Uart::EVEN, 1); + u4.enable (38400, ucoo::Uart::EVEN, 1); + // For this test, shorten B6 & B7 to have a loopback on UART1, shorten C10 + // & C11 to connect UART3 to UART4. + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPBEN + | RCC_AHB1ENR_IOPCEN); + gpio_mode_setup (GPIOB, GPIO_MODE_AF, GPIO_PUPD_NONE, + GPIO6 | GPIO7); + gpio_set_af (GPIOB, GPIO_AF7, GPIO6 | GPIO7); + gpio_mode_setup (GPIOC, GPIO_MODE_AF, GPIO_PUPD_NONE, + GPIO10 | GPIO11); + gpio_set_af (GPIOC, GPIO_AF7, GPIO10); + gpio_set_af (GPIOC, GPIO_AF8, GPIO11); + // Loop to report any activity on ports and provide a simple UI. + char buf[64]; + int buf_i = 0; + ucoo::Uart *u = &u1; + while (1) + { + check_act (ts, u1, '1'); + check_act (ts, u3, '3'); + check_act (ts, u4, '4'); + while (ts.poll ()) + { + char c = ts.getc (); + switch (c) + { + case '?': + static const char help[] = + "? - help\n" + "1, 3, 4 - set output uart\n" + ": - reset output buffer index\n" + "! - send output buffer\n" + "O, E, N - change parity to Odd, Even or None\n" + "any - fill output buffer\n"; + ts.write (help, sizeof (help)); + break; + case '1': + u = &u1; + break; + case '3': + u = &u3; + break; + case '4': + u = &u4; + break; + case ':': + buf_i = 0; + break; + case '!': + u->write (buf, buf_i); + break; + case 'O': + u->enable (38400, ucoo::Uart::ODD, 1); + break; + case 'E': + u->enable (38400, ucoo::Uart::EVEN, 1); + break; + case 'N': + u->enable (38400, ucoo::Uart::NONE, 1); + break; + default: + if (buf_i < static_cast (sizeof (buf))) + buf[buf_i++] = c; + break; + } + } + } +} diff --git a/ucoo/hal/uart/uart.hh b/ucoo/hal/uart/uart.hh new file mode 100644 index 0000000..f4efd5b --- /dev/null +++ b/ucoo/hal/uart/uart.hh @@ -0,0 +1,36 @@ +#ifndef ucoo_hal_uart_uart_hh +#define ucoo_hal_uart_uart_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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_host) +# include "ucoo/arch/host/host_stream.hh" +namespace ucoo { typedef HostStream Uart; } +#elif defined (TARGET_stm32) +# include "uart.stm32.hh" +#else +# error "not implemented for this target" +#endif + +#endif // ucoo_hal_uart_uart_hh diff --git a/ucoo/hal/uart/uart.stm32.cc b/ucoo/hal/uart/uart.stm32.cc new file mode 100644 index 0000000..14dc849 --- /dev/null +++ b/ucoo/hal/uart/uart.stm32.cc @@ -0,0 +1,221 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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 "uart.stm32.hh" + +#include +#include +#include + +#ifndef TARGET_stm32f4 +// Need RCC adaptations and USART6 different handling for F1. +# error "it's a trap, only implemented for F4 for the moment" +#endif + +namespace ucoo { + +static const int uart_nb = 6; + +/// Information on UART hardware structure. +struct uart_hardware_t +{ + /// UART base address. + uint32_t base; + /// APB number. + int apb; + /// RCC enable bit. + uint32_t rcc_en; + /// Corresponding IRQ. + int irq; +}; + +/// Information on UART hardware array, this is zero indexed, USART1 is at +/// index 0. +static const uart_hardware_t uart_hardware[uart_nb] = +{ + { USART1, 2, RCC_APB2ENR_USART1EN, NVIC_USART1_IRQ }, + { USART2, 1, RCC_APB1ENR_USART2EN, NVIC_USART2_IRQ }, + { USART3, 1, RCC_APB1ENR_USART3EN, NVIC_USART3_IRQ }, + { UART4, 1, RCC_APB1ENR_UART4EN, NVIC_UART4_IRQ }, + { UART5, 1, RCC_APB1ENR_UART5EN, NVIC_UART5_IRQ }, + { USART6, 2, RCC_APB2ENR_USART6EN, NVIC_USART6_IRQ }, +}; + +static Uart *uart_instances[uart_nb]; + +} // namespace ucoo + +extern "C" { + +void usart1_isr () { ucoo::Uart::isr (0); } + +void usart2_isr () { ucoo::Uart::isr (1); } + +void usart3_isr () { ucoo::Uart::isr (2); } + +void uart4_isr () { ucoo::Uart::isr (3); } + +void uart5_isr () { ucoo::Uart::isr (4); } + +void usart6_isr () { ucoo::Uart::isr (5); } + +} + +namespace ucoo { + +Uart::Uart (int n) + : n_ (n), error_char_ (default_error_char), enabled_ (false) +{ + assert (n < uart_nb); + assert (!uart_instances[n]); + uart_instances[n] = this; +} + +Uart::~Uart () +{ + disable (); + uart_instances[n_] = 0; +} + +void +Uart::enable (int speed, Parity parity, int stop_bits) +{ + enabled_ = true; + uint32_t base = uart_hardware[n_].base; + // Turn on. + rcc_peripheral_enable_clock + (uart_hardware[n_].apb == 1 ? &RCC_APB1ENR : &RCC_APB2ENR, + uart_hardware[n_].rcc_en); + // Set speed, rounded to nearest. + int apb_freq = uart_hardware[n_].apb == 1 ? rcc_ppre1_frequency + : rcc_ppre2_frequency; + USART_BRR (base) = (2 * apb_freq + speed) / (2 * speed); + // Set parameters and enable. + if (stop_bits == 1) + USART_CR2 (base) = USART_CR2_STOPBITS_1; + else if (stop_bits == 2) + USART_CR2 (base) = USART_CR2_STOPBITS_2; + else + assert_unreachable (); + USART_CR3 (base) = 0; + uint32_t cr1 = USART_CR1_UE | USART_CR1_RXNEIE | USART_CR1_TE | USART_CR1_RE; + if (parity != NONE) + cr1 |= USART_CR1_M | USART_CR1_PCE; + if (parity == ODD) + cr1 |= USART_CR1_PS; + USART_CR1 (base) = cr1; + // Reset status. + (void) USART_SR (base); + (void) USART_DR (base); + // Enable interrupts. + nvic_enable_irq (uart_hardware[n_].irq); +} + +void +Uart::disable () +{ + if (enabled_) + { + enabled_ = false; + uint32_t base = uart_hardware[n_].base; + // Stop UART. + nvic_disable_irq (uart_hardware[n_].irq); + USART_CR1 (base) = 0; + // Turn off. + rcc_peripheral_disable_clock + (uart_hardware[n_].apb == 1 ? &RCC_APB1ENR : &RCC_APB2ENR, + uart_hardware[n_].rcc_en); + } +} + +void +Uart::set_error_char (char c) +{ + error_char_ = c; +} + +int +Uart::read (char *buf, int count) +{ + assert (enabled_); + if (block_) + while (rx_fifo_.empty ()) + barrier (); + return rx_fifo_.read (buf, count); +} + +int +Uart::write (const char *buf, int count) +{ + assert (enabled_); + int left = count; + while (left) + { + int r = tx_fifo_.write (buf, left); + if (r) + { + USART_CR1 (uart_hardware[n_].base) |= USART_CR1_TXEIE; + buf += r; + left -= r; + } + if (!block_) + break; + } + return count - left; +} + +int +Uart::poll () +{ + return rx_fifo_.empty () ? 0 : 1; +} + +void +Uart::isr (int n) +{ + uint32_t base = uart_hardware[n].base; + uint32_t sr = USART_SR (base); + uint32_t dr = USART_DR (base); + assert (uart_instances[n]); + Uart &uart = *uart_instances[n]; + if (sr & (USART_SR_ORE | USART_SR_NE | USART_SR_FE | USART_SR_PE)) + { + dr = uart.error_char_; + // Datasheet is not really clear about this when error bits are set. + sr |= USART_SR_RXNE; + } + if (sr & USART_SR_RXNE) + { + if (!uart.rx_fifo_.full ()) + uart.rx_fifo_.push (dr); + } + if (sr & USART_SR_TXE) + { + if (!uart.tx_fifo_.empty ()) + USART_DR (base) = static_cast (uart.tx_fifo_.pop ()); + if (uart.tx_fifo_.empty ()) + USART_CR1 (base) &= ~USART_CR1_TXEIE; + } +} + +} // namespace ucoo diff --git a/ucoo/hal/uart/uart.stm32.hh b/ucoo/hal/uart/uart.stm32.hh new file mode 100644 index 0000000..25d6f6e --- /dev/null +++ b/ucoo/hal/uart/uart.stm32.hh @@ -0,0 +1,78 @@ +#ifndef ucoo_hal_uart_uart_stm32_hh +#define ucoo_hal_uart_uart_stm32_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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/stream.hh" +#include "ucoo/utils/fifo.hh" + +#include "config/hal/uart.hh" + +namespace ucoo { + +/// Universal asynchronous receiver transmitter (UART). +/// +/// When an error is detected on RX, error character is inserted in receive +/// FIFO. +class Uart : public Stream +{ + public: + /// Parity setting. + enum Parity { ODD, EVEN, NONE }; + /// Default error character. + static const char default_error_char = '~'; + public: + /// Constructor for the Nth UART. + Uart (int n); + /// Shutdown UART. + ~Uart (); + /// Enable and setup UART. + void enable (int speed, Parity parity = NONE, int stop_bits = 1); + /// Disable. + void disable (); + /// Change the error character. + void set_error_char (char c); + /// See Stream::read. + int read (char *buf, int count); + /// See Stream::write. + int write (const char *buf, int count); + /// See Stream::poll. + int poll (); + /// Handle interrupts. + static void isr (int n); + private: + /// UART number. + int n_; + /// RX FIFO, filled by interrupt handler. + Fifo rx_fifo_; + /// TX FIFO, emptied by interrupt handler. + Fifo tx_fifo_; + /// Error character, inserted in case of error. + char error_char_; + /// Is it enabled? + bool enabled_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_uart_uart_stm32_hh diff --git a/ucoo/hal/usb/Config b/ucoo/hal/usb/Config new file mode 100644 index 0000000..9adaece --- /dev/null +++ b/ucoo/hal/usb/Config @@ -0,0 +1,12 @@ +[hal/usb] +# Theses are APBTeam IDs, given by Openmoko! +vendor_id = 0x1d50 +product_id = 0x6052 +# Number of streams, interfaces, or pair of endpoints. +stream_nb = 1 +# Set to 0 if powered from USB cable, 1 if device has its own power supply. +self_powered = 0 +# Maximum power consumed from USB cable (mA). +max_power = 100 +# End point size, you should use 64. +ep_size = 64 diff --git a/ucoo/hal/usb/Module b/ucoo/hal/usb/Module new file mode 100644 index 0000000..433c8b2 --- /dev/null +++ b/ucoo/hal/usb/Module @@ -0,0 +1 @@ +hal_usb_SOURCES = usb.stm32.cc usb_desc.stm32.c diff --git a/ucoo/hal/usb/test/Config b/ucoo/hal/usb/test/Config new file mode 100644 index 0000000..49b2f0b --- /dev/null +++ b/ucoo/hal/usb/test/Config @@ -0,0 +1,2 @@ +[hal/usb] +stream_nb = 1 diff --git a/ucoo/hal/usb/test/Makefile b/ucoo/hal/usb/test/Makefile new file mode 100644 index 0000000..cec9ded --- /dev/null +++ b/ucoo/hal/usb/test/Makefile @@ -0,0 +1,9 @@ +BASE = ../../../.. + +TARGETS = stm32f4 +stm32f4_PROGS = test_usb +test_usb_SOURCES = test_usb.cc + +MODULES = hal/usb + +include $(BASE)/build/top.mk diff --git a/ucoo/hal/usb/test/test_usb.cc b/ucoo/hal/usb/test/test_usb.cc new file mode 100644 index 0000000..a1fe362 --- /dev/null +++ b/ucoo/hal/usb/test/test_usb.cc @@ -0,0 +1,73 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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/usb/usb.hh" +#include "ucoo/arch/arch.hh" + +int +main (int argc, const char **argv) +{ + ucoo::arch_init (argc, argv); + ucoo::UsbStreamControl usc ("APBTeam", "USB test"); + ucoo::UsbStream us[] = { + ucoo::UsbStream (usc, 0), +#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 2 + ucoo::UsbStream (usc, 1), +#endif +#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 3 + ucoo::UsbStream (usc, 2), +#endif + }; + if (UCOO_CONFIG_HAL_USB_STREAM_NB > 1) + { + for (int i = 0; i < UCOO_CONFIG_HAL_USB_STREAM_NB; i++) + us[i].block (false); + } + char buf[6]; + while (1) + { + for (int i = 0; i < UCOO_CONFIG_HAL_USB_STREAM_NB; i++) + { + int len = us[i].read (buf + 2, sizeof (buf) - 2); + if (len) + { + buf[0] = i + '0'; + buf[1] = '>'; + len += 2; + if (UCOO_CONFIG_HAL_USB_STREAM_NB == 1) + us[i].write (buf, len); + else + { + const char *p = buf; + while (len) + { + int r = us[i].write (p, len); + p += r; + len -= r; + } + } + } + } + } +} + diff --git a/ucoo/hal/usb/usb.hh b/ucoo/hal/usb/usb.hh new file mode 100644 index 0000000..5324058 --- /dev/null +++ b/ucoo/hal/usb/usb.hh @@ -0,0 +1,33 @@ +#ifndef ucoo_hal_usb_usb_hh +#define ucoo_hal_usb_usb_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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. +// +// }}} + +#ifdef TARGET_stm32 +# include "usb.stm32.hh" +#else +# error "not implemented for this target" +#endif + +#endif // ucoo_hal_usb_usb_hh diff --git a/ucoo/hal/usb/usb.stm32.cc b/ucoo/hal/usb/usb.stm32.cc new file mode 100644 index 0000000..0410df5 --- /dev/null +++ b/ucoo/hal/usb/usb.stm32.cc @@ -0,0 +1,160 @@ +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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 "usb.stm32.hh" +#include + +#include +#include +#include + +#include "usb_desc.stm32.h" + +static usbd_device *usbdev; + +extern "C" { + +void +otg_fs_isr () +{ + usbd_poll (usbdev); +} + +} + +namespace ucoo { + +UsbStreamControl *UsbStreamControl::instance_; + +const char *strings[] = { + NULL, + NULL +}; + +UsbStreamControl::RxBuffer::RxBuffer (void) + : size (0), offset (0) +{ +} + +UsbStreamControl::UsbStreamControl (const char *vendor, const char *product) + : configured_ (false) +{ + assert (!instance_); + instance_ = this; + strings[0] = vendor; + strings[1] = product; + rcc_peripheral_enable_clock (&RCC_AHB2ENR, RCC_AHB2ENR_OTGFSEN); + rcc_peripheral_enable_clock (&RCC_AHB1ENR, RCC_AHB1ENR_IOPAEN); + gpio_mode_setup (GPIOA, GPIO_MODE_AF, GPIO_PUPD_NONE, + GPIO9 | GPIO11 | GPIO12); + gpio_set_af (GPIOA, GPIO_AF10, GPIO9 | GPIO11 | GPIO12); + usbdev = usbd_init (&otgfs_usb_driver, &usb_desc_dev, &usb_desc_config, + strings, lengthof (strings)); + usbd_register_set_config_callback (usbdev, set_config); + nvic_enable_irq (NVIC_OTG_FS_IRQ); +} + +void +UsbStreamControl::set_config (usbd_device *usbdev, uint16_t configured) +{ + instance_->configured_ = configured; + if (configured) + { + for (int i = 0; i < stream_nb_; i++) + { + usbd_ep_setup (usbdev, 0x01 + i, USB_ENDPOINT_ATTR_BULK, ep_size_, + rx_callback); + usbd_ep_setup (usbdev, 0x81 + i, USB_ENDPOINT_ATTR_BULK, ep_size_, + NULL); + } + } +} + +void +UsbStreamControl::rx_callback (usbd_device *usbdev, uint8_t ep) +{ + assert (ep > 0 && ep <= stream_nb_); + int num = ep - 1; + RxBuffer &rb = instance_->rx_buffer_[num]; + assert (rb.size == 0 && rb.offset == 0); + usbd_ep_nak_set (usbdev, ep, 1); + rb.size = usbd_ep_read_packet (usbdev, ep, rb.buf, ep_size_); +} + +UsbStream::UsbStream (UsbStreamControl &control, int num) + : control_ (control), num_ (num) +{ + assert (num < UsbStreamControl::stream_nb_); +} + +int +UsbStream::read (char *buf, int count) +{ + UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_]; + /* Wait for reception. */ + if (!rb.size && !block_) + return 0; + while (!rb.size) + barrier (); + /* Copy to provided buffer. */ + int len = std::min (count, rb.size - rb.offset); + buf = std::copy (rb.buf + rb.offset, rb.buf + rb.offset + len, buf); + rb.offset += len; + /* Reload buffer? */ + if (rb.offset == rb.size) + { + rb.offset = rb.size = 0; + barrier (); + usbd_ep_nak_set (usbdev, num_ + 1, 0); + } + /* Done. */ + return len; +} + +int +UsbStream::write (const char *buf, int count) +{ + int left = count; + while (left) + { + if (control_.configured_) + { + int len = std::min (left, UsbStreamControl::ep_size_); + len = usbd_ep_write_packet (usbdev, num_ + 0x81, buf, len); + buf += len; + left -= len; + } + if (!block_) + break; + } + return count - left; +} + +int +UsbStream::poll () +{ + UsbStreamControl::RxBuffer &rb = control_.rx_buffer_[num_]; + return rb.size - rb.offset; +} + +} // namespace ucoo diff --git a/ucoo/hal/usb/usb.stm32.hh b/ucoo/hal/usb/usb.stm32.hh new file mode 100644 index 0000000..118e883 --- /dev/null +++ b/ucoo/hal/usb/usb.stm32.hh @@ -0,0 +1,98 @@ +#ifndef ucoo_hal_usb_usb_stm32_hh +#define ucoo_hal_usb_usb_stm32_hh +// ucoolib - Microcontroller object oriented library. {{{ +// +// Copyright (C) 2012 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/stream.hh" +#include "ucoo/common.hh" + +#include "config/hal/usb.hh" + +#include + +namespace ucoo { + +class UsbStream; + +/// Top control class for an USB device. This is a limited implementation +/// which fulfill most of our needs: one or more interfaces, each of them is +/// handled as a character stream. This should be instantiated only once. +class UsbStreamControl +{ + public: + /// Construct a new USB control object, with given VENDOR and PRODUCT + /// strings. + UsbStreamControl (const char *vendor, const char *product); + /// Return true if the device is configured. This means that the + /// connection is done with the host and data can be exchanged. + bool is_configured () const { return configured_; } + private: + /// Called by USB stack when device is configured. This is expected to + /// setup endpoints. + static void set_config (usbd_device *usbdev, uint16_t wValue); + /// Called by USB stack when a frame is received on a OUT endpoint. + static void rx_callback (usbd_device *usbdev, uint8_t ep); + private: + /// Size of endpoints. + static const int ep_size_ = UCOO_CONFIG_HAL_USB_EP_SIZE; + /// Number of streams (also interfaces or pair of endpoints). + static const int stream_nb_ = UCOO_CONFIG_HAL_USB_STREAM_NB; + /// Pointer to the one and only instance. + static UsbStreamControl *instance_; + /// Whether device is currently configured. + bool configured_; + /// Internal RX buffer type. + struct RxBuffer + { + char buf[ep_size_]; + int size, offset; + RxBuffer (void); + }; + /// Internal RX buffer, one per stream. + RxBuffer rx_buffer_[stream_nb_]; + friend class UsbStream; +}; + +/// One USB stream, instantiated for each stream, interface, or pair of +/// endpoints. +class UsbStream : public Stream +{ + public: + /// Construct from control object and stream index. + UsbStream (UsbStreamControl &control, int num); + /// See Stream::read. + int read (char *buf, int count); + /// See Stream::write. + int write (const char *buf, int count); + /// See Stream::poll. + int poll (); + private: + /// Reference to control object. + UsbStreamControl &control_; + /// Stream index. + int num_; +}; + +} // namespace ucoo + +#endif // ucoo_hal_usb_usb_stm32_hh diff --git a/ucoo/hal/usb/usb_desc.stm32.c b/ucoo/hal/usb/usb_desc.stm32.c new file mode 100644 index 0000000..8d6fc87 --- /dev/null +++ b/ucoo/hal/usb/usb_desc.stm32.c @@ -0,0 +1,193 @@ +/* ucoolib - Microcontroller object oriented library. {{{ + * + * Copyright (C) 2012 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 "usb_desc.stm32.h" + +#include "config/hal/usb.hh" + +const struct usb_device_descriptor usb_desc_dev = { + .bLength = USB_DT_DEVICE_SIZE, + .bDescriptorType = USB_DT_DEVICE, + .bcdUSB = 0x0200, + .bDeviceClass = 0xff, + .bDeviceSubClass = 0, + .bDeviceProtocol = 0, + .bMaxPacketSize0 = 64, + .idVendor = UCOO_CONFIG_HAL_USB_VENDOR_ID, + .idProduct = UCOO_CONFIG_HAL_USB_PRODUCT_ID, + .bcdDevice = 0x0000, + .iManufacturer = 1, + .iProduct = 2, + .iSerialNumber = 0, + .bNumConfigurations = 1, +}; + +static const struct usb_endpoint_descriptor usb_desc_endp_1[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x01, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE, + .bInterval = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x81, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE, + .bInterval = 0, + }, +}; + +static const struct usb_interface_descriptor usb_desc_iface_1[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 0, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = usb_desc_endp_1, + }, +}; + +#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 2 + +static const struct usb_endpoint_descriptor usb_desc_endp_2[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x02, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE, + .bInterval = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x82, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE, + .bInterval = 0, + }, +}; + +static const struct usb_interface_descriptor usb_desc_iface_2[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 1, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = usb_desc_endp_2, + }, +}; + +#endif /* UCOO_CONFIG_HAL_USB_STREAM_NB >= 2 */ + +#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 3 + +static const struct usb_endpoint_descriptor usb_desc_endp_3[] = { + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x03, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE, + .bInterval = 0, + }, + { + .bLength = USB_DT_ENDPOINT_SIZE, + .bDescriptorType = USB_DT_ENDPOINT, + .bEndpointAddress = 0x83, + .bmAttributes = USB_ENDPOINT_ATTR_BULK, + .wMaxPacketSize = UCOO_CONFIG_HAL_USB_EP_SIZE, + .bInterval = 0, + }, +}; + +static const struct usb_interface_descriptor usb_desc_iface_3[] = { + { + .bLength = USB_DT_INTERFACE_SIZE, + .bDescriptorType = USB_DT_INTERFACE, + .bInterfaceNumber = 2, + .bAlternateSetting = 0, + .bNumEndpoints = 2, + .bInterfaceClass = 0xff, + .bInterfaceSubClass = 0, + .bInterfaceProtocol = 0, + .iInterface = 0, + + .endpoint = usb_desc_endp_3, + }, +}; + +#endif /* UCOO_CONFIG_HAL_USB_STREAM_NB >= 3 */ + +#if UCOO_CONFIG_HAL_USB_STREAM_NB > 3 +# error "too many streams requested" +#endif + +static const struct usb_interface usb_desc_ifaces[] = { + { + .num_altsetting = 1, + .altsetting = usb_desc_iface_1, + }, +#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 2 + { + .num_altsetting = 1, + .altsetting = usb_desc_iface_2, + }, +#endif +#if UCOO_CONFIG_HAL_USB_STREAM_NB >= 3 + { + .num_altsetting = 1, + .altsetting = usb_desc_iface_3, + }, +#endif +}; + +const struct usb_config_descriptor usb_desc_config = { + .bLength = USB_DT_CONFIGURATION_SIZE, + .bDescriptorType = USB_DT_CONFIGURATION, + .wTotalLength = 0, + .bNumInterfaces = UCOO_CONFIG_HAL_USB_STREAM_NB, + .bConfigurationValue = 1, + .iConfiguration = 0, + .bmAttributes = 0x80 | (UCOO_CONFIG_HAL_USB_SELF_POWERED ? 0x40 : 0), + .bMaxPower = UCOO_CONFIG_HAL_USB_MAX_POWER / 2, + + .interface = usb_desc_ifaces, +}; + diff --git a/ucoo/hal/usb/usb_desc.stm32.h b/ucoo/hal/usb/usb_desc.stm32.h new file mode 100644 index 0000000..dca84b7 --- /dev/null +++ b/ucoo/hal/usb/usb_desc.stm32.h @@ -0,0 +1,33 @@ +#ifndef ucoo_hal_usb_usb_desc_stm32_h +#define ucoo_hal_usb_usb_desc_stm32_h +/* ucoolib - Microcontroller object oriented library. {{{ + * + * Copyright (C) 2012 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 + +/** USB device descriptor. */ +extern const struct usb_device_descriptor usb_desc_dev; +/** USB configuration descriptor. */ +extern const struct usb_config_descriptor usb_desc_config; + +#endif /* ucoo_hal_usb_usb_desc_stm32_h */ -- cgit v1.2.3