add Chapter18

This commit is contained in:
Amar Mahmutbegovic
2025-02-06 00:19:59 +01:00
parent 9cc9cc7d73
commit 8634accda5
1533 changed files with 1092521 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
#pragma once
#include <expected>
#include <units.hpp>
namespace hal
{
class adc {
public:
enum class error {
timeout
};
virtual void init() = 0;
virtual std::expected<units::voltage, adc::error> get_reading() = 0;
};
};

View File

@@ -0,0 +1,22 @@
#pragma once
#include <adc.hpp>
#include <units.hpp>
#include <stm32f0xx_hal.h>
#include <stm32f072xb.h>
namespace hal
{
class adc_stm32 : public adc{
public:
adc_stm32(units::voltage ref_voltage) : ref_voltage_(ref_voltage) {}
void init() override;
std::expected<units::voltage, adc::error> get_reading() override;
private:
ADC_HandleTypeDef adc_handle_;
units::voltage ref_voltage_;
};
};

View File

@@ -0,0 +1,47 @@
#include <adc_stm32.hpp>
void hal::adc_stm32::init() {
ADC_ChannelConfTypeDef sConfig = {0};
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
adc_handle_.Instance = ADC1;
adc_handle_.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
adc_handle_.Init.Resolution = ADC_RESOLUTION_12B;
adc_handle_.Init.DataAlign = ADC_DATAALIGN_RIGHT;
adc_handle_.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
adc_handle_.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
adc_handle_.Init.LowPowerAutoWait = DISABLE;
adc_handle_.Init.LowPowerAutoPowerOff = DISABLE;
adc_handle_.Init.ContinuousConvMode = DISABLE;
adc_handle_.Init.DiscontinuousConvMode = DISABLE;
adc_handle_.Init.ExternalTrigConv = ADC_SOFTWARE_START;
adc_handle_.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
adc_handle_.Init.DMAContinuousRequests = DISABLE;
adc_handle_.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&adc_handle_) != HAL_OK)
{
//Error_Handler();
}
/** Configure for the selected ADC regular channel to be converted.
*/
sConfig.Channel = ADC_CHANNEL_0;
sConfig.Rank = ADC_RANK_CHANNEL_NUMBER;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
if (HAL_ADC_ConfigChannel(&adc_handle_, &sConfig) != HAL_OK)
{
//Error_Handler();
}
}
std::expected<units::voltage, hal::adc::error> hal::adc_stm32::get_reading() {
HAL_ADC_Start(&adc_handle_);
if(HAL_ADC_PollForConversion(&adc_handle_, 1000) != HAL_OK) {
return std::unexpected(hal::adc::error::timeout);
}
auto adc_val = HAL_ADC_GetValue(&adc_handle_);
return ref_voltage_ * adc_val / 4096.f;
}

View File

@@ -0,0 +1,19 @@
#pragma once
#include <cstdint>
#include <functional>
namespace hal
{
class gpio
{
public:
gpio(const std::function<void()> & on_press = nullptr);
void execute_interrupt_handler() const;
[[nodiscard]] virtual bool is_interrupt_generated() const = 0;
virtual void clear_interrupt_flag() const = 0;
private:
std::function<void()> on_press_;
};
}; // namespace hal

View File

@@ -0,0 +1,19 @@
#pragma once
#include <array>
#include <cstdint>
#include <gpio.hpp>
namespace hal {
struct gpio_interrupt_manager {
static void register_interrupt_handler(gpio * pin);
static void execute_interrupt_handlers();
static constexpr std::size_t c_gpio_handlers_num = 16;
static inline std::array<gpio*, c_gpio_handlers_num> gpio_handlers{};
static inline std::size_t w_idx = 0;
};
};

View File

@@ -0,0 +1,70 @@
#include <gpio.hpp>
#include <stm32f072xb.h>
namespace hal {
enum class pin : uint16_t {
p_invalid = 0,
p0 = 0x0001U,
p1 = 0x0002U,
p2 = 0x0004U,
p3 = 0x0008U,
p4 = 0x0010U,
p5 = 0x0020U,
p6 = 0x0040U,
p7 = 0x0080U,
p8 = 0x0100U,
p9 = 0x0200U,
p10 = 0x0400U,
p11 = 0x0800U,
p12 = 0x1000U,
p13 = 0x2000U,
p14 = 0x4000U,
p15 = 0x8000U,
all = 0xFFFFU
};
struct port_a {
static constexpr uint8_t c_pin_num = 16;
static inline GPIO_TypeDef * port = reinterpret_cast<GPIO_TypeDef*>(GPIOA);
static void init_clock () {
__HAL_RCC_GPIOA_CLK_ENABLE();
}
};
template<typename Port>
class gpio_stm32 : public gpio {
public:
gpio_stm32(pin the_pin, const std::function<void()> & on_press = nullptr)
: gpio(on_press), the_pin_(the_pin) {
Port::init_clock();
GPIO_InitTypeDef GPIO_InitStruct { static_cast<uint16_t>(the_pin),
GPIO_MODE_IT_RISING,
GPIO_NOPULL,
GPIO_SPEED_FREQ_LOW,
0 };
HAL_GPIO_Init(Port::port, &GPIO_InitStruct);
if(on_press) {
enable_interrupt();
}
}
[[nodiscard]] bool is_interrupt_generated() const override {
return __HAL_GPIO_EXTI_GET_IT(static_cast<uint16_t>(the_pin_));
}
void clear_interrupt_flag() const override {
__HAL_GPIO_EXTI_CLEAR_IT(static_cast<uint16_t>(the_pin_));
}
private:
pin the_pin_ = pin::p_invalid;
void enable_interrupt() {
// TODO: check EXTI line macro according to pin used
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);
}
};
};

View File

@@ -0,0 +1,21 @@
#include <gpio.hpp>
#include <gpio_interrupt_manager.hpp>
namespace hal {
gpio::gpio(const std::function<void()> & on_press) {
on_press_ = on_press;
gpio_interrupt_manager::register_interrupt_handler(this);
}
void gpio::execute_interrupt_handler () const {
if(is_interrupt_generated())
{
clear_interrupt_flag();
if(on_press_) {
on_press_();
}
}
}
};

View File

@@ -0,0 +1,17 @@
#include <gpio_interrupt_manager.hpp>
namespace hal {
void gpio_interrupt_manager::register_interrupt_handler(gpio * pin) {
gpio_handlers.at(w_idx++) = pin;
}
void gpio_interrupt_manager::execute_interrupt_handlers() {
for(std::size_t i = 0; i < w_idx; i++) {
gpio_handlers[i]->execute_interrupt_handler();
}
}
extern "C" void EXTI4_15_IRQHandler(void) {
gpio_interrupt_manager::execute_interrupt_handlers();
}
};

View File

@@ -0,0 +1,33 @@
#pragma once
#include <cstdint>
#include <stm32f0xx_hal.h>
namespace hal
{
inline void init()
{
HAL_Init();
}
inline std::uint32_t get_pc()
{
std::uint32_t pc;
__asm volatile ("mov %0, pc" : "=r" (pc) );
return pc;
}
struct time
{
static std::uint32_t get_ms()
{
return HAL_GetTick();
}
static void delay_ms(uint32_t delay)
{
HAL_Delay(delay);
}
};
}; // namespace hal

View File

@@ -0,0 +1,21 @@
#pragma once
#include <stm32f0xx_hal.h>
#include <stm32f072xb.h>
namespace hal::stm32{
struct uart {
uart() = delete;
static inline HAL_StatusTypeDef init(UART_HandleTypeDef *huart) {
return HAL_UART_Init(huart);
}
static inline HAL_StatusTypeDef transmit(UART_HandleTypeDef *huart,
uint8_t *pData,
uint16_t Size,
uint32_t Timeout) {
return HAL_UART_Transmit(huart, pData, Size, Timeout);
}
};
};

View File

@@ -0,0 +1,14 @@
#pragma once
#include <cstdint>
#include <span>
namespace hal
{
class uart
{
public:
virtual void init(std::uint32_t baudrate) = 0;
virtual void write(std::span<const char> data) = 0;
};
}; // namespace hal

View File

@@ -0,0 +1,46 @@
#pragma once
#include <span>
#include <cstdint>
#include <uart.hpp>
#include <stm32f0xx_hal_uart.hpp>
namespace hal
{
template <typename HalUart>
class uart_stm32 : public uart
{
public:
uart_stm32(USART_TypeDef *inst) : instance_(inst) {}
void init(std::uint32_t baudrate = c_baudrate_default) override {
huart_.Instance = instance_;
huart_.Init.BaudRate = baudrate;
huart_.Init.WordLength = UART_WORDLENGTH_8B;
huart_.Init.StopBits = UART_STOPBITS_1;
huart_.Init.Parity = UART_PARITY_NONE;
huart_.Init.Mode = UART_MODE_TX_RX;
huart_.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart_.Init.OverSampling = UART_OVERSAMPLING_16;
huart_.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart_.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
// TODO: add GPIO initialization for real hardware
huart_.MspInitCallback = nullptr;
HalUart::init(&huart_);
}
void write(std::span<const char> data) override {
// we must cast away costness due to ST HAL's API
char * data_ptr = const_cast<char *>(data.data());
HalUart::transmit(&huart_, reinterpret_cast<uint8_t *>(data_ptr), data.size(),
HAL_MAX_DELAY);
}
private:
UART_HandleTypeDef huart_;
USART_TypeDef *instance_;
std::uint32_t baudrate_;
static constexpr std::uint32_t c_baudrate_default = 115200;
};
}; // namespace hal

View File

@@ -0,0 +1,34 @@
#include <uart_stm32.hpp>
template <typename HalUart>
hal::uart_stm32<HalUart>::uart_stm32(USART_TypeDef *inst)
: instance_(inst)
{
}
template <typename HalUart>
void hal::uart_stm32<HalUart>::init(std::uint32_t baudrate)
{
huart_.Instance = instance_;
huart_.Init.BaudRate = baudrate;
huart_.Init.WordLength = UART_WORDLENGTH_8B;
huart_.Init.StopBits = UART_STOPBITS_1;
huart_.Init.Parity = UART_PARITY_NONE;
huart_.Init.Mode = UART_MODE_TX_RX;
huart_.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart_.Init.OverSampling = UART_OVERSAMPLING_16;
huart_.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart_.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
// TODO: add GPIO initialization for real hardware
huart_.MspInitCallback = nullptr;
HalUart::init(&huart_);
}
template <typename HalUart>
void hal::uart_stm32<HalUart>::write(std::span<const char> data)
{
// we must cast away costness due to ST HAL's API
char * data_ptr = const_cast<char *>(data.data());
HalUart::transmit(&huart_, reinterpret_cast<uint8_t *>(data_ptr), data.size(),
HAL_MAX_DELAY);
}