-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
stm32/machine_i2s: Support I2S peripheral mode #8451
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
base: master
Are you sure you want to change the base?
Conversation
There may still be the opportunity to implement this breaking constructor change. In both the library and quick reference docs, I2S is clearly called out as a Technical Preview, that may be changed.
|
Yes, that's true! Considering what a possible I2C peripheral class would look like, it would probably be With that in mind, it kind of makes sense to have But on the other hand, I2S is different to I2C with controller/peripheral, because we are using the same class just in a different mode, and it already has TX/RX mode, unlike I2C. The main argument for changing |
@miketeachman from my measurements, the But the docs suggest that it is samples per second. I think it makes sense to be frames per second, because for rate=44100 you want both L and R channels to sample at that rate. |
2f2b83a
to
3c1ef0f
Compare
A CD audio stream is typically described as having a 44.1KHz sample rate, in that each channel is sampled at that rate (just over config = {
'sck' : Pin('W29'),
'ws' : Pin('W16'),
'sd' : Pin('Y4'),
'mode' : I2S.TX,
'bits' : 16, # Sample size in bits/channel
'format' : I2S.STEREO,
'rate' : 44100, # Sample rate in Hz
'ibuf' : BUFSIZE, # Buffer size
} So the value of 44100 is the "audio sample rate" in terms of sampling theory and the frame rate in terms of the data stream. Perhaps the docs should clarify this. |
Yes this matches with what I measure. |
Codecov Report
@@ Coverage Diff @@
## master #8451 +/- ##
=======================================
Coverage 98.25% 98.25%
=======================================
Files 154 154
Lines 20275 20275
=======================================
Hits 19922 19922
Misses 353 353 Continue to review full report at Codecov.
|
This is definitely misleading. It would be better to change the docs to read "specifies audio sampling rate (Hz)" |
ports/stm32/machine_i2s.c
Outdated
mp_raise_ValueError(MP_ERROR_TEXT("rate required")); | ||
} | ||
init->AudioFreq = args[ARG_rate].u_int; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To aid in code comprehension, I think this logic is better placed around line 761, in the section of code where arguments are validated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
I'm curious on the motivation to add support for the passive mode. e.g is MicroPython support needed for I2S DAC devices that only function in a controller mode? |
Sorry, I disagree. To me, it seems unnecessary and confusing to add two new terms ("passive" and "active") into the MicroPython lexicon. The existing terms "controller" and "peripheral" accurately describe the I2S operation modes and provide consistency across other machine module classes, such as I2C and SPI. In electrical engineering, the terms "active" and "passive" are used to categorize electrical components. When looking at how the Based on this discussion, I suggest the following for the
or, a more compact version
|
One use case that triggered this PR is to have system-wide synchronisation of the I2S streams with other peripherals. So the I2S clock and WS signal are generated externally, they are fed into the I2S source and sink (both in passive mode) and then these signals also drive other (non-I2S) peripherals so they are in sync with the sampling of the I2S device. (And in this application the non-I2S peripherals cannot be clocked directly from an active I2S device.) |
Yes that's a fair point. And in the network and BLE API the term My main reasoning with active/passive is that when two devices are communicating over I2S (eg two pyboards!) neither are really the controller or peripheral, rather they are peers. And then active/passive just refers to which one is driving the lines. But it would be more common to have an actual I2S peripheral (eg mic, speaker), in which case controller/peripheral would make sense. Also, So I'm happy to use controller/peripheral.
I don't think we should look to the STM32 Cube HAL constants to make decisions (that didn't always work out well in the past). But I think you're right that we should put controller/peripheral first in the constant name, because that's conceptually the first thing you need to decide: "am I implementing a controller or peripheral?". I think
|
Changes unrelated to passive mode are moved to #8457. This PR will be rebased on that once merged. |
That's a very interesting I2S system. I was trying to guess what the application does, but ultimately was stumped. Although, I was imagining a retro mirror ball and lights somewhere in the mix :) |
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
3c1ef0f
to
3b7acbd
Compare
Signed-off-by: Damien George <damien@micropython.org>
Signed-off-by: Damien George <damien@micropython.org>
I've rebased this on latest master, and changed the names to use controller/peripheral. Still need to test non-blocking and asyncio mode. |
For a regression test, I tested this PR against the examples in https://github.com/miketeachman/micropython-i2s-examples/tree/peripheral-pr, using a Pyboard D SF2. All examples worked. |
…n-main Translations update from Hosted Weblate
This adds support for passive (aka "slave") mode on stm32 machine.I2S.
Passive mode is pretty much exactly the same as standard/active/master mode except that the other side drives the WS and SCK pins (hence the name passive, the WS and SCK pins are inputs). I chose the terminology "passive" instead of "peripheral" because I think "passive" is more descriptive here.
To configure passive mode use:
An alternative way to select passive mode would be a
passive=True
argument to the constructor. But I think adding two new modes makes more sense.The changes in this PR are:
I2S.TX_PASSIVE
andI2S.RX_PASSIVE
constants, and make them workrate
argument is optional when selecting passive modeI2S.deinit()
so it can be called multiple times without crashing (due to freeing ringbuf memory twice)It could be an option to rename the
I2S.TX
mode toI2S.TX_ACTIVE
but that would be a breaking change, so I don't suggest to do that (but conceptually this naming helps to understand how the modes work).Things not done here: