162 lines
4.9 KiB
ReStructuredText
162 lines
4.9 KiB
ReStructuredText
Peripherals Module
|
|
==================
|
|
|
|
The peripherals module contains various external devices for which (hopefully) reusable abstractions have been created.
|
|
All interfacing with hardware is done through static dispatch: hardware wrappers are to be passed in as copy-constructible
|
|
handle objects, with the objects themselves being specified as template parameters. This includes a static HAL object,
|
|
should the class need generic HAL features, like a delay function.
|
|
|
|
HAL Abstraction
|
|
---------------
|
|
|
|
As mentioned earlier, the HAL gets abstracted with simple wrapper classes that are passed into the consuming object as
|
|
template parameters. There's a special class to encapsulate more static HAL functions, such as delays, which is referred
|
|
to as the "static HAL" struct.
|
|
|
|
An example implementation of mildly fleshed out HAL abstraction can be found in the "Peripherals::Hal::St" namespace.
|
|
|
|
To make peripheral devices reusable and also configurable, the library composes all HAL-dependencies as templated members.
|
|
A few common interfaces have come from this, specifically the GPIO and Serial interfaces. Along with the static HAL itself.
|
|
Requirements for these common classes can be outlined as follows:
|
|
|
|
.. code-block:: c++
|
|
|
|
// A class for statically composing "static" features of a HAL.
|
|
struct StaticHal
|
|
{
|
|
static std::uint32_t getMillis();
|
|
static void delay(const std::uint32_t milliseconds);
|
|
static void delayUs(const std::uint32_t micros);
|
|
static void enableInterrupts();
|
|
static void disableInterrupts();
|
|
};
|
|
|
|
.. code-block:: c++
|
|
|
|
// A common serial interface, for sending and receiving data.
|
|
struct SerialInterface
|
|
{
|
|
bool transmit(std::uint8_t* data, const std::uint32_t data_len);
|
|
template<typename Td, std::size_t N>
|
|
bool transmit(std::array<Td, N>& array);
|
|
|
|
bool receive(std::uint8_t* data, const std::uint32_t data_len);
|
|
template<typename Td, std::size_t N>
|
|
bool receive(std::array<Td, N>& array);
|
|
};
|
|
|
|
.. code-block:: c++
|
|
|
|
// A common GPIO interface.
|
|
struct Gpio
|
|
{
|
|
void set(const bool& state);
|
|
void toggle();
|
|
bool read() const;
|
|
};
|
|
|
|
Usage Notes
|
|
-----------
|
|
|
|
It would be recommended to type-def whatever configurations you use, and go from there. The peripherals themselves should
|
|
be passed around as pointers or references -- they don't typically play well with copy constructors. And really, one object
|
|
per physical peripheral should exist.
|
|
|
|
It should also be noted that **constructors for peripherals can be non-trivial**. (Peripherals in this case being the non-HAL
|
|
ones.) They will do initialization in there, so that the object is usable right after successful construction. This means
|
|
you have to ensure that HAL setup is completed *before* the instances are constructed. Having them as global instances
|
|
will be affected by this, a quick fix is to just dynamically allocate them. Or use other means of deferred construction.
|
|
|
|
A few examples follow, based on the STM32 HAL.
|
|
|
|
Using a simple main, where the constructor is placed after all of the init functions:
|
|
|
|
.. code-block:: c++
|
|
|
|
#include <peripherals_button.hpp>
|
|
#include <peripherals_hal_st.hpp>
|
|
|
|
using Button
|
|
= Peripherals::Button<Peripherals::Hal::St::Gpio, Peripherals::Hal::St::StaticHal>;
|
|
|
|
void useButton(Button& b);
|
|
|
|
int main() {
|
|
HAL_Init();
|
|
SystemClock_Config();
|
|
|
|
MX_GPIO_Init();
|
|
|
|
Button b1({ BTN_GPIO_Port, BTN_Pin, false });
|
|
|
|
while (true) {
|
|
useButton(b1);
|
|
}
|
|
}
|
|
|
|
Using a scenario where the class instance is kept as a global. In this case, dynamic allocation is used to achieve proper
|
|
constructor order:
|
|
|
|
.. code-block:: c++
|
|
|
|
#include <peripherals_button.hpp>
|
|
#include <peripherals_hal_st.hpp>
|
|
|
|
using Button
|
|
= Peripherals::Button<Peripherals::Hal::St::Gpio, Peripherals::Hal::St::StaticHal>;
|
|
|
|
Button* b1;
|
|
|
|
void useButton(Button& b);
|
|
|
|
int main() {
|
|
HAL_Init();
|
|
SystemClock_Config();
|
|
|
|
MX_GPIO_Init();
|
|
|
|
b1 = new Button({ BTN_GPIO_Port, BTN_Pin, false });
|
|
|
|
while (true) {
|
|
useButton(*b1);
|
|
}
|
|
}
|
|
|
|
Using the StaticPointer class from the Utility module of this library is also a way of deferring the construction, while
|
|
maintaining complete static allocation:
|
|
|
|
.. code-block:: c++
|
|
|
|
#include <peripherals_button.hpp>
|
|
#include <peripherals_hal_st.hpp>
|
|
#include <utility_staticpointer.hpp>
|
|
|
|
using Button
|
|
= Peripherals::Button<Peripherals::Hal::St::Gpio, Peripherals::Hal::St::StaticHal>;
|
|
|
|
Utility::StaticPointer<Button> b1;
|
|
|
|
void useButton(Button& b);
|
|
|
|
int main() {
|
|
HAL_Init();
|
|
SystemClock_Config();
|
|
|
|
MX_GPIO_Init();
|
|
|
|
b1.setup({ BTN_GPIO_Port, BTN_Pin, false });
|
|
|
|
while (true) {
|
|
useButton(*b1);
|
|
}
|
|
}
|
|
|
|
|
|
Public Members
|
|
--------------
|
|
|
|
.. doxygennamespace:: Peripherals
|
|
:content-only:
|
|
:undoc-members:
|
|
:members:
|