update lookup table example

This commit is contained in:
Amar Mahmutbegovic
2024-09-23 00:17:56 +02:00
parent 6090eba6d3
commit 87087b3bfb
11 changed files with 301 additions and 72 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
**/build/ **/build/
**/.cache/ **/.cache/
**/.vscode/ **/.vscode/
*.out
compile_commands.json compile_commands.json

View File

@@ -9,6 +9,7 @@ Checks: >
-performance-no-int-to-ptr, -performance-no-int-to-ptr,
portability-*, portability-*,
readability-*, readability-*,
-readability-identifier-length
readability-identifier-naming readability-identifier-naming
CheckOptions: CheckOptions:

View File

@@ -86,7 +86,9 @@ include_directories(
${CMAKE_SOURCE_DIR}/hal/uart/inc ${CMAKE_SOURCE_DIR}/hal/uart/inc
${CMAKE_SOURCE_DIR}/hal/inc ${CMAKE_SOURCE_DIR}/hal/inc
${CMAKE_SOURCE_DIR}/hal/gpio/inc ${CMAKE_SOURCE_DIR}/hal/gpio/inc
${CMAKE_SOURCE_DIR}/hal/adc/inc
${CMAKE_SOURCE_DIR}/cstdlib_support ${CMAKE_SOURCE_DIR}/cstdlib_support
${CMAKE_SOURCE_DIR}/util/inc
) )
set(EXECUTABLE ${PROJECT_NAME}.elf) set(EXECUTABLE ${PROJECT_NAME}.elf)
@@ -108,7 +110,9 @@ add_executable(
hal/uart/src/uart_stm32.cpp hal/uart/src/uart_stm32.cpp
hal/gpio/src/gpio.cpp hal/gpio/src/gpio.cpp
hal/gpio/src/gpio_interrupt_manager.cpp hal/gpio/src/gpio_interrupt_manager.cpp
hal/adc/src/adc_stm32.cpp
cstdlib_support/retarget.cpp cstdlib_support/retarget.cpp
util/src/units.cpp
${MAIN_CPP_PATH}/${MAIN_CPP_FILE_NAME} ${MAIN_CPP_PATH}/${MAIN_CPP_FILE_NAME}
) )

View File

@@ -4,69 +4,31 @@
#include <stm32f072xb.h> #include <stm32f072xb.h>
#include <hal.hpp> #include <hal.hpp>
#include <units.hpp>
#include <uart_stm32.hpp> #include <uart_stm32.hpp>
#include <adc_stm32.hpp>
#include <retarget.hpp> #include <retarget.hpp>
#include <signal.hpp>
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <gpio_stm32.hpp> namespace {
struct voltage_divider {
ADC_HandleTypeDef hadc; units::resistance r2;
units::voltage vcc;
static void MX_ADC_Init(void)
{
/* USER CODE BEGIN ADC_Init 0 */
/* USER CODE END ADC_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC_Init 1 */
/* USER CODE END ADC_Init 1 */
/** Configure the global features of the ADC (Clock, Resolution, Data Alignment and number of conversion)
*/
hadc.Instance = ADC1;
hadc.Init.ClockPrescaler = ADC_CLOCK_ASYNC_DIV1;
hadc.Init.Resolution = ADC_RESOLUTION_12B;
hadc.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;
hadc.Init.EOCSelection = ADC_EOC_SINGLE_CONV;
hadc.Init.LowPowerAutoWait = DISABLE;
hadc.Init.LowPowerAutoPowerOff = DISABLE;
hadc.Init.ContinuousConvMode = DISABLE;
hadc.Init.DiscontinuousConvMode = DISABLE;
hadc.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
hadc.Init.DMAContinuousRequests = DISABLE;
hadc.Init.Overrun = ADC_OVR_DATA_PRESERVED;
if (HAL_ADC_Init(&hadc) != 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(&hadc, &sConfig) != HAL_OK)
{
//Error_Handler();
}
/* USER CODE BEGIN ADC_Init 2 */
/* USER CODE END ADC_Init 2 */
}
units::resistance get_r1(units::voltage vadc) {
return r2 * (vcc/vadc - 1);
}
};
};
int main() int main()
{ {
using namespace units;
hal::init(); hal::init();
hal::uart_stm32 uart(USART2); hal::uart_stm32 uart(USART2);
@@ -74,28 +36,58 @@ int main()
retarget::set_stdio_uart(&uart); retarget::set_stdio_uart(&uart);
MX_ADC_Init(); hal::adc_stm32 adc(3.3_V);
adc.init();
constexpr float A = 1.18090254918130e-3;
constexpr float B = 2.16884014794388e-4;
constexpr float C = 1.90058756197216e-6;
constexpr float D = 1.83161892641824e-8;
const hal::gpio_stm32<hal::port_a> button1(hal::pin::p4, [](){ constexpr int c_lut_points = 50;
printf("Button1 pressed!\r\n");
});
const hal::gpio_stm32<hal::port_a> button2(hal::pin::p5, [](){ constexpr signal<float, c_lut_points> resistance(1e3, 10e3);
printf("Button2 pressed!\r\n");
});
constexpr auto temperature_k = 1 / (A +
B * signal(resistance, [](float x)
{ return std::log(x); }) +
C * signal(resistance, [](float x)
{ return std::pow(std::log(x), 2); }) +
D * signal(resistance, [](float x)
{ return std::pow(std::log(x), 3); }));
constexpr auto temperature_celsius = temperature_k - 273.15;
voltage_divider divider{10e3_Ohm, 3.3_V};
while(true) while(true)
{ {
HAL_ADC_Start(&hadc); auto adc_val = adc.get_reading();
HAL_ADC_PollForConversion(&hadc, 1000); if(adc_val) {
auto adc_val_voltage = *adc_val;
auto thermistor_r = divider.get_r1(adc_val_voltage);
auto adc_val = HAL_ADC_GetValue(&hadc); auto it = std::lower_bound(resistance.begin(), resistance.end(), thermistor_r.get());
float mv = 3.3f * static_cast<float>(adc_val) / 4096.f;
printf("%d, %.2f\r\n", adc_val, mv); if(it != resistance.end()) {
hal::time::delay_ms(1000);
std::size_t pos = std::distance(resistance.begin(), it);
float temperature = temperature_celsius.at(pos);
printf("%d mV, %d Ohm, %d.%d C\r\n", static_cast<int>(adc_val_voltage.get_mili()),
static_cast<int>(thermistor_r.get()),
static_cast<int>(temperature),
static_cast<int>(10*(temperature-std::floor(temperature)))
);
}
}
hal::time::delay_ms(200);
} }
} }
// adc FeedVoltageSampleToChannel 0 3100 10 // adc FeedVoltageSampleToChannel 0 3000 3 -> 1001 Ohm
// adc FeedVoltageSampleToChannel 0 2800 3 -> 1787 Ohm
// adc FeedVoltageSampleToChannel 0 2400 3 -> 3754 Ohm
// adc FeedVoltageSampleToChannel 0 2200 3 -> 5003 Ohm
// adc FeedVoltageSampleToChannel 0 2000 3 -> 6502 Ohm
// adc FeedVoltageSampleToChannel 0 1700 3 -> 9412 Ohm

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

@@ -3,8 +3,6 @@
#include <cstdint> #include <cstdint>
#include <functional> #include <functional>
//#include <gpio_interrupt_handler.hpp>
namespace hal namespace hal
{ {
class gpio class gpio

View File

@@ -0,0 +1,102 @@
#pragma once
#include <array>
#include <cmath>
template <typename T, std::size_t N>
struct signal : public std::array<T, N>
{
constexpr signal() {}
constexpr signal(T begin, T end)
{
static_assert(N > 1, "N must be bigger than 1");
float step = (end - begin) / (N - 1);
for (std::size_t i = 0; i < N; i++)
{
this->at(i) = begin + i * step;
}
}
constexpr signal(const std::array<T, N> &x, auto fun)
{
for (std::size_t i = 0; i < N; i++)
{
this->at(i) = fun(x.at(i));
}
}
constexpr signal(const signal &sig, auto fun)
{
for (std::size_t i = 0; i < N; i++)
{
this->at(i) = fun(sig.at(i));
}
}
constexpr signal operator+(const T &t) const
{
return signal(*this, [&](T elem)
{ return elem + t; });
};
constexpr signal operator-(const T &t) const
{
return signal(*this, [&](T elem)
{ return elem - t; });
};
constexpr signal operator*(const T &t) const
{
return signal(*this, [&](T elem)
{ return elem * t; });
};
constexpr signal operator/(const T &t) const
{
return signal(*this, [&](T elem)
{ return elem / t; });
};
constexpr signal operator+(const signal &sig) const
{
signal ret;
for (std::size_t i = 0; i < N; i++)
{
ret.at(i) = this->at(i) + sig.at(i);
}
return ret;
};
constexpr signal operator-(const signal &sig) const
{
signal ret;
for (std::size_t i = 0; i < N; i++)
{
ret.at(i) = this->at(i) - sig.at(i);
}
return ret;
};
friend constexpr signal operator+(const T &t, const signal &sig)
{
return sig + t;
}
friend constexpr signal operator*(const T &t, const signal &sig)
{
return sig * t;
}
friend constexpr signal operator/(const T &t, const signal &sig)
{
signal ret;
for (std::size_t i = 0; i < N; i++)
{
ret.at(i) = t / sig.at(i);
}
return ret;
}
};

View File

@@ -0,0 +1,33 @@
#pragma once
namespace units
{
template<typename T, typename ST>
class unit {
private:
T val_;
public:
explicit unit(T val) : val_(val){}
[[nodiscard]] T get() const {return val_;}
[[nodiscard]] T get_mili() const {return 1e3 * val_;}
constexpr T operator/(const unit& second) const{
return val_ / second.get();
}
constexpr unit operator*(const T& second) const{
return unit(val_ * second);
}
constexpr unit operator/(const T& second) const{
return unit(val_ / second);
}
};
using voltage = unit<float, struct the_voltage>;
using resistance = unit<float, struct the_resistance>;
voltage operator""_V(long double volts);
resistance operator""_Ohm(long double ohms);
};

View File

@@ -0,0 +1,11 @@
#include <units.hpp>
namespace units {
voltage operator""_V(long double volts) {
return voltage(static_cast<float>(volts));
}
resistance operator""_Ohm(long double ohms) {
return resistance(static_cast<float>(ohms));
}
};