-
Notifications
You must be signed in to change notification settings - Fork 154
I2S driver #769
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
Open
rleh
wants to merge
28
commits into
modm-io:develop
Choose a base branch
from
rleh:feature/i2s-stm32f407
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
I2S driver #769
Changes from 18 commits
Commits
Show all changes
28 commits
Select commit
Hold shift + click to select a range
8f66fcc
[architecture] I2sMaster created
ledneczki e158b11
[dma] Support double buffer (only stm32-stream-channel)
rleh 294b380
[rcc] Add support for I2S pll on STM32F4
ledneczki e8b8e36
[board] Disco-F469: MicroSD card connector
rleh 5a040e0
[stm32] I2S master implementation with DMA
ledneczki d51569b
[driver] Add CS43L22 audio DAC (I2S + I²C)
ledneczki 3bb021d
[board] Adapt STM32F4-Disco BSP for I2S DAC CS43L22
ledneczki ef6baee
[example] STM32F4-Disco: CS43L22 I2S DAC example
rleh 9d7cae5
[driver] Add MA12070P audio DAC (I2S + I²C)
rleh d31ea26
WIP [example] STM32F469-Disco: MA12070P I2S DAC example
rleh 1a8494b
fixup_example_cs43l22
rleh 9f243a2
fixup_platform_i2s
rleh 5251e28
fixup_architecture_i2s
rleh cb87fe0
fixup_rcc
rleh db6e309
fixup_ma12070p
rleh 7b42b83
fixup_cs43l22
rleh cc6cb20
fixup_disco_f407vg
rleh 9d38a46
fixup_example_ma12070p
rleh eacad10
fixup platform i2s: disable stm32h7
rleh 001c09a
fixup platform i2s: stm32f410 has no PllI2s
rleh 9b7d3e8
fixup driver ma12070p
rleh a4cffe6
fixup example stm32f469_discovery/audio_ma12070p
rleh 7406d7d
fixup audio_ma12070p: move to nucleo-f429 dev board
rleh a816af3
fixup example ma12070p: adapt changed I2sMaster API
rleh 3ead27e
fixup platform/i2s: fix prescaler calculation, i2s config is now temp…
rleh 2c85e4f
fixup dma: enable double buffer also for 'stm32-mux-stream' IP
rleh 4859b64
fixup driver ma12070p
rleh 812d354
fixup driver cs43l22
rleh File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,166 @@ | ||
/* | ||
* Copyright (c) 2022, Raphael Lehmann | ||
* Copyright (c) 2021, Christopher Durand | ||
* | ||
* This file is part of the modm project. | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. | ||
*/ | ||
// ---------------------------------------------------------------------------- | ||
|
||
#include <arm_math.h> | ||
#include <modm/board.hpp> | ||
#include <modm/processing.hpp> | ||
#include <modm/driver/dac/ma12070p.hpp> | ||
#include <modm/platform/i2c/i2c_master_1.hpp> | ||
#include <modm/platform/i2s/i2s_master_2.hpp> | ||
#include <numbers> | ||
#include <optional> | ||
|
||
using namespace Board; | ||
using namespace modm::literals; | ||
|
||
// I²C pins shared with touchscreen: | ||
using Scl = GpioB8; | ||
using Sda = GpioB9; | ||
using I2cMaster = modm::platform::I2cMaster1; | ||
using Ma12070p = modm::Ma12070p<I2cMaster>; | ||
|
||
using I2sWs = GpioOutputB12; | ||
using I2sMck = GpioOutputC6; | ||
using I2sCk = GpioOutputB13; | ||
using I2sData = GpioOutputC1; | ||
using DmaTx = Dma1::Channel4; | ||
using I2sMaster = modm::platform::I2sMaster2<DmaTx>; | ||
|
||
|
||
struct I2sSystemClock | ||
{ | ||
static constexpr uint32_t I2sPll = 86_MHz; | ||
|
||
static void | ||
enable() | ||
{ | ||
const Rcc::PllI2sFactors pllI2sFactors{ | ||
.pllN = 258, // 1 MHz * N=258 -> 258 MHz | ||
.pllR = 3 // 258 MHz / R=3 -> 86 MHz | ||
}; | ||
Rcc::enablePllI2s(pllI2sFactors); | ||
} | ||
}; | ||
|
||
constexpr uint8_t ma12070pAddressI2c = 0x20; | ||
Ma12070p ma12070p{ma12070pAddressI2c}; | ||
|
||
template<typename T, std::size_t length> | ||
constexpr auto computeSinTable(uint8_t cycles=1) | ||
{ | ||
std::array<T, length> data{}; | ||
constexpr auto HalfOutput = std::numeric_limits<T>::max() / 2; // 16 bit full scale | ||
for (size_t i = 0; i < data.size(); ++i) { | ||
constexpr auto pi = std::numbers::pi_v<float>; | ||
data[i] = HalfOutput * (1 + arm_sin_f32(i * (2*pi / data.size() * cycles))); | ||
} | ||
return data; | ||
} | ||
|
||
constexpr std::size_t bufferSize = 960; | ||
auto bufferA = computeSinTable<uint16_t, bufferSize>(1); | ||
auto bufferB = computeSinTable<uint16_t, bufferSize>(2); | ||
volatile bool bufferA_ready{true}; | ||
volatile bool bufferB_ready{true}; | ||
|
||
void | ||
transferCompleteIrqHandler() | ||
{ | ||
LedGreen::reset(); | ||
|
||
if (bufferA_ready) { | ||
I2sMaster::setTxBuffer(uintptr_t(bufferA.data()), bufferSize); | ||
bufferA_ready = false; | ||
} | ||
else if (bufferB_ready) { | ||
I2sMaster::setTxBuffer(uintptr_t(bufferB.data()), bufferSize); | ||
bufferB_ready = false; | ||
} | ||
else { | ||
LedRed::toggle(); | ||
//MODM_LOG_ERROR << "No buffer ready for DMA :(" << modm::endl; | ||
} | ||
I2sMaster::startDma(); | ||
|
||
LedGreen::set(); | ||
} | ||
|
||
int | ||
main() | ||
{ | ||
Board::initialize(); | ||
I2sSystemClock::enable(); | ||
Board::initializeTouchscreen(); // for I2c | ||
Dma1::enable(); | ||
Dma2::enable(); | ||
|
||
MODM_LOG_INFO << "Audio MA12070P demo on ST Discovery F469NI" << modm::endl; | ||
|
||
while (!RF_CALL_BLOCKING(ma12070p.initialize())) { | ||
MODM_LOG_ERROR << "Unable to initialize MA12070P" << modm::endl; | ||
} | ||
|
||
|
||
modm::ma12070p::I2sAndVlpConfig config { | ||
.pcmWordFormat = modm::ma12070p::PcmWordFormat::RightJustifed16b, | ||
.clockPolarity = modm::ma12070p::ClockPolarity::FallingEdge, | ||
.frameSize = modm::ma12070p::FrameSize::Bits32, | ||
.wordSelectPolarity = modm::ma12070p::WordSelectPolarity::High, | ||
.rightLeftOrder = modm::ma12070p::RightLeftOrder::LeftFirst, | ||
.useVlp = true, | ||
.useLimiter = true, | ||
}; | ||
while (!RF_CALL_BLOCKING(ma12070p.configureI2sAndVlp(config))) { | ||
MODM_LOG_ERROR << "Unable to configure I2S ansd VLP settings of MA12070P" << modm::endl; | ||
} | ||
|
||
while (!RF_CALL_BLOCKING(ma12070p.setMasterVolume(-20_q_db))) { | ||
MODM_LOG_ERROR << "Unable to set master volume of MA12070P" << modm::endl; | ||
} | ||
|
||
std::optional<modm::ma12070p::VlpMonitor_t> vlpMonitor; | ||
std::optional<modm::ma12070p::ErrorRegister_t> errorRegister; | ||
|
||
I2sMaster::connect<I2sMck::Mck, I2sCk::Ck, I2sWs::Ws, I2sData::Sd>(); | ||
I2sMaster::initialize<I2sSystemClock, 48_kHz, 1_pct>( | ||
I2sMaster::BitDepth::SixteenWithChannel16, | ||
I2sMaster::MasterClockOutput::Enabled, | ||
I2sMaster::I2sStandard::Philips); | ||
|
||
I2sMaster::setTransferCompleteIrqHandler(transferCompleteIrqHandler); | ||
I2sMaster::setTxBuffer(uintptr_t(bufferA.data()), bufferSize); | ||
I2sMaster::start(); | ||
|
||
while (true) | ||
{ | ||
vlpMonitor = RF_CALL_BLOCKING(ma12070p.readVlpMonitor()); | ||
if(!vlpMonitor) { | ||
MODM_LOG_ERROR << "Unable to read VLP monitor register" << modm::endl; | ||
} | ||
else { | ||
MODM_LOG_ERROR << *vlpMonitor << modm::endl; | ||
} | ||
errorRegister = RF_CALL_BLOCKING(ma12070p.readAccumulatedErrors()); | ||
if(!errorRegister) { | ||
MODM_LOG_ERROR << "Unable to read accumulated error register" << modm::endl; | ||
} | ||
else { | ||
MODM_LOG_ERROR << *errorRegister << modm::endl; | ||
} | ||
|
||
if (I2sMaster::hasDmaError()) { | ||
MODM_LOG_ERROR << "I2S DMA Error :(" << modm::endl; | ||
} | ||
} | ||
|
||
return 0; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<library> | ||
<extends>modm:disco-f469ni</extends> | ||
<options> | ||
<option name="modm:build:build.path">../../../build/stm32f469_discovery/audio_ma12070p</option> | ||
</options> | ||
<modules> | ||
<module>modm:build:scons</module> | ||
<module>modm:cmsis:dsp:fast_math</module> | ||
<module>modm:driver:ma12070p</module> | ||
<module>modm:platform:i2c:1</module> | ||
<module>modm:platform:i2s:2</module> | ||
<module>modm:processing:timer</module> | ||
</modules> | ||
</library> |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.