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/feature/audio/audiokit in os #1426

Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/os/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ target_link_libraries(LekaOS
IMUKit
MotionKit
EventLoopKit
CoreDAC
AudioKit
)

target_link_custom_leka_targets(LekaOS)
28 changes: 25 additions & 3 deletions app/os/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
#include "rtos/Thread.h"

#include "ActivityKit.h"
#include "AudioKit.h"
#include "ChooseReinforcer.h"
#include "CoreBattery.h"
#include "CoreBufferedSerial.h"
#include "CoreDAC.h"
#include "CoreDMA2D.hpp"
#include "CoreDSI.hpp"
#include "CoreFlashIS25LP016D.h"
Expand All @@ -37,6 +39,7 @@
#include "CoreSDRAM.hpp"
#include "CoreSPI.h"
#include "CoreSTM32Hal.h"
#include "CoreSTM32HalBasicTimer.h"
#include "CoreTimeout.h"
#include "CoreVideo.hpp"
#include "DisplayTags.h"
Expand Down Expand Up @@ -65,6 +68,7 @@
#include "SuperSimon.h"
#include "VideoKit.h"
#include "bootutil/bootutil.h"
#include "commands/BehaviorCommand.h"
#include "commands/LedFullCommand.h"
#include "commands/LedRangeCommand.h"
#include "commands/LedSingleCommand.h"
Expand Down Expand Up @@ -229,14 +233,28 @@ namespace motors {

} // namespace motors

auto hal = CoreSTM32Hal {};

namespace audio {

namespace internal {

extern "C" auto hal_timer = CoreSTM32HalBasicTimer {hal};
extern "C" auto coredac = CoreDAC {hal, hal_timer};

} // namespace internal

auto kit = AudioKit {internal::hal_timer, internal::coredac};

} // namespace audio

namespace display::internal {

auto event_loop = EventLoopKit {};
auto backlight = CorePwm {SCREEN_BACKLIGHT_PWM};

auto corell = CoreLL {};
auto pixel = CGPixel {corell};
auto hal = CoreSTM32Hal {};
auto coresdram = CoreSDRAM {hal};
auto coredma2d = CoreDMA2D {hal};
auto coredsi = CoreDSI {hal};
Expand Down Expand Up @@ -278,8 +296,8 @@ namespace motion::internal {

auto motionkit = MotionKit {motors::left::motor, motors::right::motor, imukit, motion::internal::timeout};

auto behaviorkit = BehaviorKit {videokit, ledkit, motors::left::motor, motors::right::motor};
auto reinforcerkit = ReinforcerKit {videokit, ledkit, motionkit};
auto behaviorkit = BehaviorKit {videokit, ledkit, motors::left::motor, motors::right::motor, audio::kit};
auto reinforcerkit = ReinforcerKit {videokit, ledkit, audio::kit, motionkit};

namespace command {

Expand All @@ -292,6 +310,7 @@ namespace command {
auto led_range = LedRangeCommand {leds::ears, leds::belt};
auto motors = MotorsCommand {motors::left::motor, motors::right::motor};
auto reinforcer = ReinforcerCommand {reinforcerkit};
auto behavior = BehaviorCommand {behaviorkit};

} // namespace internal

Expand All @@ -301,6 +320,7 @@ namespace command {
&internal::led_range,
&internal::motors,
&internal::reinforcer,
&internal::behavior,
});

} // namespace command
Expand Down Expand Up @@ -565,6 +585,8 @@ auto main() -> int
imu::lsm6dsox.init();
imukit.init();

audio::kit.initialize();

robot::controller.initializeComponents();
robot::controller.registerOnUpdateLoadedCallback(firmware::setPendingUpdate);
robot::controller.registerOnFactoryResetNotificationCallback(factory_reset::set);
Expand Down
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/drivers/DAC.h"
#include "interface/drivers/STM32Hal.h"
#include "interface/drivers/STM32HalBasicTimer.h"

namespace leka {

class CoreDAC : public interface::DACDMA
{
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) final;
void registerDMACallbacks(std::function<void()> const &on_half_transfer,
std::function<void()> const &on_complete_transfer) final;

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/drivers/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
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);
}
Loading
Loading