Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Yann/exploration/haptic/audio #1420

8 changes: 8 additions & 0 deletions config/mbed_app.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@
"USE_HAL_JPEG_REGISTER_CALLBACKS": {
"macro_name": "USE_HAL_JPEG_REGISTER_CALLBACKS",
"value": "1U"
},
"USE_HAL_TIM_REGISTER_CALLBACKS": {
"macro_name": "USE_HAL_TIM_REGISTER_CALLBACKS",
"value": "1U"
},
"USE_HAL_DAC_REGISTER_CALLBACKS": {
"macro_name": "USE_HAL_DAC_REGISTER_CALLBACKS",
"value": "1U"
}
},
"target_overrides": {
Expand Down
1 change: 1 addition & 0 deletions drivers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
add_subdirectory(${DRIVERS_DIR}/CoreBufferedSerial)
add_subdirectory(${DRIVERS_DIR}/CoreEventFlags)
add_subdirectory(${DRIVERS_DIR}/CoreEventQueue)
add_subdirectory(${DRIVERS_DIR}/CoreDAC)
add_subdirectory(${DRIVERS_DIR}/CoreI2C)
add_subdirectory(${DRIVERS_DIR}/CoreInterruptIn)
add_subdirectory(${DRIVERS_DIR}/CoreLL)
Expand Down
28 changes: 28 additions & 0 deletions drivers/CoreDAC/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Leka - LekaOS
# Copyright 2024 APF France handicap
# SPDX-License-Identifier: Apache-2.0

add_library(CoreDAC STATIC)

target_include_directories(CoreDAC
PUBLIC
include
)

target_sources(CoreDAC
PRIVATE
source/CoreSTM32HalBasicTimer.cpp
source/CoreDAC.cpp
)

if(NOT(${CMAKE_PROJECT_NAME} STREQUAL "LekaOSUnitTests"))
target_sources(CoreDAC
PUBLIC
source/HAL_IRQHandlers.cpp
)
endif()

target_link_libraries(CoreDAC
mbed-os
CoreSTM32Hal
)
49 changes: 49 additions & 0 deletions drivers/CoreDAC/include/CoreDAC.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// Leka - LekaOS
// Copyright 2024 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <array>
#include <functional>
#include <span>

#include "interface/STM32HalBasicTimer.h"
#include "interface/drivers/DAC.h"
#include "interface/drivers/STM32Hal.h"

namespace leka {

class CoreDAC : public interface::DACBase
{
public:
CoreDAC(interface::STM32Hal &hal, interface::STM32HalBasicTimer &hal_timer);

[[nodiscard]] auto getHandle() -> DAC_HandleTypeDef & final;

void initialize() final;
void terminate() final;

void registerDataToPlay(std::span<uint16_t> data);
void registerDMACallbacks(std::function<void()> const &on_half_transfer,
std::function<void()> const &on_complete_transfer);

void start() final;
void stop() final;

private:
void _registerMspCallbacks();
void _initializeDMA();

interface::STM32Hal &_hal;
interface::STM32HalBasicTimer &_hal_timer;

DAC_HandleTypeDef _hdac {};
DMA_HandleTypeDef _hdma {};

std::span<uint16_t> _data;
std::function<void()> _on_half_transfer {};
std::function<void()> _on_complete_transfer {};
};

} // namespace leka
41 changes: 41 additions & 0 deletions drivers/CoreDAC/include/CoreSTM32HalBasicTimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// Leka - LekaOS
// Copyright 2024 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include <functional>

#include "interface/STM32HalBasicTimer.h"

namespace leka {

class CoreSTM32HalBasicTimer : public interface::STM32HalBasicTimer
{
static constexpr float DEFAULT_AUDIO_FILE_SAMPLE_RATE = 44'100;

public:
CoreSTM32HalBasicTimer(interface::STM32Hal &hal);

[[nodiscard]] auto getHandle() -> TIM_HandleTypeDef & final;

void registerCallback(std::function<void()> const &callback);
void linkDACTimer(DAC_ChannelConfTypeDef *config) final;

void initialize(float frequency = DEFAULT_AUDIO_FILE_SAMPLE_RATE) final;
void terminate() final;

void start() final;
void stop() final;

private:
void _registerMspCallbacks();

interface::STM32Hal &_hal;

TIM_HandleTypeDef _htim {};

std::function<void()> _callback {};
};

} // namespace leka
27 changes: 27 additions & 0 deletions drivers/CoreDAC/include/interface/STM32HalBasicTimer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Leka - LekaOS
// Copyright 2024 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#pragma once

#include "interface/drivers/STM32Hal.h"

namespace leka::interface {

class STM32HalBasicTimer
{
public:
virtual ~STM32HalBasicTimer() = default;

[[nodiscard]] virtual auto getHandle() -> TIM_HandleTypeDef & = 0;

virtual void linkDACTimer(DAC_ChannelConfTypeDef *config) = 0;

virtual void initialize(float frequency) = 0;
virtual void terminate() = 0;

virtual void start() = 0;
virtual void stop() = 0;
};

} // namespace leka::interface
116 changes: 116 additions & 0 deletions drivers/CoreDAC/source/CoreDAC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
// Leka - LekaOS
// Copyright 2024 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#include "CoreDAC.h"

using namespace leka;

CoreDAC::CoreDAC(interface::STM32Hal &hal, interface::STM32HalBasicTimer &hal_timer) : _hal(hal), _hal_timer(hal_timer)
{
_hdac.Instance = DAC;
}

auto CoreDAC::getHandle() -> DAC_HandleTypeDef &
{
return _hdac;
}

void CoreDAC::initialize()
{
_registerMspCallbacks();

_hal.HAL_DAC_Init(&_hdac);

DAC_ChannelConfTypeDef config = {};
config.DAC_OutputBuffer = DAC_OUTPUTBUFFER_ENABLE;
_hal_timer.linkDACTimer(&config);
_hal.HAL_DAC_ConfigChannel(&_hdac, &config, DAC_CHANNEL_1);

static const auto &self = *this;
_hal.HAL_DAC_RegisterCallback(&_hdac, HAL_DAC_CH1_HALF_COMPLETE_CB_ID,
[]([[maybe_unused]] DAC_HandleTypeDef *hdac) {
if (self._on_half_transfer != nullptr) {
self._on_half_transfer();
}
});
_hal.HAL_DAC_RegisterCallback(&_hdac, HAL_DAC_CH1_COMPLETE_CB_ID, []([[maybe_unused]] DAC_HandleTypeDef *hdac) {
if (self._on_complete_transfer != nullptr) {
self._on_complete_transfer();
}
});
}

void CoreDAC::terminate()
{
_hal.HAL_DAC_DeInit(&_hdac);
}

void CoreDAC::registerDataToPlay(std::span<uint16_t> data)
{
_data = data;
}

void CoreDAC::registerDMACallbacks(std::function<void()> const &on_half_transfer,
std::function<void()> const &on_complete_transfer)
{
_on_half_transfer = on_half_transfer;
_on_complete_transfer = on_complete_transfer;
}

void CoreDAC::start()
{
_hal_timer.start();
_hal.HAL_DAC_Start_DMA(&_hdac, DAC_CHANNEL_1, reinterpret_cast<uint32_t *>(_data.data()), _data.size(),
DAC_ALIGN_12B_R);
}

void CoreDAC::stop()
{
_hal.HAL_DAC_Stop_DMA(&_hdac, DAC_CHANNEL_1);
}

void CoreDAC::_registerMspCallbacks()
{
static auto &self = *this;

_hal.HAL_DAC_RegisterCallback(&_hdac, HAL_DAC_MSPINIT_CB_ID, []([[maybe_unused]] DAC_HandleTypeDef *hdac) {
__HAL_LINKDMA(&self._hdac, DMA_Handle1, self._hdma);
self._initializeDMA();

self._hal.HAL_RCC_DAC_CLK_ENABLE();
});

_hal.HAL_DAC_RegisterCallback(&_hdac, HAL_DAC_MSPDEINIT_CB_ID, []([[maybe_unused]] DAC_HandleTypeDef *hdac) {
self._hal.HAL_DMA_DeInit(&self._hdma);

self._hal.HAL_RCC_DAC_CLK_DISABLE();
});
}

void CoreDAC::_initializeDMA()
{
_hal.HAL_RCC_DMA1_CLK_ENABLE();

_hal.HAL_NVIC_SetPriority(DMA1_Stream5_IRQn, 3, 0);
_hal.HAL_NVIC_EnableIRQ(DMA1_Stream5_IRQn);

_hdma.Instance = DMA1_Stream5; // DMA1_Stream5 is the only DMA channel for DAC

_hdma.Init.Channel = DMA_CHANNEL_7;
_hdma.Init.Direction = DMA_MEMORY_TO_PERIPH;
_hdma.Init.PeriphInc = DMA_PINC_DISABLE;
_hdma.Init.MemInc = DMA_MINC_ENABLE;
_hdma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
_hdma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
_hdma.Init.Mode = DMA_CIRCULAR;
_hdma.Init.Priority = DMA_PRIORITY_LOW;
_hdma.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
_hdma.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
_hdma.Init.MemBurst = DMA_MBURST_SINGLE;
// Single mem burst is more ressource consuming than 4 burst or more
// However the buffer apparently needs to be of a size multiple of the burst mode chosen
_hdma.Init.PeriphBurst = DMA_PBURST_SINGLE;

_hal.HAL_DMA_Init(&_hdma);
}
86 changes: 86 additions & 0 deletions drivers/CoreDAC/source/CoreSTM32HalBasicTimer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Leka - LekaOS
// Copyright 2024 APF France handicap
// SPDX-License-Identifier: Apache-2.0

#include "CoreSTM32HalBasicTimer.h"
#include <cmath>

using namespace leka;

CoreSTM32HalBasicTimer::CoreSTM32HalBasicTimer(interface::STM32Hal &hal) : _hal(hal)
{
_htim.Instance = TIM6;
}

auto CoreSTM32HalBasicTimer::getHandle() -> TIM_HandleTypeDef &
{
return _htim;
}

void CoreSTM32HalBasicTimer::registerCallback(std::function<void()> const &callback)
{
_callback = callback;
}

void CoreSTM32HalBasicTimer::initialize(float frequency)
{
_registerMspCallbacks();

// CK_Timer = CK_INT / ((Prescaler + 1) * (Period + 1))
const auto CK_INT = float {108'000'000.0};
auto divider = static_cast<int>(std::round(CK_INT / frequency));

_htim.Init.Prescaler = 0;
_htim.Init.Period = divider - 1; // ? min 1
_htim.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
_hal.HAL_TIM_Base_Init(&_htim);

auto timerMasterConfig = TIM_MasterConfigTypeDef {};
timerMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
_hal.HAL_TIMEx_MasterConfigSynchronization(&_htim, &timerMasterConfig);

static const auto &self = *this;
_hal.HAL_TIM_RegisterCallback(&_htim, HAL_TIM_PERIOD_ELAPSED_CB_ID, []([[maybe_unused]] TIM_HandleTypeDef *htim) {
if (self._callback != nullptr) {
self._callback();
}
});
}

void CoreSTM32HalBasicTimer::_registerMspCallbacks()
{
static const auto &self = *this;

_hal.HAL_TIM_RegisterCallback(&_htim, HAL_TIM_BASE_MSPINIT_CB_ID, []([[maybe_unused]] TIM_HandleTypeDef *htim) {
self._hal.HAL_RCC_TIM6_CLK_ENABLE();

self._hal.HAL_NVIC_SetPriority(TIM6_DAC_IRQn, 0x00, 0x00);
self._hal.HAL_NVIC_EnableIRQ(TIM6_DAC_IRQn);
});

_hal.HAL_TIM_RegisterCallback(&_htim, HAL_TIM_BASE_MSPDEINIT_CB_ID, []([[maybe_unused]] TIM_HandleTypeDef *htim) {
self._hal.HAL_RCC_TIM6_CLK_DISABLE();
});
}

void CoreSTM32HalBasicTimer::linkDACTimer(DAC_ChannelConfTypeDef *config)
{
if (config != nullptr) {
config->DAC_Trigger = DAC_TRIGGER_T6_TRGO;
}
}

void CoreSTM32HalBasicTimer::terminate()
{
_hal.HAL_TIM_Base_DeInit(&_htim);
}

void CoreSTM32HalBasicTimer::start()
{
_hal.HAL_TIM_Base_Start_IT(&_htim);
}

void CoreSTM32HalBasicTimer::stop()
{
_hal.HAL_TIM_Base_Stop_IT(&_htim);
}
Loading
Loading