Skip to content

Commit 54fa988

Browse files
ledneczkirleh
authored andcommitted
[I2S] Add first draft of I2S master configuration
Clock divider for the I2S peripheral is done compile time.
1 parent 202c862 commit 54fa988

File tree

6 files changed

+260
-9
lines changed

6 files changed

+260
-9
lines changed

src/modm/board/disco_f407vg/board.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ struct SystemClock {
4545
static constexpr uint32_t Spi5 = Apb2;
4646
static constexpr uint32_t Spi6 = Apb2;
4747

48+
static constexpr uint32_t I2s2 = Spi2;
49+
static constexpr uint32_t I2s3 = Spi3;
50+
51+
static constexpr uint32_t I2sPll = 86_MHz;
52+
4853
static constexpr uint32_t Usart1 = Apb2;
4954
static constexpr uint32_t Usart2 = Apb1;
5055
static constexpr uint32_t Usart3 = Apb1;
@@ -202,7 +207,7 @@ initializeCs43()
202207
{
203208
cs43::I2sMaster::connect<cs43::Mclk::Mck, cs43::Sclk::Ck,
204209
cs43::Lrck::Ws, cs43::Sdin::Sd>();
205-
210+
cs43::I2sMaster::initialize<SystemClock, 48_kHz>();
206211
cs43::Reset::setOutput(modm::Gpio::High);
207212

208213
cs43::I2cMaster::connect<cs43::Scl::Scl, cs43::Sda::Sda>();
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/*
2+
* Copyright (c) 2013, Kevin Läufer
3+
* Copyright (c) 2013-2017, Niklas Hauser
4+
* Copyright (c) 2014, Daniel Krebs
5+
* Copyright (c) 2020, Mike Wolfram,
6+
* Copyright (c) 2021, Marton Ledneczki
7+
*
8+
* This file is part of the modm project.
9+
*
10+
* This Source Code Form is subject to the terms of the Mozilla Public
11+
* License, v. 2.0. If a copy of the MPL was not distributed with this
12+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
13+
*/
14+
// ----------------------------------------------------------------------------
15+
16+
#ifndef MODM_STM32_I2S_BASE_HPP
17+
#define MODM_STM32_I2S_BASE_HPP
18+
19+
#include <stdint.h>
20+
#include "../device.hpp"
21+
#include <modm/architecture/interface/register.hpp>
22+
23+
namespace modm
24+
{
25+
26+
namespace platform
27+
{
28+
29+
/**
30+
* Base class for the I2S classes
31+
*
32+
* Provides some common enum that do not depend on the specific I2S.
33+
*
34+
* @author Marton Ledneczki
35+
* @ingroup modm_platform_i2s
36+
*/
37+
class I2sBase
38+
{
39+
public:
40+
enum class
41+
Interrupt : uint32_t
42+
{
43+
RxBufferNotEmpty = SPI_CR2_RXNEIE,
44+
TxBufferEmpty = SPI_CR2_TXEIE,
45+
Error = SPI_CR2_ERRIE,
46+
RxDmaEnable = SPI_CR2_RXDMAEN,
47+
TxDmaEnable = SPI_CR2_TXDMAEN,
48+
};
49+
MODM_FLAGS32(Interrupt);
50+
51+
enum class
52+
InterruptFlag : uint32_t
53+
{
54+
TxBufferEmpty = SPI_SR_TXE,
55+
RxBufferNotEmpty = SPI_SR_RXNE,
56+
CrcError = SPI_SR_CRCERR,
57+
ModeFaultError = SPI_SR_MODF,
58+
OverrunError = SPI_SR_OVR,
59+
Busy = SPI_SR_BSY,
60+
};
61+
MODM_FLAGS32(InterruptFlag);
62+
63+
enum class
64+
MasterSelection : uint32_t
65+
{
66+
Slave = 0b0, ///< Configure I2S as Slave
67+
Master = SPI_I2SCFGR_I2SCFG_1, ///< Configure I2S as Master
68+
All = Master,
69+
};
70+
71+
enum class
72+
DirectionSelection : uint32_t
73+
{
74+
Transmitter = 0b0, ///< Configure I2S as Transmitter
75+
Receiver = SPI_I2SCFGR_I2SCFG_0, ///< COnfigure I2S as Receiver
76+
All = Receiver,
77+
};
78+
79+
enum class
80+
BitDepth : uint32_t
81+
{
82+
Sixteen = 0b0,
83+
Twentyfour = SPI_I2SCFGR_DATLEN_0,
84+
Thirtytwo = SPI_I2SCFGR_DATLEN_1,
85+
All = Thirtytwo,
86+
};
87+
88+
enum class
89+
MasterClockOutput : uint32_t
90+
{
91+
Disabled = 0b0,
92+
Enabled = SPI_I2SPR_MCKOE,
93+
All = Enabled,
94+
};
95+
96+
enum class
97+
OddFactor : uint32_t
98+
{
99+
Disabled = 0,
100+
Enabled = SPI_I2SPR_ODD,
101+
All = Enabled,
102+
};
103+
};
104+
105+
} // namespace platform
106+
107+
} // namespace modm
108+
109+
#endif // MODM_STM32_I2S_BASE_HPP
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
/*
2+
* Copyright (c) 2013, Kevin Läufer
3+
* Copyright (c) 2013-2018, Niklas Hauser
4+
* Copyright (c) 2014, Daniel Krebs
5+
* Copyright (c) 2020, Mike Wolfram
6+
* Copyright (c) 2021, Marton Ledneczki
7+
*
8+
* This file is part of the modm project.
9+
*
10+
* This Source Code Form is subject to the terms of the Mozilla Public
11+
* License, v. 2.0. If a copy of the MPL was not distributed with this
12+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
13+
*/
14+
// ----------------------------------------------------------------------------
15+
16+
#ifndef MODM_STM32_I2S_HAL{{ id }}_HPP
17+
#define MODM_STM32_I2S_HAL{{ id }}_HPP
18+
19+
#include "i2s_base.hpp"
20+
21+
namespace modm
22+
{
23+
24+
namespace platform
25+
{
26+
27+
/**
28+
* Serial peripheral interface (I2S{{ id }})
29+
*
30+
* TODO: Very basic implementation that exposes more hardware features than
31+
* the regular Spi classes.
32+
*
33+
* @author Marton Ledneczki
34+
* @ingroup modm_platform_i2s modm_platform_i2s_{{id}}
35+
*/
36+
class I2sHal{{ id }} : public I2sBase
37+
{
38+
public:
39+
/// TODO: Enables the clock, resets the hardware and sets the SPE bit
40+
static void
41+
enable();
42+
43+
/// Disables the hw module (by disabling its clock line)
44+
static void
45+
disable();
46+
47+
/**
48+
* Initialize I2s Peripheral
49+
*
50+
* TODO: Enables clocks
51+
*/
52+
static void
53+
initialize( OddFactor oddFactor, uint8_t i2s_div,
54+
MasterSelection masterSelection = MasterSelection::Master,
55+
DirectionSelection directionSelection = DirectionSelection::Transmitter,
56+
BitDepth bitDepth = BitDepth::Sixteen,
57+
MasterClockOutput masterClockOutput = MasterClockOutput::Enabled);
58+
};
59+
60+
} // namespace platform
61+
62+
} // namespace modm
63+
64+
#include "i2s_hal_{{ id }}_impl.hpp"
65+
66+
#endif // MODM_STM32_I2S_HAL{{ id }}_HPP
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright (c) 2013, Kevin Läufer
3+
* Copyright (c) 2013-2017, Niklas Hauser
4+
* Copyright (c) 2014, Daniel Krebs
5+
* Copyright (c) 2020, Mike Wolfram
6+
* Copyright (c) 2021, Marton Ledneczki
7+
*
8+
* This file is part of the modm project.
9+
*
10+
* This Source Code Form is subject to the terms of the Mozilla Public
11+
* License, v. 2.0. If a copy of the MPL was not distributed with this
12+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
13+
*/
14+
// ----------------------------------------------------------------------------
15+
16+
#ifndef MODM_STM32_I2S_HAL{{ id }}_HPP
17+
# error "Don't include this file directly, use 'i2s_hal{{ id }}.hpp' instead!"
18+
#endif
19+
#include <modm/platform/clock/rcc.hpp>
20+
21+
void inline
22+
modm::platform::I2sHal{{ id }}::enable()
23+
{
24+
Rcc::enable<Peripheral::Spi{{id}}>();
25+
SPI{{ id }}->I2SCFGR |= SPI_I2SCFGR_I2SMOD | SPI_I2SCFGR_I2SE; // I2S Enable
26+
}
27+
28+
void inline
29+
modm::platform::I2sHal{{ id }}::disable()
30+
{
31+
SPI{{ id }}->I2SCFGR &= ~(uint32_t)SPI_I2SCFGR_I2SE;
32+
Rcc::disable<Peripheral::Spi{{id}}>();
33+
}
34+
35+
void inline
36+
modm::platform::I2sHal{{ id }}::initialize( OddFactor oddFactor, uint8_t i2s_div,
37+
MasterSelection masterSelection,
38+
DirectionSelection directionSelection,
39+
BitDepth bitDepth,
40+
MasterClockOutput masterClockOutput)
41+
{
42+
enable();
43+
// disable peripheral, and clear fields to be set
44+
SPI{{ id }}->I2SCFGR &= ~(uint32_t)(SPI_I2SCFGR_I2SE | SPI_I2SCFGR_I2SCFG | SPI_I2SCFGR_PCMSYNC |
45+
SPI_I2SCFGR_I2SSTD | SPI_I2SCFGR_CKPOL | SPI_I2SCFGR_DATLEN |
46+
SPI_I2SCFGR_CHLEN);
47+
SPI{{ id }}->I2SPR &= ~(uint32_t)(SPI_I2SPR_MCKOE | SPI_I2SPR_ODD | SPI_I2SPR_I2SDIV);
48+
// set parameters
49+
SPI{{ id }}->I2SCFGR |= static_cast<uint32_t>(masterSelection) |
50+
static_cast<uint32_t>(directionSelection) |
51+
static_cast<uint32_t>(bitDepth);
52+
SPI{{ id }}->I2SPR |= static_cast<uint32_t>(masterClockOutput) |
53+
static_cast<uint32_t>(oddFactor) |
54+
i2s_div;
55+
// re-enable peripheral
56+
SPI{{ id }}->I2SCFGR |= SPI_I2SCFGR_I2SE;
57+
}

src/modm/platform/i2s/stm32/i2s_master.hpp.in

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,10 +18,12 @@
1818
#ifndef MODM_STM32_I2S_MASTER{{ id }}_HPP
1919
#define MODM_STM32_I2S_MASTER{{ id }}_HPP
2020

21+
#include <cstdlib>
22+
2123
#include <modm/architecture/interface/i2s_master.hpp>
2224
#include <modm/platform/gpio/connector.hpp>
2325
#include <modm/math/algorithm/prescaler.hpp>
24-
//#include "i2s_hal_{{ id }}.hpp" TODO
26+
#include "i2s_hal_{{ id }}.hpp"
2527

2628
namespace modm
2729
{
@@ -40,11 +42,9 @@ namespace platform
4042
class I2sMaster{{ id }} : public modm::I2sMaster
4143
{
4244
public:
43-
//using Hal = I2sHal{{ id }}; TODO
45+
using Hal = I2sHal{{ id }};
4446

45-
//using DataSize = Hal::DataSize; TODO
4647

47-
public:
4848
template< template<Peripheral _> class... Signals >
4949
static void
5050
connect()
@@ -63,7 +63,21 @@ public:
6363
Connector::connect();
6464
}
6565

66-
66+
template< class SystemClock, frequency_t samplerate, percent_t tolerance=pct(0.019) >
67+
static inline void
68+
initialize()
69+
{
70+
constexpr float prescaler = static_cast<float>(SystemClock::I2sPll) / (samplerate*16*2*8);
71+
constexpr uint8_t i2s_div = static_cast<uint8_t>(prescaler/2);
72+
constexpr uint8_t odd_factor = ((prescaler - static_cast<float>(i2s_div*2)) >= 0.5) ? 1 : 0;
73+
constexpr float real_samplerate = static_cast<float>(SystemClock::I2sPll) /
74+
(16*2*8*(2*i2s_div+odd_factor));
75+
static_assert(i2s_div > 1, "I2S{{ id }}: i2s_div can not be 1 or 0!");
76+
static_assert(abs(samplerate - real_samplerate)/static_cast<float>(samplerate) < pct2f(tolerance),
77+
"I2S{{ id }}: Exceeding specified tolerance, when determining prescelar.");
78+
Hal::initialize(odd_factor ? Hal::OddFactor::Enabled : Hal::OddFactor::Disabled,
79+
i2s_div);
80+
}
6781
// end documentation inherited
6882
};
6983

src/modm/platform/i2s/stm32/module.lb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,8 @@ class Instance(Module):
4040
env.substitutions = properties
4141
env.outbasepath = "modm/src/modm/platform/i2s"
4242

43-
#env.template("i2s_hal.hpp.in", "i2s_hal_{}.hpp".format(self.instance))
44-
#env.template("i2s_hal_impl.hpp.in", "i2s_hal_{}_impl.hpp".format(self.instance))
43+
env.template("i2s_hal.hpp.in", "i2s_hal_{}.hpp".format(self.instance))
44+
env.template("i2s_hal_impl.hpp.in", "i2s_hal_{}_impl.hpp".format(self.instance))
4545
env.template("i2s_master.hpp.in", "i2s_master_{}.hpp".format(self.instance))
4646
#env.template("i2s_master.cpp.in", "i2s_master_{}.cpp".format(self.instance))
4747
if env.has_module(":platform:dma"):
@@ -77,4 +77,4 @@ def build(env):
7777
env.substitutions = get_properties(env)
7878
env.outbasepath = "modm/src/modm/platform/i2s"
7979

80-
#env.template("i2s_base.hpp.in")
80+
env.template("i2s_base.hpp.in")

0 commit comments

Comments
 (0)