Skip to content

Commit 5a040e0

Browse files
ledneczkirleh
andcommitted
[stm32] I2S master implementation with DMA
Co-authored-by: Raphael Lehmann <[email protected]>
1 parent e8b8e36 commit 5a040e0

File tree

6 files changed

+573
-0
lines changed

6 files changed

+573
-0
lines changed

README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,26 @@ Please [discover modm's peripheral drivers for your specific device][discover].
325325
<td align="center">✅</td>
326326
<td align="center">✅</td>
327327
</tr><tr>
328+
<td align="left">I2S</td>
329+
<td align="center">✅</td>
330+
<td align="center">✅</td>
331+
<td align="center">✅</td>
332+
<td align="center">✅</td>
333+
<td align="center">✅</td>
334+
<td align="center">✅</td>
335+
<td align="center">✅</td>
336+
<td align="center">✅</td>
337+
<td align="center">✅</td>
338+
<td align="center">✅</td>
339+
<td align="center">✅</td>
340+
<td align="center">✕</td>
341+
<td align="center">○</td>
342+
<td align="center">✕</td>
343+
<td align="center">✕</td>
344+
<td align="center">✕</td>
345+
<td align="center">✕</td>
346+
<td align="center">✕</td>
347+
</tr><tr>
328348
<td align="left">I<sup>2</sup>C</td>
329349
<td align="center">✅</td>
330350
<td align="center">✅</td>
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
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+
* Copyright (c) 2021-2022, Raphael Lehmann
8+
*
9+
* This file is part of the modm project.
10+
*
11+
* This Source Code Form is subject to the terms of the Mozilla Public
12+
* License, v. 2.0. If a copy of the MPL was not distributed with this
13+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
14+
*/
15+
// ----------------------------------------------------------------------------
16+
17+
#ifndef MODM_STM32_I2S_BASE_HPP
18+
#define MODM_STM32_I2S_BASE_HPP
19+
20+
#include <stdint.h>
21+
#include "../device.hpp"
22+
#include <modm/architecture/interface/register.hpp>
23+
24+
namespace modm
25+
{
26+
27+
namespace platform
28+
{
29+
30+
/**
31+
* Base class for the I2S classes
32+
*
33+
* Provides some common enum that do not depend on the specific I2S.
34+
*
35+
* @author Marton Ledneczki
36+
* @ingroup modm_platform_i2s
37+
*/
38+
class I2sBase
39+
{
40+
public:
41+
enum class
42+
Interrupt : uint32_t
43+
{
44+
RxBufferNotEmpty = SPI_CR2_RXNEIE,
45+
TxBufferEmpty = SPI_CR2_TXEIE,
46+
Error = SPI_CR2_ERRIE,
47+
RxDmaEnable = SPI_CR2_RXDMAEN,
48+
TxDmaEnable = SPI_CR2_TXDMAEN,
49+
};
50+
MODM_FLAGS32(Interrupt);
51+
52+
enum class
53+
InterruptFlag : uint32_t
54+
{
55+
TxBufferEmpty = SPI_SR_TXE,
56+
RxBufferNotEmpty = SPI_SR_RXNE,
57+
CrcError = SPI_SR_CRCERR,
58+
ModeFaultError = SPI_SR_MODF,
59+
OverrunError = SPI_SR_OVR,
60+
Busy = SPI_SR_BSY,
61+
};
62+
MODM_FLAGS32(InterruptFlag);
63+
64+
enum class
65+
MasterSelection : uint32_t
66+
{
67+
Slave = 0b0, ///< Configure I2S as Slave
68+
Master = SPI_I2SCFGR_I2SCFG_1, ///< Configure I2S as Master
69+
All = Master,
70+
};
71+
72+
enum class
73+
DirectionSelection : uint32_t
74+
{
75+
Transmitter = 0b0, ///< Configure I2S as Transmitter
76+
Receiver = SPI_I2SCFGR_I2SCFG_0, ///< COnfigure I2S as Receiver
77+
All = Receiver,
78+
};
79+
80+
enum class
81+
BitDepth : uint32_t
82+
{
83+
Sixteen = 0b0,
84+
Twentyfour = SPI_I2SCFGR_DATLEN_0,
85+
Thirtytwo = SPI_I2SCFGR_DATLEN_1,
86+
All = Thirtytwo,
87+
};
88+
89+
enum class
90+
MasterClockOutput : uint32_t
91+
{
92+
Disabled = 0b0,
93+
Enabled = SPI_I2SPR_MCKOE,
94+
All = Enabled,
95+
};
96+
97+
enum class
98+
OddFactor : uint32_t
99+
{
100+
Disabled = 0,
101+
Enabled = SPI_I2SPR_ODD,
102+
All = Enabled,
103+
};
104+
};
105+
106+
} // namespace platform
107+
108+
} // namespace modm
109+
110+
#endif // MODM_STM32_I2S_BASE_HPP
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
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+
* Copyright (c) 2021-2022, Raphael Lehmann
8+
*
9+
* This file is part of the modm project.
10+
*
11+
* This Source Code Form is subject to the terms of the Mozilla Public
12+
* License, v. 2.0. If a copy of the MPL was not distributed with this
13+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
14+
*/
15+
// ----------------------------------------------------------------------------
16+
17+
#ifndef MODM_STM32_I2S_HAL{{ id }}_HPP
18+
#define MODM_STM32_I2S_HAL{{ id }}_HPP
19+
20+
#include "i2s_base.hpp"
21+
22+
namespace modm
23+
{
24+
25+
namespace platform
26+
{
27+
28+
/**
29+
* Serial peripheral interface (I2S{{ id }})
30+
*
31+
* TODO: Very basic implementation that exposes more hardware features than
32+
* the regular Spi classes.
33+
*
34+
* @author Marton Ledneczki
35+
* @ingroup modm_platform_i2s modm_platform_i2s_{{id}}
36+
*/
37+
class I2sHal{{ id }} : public I2sBase
38+
{
39+
public:
40+
/// TODO: Enables the clock, resets the hardware and sets the SPE bit
41+
static void
42+
enable();
43+
44+
/// Disables the hw module (by disabling its clock line)
45+
static void
46+
disable();
47+
48+
/**
49+
* Initialize I2s Peripheral
50+
*
51+
* TODO: Enables clocks
52+
*/
53+
static void
54+
initialize( OddFactor oddFactor, uint8_t i2s_div,
55+
MasterSelection masterSelection = MasterSelection::Master,
56+
DirectionSelection directionSelection = DirectionSelection::Transmitter,
57+
BitDepth bitDepth = BitDepth::Sixteen,
58+
MasterClockOutput masterClockOutput = MasterClockOutput::Enabled);
59+
60+
static void
61+
start();
62+
63+
static void
64+
stop();
65+
66+
static void
67+
write(uint16_t sample);
68+
69+
static void
70+
enableDma(bool enable = true);
71+
72+
static void
73+
enableInterruptVector(bool enable, uint32_t priority);
74+
75+
static void
76+
enableInterrupt(Interrupt_t interrupt);
77+
78+
static void
79+
disableInterrupt(Interrupt_t interrupt);
80+
81+
static InterruptFlag_t
82+
getInterruptFlags();
83+
84+
static void
85+
acknowledgeInterruptFlag(InterruptFlag_t flags);
86+
};
87+
88+
} // namespace platform
89+
90+
} // namespace modm
91+
92+
#include "i2s_hal_{{ id }}_impl.hpp"
93+
94+
#endif // MODM_STM32_I2S_HAL{{ id }}_HPP
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
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+
* Copyright (c) 2021-2022, Raphael Lehmann
8+
*
9+
* This file is part of the modm project.
10+
*
11+
* This Source Code Form is subject to the terms of the Mozilla Public
12+
* License, v. 2.0. If a copy of the MPL was not distributed with this
13+
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
14+
*/
15+
// ----------------------------------------------------------------------------
16+
17+
#ifndef MODM_STM32_I2S_HAL{{ id }}_HPP
18+
# error "Don't include this file directly, use 'i2s_hal{{ id }}.hpp' instead!"
19+
#endif
20+
21+
#include <modm/platform/clock/rcc.hpp>
22+
23+
void inline
24+
modm::platform::I2sHal{{ id }}::enable()
25+
{
26+
Rcc::enable<Peripheral::Spi{{ id }}>();
27+
SPI{{ id }}->CR1 = 0;
28+
SPI{{ id }}->I2SCFGR = SPI_I2SCFGR_I2SMOD;
29+
}
30+
31+
void inline
32+
modm::platform::I2sHal{{ id }}::disable()
33+
{
34+
SPI{{ id }}->I2SCFGR = 0;
35+
Rcc::disable<Peripheral::Spi{{ id }}>();
36+
}
37+
38+
void inline
39+
modm::platform::I2sHal{{ id }}::initialize( OddFactor oddFactor, uint8_t i2s_div,
40+
MasterSelection masterSelection,
41+
DirectionSelection directionSelection,
42+
BitDepth bitDepth,
43+
MasterClockOutput masterClockOutput)
44+
{
45+
enable();
46+
// disable peripheral, and clear all fields except I2S mode bit
47+
SPI{{ id }}->I2SCFGR = SPI_I2SCFGR_I2SMOD;
48+
SPI{{ id }}->I2SPR = 0x0002; // = reset value acording to reference manual
49+
50+
// set parameters
51+
SPI{{ id }}->I2SPR |= static_cast<uint32_t>(masterClockOutput) |
52+
static_cast<uint32_t>(oddFactor) |
53+
i2s_div;
54+
SPI{{ id }}->I2SCFGR |= static_cast<uint32_t>(masterSelection) |
55+
static_cast<uint32_t>(directionSelection) |
56+
static_cast<uint32_t>(bitDepth);
57+
}
58+
59+
void inline
60+
modm::platform::I2sHal3::start()
61+
{
62+
SPI{{ id }}->I2SCFGR |= SPI_I2SCFGR_I2SE;
63+
}
64+
65+
void inline
66+
modm::platform::I2sHal3::enableDma(bool enable)
67+
{
68+
if (enable) {
69+
SPI{{ id }}->CR2 |= SPI_CR2_TXDMAEN;
70+
}
71+
else {
72+
SPI{{ id }}->CR2 &= ~SPI_CR2_TXDMAEN;
73+
}
74+
}
75+
76+
void inline
77+
modm::platform::I2sHal{{ id }}::write(uint16_t sample)
78+
{
79+
SPI{{ id }}->DR = sample;
80+
}
81+
82+
void inline
83+
modm::platform::I2sHal{{ id }}::enableInterruptVector(bool enable, uint32_t priority)
84+
{
85+
if (enable) {
86+
// Set priority for the interrupt vector
87+
NVIC_SetPriority(SPI{{ id }}_IRQn, priority);
88+
// register IRQ at the NVIC
89+
NVIC_EnableIRQ(SPI{{ id }}_IRQn);
90+
}
91+
else {
92+
NVIC_DisableIRQ(SPI{{ id }}_IRQn);
93+
}
94+
}
95+
96+
void inline
97+
modm::platform::I2sHal{{ id }}::enableInterrupt(Interrupt_t interrupt)
98+
{
99+
SPI{{ id }}->CR2 |= interrupt.value;
100+
}
101+
102+
void inline
103+
modm::platform::I2sHal{{ id }}::disableInterrupt(Interrupt_t interrupt)
104+
{
105+
SPI{{ id }}->CR2 &= ~interrupt.value;
106+
}
107+
108+
modm::platform::I2sHal{{ id }}::InterruptFlag_t inline
109+
modm::platform::I2sHal{{ id }}::getInterruptFlags()
110+
{
111+
return InterruptFlag_t(SPI{{ id }}->SR);
112+
}
113+
114+
void inline
115+
modm::platform::I2sHal{{ id }}::acknowledgeInterruptFlag(InterruptFlag_t flags)
116+
{
117+
SPI{{ id }}->SR = flags.value;
118+
}

0 commit comments

Comments
 (0)