From 7175193561a2dcbcd167fb121005efeab336ac11 Mon Sep 17 00:00:00 2001 From: BlackMark Date: Mon, 30 Mar 2020 19:45:33 +0200 Subject: [PATCH] Rename project to fantemp --- .gitmodules | 16 +- thermistor.atsln => fantemp.atsln | 2 +- fantemp/adc/.clang-format | 13 + fantemp/adc/.gitattributes | 9 + fantemp/adc/.gitignore | 11 + fantemp/adc/LICENSE | 21 + fantemp/adc/adc.hpp | 219 +++++++ fantemp/adc/config.hpp | 73 +++ fantemp/adc/hardware.hpp | 95 +++ {thermistor => fantemp}/clock.hpp | 0 .../fantemp.cppproj | 6 +- fantemp/flash/.clang-format | 13 + fantemp/flash/.gitattributes | 9 + fantemp/flash/.gitignore | 11 + fantemp/flash/LICENSE | 21 + fantemp/flash/flash.hpp | 12 + fantemp/io/.clang-format | 13 + fantemp/io/.gitattributes | 9 + fantemp/io/.gitignore | 11 + fantemp/io/LICENSE | 21 + fantemp/io/io.hpp | 557 ++++++++++++++++++ {thermistor => fantemp}/main.cpp | 6 +- {thermistor => fantemp}/pwm.cpp | 0 {thermistor => fantemp}/pwm.hpp | 0 {thermistor => fantemp}/thermistor.cpp | 0 {thermistor => fantemp}/thermistor.hpp | 0 fantemp/uart/.clang-format | 13 + fantemp/uart/.gitattributes | 9 + fantemp/uart/.gitignore | 11 + fantemp/uart/LICENSE | 21 + fantemp/uart/config.hpp | 50 ++ fantemp/uart/hardware.hpp | 389 ++++++++++++ fantemp/uart/hardware0.hpp | 169 ++++++ fantemp/uart/hardware1.hpp | 166 ++++++ fantemp/uart/software.hpp | 21 + fantemp/uart/uart.hpp | 373 ++++++++++++ fantemp/uart/utils.hpp | 143 +++++ thermistor/adc | 1 - thermistor/flash | 1 - thermistor/io | 1 - thermistor/uart | 1 - 41 files changed, 2498 insertions(+), 19 deletions(-) rename thermistor.atsln => fantemp.atsln (85%) create mode 100644 fantemp/adc/.clang-format create mode 100644 fantemp/adc/.gitattributes create mode 100644 fantemp/adc/.gitignore create mode 100644 fantemp/adc/LICENSE create mode 100644 fantemp/adc/adc.hpp create mode 100644 fantemp/adc/config.hpp create mode 100644 fantemp/adc/hardware.hpp rename {thermistor => fantemp}/clock.hpp (100%) rename thermistor/thermistor.cppproj => fantemp/fantemp.cppproj (98%) create mode 100644 fantemp/flash/.clang-format create mode 100644 fantemp/flash/.gitattributes create mode 100644 fantemp/flash/.gitignore create mode 100644 fantemp/flash/LICENSE create mode 100644 fantemp/flash/flash.hpp create mode 100644 fantemp/io/.clang-format create mode 100644 fantemp/io/.gitattributes create mode 100644 fantemp/io/.gitignore create mode 100644 fantemp/io/LICENSE create mode 100644 fantemp/io/io.hpp rename {thermistor => fantemp}/main.cpp (88%) rename {thermistor => fantemp}/pwm.cpp (100%) rename {thermistor => fantemp}/pwm.hpp (100%) rename {thermistor => fantemp}/thermistor.cpp (100%) rename {thermistor => fantemp}/thermistor.hpp (100%) create mode 100644 fantemp/uart/.clang-format create mode 100644 fantemp/uart/.gitattributes create mode 100644 fantemp/uart/.gitignore create mode 100644 fantemp/uart/LICENSE create mode 100644 fantemp/uart/config.hpp create mode 100644 fantemp/uart/hardware.hpp create mode 100644 fantemp/uart/hardware0.hpp create mode 100644 fantemp/uart/hardware1.hpp create mode 100644 fantemp/uart/software.hpp create mode 100644 fantemp/uart/uart.hpp create mode 100644 fantemp/uart/utils.hpp delete mode 160000 thermistor/adc delete mode 160000 thermistor/flash delete mode 160000 thermistor/io delete mode 160000 thermistor/uart diff --git a/.gitmodules b/.gitmodules index 6e527ed..29dd130 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,12 +1,12 @@ -[submodule "thermistor/uart"] - path = thermistor/uart +[submodule "fantemp/uart"] + path = fantemp/uart url = git@git.blackmark.me:avr/uart.git -[submodule "thermistor/flash"] - path = thermistor/flash +[submodule "fantemp/flash"] + path = fantemp/flash url = git@git.blackmark.me:avr/flash.git -[submodule "thermistor/io"] - path = thermistor/io +[submodule "fantemp/io"] + path = fantemp/io url = git@git.blackmark.me:avr/io.git -[submodule "thermistor/adc"] - path = thermistor/adc +[submodule "fantemp/adc"] + path = fantemp/adc url = git@git.blackmark.me:avr/adc.git diff --git a/thermistor.atsln b/fantemp.atsln similarity index 85% rename from thermistor.atsln rename to fantemp.atsln index b173978..2f7bec5 100644 --- a/thermistor.atsln +++ b/fantemp.atsln @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Atmel Studio Solution File, Format Version 11.00 VisualStudioVersion = 14.0.23107.0 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "thermistor", "thermistor\thermistor.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}" +Project("{E66E83B9-2572-4076-B26E-6BE79FF3018A}") = "fantemp", "fantemp\fantemp.cppproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/fantemp/adc/.clang-format b/fantemp/adc/.clang-format new file mode 100644 index 0000000..63ebf38 --- /dev/null +++ b/fantemp/adc/.clang-format @@ -0,0 +1,13 @@ +--- +BasedOnStyle: LLVM +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: ForIndentation +AlignEscapedNewlines: DontAlign +AllowShortFunctionsOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true +... diff --git a/fantemp/adc/.gitattributes b/fantemp/adc/.gitattributes new file mode 100644 index 0000000..3e5b64f --- /dev/null +++ b/fantemp/adc/.gitattributes @@ -0,0 +1,9 @@ +*.h eol=lf +*.hpp eol=lf +*.c eol=lf +*.cpp eol=lf +.git* eol=lf +*.vcxproj* eol=crlf +*.cppproj eol=crlf +*.sln eol=crlf +*.atsln eol=crlf diff --git a/fantemp/adc/.gitignore b/fantemp/adc/.gitignore new file mode 100644 index 0000000..9f584cc --- /dev/null +++ b/fantemp/adc/.gitignore @@ -0,0 +1,11 @@ +.vs +Release +Debug +*.componentinfo.xml +*.elf +*.o +*.hex +*.srec +*.eeprom +*.lss +*.map diff --git a/fantemp/adc/LICENSE b/fantemp/adc/LICENSE new file mode 100644 index 0000000..80da57f --- /dev/null +++ b/fantemp/adc/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 BlackMark + +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 (including the next +paragraph) 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. diff --git a/fantemp/adc/adc.hpp b/fantemp/adc/adc.hpp new file mode 100644 index 0000000..a2f0d57 --- /dev/null +++ b/fantemp/adc/adc.hpp @@ -0,0 +1,219 @@ +#ifndef ADC_HPP +#define ADC_HPP + +#include "config.hpp" +#include "hardware.hpp" + +#include + +#include "../io/io.hpp" + +namespace adc { + +namespace detail { + +extern void (*fnAdcIntHandler)(uint16_t); + +using reg_ptr_t = volatile uint8_t *; + +template +static inline reg_ptr_t getRegPtr() +{ + return reinterpret_cast(Address); +} + +template +class AdcImpl { + public: + static uint16_t read() + { + *getRegPtr() |= 1 << ControlFlagsA::START_CONV; + while (*getRegPtr() & (1 << ControlFlagsA::START_CONV)) + ; + + uint16_t adcSample = *getRegPtr(); + adcSample |= *getRegPtr() << 8; + return adcSample; + } + + protected: + static void init(uint8_t muxVal) + { + *getRegPtr() = muxVal | calcRef(); + + auto ctrlStatA = calcCtrlStatA(detail::fnAdcIntHandler != nullptr); + *getRegPtr() = ctrlStatA; + + constexpr auto ctrlStatB = calcCtrlStatB(); + *getRegPtr() = ctrlStatB; + } + + static constexpr auto calcRef() + { + uint8_t muxVal = 0; + + if constexpr (Cfg::VREF == VoltageRef::AVCC) { + muxVal |= 1 << ControlFlagsMUX::REF_SEL_0; + } else if constexpr (Cfg::VREF == VoltageRef::INTERNAL) { + muxVal |= (1 << ControlFlagsMUX::REF_SEL_0) | (1 << ControlFlagsMUX::REF_SEL_1); + } + + return muxVal; + } + + static constexpr uint8_t calcPrescaler() + { + constexpr auto validPrescaler = Cfg::PRESCALER == 2 || Cfg::PRESCALER == 4 || Cfg::PRESCALER == 8 || + Cfg::PRESCALER == 16 || Cfg::PRESCALER == 32 || Cfg::PRESCALER == 64 || + Cfg::PRESCALER == 128; + static_assert(validPrescaler, "Invalid prescaler"); + + // clang-format off + switch (Cfg::PRESCALER) { + case 2: return 1; + case 4: return 2; + case 8: return 3; + case 16: return 4; + case 32: return 5; + case 64: return 6; + case 128: return 7; + } + // clang-format on + } + + static auto calcCtrlStatA(bool interruptEnable) + { + uint8_t ctrlStatA = 1 << ControlFlagsA::ENABLE; + + if constexpr (Cfg::MODE == Mode::AUTO) { + ctrlStatA |= 1 << ControlFlagsA::AUTO_TRIGGER; + } else if (interruptEnable) { + ctrlStatA |= 1 << ControlFlagsA::CONV_COMPLETE_INT_ENABLE; + } + + return ctrlStatA | calcPrescaler(); + } + + static constexpr uint8_t calcCtrlStatB() + { + if constexpr (Cfg::MODE == Mode::AUTO) { + // clang-format off + switch (Cfg::TRIGGER_SRC) { + case TriggerSource::FREE_RUNNING: return 0; + case TriggerSource::ANALOG_COMP: return 1; + case TriggerSource::EXTERNAL_INT_0: return 2; + case TriggerSource::TIMER0_COMP_A: return 3; + case TriggerSource::TIMER0_OVERFLOW: return 4; + case TriggerSource::TIMER1_COMP_B: return 5; + case TriggerSource::TIMER1_OVERFLOW: return 6; + case TriggerSource::TIMER1_CAPTURE: return 7; + } + // clang-format on + } + + return 0; + } +}; + +} // namespace detail + +template +class Adc { + public: + static_assert(sizeof(Input) == -1, "Invalid input source selected"); +}; + +template +class Adc : public detail::AdcImpl { + using callback_t = void (*)(uint16_t); + + public: + static_assert(detail::supports_adc_v, "Pin does not support ADC"); + + static void init(callback_t callback) + { + detail::fnAdcIntHandler = callback; + init(); + } + + static void init() + { + constexpr auto muxVal = calcChannel(); + detail::AdcImpl::init(muxVal); + } + + private: + static constexpr auto calcChannel() + { + return static_cast(pin) - static_cast(io::P::C0); + } +}; + +template +class Adc : public detail::AdcImpl { + using callback_t = void (*)(uint16_t); + + public: + static void init(callback_t callback) + { + detail::fnAdcIntHandler = callback; + init(); + } + + static void init() + { + constexpr auto muxVal = calcChannel(); + detail::AdcImpl::init(muxVal); + } + + private: + static constexpr auto calcChannel() + { + using mx = detail::ControlFlagsMUX; + // clang-format off + switch (src) { + case InputSource::TEMP: return 1 << mx::CHANNEL_SEL_3; + case InputSource::VBG: return (1 << mx::CHANNEL_SEL_3) | (1 << mx::CHANNEL_SEL_2) | (1 << mx::CHANNEL_SEL_1); + case InputSource::GND: return (1 << mx::CHANNEL_SEL_3) | (1 << mx::CHANNEL_SEL_2) | (1 << mx::CHANNEL_SEL_1) | (1 << mx::CHANNEL_SEL_0); + } + // clang-format on + } +}; + +} // namespace adc + +#endif + +////////////////////////////////////////////////////////////////////////// + +#ifdef ADC_INT_VECTOR + +#include + +#include + +namespace adc { +namespace detail { + +#if defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega328P__) + +void (*fnAdcIntHandler)(uint16_t) = nullptr; + +ISR(ADC_vect) +{ + if (fnAdcIntHandler) { + const auto adcSample = *getRegPtr() | (*getRegPtr() << 8); + fnAdcIntHandler(adcSample); + } +} + +#else +#error "This chip is not supported" +#endif + +} // namespace detail +} // namespace adc + +#undef ADC_INT_VECTORS + +#endif diff --git a/fantemp/adc/config.hpp b/fantemp/adc/config.hpp new file mode 100644 index 0000000..4e7d412 --- /dev/null +++ b/fantemp/adc/config.hpp @@ -0,0 +1,73 @@ +#pragma once + +#include + +namespace adc { + +namespace detail { + +enum class Mode { + SINGLE, + AUTO, + FREE_RUNNING, +}; + +} // namespace detail + +enum class TriggerSource { + FREE_RUNNING, + ANALOG_COMP, + EXTERNAL_INT_0, + TIMER0_COMP_A, + TIMER0_OVERFLOW, + TIMER1_COMP_B, + TIMER1_OVERFLOW, + TIMER1_CAPTURE, +}; + +template +struct AutoMode { + static constexpr auto SRC = src; +}; + +struct FreeRunningMode { +}; + +struct SingleMode { +}; + +enum class VoltageRef { + EXTERNAL, + AVCC, + INTERNAL, +}; + +enum class InputSource { + TEMP, + VBG, + GND, +}; + +template +struct Config { + static constexpr auto MODE = detail::Mode::AUTO; + static constexpr auto TRIGGER_SRC = Mode::SRC; + static constexpr auto VREF = vref; + static constexpr auto PRESCALER = prescaler; +}; + +template +struct Config { + static constexpr auto MODE = detail::Mode::FREE_RUNNING; + static constexpr auto VREF = vref; + static constexpr auto PRESCALER = prescaler; +}; + +template +struct Config { + static constexpr auto MODE = detail::Mode::SINGLE; + static constexpr auto VREF = vref; + static constexpr auto PRESCALER = prescaler; +}; + +} // namespace adc diff --git a/fantemp/adc/hardware.hpp b/fantemp/adc/hardware.hpp new file mode 100644 index 0000000..903c08f --- /dev/null +++ b/fantemp/adc/hardware.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include + +#include "../io/io.hpp" + +namespace adc { + +namespace detail { + +#if defined(__AVR_ATmega328P__) + +/* +The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's: + constexpr auto *foo = ptr; + +Workaround is to store the address of the ptr in a uintptr_t and reinterpret_cast it at call site. +The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced +pointer and casts it to uint16_t, which is still not a legal constexpr. +The workaround therefore is to disable the pointer-cast-and-dereference macro _MMIO_BYTE temporarily. +*/ + +#pragma push_macro("_MMIO_BYTE") +#undef _MMIO_BYTE +#define _MMIO_BYTE + +struct Registers { + static constexpr uintptr_t MUX_SEL_ADDR = ADMUX; + static constexpr uintptr_t CTRL_STAT_A_ADDR = ADCSRA; + static constexpr uintptr_t DATA_L_ADDR = ADCL; + static constexpr uintptr_t DATA_H_ADDR = ADCH; + static constexpr uintptr_t CTRL_STAT_B_ADDR = ADCSRB; + static constexpr uintptr_t DIG_IN_DIS_ADDR = DIDR0; +}; + +enum class ControlFlagsMUX { + CHANNEL_SEL_0 = MUX0, + CHANNEL_SEL_1 = MUX1, + CHANNEL_SEL_2 = MUX2, + CHANNEL_SEL_3 = MUX3, + LEFT_ADJ_RES = ADLAR, + REF_SEL_0 = REFS0, + REF_SEL_1 = REFS1, +}; + +enum class ControlFlagsA { + PRESCALER_SEL_0 = ADPS0, + PRESCALER_SEL_1 = ADPS1, + PRESCALER_SEL_2 = ADPS2, + CONV_COMPLETE_INT_ENABLE = ADIE, + CONV_COMPLETE = ADIF, + AUTO_TRIGGER = ADATE, + START_CONV = ADSC, + ENABLE = ADEN, +}; + +enum class ControlFlagsB { + TRIGGER_SRC_0 = ADTS0, + TRIGGER_SRC_1 = ADTS1, + TRIGGER_SRC_2 = ADTS2, + ANALOG_COMP_MUX_ENABLE = ACME, +}; + +enum class ControlFlagsDigInDis { + DIGITAL_INPUT_DISABLE_0 = ADC0D, + DIGITAL_INPUT_DISABLE_1 = ADC1D, + DIGITAL_INPUT_DISABLE_2 = ADC2D, + DIGITAL_INPUT_DISABLE_3 = ADC3D, + DIGITAL_INPUT_DISABLE_4 = ADC4D, + DIGITAL_INPUT_DISABLE_5 = ADC5D, +}; + +// clang-format off +constexpr int operator<<(const int &lhs, const ControlFlagsMUX &rhs) { return lhs << static_cast(rhs); } +constexpr int operator<<(const int &lhs, const ControlFlagsA &rhs) { return lhs << static_cast(rhs); } +constexpr int operator<<(const int &lhs, const ControlFlagsB &rhs) { return lhs << static_cast(rhs); } +// clang-format on + +template +struct supports_adc { + static constexpr auto value = (io::detail::getBus(pin) == io::Bus::C) ? true : false; +}; + +template +constexpr auto supports_adc_v = supports_adc::value; + +#pragma pop_macro("_MMIO_BYTE") + +#else +#error "This chip is not supported" +#endif + +} // namespace detail + +} // namespace adc diff --git a/thermistor/clock.hpp b/fantemp/clock.hpp similarity index 100% rename from thermistor/clock.hpp rename to fantemp/clock.hpp diff --git a/thermistor/thermistor.cppproj b/fantemp/fantemp.cppproj similarity index 98% rename from thermistor/thermistor.cppproj rename to fantemp/fantemp.cppproj index bce292a..3c2f23a 100644 --- a/thermistor/thermistor.cppproj +++ b/fantemp/fantemp.cppproj @@ -12,9 +12,9 @@ $(MSBuildProjectName) .elf $(MSBuildProjectDirectory)\$(Configuration) - thermistor - thermistor - thermistor + fantemp + fantemp + fantemp avr-g++-9.1.0 true false diff --git a/fantemp/flash/.clang-format b/fantemp/flash/.clang-format new file mode 100644 index 0000000..63ebf38 --- /dev/null +++ b/fantemp/flash/.clang-format @@ -0,0 +1,13 @@ +--- +BasedOnStyle: LLVM +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: ForIndentation +AlignEscapedNewlines: DontAlign +AllowShortFunctionsOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true +... diff --git a/fantemp/flash/.gitattributes b/fantemp/flash/.gitattributes new file mode 100644 index 0000000..3e5b64f --- /dev/null +++ b/fantemp/flash/.gitattributes @@ -0,0 +1,9 @@ +*.h eol=lf +*.hpp eol=lf +*.c eol=lf +*.cpp eol=lf +.git* eol=lf +*.vcxproj* eol=crlf +*.cppproj eol=crlf +*.sln eol=crlf +*.atsln eol=crlf diff --git a/fantemp/flash/.gitignore b/fantemp/flash/.gitignore new file mode 100644 index 0000000..9f584cc --- /dev/null +++ b/fantemp/flash/.gitignore @@ -0,0 +1,11 @@ +.vs +Release +Debug +*.componentinfo.xml +*.elf +*.o +*.hex +*.srec +*.eeprom +*.lss +*.map diff --git a/fantemp/flash/LICENSE b/fantemp/flash/LICENSE new file mode 100644 index 0000000..80da57f --- /dev/null +++ b/fantemp/flash/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 BlackMark + +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 (including the next +paragraph) 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. diff --git a/fantemp/flash/flash.hpp b/fantemp/flash/flash.hpp new file mode 100644 index 0000000..9cfd8e1 --- /dev/null +++ b/fantemp/flash/flash.hpp @@ -0,0 +1,12 @@ +#pragma once + +#include + +#define F(str) (reinterpret_cast(PSTR(str))) + +namespace detail { + +// Only used for C++ type safety, because otherwise a PSTR would be indistinguishable from a normal c-string +struct FlashString; + +} // namespace detail diff --git a/fantemp/io/.clang-format b/fantemp/io/.clang-format new file mode 100644 index 0000000..63ebf38 --- /dev/null +++ b/fantemp/io/.clang-format @@ -0,0 +1,13 @@ +--- +BasedOnStyle: LLVM +ColumnLimit: 120 +IndentWidth: 4 +TabWidth: 4 +UseTab: ForIndentation +AlignEscapedNewlines: DontAlign +AllowShortFunctionsOnASingleLine: Empty +AlwaysBreakTemplateDeclarations: true +BreakBeforeBraces: Custom +BraceWrapping: + AfterFunction: true +... diff --git a/fantemp/io/.gitattributes b/fantemp/io/.gitattributes new file mode 100644 index 0000000..3e5b64f --- /dev/null +++ b/fantemp/io/.gitattributes @@ -0,0 +1,9 @@ +*.h eol=lf +*.hpp eol=lf +*.c eol=lf +*.cpp eol=lf +.git* eol=lf +*.vcxproj* eol=crlf +*.cppproj eol=crlf +*.sln eol=crlf +*.atsln eol=crlf diff --git a/fantemp/io/.gitignore b/fantemp/io/.gitignore new file mode 100644 index 0000000..9f584cc --- /dev/null +++ b/fantemp/io/.gitignore @@ -0,0 +1,11 @@ +.vs +Release +Debug +*.componentinfo.xml +*.elf +*.o +*.hex +*.srec +*.eeprom +*.lss +*.map diff --git a/fantemp/io/LICENSE b/fantemp/io/LICENSE new file mode 100644 index 0000000..80da57f --- /dev/null +++ b/fantemp/io/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 BlackMark + +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 (including the next +paragraph) 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. diff --git a/fantemp/io/io.hpp b/fantemp/io/io.hpp new file mode 100644 index 0000000..508fe47 --- /dev/null +++ b/fantemp/io/io.hpp @@ -0,0 +1,557 @@ +#pragma once + +#include + +#include +#include + +////////////////////////////////////////////////////////////////////////// +// Preprocessor defines + +#if defined(__AVR_ATmega32__) || defined(__AVR_ATmega32A__) || defined(__AVR_ATmega644P__) || \ + defined(__AVR_ATmega1284P__) +#define GPIO_32 +#endif + +#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega8A__) || defined(__AVR_ATmega168A__) || defined(__AVR_ATmega328P__) +#define GPIO_23 +#endif + +#if defined(__AVR_ATtiny13A__) || defined(__AVR_ATtiny85__) +#define GPIO_6 +#endif + +#if defined(__AVR_ATmega644P__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega168A__) || \ + defined(__AVR_ATmega328P__) || defined(__AVR_ATtiny13A__) || defined(__AVR_ATtiny85__) +#define HARDWARE_TOGGLE +#endif + +#ifdef GPIO_32 +#define PORT_A_AVAILABLE +#endif + +#if defined(GPIO_32) || defined(GPIO_23) || defined(GPIO_6) +#define PORT_B_AVAILABLE +#endif + +#if defined(GPIO_32) || defined(GPIO_23) +#define PORT_C_AVAILABLE +#define PORT_D_AVAILABLE +#define PIN_B6_AVAILABLE +#define PIN_B7_AVAILABLE +#endif + +#if defined(GPIO_32) +#define PIN_C7_AVAILABLE +#endif + +#define FORCE_INLINE __attribute__((always_inline)) + +////////////////////////////////////////////////////////////////////////// +// Library implementation + +namespace io { + +enum class Dir { IN, OUT }; + +enum class P { +#ifdef PORT_A_AVAILABLE + A0 = 0x00, + A1 = 0x01, + A2 = 0x02, + A3 = 0x03, + A4 = 0x04, + A5 = 0x05, + A6 = 0x06, + A7 = 0x07, +#endif + +#ifdef PORT_B_AVAILABLE + B0 = 0x10, + B1 = 0x11, + B2 = 0x12, + B3 = 0x13, + B4 = 0x14, + B5 = 0x15, +#ifdef PIN_B6_AVAILABLE + B6 = 0x16, +#endif +#ifdef PIN_B7_AVAILABLE + B7 = 0x17, +#endif +#endif + +#ifdef PORT_C_AVAILABLE + C0 = 0x20, + C1 = 0x21, + C2 = 0x22, + C3 = 0x23, + C4 = 0x24, + C5 = 0x25, + C6 = 0x26, +#ifdef PIN_C7_AVAILABLE + C7 = 0x27, +#endif +#endif + +#ifdef PORT_D_AVAILABLE + D0 = 0x30, + D1 = 0x31, + D2 = 0x32, + D3 = 0x33, + D4 = 0x34, + D5 = 0x35, + D6 = 0x36, + D7 = 0x37, +#endif +}; + +enum class Bus { +#ifdef PORT_A_AVAILABLE + A = 0x00, +#endif +#ifdef PORT_B_AVAILABLE + B = 0x01, +#endif +#ifdef PORT_C_AVAILABLE + C = 0x02, +#endif +#ifdef PORT_D_AVAILABLE + D = 0x03, +#endif +}; + +////////////////////////////////////////////////////////////////////////// +// Implementation details + +namespace detail { + +/* +The following works in avr-gcc 5.4.0, but is not legal C++, because ptr's are not legal constexpr's: + constexpr auto *foo = ptr; + +Workaround is to store the address of the ptr in a uintptr_t and reinterpret_cast it at call site. +The _SFR_ADDR macro in sfr_defs.h would give the address, but it does that by taking the address of the dereferenced +pointer and casts it to uint16_t, which is still not a legal constexpr. +The workaround therefore is to disable the pointer-cast-and-dereference macro _MMIO_BYTE temporarily. +*/ + +#pragma push_macro("_MMIO_BYTE") +#undef _MMIO_BYTE +#define _MMIO_BYTE + +#ifdef PORT_A_AVAILABLE +static constexpr uintptr_t PORT_A_DIR_REG_ADDR = DDRA; +static constexpr uintptr_t PORT_A_OUTPUT_REG_ADDR = PORTA; +static constexpr uintptr_t PORT_A_INPUT_REG_ADDR = PINA; +#else +static constexpr uintptr_t PORT_A_DIR_REG_ADDR = 0; +static constexpr uintptr_t PORT_A_OUTPUT_REG_ADDR = 0; +static constexpr uintptr_t PORT_A_INPUT_REG_ADDR = 0; +#endif + +#ifdef PORT_B_AVAILABLE + +static constexpr uintptr_t PORT_B_DIR_REG_ADDR = DDRB; +static constexpr uintptr_t PORT_B_OUTPUT_REG_ADDR = PORTB; +static constexpr uintptr_t PORT_B_INPUT_REG_ADDR = PINB; +#else +static constexpr uintptr_t PORT_B_DIR_REG_ADDR = 0; +static constexpr uintptr_t PORT_B_OUTPUT_REG_ADDR = 0; +static constexpr uintptr_t PORT_B_INPUT_REG_ADDR = 0; +#endif + +#ifdef PORT_C_AVAILABLE +static constexpr uintptr_t PORT_C_DIR_REG_ADDR = DDRC; +static constexpr uintptr_t PORT_C_OUTPUT_REG_ADDR = PORTC; +static constexpr uintptr_t PORT_C_INPUT_REG_ADDR = PINC; +#else +static constexpr uintptr_t PORT_C_DIR_REG_ADDR = 0; +static constexpr uintptr_t PORT_C_OUTPUT_REG_ADDR = 0; +static constexpr uintptr_t PORT_C_INPUT_REG_ADDR = 0; +#endif + +#ifdef PORT_D_AVAILABLE +static constexpr uintptr_t PORT_D_DIR_REG_ADDR = DDRD; +static constexpr uintptr_t PORT_D_OUTPUT_REG_ADDR = PORTD; +static constexpr uintptr_t PORT_D_INPUT_REG_ADDR = PIND; +#else +static constexpr uintptr_t PORT_D_DIR_REG_ADDR = 0; +static constexpr uintptr_t PORT_D_OUTPUT_REG_ADDR = 0; +static constexpr uintptr_t PORT_D_INPUT_REG_ADDR = 0; +#endif + +#pragma pop_macro("_MMIO_BYTE") + +static constexpr auto getBus(const P pin) +{ + // Upper 4 bits of pin encode which port this pin is on + uint8_t port = static_cast(pin) >> 4 & 0x0F; + return static_cast(port); +} + +static constexpr auto getPinBit(const P pin) +{ + // Lower 4 bits of pin encode which pin bit it is + uint8_t pinBit = static_cast(pin) & 0x0F; + return pinBit; +} + +static constexpr auto getDDR(const Bus bus) +{ + switch (static_cast(bus)) { + case 0: // Bus::A + return PORT_A_DIR_REG_ADDR; + case 1: // Bus::B + return PORT_B_DIR_REG_ADDR; + case 2: // Bus::C + return PORT_C_DIR_REG_ADDR; + case 3: // Bus::D + return PORT_D_DIR_REG_ADDR; + } +} + +static constexpr auto getPORT(const Bus bus) +{ + switch (static_cast(bus)) { + case 0: // Bus::A + return PORT_A_OUTPUT_REG_ADDR; + case 1: // Bus::B + return PORT_B_OUTPUT_REG_ADDR; + case 2: // Bus::C + return PORT_C_OUTPUT_REG_ADDR; + case 3: // Bus::D + return PORT_D_OUTPUT_REG_ADDR; + } +} + +static constexpr auto getPIN(const Bus bus) +{ + switch (static_cast(bus)) { + case 0: // Bus::A + return PORT_A_INPUT_REG_ADDR; + case 1: // Bus::B + return PORT_B_INPUT_REG_ADDR; + case 2: // Bus::C + return PORT_C_INPUT_REG_ADDR; + case 3: // Bus::D + return PORT_D_INPUT_REG_ADDR; + } +} + +using reg_ptr_t = volatile uint8_t *; + +template +static inline reg_ptr_t getRegPtr() +{ + return reinterpret_cast(Address); +} + +template