Skip to content

Commit

Permalink
✨ (dac): Add CoreDAC
Browse files Browse the repository at this point in the history
Co-Authored-By: Maxime Blanc <[email protected]>
Co-Authored-By: SamHadjes <[email protected]>
  • Loading branch information
3 people committed Jul 2, 2024
1 parent fc899b1 commit 44e1993
Show file tree
Hide file tree
Showing 11 changed files with 295 additions and 1 deletion.
4 changes: 4 additions & 0 deletions config/mbed_app.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
"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/CoreDAC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ target_include_directories(CoreDAC
target_sources(CoreDAC
PRIVATE
source/CoreSTM32HalBasicTimer.cpp
source/CoreDAC.cpp
)

if(NOT(${CMAKE_PROJECT_NAME} STREQUAL "LekaOSUnitTests"))
Expand Down
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/drivers/DAC.h"
#include "interface/drivers/STM32Hal.h"
#include "interface/drivers/STM32HalBasicTimer.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
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);
}
9 changes: 8 additions & 1 deletion drivers/CoreDAC/source/HAL_IRQHandlers.cpp
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
#include "CoreDAC.h"
#include "CoreSTM32HalBasicTimer.h"

extern "C" {

namespace audio::internal {
extern leka::CoreSTM32HalBasicTimer hal_timer;
}
extern leka::CoreDAC coredac;
} // namespace audio::internal

void TIM6_DAC_IRQHandler()
{
Expand All @@ -16,4 +18,9 @@ void TIM7_DAC_IRQHandler()
HAL_TIM_IRQHandler(&audio::internal::hal_timer.getHandle());
}

void DMA1_Stream5_IRQHandler()
{
HAL_DMA_IRQHandler(audio::internal::coredac.getHandle().DMA_Handle1);
}

} // extern "C"
14 changes: 14 additions & 0 deletions drivers/CoreSTM32Hal/include/CoreSTM32Hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ class CoreSTM32Hal : public interface::STM32Hal

void HAL_RCC_FMC_CLK_ENABLE() final;

void HAL_RCC_DMA1_CLK_ENABLE() final;
void HAL_RCC_DMA2_CLK_ENABLE() final;

void HAL_RCC_DAC_CLK_ENABLE() final;
void HAL_RCC_DAC_CLK_DISABLE() final;

void HAL_RCC_JPEG_CLK_ENABLE() final;
void HAL_RCC_JPEG_FORCE_RESET() final;
void HAL_RCC_JPEG_RELEASE_RESET() final;
Expand Down Expand Up @@ -118,6 +122,16 @@ class CoreSTM32Hal : public interface::STM32Hal
auto HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim) -> HAL_StatusTypeDef final;
auto HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim) -> HAL_StatusTypeDef final;
auto HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim) -> HAL_StatusTypeDef final;

auto HAL_DAC_Init(DAC_HandleTypeDef *hdac) -> HAL_StatusTypeDef final;
auto HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel)
-> HAL_StatusTypeDef final;
auto HAL_DAC_RegisterCallback(DAC_HandleTypeDef *hdac, HAL_DAC_CallbackIDTypeDef CallbackID,
pDAC_CallbackTypeDef pCallback) -> HAL_StatusTypeDef final;
auto HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t *pData, uint32_t Length,
uint32_t Alignment) -> HAL_StatusTypeDef final;
auto HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel) -> HAL_StatusTypeDef final;
auto HAL_DAC_DeInit(DAC_HandleTypeDef *hdac) -> HAL_StatusTypeDef final;
};

} // namespace leka
48 changes: 48 additions & 0 deletions drivers/CoreSTM32Hal/source/CoreSTM32Hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,26 @@ void CoreSTM32Hal::HAL_RCC_FMC_CLK_ENABLE()
__HAL_RCC_FMC_CLK_ENABLE(); // NOLINT
}

void CoreSTM32Hal::HAL_RCC_DMA1_CLK_ENABLE()
{
__HAL_RCC_DMA1_CLK_ENABLE(); // NOLINT
}

void CoreSTM32Hal::HAL_RCC_DMA2_CLK_ENABLE()
{
__HAL_RCC_DMA2_CLK_ENABLE(); // NOLINT
}

void CoreSTM32Hal::HAL_RCC_DAC_CLK_ENABLE()
{
__HAL_RCC_DAC_CLK_ENABLE(); // NOLINT
}

void CoreSTM32Hal::HAL_RCC_DAC_CLK_DISABLE()
{
__HAL_RCC_DAC_CLK_DISABLE(); // NOLINT
}

void CoreSTM32Hal::HAL_RCC_JPEG_CLK_ENABLE()
{
__HAL_RCC_JPEG_CLK_ENABLE(); // NOLINT
Expand Down Expand Up @@ -363,4 +378,37 @@ auto CoreSTM32Hal::HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim) -> HAL_StatusTyp
return ::HAL_TIM_Base_DeInit(htim);
}

auto CoreSTM32Hal::HAL_DAC_Init(DAC_HandleTypeDef *hdac) -> HAL_StatusTypeDef
{
return ::HAL_DAC_Init(hdac);
}

auto CoreSTM32Hal::HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel)
-> HAL_StatusTypeDef
{
return ::HAL_DAC_ConfigChannel(hdac, sConfig, Channel);
}

auto CoreSTM32Hal::HAL_DAC_RegisterCallback(DAC_HandleTypeDef *hdac, HAL_DAC_CallbackIDTypeDef CallbackID,
pDAC_CallbackTypeDef pCallback) -> HAL_StatusTypeDef
{
return ::HAL_DAC_RegisterCallback(hdac, CallbackID, pCallback);
}

auto CoreSTM32Hal::HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t *pData, uint32_t Length,
uint32_t Alignment) -> HAL_StatusTypeDef
{
return ::HAL_DAC_Start_DMA(hdac, Channel, pData, Length, Alignment);
}

auto CoreSTM32Hal::HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel) -> HAL_StatusTypeDef
{
return ::HAL_DAC_Stop_DMA(hdac, Channel);
}

auto CoreSTM32Hal::HAL_DAC_DeInit(DAC_HandleTypeDef *hdac) -> HAL_StatusTypeDef
{
return ::HAL_DAC_DeInit(hdac);
}

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

#pragma once

#include "interface/drivers/STM32Hal.h"

namespace leka::interface {

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

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

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

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

} // namespace leka::interface
14 changes: 14 additions & 0 deletions include/interface/drivers/STM32Hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,12 @@ class STM32Hal

virtual void HAL_RCC_FMC_CLK_ENABLE() = 0;

virtual void HAL_RCC_DMA1_CLK_ENABLE() = 0;
virtual void HAL_RCC_DMA2_CLK_ENABLE() = 0;

virtual void HAL_RCC_DAC_CLK_ENABLE() = 0;
virtual void HAL_RCC_DAC_CLK_DISABLE() = 0;

virtual void HAL_RCC_JPEG_CLK_ENABLE() = 0;
virtual void HAL_RCC_JPEG_FORCE_RESET() = 0;
virtual void HAL_RCC_JPEG_RELEASE_RESET() = 0;
Expand Down Expand Up @@ -121,6 +125,16 @@ class STM32Hal
virtual auto HAL_TIM_Base_Start_IT(TIM_HandleTypeDef *htim) -> HAL_StatusTypeDef = 0;
virtual auto HAL_TIM_Base_Stop_IT(TIM_HandleTypeDef *htim) -> HAL_StatusTypeDef = 0;
virtual auto HAL_TIM_Base_DeInit(TIM_HandleTypeDef *htim) -> HAL_StatusTypeDef = 0;

virtual auto HAL_DAC_Init(DAC_HandleTypeDef *hdac) -> HAL_StatusTypeDef = 0;
virtual auto HAL_DAC_ConfigChannel(DAC_HandleTypeDef *hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel)
-> HAL_StatusTypeDef = 0;
virtual auto HAL_DAC_RegisterCallback(DAC_HandleTypeDef *hdac, HAL_DAC_CallbackIDTypeDef CallbackID,
pDAC_CallbackTypeDef pCallback) -> HAL_StatusTypeDef = 0;
virtual auto HAL_DAC_Start_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel, uint32_t *pData, uint32_t Length,
uint32_t Alignment) -> HAL_StatusTypeDef = 0;
virtual auto HAL_DAC_Stop_DMA(DAC_HandleTypeDef *hdac, uint32_t Channel) -> HAL_StatusTypeDef = 0;
virtual auto HAL_DAC_DeInit(DAC_HandleTypeDef *hdac) -> HAL_StatusTypeDef = 0;
};

} // namespace leka::interface
1 change: 1 addition & 0 deletions tests/unit/headers/mbed/mbed_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@
#define TARGET_LSE_DRIVE_LOAD_LEVEL RCC_LSEDRIVE_LOW // set by target:MCU_STM32F7
#define USE_HAL_JPEG_REGISTER_CALLBACKS 1U // set by application
#define USE_HAL_TIM_REGISTER_CALLBACKS 1U // set by application
#define USE_HAL_DAC_REGISTER_CALLBACKS 1U // set by application
// Macros
#define WSF_MS_PER_TICK 1 // defined by library:cordio
#define _RTE_ // defined by library:rtos
Expand Down
15 changes: 15 additions & 0 deletions tests/unit/mocks/mocks/leka/CoreSTM32Hal.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,10 @@ class CoreSTM32Hal : public interface::STM32Hal
MOCK_METHOD(void, HAL_RCC_TIM7_CLK_ENABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_TIM7_CLK_DISABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_FMC_CLK_ENABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_DMA1_CLK_ENABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_DMA2_CLK_ENABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_DAC_CLK_ENABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_DAC_CLK_DISABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_JPEG_CLK_ENABLE, (), (override));
MOCK_METHOD(void, HAL_RCC_JPEG_FORCE_RESET, (), (override));
MOCK_METHOD(void, HAL_RCC_JPEG_RELEASE_RESET, (), (override));
Expand Down Expand Up @@ -125,6 +128,18 @@ class CoreSTM32Hal : public interface::STM32Hal
MOCK_METHOD(HAL_StatusTypeDef, HAL_TIM_Base_Start_IT, (TIM_HandleTypeDef * htim), (override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_TIM_Base_Stop_IT, (TIM_HandleTypeDef * htim), (override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_TIM_Base_DeInit, (TIM_HandleTypeDef * htim), (override));

MOCK_METHOD(HAL_StatusTypeDef, HAL_DAC_Init, (DAC_HandleTypeDef * hdac), (override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_DAC_ConfigChannel,
(DAC_HandleTypeDef * hdac, DAC_ChannelConfTypeDef *sConfig, uint32_t Channel), (override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_DAC_RegisterCallback,
(DAC_HandleTypeDef * hdac, HAL_DAC_CallbackIDTypeDef CallbackID, pDAC_CallbackTypeDef pCallback),
(override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_DAC_Start_DMA,
(DAC_HandleTypeDef * hdac, uint32_t Channel, uint32_t *pData, uint32_t Length, uint32_t Alignment),
(override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_DAC_Stop_DMA, (DAC_HandleTypeDef * hdac, uint32_t Channel), (override));
MOCK_METHOD(HAL_StatusTypeDef, HAL_DAC_DeInit, (DAC_HandleTypeDef * hdac), (override));
};

} // namespace leka::mock

0 comments on commit 44e1993

Please sign in to comment.