daisy_bsp
daisy_bsp copied to clipboard
Audio examples don't seem to work with new codec
Hi!
Unfortunately, the sound examples in the daisy_bsp crate don't seem to work on my Seed. I'm not completey sure why yet, but I think I can narrow it down. All other examples work great without a problem. I got one of the latest boards, with the WM8731 codec. It might have something to do with swap due to the ongoing chip shortage.
What I am sure of:
- codec works fine when I upload C++ compiled binaries
- codec doesn't receive any serial data on pin 4 (DACDAT) with Rust compiled binaries (could confirm with oscilloscope)
- MCLK_A, FS_A, SCK_A and SD_B behave as expected
- TX_BUFFER in audio.rs gets passed and stores the right values
- DMA1 interrupts behave as expected
I'm not sure if:
- DMA1 performs properly between memory and peripheral
- one needs to setup the SAI differently (but I will investigate on that)
- it is Rust version specific error/bug
or I could have messed up completely and just overlooked something very obvious
Oooh, I hadn't heard we have a new codec!
I think you're right about the chip shortage, most AKM codecs have been unobtainium for a while now.
So the bad news is that the WM8731 needs to be configured via I2C before you can start it up.
The good news is that I wrote a WM8731 driver for the esp32 a while back and it won't be a lot of work to port the I2C code to the Seed.
If you'd like to tackl it you can find the esp32 implementation here:
https://github.com/antoinevg/stage_esp32/tree/master/api/src/driver/wm8731
Otherwise I'm happy to take a look if/when I can get my hands on one of the new Seed boards!
Many thanks for the fast reply!
I'm glad you already have a solution ready. I'll try add the driver myself and post about the result soon.
I got the I2C configuration going now, the codec receives the same instructions as the ESP32 driver and acknowlegdes all of them. But the same problem as before remains: The STM32H7 doesn't send the I2S data to the DAC input. I might have an idea though. Since rev 1.1 of the daisy board doesn't have a proper schematic for reference, I fear that this specific pin might have been moved to a different pin on the STM32H7 side. I will try the different SAI pin configurations for the I2S data lane in the coming week and report later!
Nice! Looking forward! :-)
A little question: Does it make a difference if the pac crate uses a similar (but probably different) chipset to access its peripherals?
It looks like rustdoc
doesn't check what features are set in Cargo.toml
when generating these and just grabs the first one that's defined in the origin crate.
We do pull in the stm32h750
version though:
https://github.com/antoinevg/daisy_bsp/blob/4d827f584c7ade0c951c460b65edabcfb52a89ec/Cargo.toml#L33
Okay, good to know!
I forked the bsp crate and committed all my changes (https://github.com/backtail/daisy_bsp/commit/61b8844f4d2dda9c4218e3976d2d01d9932b6e4b). The SAI pin config seems to be right, I double checked with working C++ library.
Maybe you could quickly glance through my changes and spot a problem. The SDA_A
pin on the Codec still doesn't receive any data from the MCU. My suspicion is that the DMA isn't working properly and I don't exactly know how to debug this problem.
The audio data lies properly in the TX_BUFFER
and the DMA1_STR1()
intterrupt seems to work fine.
In theory the DMA configuration should remain unchanged as the interface should be independent of whatever Codec is attached to SAI.
Something else that springs to mind is that the SAI / I2S interface may not be configured correctly for the new codec.
What I was using for the AK4556:
https://github.com/antoinevg/daisy_bsp/blob/4d827f584c7ade0c951c460b65edabcfb52a89ec/src/audio.rs#L128-L135
Things to look at are the framing and also bit rate, if I recall correctly my esp-idf I2C code configured the WM8731 to use 16bit @ 48kHz rather than 24bit @ 48kHz.
For what it's worth, here's the corresponding SAI config code from my esp-idf implementation:
https://github.com/antoinevg/stage_esp32/blob/a85f56dda98fcda5f6f5af3603f2777236b2c55b/api/src/driver/wm8731/mod.rs#L202-L227
pub unsafe fn init(port: i2s_port_t, pins: Pins, config: &audio::Config) -> Result<(), EspError> {
// initialize i2s driver
log!(TAG, "initialize i2s peripheral");
let i2s_config = i2s_config_t {
mode: i2s_mode_t::I2S_MODE_MASTER
| i2s_mode_t::I2S_MODE_RX
| i2s_mode_t::I2S_MODE_TX,
sample_rate: config.fs as c_int,
bits_per_sample: i2s_bits_per_sample_t::I2S_BITS_PER_SAMPLE_16BIT,
channel_format: i2s_channel_fmt_t::I2S_CHANNEL_FMT_RIGHT_LEFT,
communication_format: i2s_comm_format_t::I2S_COMM_FORMAT_I2S
| i2s_comm_format_t::I2S_COMM_FORMAT_I2S_MSB,
intr_alloc_flags: ESP_INTR_FLAG_LEVEL1 as i32,
dma_buf_count: 4,
dma_buf_len: config.block_length as i32,
use_apll: false,
..i2s_config_t::default()
};
i2s_driver_install(port, &i2s_config, 0, core::ptr::null_mut()).as_result()?;
// configure pins for i2s peripheral
log!(TAG, "configure pins for i2s peripheral: {:?}", pins);
i2s_set_pin(port, &pins.into()).as_result()?;
// zero dma buffer
i2s_zero_dma_buffer(port).as_result()?;
Maybe also worth comparing against what Electrosmith have in their repo:
https://github.com/electro-smith/libDaisy/tree/master/src/dev https://github.com/electro-smith/libDaisy/tree/master/src/per
Any progress on this? I finally was able to interface an SSD1306 to my Daisy Pod today :'). Wanted to start doing some audio examples now but I have a newer pod which means I have the newer codec so looks like I won't be able to until this get's figured out
Unfortuntely, I have not figured out how to setup the configuration for the WM8731 yet... I have used the same config setup as in the C++ libdaisy today. No audio output yet. Still, i am not sure, if data is being transferred correctly from buffer to peripheral and sent, since I can't meausure any data signal on the WM8731 DAC input pin. However, I have not tried fiddling with the I²S setup yet, so the problem might lie there and not with the DMA.
I think I finally found the culprit!
In the new revision the transmit and receive channels of the SAI are reversed. That explains why I couldn't read any data on the codec data input pin.
https://github.com/electro-smith/libDaisy/blob/26256aaa54e4117c904ca431c0165981a6205fdf/src/daisy_seed.cpp#L267-L303
And also good news: It's very easy to check which revision it is. That means we can write the code in a manner that it works with both versions.
https://github.com/electro-smith/libDaisy/blob/26256aaa54e4117c904ca431c0165981a6205fdf/src/daisy_seed.cpp#L329-L345
I will try setup channel B of the SAI on the weekend, since I should probably spend more time studying for my exams :D
Update:
Codec is now working fine! :partying_face:
Only issue now is that I haven't quite figured out how to config the DMA. I can send and receive audio via SAI1_CHX_DR, but the DMA is not shifting to or from peripheral. I probably got the directions wrong or something along those lines.
Once that little issue is fixed up, I will implement the board version check, and then I would suggest a pull request?
How exactly is the DMA configured? Is it possible to specifically assign stream 0 of DMA1 to SAI1 block B and stream 1 with block A? I haven't reversed the DMA directions since I thought that for example https://github.com/antoinevg/daisy_bsp/blob/209d938b58d2ffe0e05af96103c17aa5a0cc0391/src/audio.rs#L106-L112
the DMA stream grabs its counterpart. Meaning, here stream 0 is configured as as mem_to_per and so it acts as transmitter. In line 108, the "whole" SAI peripheral is handed over. However I'd like to configure this as SAI1<CH_A>
or SAI1<CH_B>
respectively.
I swapped the Rx and Tx everywhere else, so the only thing missing right now, is that the right DMA channel is associated to the right peripheral.
compare to ...
https://github.com/antoinevg/daisy_bsp/blob/209d938b58d2ffe0e05af96103c17aa5a0cc0391/src/audio.rs#L128-L135
https://github.com/antoinevg/daisy_bsp/blob/209d938b58d2ffe0e05af96103c17aa5a0cc0391/src/audio.rs#L145-L151
https://github.com/antoinevg/daisy_bsp/blob/209d938b58d2ffe0e05af96103c17aa5a0cc0391/src/audio.rs#L205-L210
Am I maybe missing something obvious?
If I remember correctly, configuring the DMA direction with the appropriate dma::MemoryToPeripheral
and dma::PeripheralToMemory
types should do it:
https://github.com/antoinevg/daisy_bsp/blob/209d938b58d2ffe0e05af96103c17aa5a0cc0391/src/audio.rs#L47-L57
Okay, I did a deep dive into the rust HAL DMA configuration file and found this:
https://github.com/stm32-rs/stm32h7xx-hal/blob/b874460e54c7b27e32495dab46984fa4fb82f51f/src/dma/dma.rs#L938-L941
Here, the SAI blocks can only be configured in one specific way.
- transmit channel -> SAIA
- receive channel -> SAIB
But in the new revision of the Daisy, these directions are reversed: https://github.com/electro-smith/libDaisy/blob/26256aaa54e4117c904ca431c0165981a6205fdf/src/daisy_seed.cpp#L267-L303
That means we need to configure the DMA without HAL until this will be patched out.
@backtail do you have a working branch of this configuration of the DMA without HAL for the meantime? I just wanna start working on some audio stuff in rust on my daisy seed 😭
I am working on it right now. Either this evening or tomorrow it will be up!
Little update: Codec now works with the DMA! :tada: I just need to figure out a weird number conversion mistake, but that shouldn't be too hard. In the end, I manually set the registers for the DMA directions via pac:
// manually configure Channel B as transmit stream
let dma1_reg = unsafe { pac::Peripherals::steal().DMA1 };
dma1_reg.st[0].cr.modify(|_ , w | w.dir().peripheral_to_memory());
// manually configure Channel A as receive stream
dma1_reg.st[1].cr.modify(|_ , w | w.dir().memory_to_peripheral());
I will also update the lib with a revision check for compatibility with the old daisy boards. Will be up on monday (unfortunately I don't have time this weekend).
Here's a picture of the current audio output.
Finally finished!
You can find the major changes I did in these 2 commits (b2b4f9584172b338c32d66098a8923213e9349bd and 61b8844f4d2dda9c4218e3976d2d01d9932b6e4b).
Please refer to the examples/audio_testsignal.rs
on commit 61b8844f4d2dda9c4218e3976d2d01d9932b6e4b on how to differently setup for the new codec.
PS: the number conversion bug is also fixed
@backtail Solid work!! I just compiled and flashed it onto my daisy pod (the audio_testsignal
example) and indeed got audio output!
A few things:
- When I connect my 3.5mm TRS head phone jack into the line out of the daisy Pod, two things can happen:
- When the headphone jack is fully inserted, I only get audio in the left headphone speaker, and the right headphone speaker just produces a high pitched buzzing noise
- When the headphone jack is half way inserted, i can head audio in both headphone speakers (left and right), but can still faintly hear the hight pitched buzzing noise (though it's a lot quieter in this scenario than when the headphone jack is fully inserted).
Sounds like it might have something to do with configuring mono/stereo logic for audio output? not sure if that has been implemented for this crate yet.
Oh, and this could be unrelated, but also, whenever I flash the Pod with the audio_testsignal
example, as soon as it's flashed, it just produces a very high pitched noise, until i reset it via the reset button, and then it runs the audio_testsignal
example as expected. Any idea of why that may be?
EDIT: So i replaced the sin oscillator in audio_testsignal
with another saw oscillator and just very slightly detuned them from each other, and observed the following:
- When headphone jack is full inserted to line out, I hear both saw oscillators, in each headphone speaker, it almost sounds as if I'm hearing each oscillator by themself in each speaker, (ie osc 1 goes to left speaker and osc 2 goes to right speaker).
- When the headphone jack is halfway inserted, the result sounds as expected as you would expect with two saw oscillators slightly detuned each other (natural phasing going on).
Not sure if this is all by design or not based off the
src/audio.rs
file, so I'm just mentioning my findings in case it's not!
- When the headphone jack is fully inserted, I only get audio in the left headphone speaker, and the right headphone speaker just produces a high pitched buzzing noise
- When the headphone jack is half way inserted, i can head audio in both headphone speakers (left and right), but can still faintly hear the hight pitched buzzing noise (though it's a lot quieter in this scenario than when the headphone jack is fully inserted).
I wasn't able to reproduce this behavior. For my Daisy Pod, the Line Out
and Headphones
jacks work as expected. I didn't try it with headphones, though. However, I think that's a hardware and not a software issue either way.
Are you able to measure Pin 18
and Pin 19
of your Seed with an oscilloscope? If those signals are clean then it's very likely an issue with your Pod.
Oh, and this could be unrelated, but also, whenever I flash the Pod with the
audio_testsignal
example, as soon as it's flashed, it just produces a very high pitched noise, until i reset it via the reset button, and then it runs theaudio_testsignal
example as expected. Any idea of why that may be?
I think this may be related to the way you flash your Daisy. I have two ways of uploading the binary to the board:
-
cargo run
with a running OpenOCD connection → works seamlessly when flashing new code without hick up or harsh noiise :wink: - using the gdb debugger in VSCode and attach it to the running OpenOCD connection → once the new code is flashed, the debugger is stuck at the point where the MCU last instruction happened until I reset the device. This produces some high-pitched noise, because I believe that the debugger doesn't automatically reset the device.
EDIT: So i replaced the sin oscillator in
audio_testsignal
with another saw oscillator and just very slightly detuned them from each other, and observed the following:* When headphone jack is full inserted to line out, I hear both saw oscillators, in each headphone speaker, it almost sounds as if I'm hearing each oscillator by themself in each speaker, (ie osc 1 goes to left speaker and osc 2 goes to right speaker). * When the headphone jack is halfway inserted, the result sounds as expected as you would expect with two saw oscillators slightly detuned each other (natural phasing going on). Not sure if this is all by design or not based off the `src/audio.rs` file, so I'm just mentioning my findings in case it's not!
I think that is by design, actually. The 3.5mm jacks on the Pod have switches on them (to probably detect if TS or TRS connectors are being used). If you don't fully insert the jacks, you might touch the "right channel" switch with your "left channel" tip and that might cause the mixing of both signals on the same speaker.
Thanks a lot for your effort!
I have tried to pass through audio from line in to phones output on my Pod and the sound I get is quite distorted. Do you maybe know what could be causing it?
@miselaytes-anton I haven't had time to check that example yet. Is it only clipping? Then it might be the configuration of the input levels of the new codec (it's quite easy to adjust these). I will look at that tomorrow!
hm, I have tried lowering those, it makes the sound quieter, but it still has distortion. Looking forward to you test results.
@miselaytes-anton I was able to reproduce the noise. It's there even when no audio is being passed through! I will have to look at that in detail when I'm able to enter the lab next week (currently in quarantine) and maybe try a few little ideas the coming days.
@backtail cool thanks! I was struggling a long time myself to make the codec work. So I am really happy you made this progress, so that I can reuse your work a bit. Since my codec implementation is different from yours and I still ran into the same problems I feel it's maybe not codec related.
I commented on your code, I spotted a little error.
On little thing I did was to turn on the ADC high pass filter (Reg: 0b000101, Bit 0: 1). That got rid of the high pitch noise when no audio is being passed through. But it didn't reduce to clipping. Changing the input line levels acted a like gate threshold effect. I also believe it's not a problem with the codec, but rather with the code. It might be number conversion error.
I was able to get perfectly clean sound after I have removed .set_clock_strobe
config options, so the following lines:
https://github.com/backtail/daisy_bsp/blob/b7b80f78dafc837b90e97a265d2a3378094b84f7/src/audio.rs#L147
and
https://github.com/backtail/daisy_bsp/blob/b7b80f78dafc837b90e97a265d2a3378094b84f7/src/audio.rs#L152
Hey I have a daisy board lying around, and I can not use the audio example as well with 0.5.1. Are there any updates on this or is it working with your repo backtail?
It should be working with my repo AFAIK. Prerequisite is a Daisy Seed with the WM8731 codec, it doesn't work with the older Daisy revisions.