Loading...
 

SW4STM32 and SW4Linux fully supports the STM32MP1 asymmetric multicore Cortex/A7+M4 MPUs

   With System Workbench for Linux, Embedded Linux on the STM32MP1 family of MPUs from ST was never as simple to build and maintain, even for newcomers in the Linux world. And, if you install System Workbench for Linux in System Workbench for STM32 you can seamlessly develop and debug asymmetric applications running partly on Linux, partly on the Cortex-M4.
You can get more information from the ac6-tools website and download (registration required) various documents highlighting:

System Workbench for STM32


SPDIF Example for STM32F7?

Hi,

Searched the STM32Cube_FW_F7_V1.1.0 library yet didnt see any SPDIF example.
Is there somewhere any such example project for the SPDIF which I could use?

Christos


Thanks Bernard for taking the time to reply.
Yes, I did a cross-post in the ST forum, yet didnt receive a reply yet there.

I’m quite new to ST and the SW IDE, so got many questions, I’ll post some which are relevant to SW here now that I understand better the differentiation.

thanks again
Christos


FYI:
I have SPDIF Input working on STM32F7 Discovery board.

Actually, not so difficult to bring it up: all FW functions are there (in CubeF7).
Hints:
- use CubeMX in order to create a demo project for SPDIF. It generates almost all the code you need. Just modify some configs
- take the audio player from demo, e.g. stm32764g_discovery_audio.*
- configure SPDIF as: hSPDIFRX_IN0.Init.DataFormat = SPDIFRX_DATAFORMAT_32BITS;
it is needed for stereo over S/PDIF. Just: even your play 24bit over S/PDIF - just 2x16bit come into your FW (just 16bit stereo resolution)
- if SPDIF input buffer is half full - start DMA to SAI2 via: BSP_AUDIO_OUT_Play((uint16_t *)SPDIFIN0_RxBuf, (SPDIF_SAMPLE_NUM - 192) * 4);
- start the SPDIF Interrupt via: if (HAL_SPDIFRX_ReceiveDataFlow_IT(&hSPDIFRX_IN0, SPDIFIN0_RxBuf, SPDIF_SAMPLE_NUM) == HAL_OK)
- and let all running, in the background, no other calls (my mistake: do not start DMA and Play again),
it works in background: SPDIF Interrupt receives the audio data, DMA to SAI2 streams it out

It works !

Please see here: https://www.youtube.com/watch?v=k0vCi0mrIhIQuestion
Cool, now I have an USB and SPDIF input (front end) for my “Lyrebird True24” DAC: http://www.tjaekel.com/lyrebird/Question

If you need demo project for it: please visit: http://www.tjaekel.com/lyrebird/Question and send me an email.


Hi tjaekel,
really thanks for this, very interesting! I’m new on STM, just get my first STM32F7 discovery board, after a day of googling I find System Workbench and finally I’m able to do something with this board, then I find this post, wow!
I have compiled succesfully, just performed one simple change to avoid compiling errors.
I really hope to see other projects like this, I have learned more from your example than standard ST ones!

Thanks a lot, tjaekel!

I found your example as a great starting point for spdif applications. For my project, I’m trying to use IT + DMA to have full background processing. The application is working but I can hear small clicks in both channels appearing randomly on top of the sound coming from the RCA connection.

The main changes I made:

void SPDIF_RX_IRQHandler(void)
{
HAL_SPDIFRX_IRQHandler(&hspdif);

/* this has a side effect: if USB audio - this corrupts the sound ! */
if (HAL_SPDIFRX_ReceiveDataFlow_IT(&hspdif, SPDIFIN0_RxBuf, SPDIF_SAMPLE_NUM) == HAL_OK)
{}
}

void SPDIFRX_Start_IT(void)
{
if (HAL_SPDIFRX_ReceiveDataFlow_IT(&hspdif, SPDIFIN0_RxBuf, SPDIF_SAMPLE_NUM) == HAL_OK)
{
BSP_AUDIO_OUT_Play((uint16_t *)SPDIFIN0_RxBuf, (SPDIF_SAMPLE_NUM - 192) * 4);
}
}

So I was curious, did you run into similar issues before? USB audio is not initialized, btw.

I would be very thankful if you could point me out in the right direction or share some more code! :-)

Two issues could be there:
a) asynchronous audio clocks:
I assume, you receive digital audio via SPDIF RX and you forward the PCM code words to the onboard DAC, so that it comes out as analog on RCA connector.
Both audio ‘systems’ have their own clock: SPDIF Rx gets the clock with the signal from host, onboard DAC runs as a master and has its own clock (generated by PLL, onboard).
So, both clocks are not coupled, not synced or neither have the same frequency. Such independent free running clock ‘domains’ result in ‘not enough data’ or ‘too much data’, after a while. You get samples drops and it results in ‘clicks’ (potentially, an entire audio frame might be missing or an old one is repeated instead).
b) Double Buffering issues:
Actually, when using DMAs, they run ‘endless’ but using a Double Buffer mechanism: if one buffer half is full, the other half is used. You had to make sure to use for the audio forward, playback, the ‘opposite’ buffer: the buffer which is currently in use for a DMA from SPDIF Rx cannot be the same buffer you send (also via DMA) to the DAC. You had to make sure that the ‘opposite’ buffer is used (one for Rx, the other one for Tx).
Maybe, you need a mechanism to start SPDIF Rx as well as DAC Tx process quite at the same time (at least with minimal delay between both starts) and a logic to use the ‘opposite’ buffer.
Actually, there should be also a DMA complete interrupt. I use this one in order to ‘flip’ the buffer.

Solutions:
a) try to send a fix audio pattern, e.g. a sine wave, saw signal etc. Check the output with a scope (or try to trace and decode the audio buffer which goes to the DAC. Potentially you will see a ‘jump’ in the audio signal, periodically there is a short sequence of ‘wrong’ audio samples (potentially one SPDIF audio frame).
b) trim the audio clock: you can only fine tune the DAC audio clock, the clock for SPDIF Rx comes with the signal from the remote host. It does not solve the problem really, it makes just the period when the ‘click’ happens larger (or shorter).
Actually, a means is needed to ‘follow’ the SPDIF audio clock, to trim the DAC audio clock in relation to the SPDIF Rx clock. If you use a newer STM, e.g. a H7xx, they have PPLs with fractional divider settings and potentially you can trim a PLL ‘on the fly’ (but often other MCUs, boards - you had to stop PLL which makes it even worse).
c) check the buffer pointers, index etc. How are input and output buffer pointer moving? Do they start to ‘overlap’ (one process is faster and would hit the buffer in use for the other process).
Used this indication to trim the audio clock (make DAC audio clock a bit faster or slower).
You need a ‘clock recovery’ or a process to trim and sync (the audio clock frequency).
d) or, not sure if possible: try to bring the SPDIF Rx clock out on a pin (maybe possible, not sure). If you have such a clock signal coming out, run the DAC in slave mode, where it gets the clock from this pin.
Or maybe vice versa: try to get the DAC audio clock into, for the SPDIF Rx (but actually it does not help due to fact that the remote SPDIF Tx generates the transmission clock).

The ‘best’ solution is to have a ‘word clock’, a clock generator which provides the clock for the remote SPDIF Tx (host) as well as the SPDIF Rx receiver, your board, and the DAC on it).
Without such a ‘system word clock’ or a way for a ‘clock recovery’ (trim and feedback mechanism to hold clocks in sync) you will have always ‘clicks’, missing or too much audio samples due to a difference in the clock frequency.

Check first if the Double Buffer is properly working and how the ‘buffer pointers’ are moving and related to each other. Often there could be already an issue, e.g. you send the same buffer to DAC which is also in use to be filled by the SPDIF Rx. Or you hit the case where one process, one buffer, moves into the other one. This is just a criteria to ‘handle’ this ‘audio corruption case’. Often, I decide to run the DAC output a bit slower so that I had to drop a frame if this happens (better to drop instead to send something ‘unknown’, old, when opposite case).
If the buffers ‘overlap’ each other, one process ‘passes’ the other one - this is very bad: you might send an entire internal buffer with wrong content (e.g. very old, from previous ‘loop’). So, make sure, you have just the smallest drop of an audio frame (e.g. one SPDIF audio packet), not an entire internal buffer ‘overrun’ or ‘underrun’.

Amazing explanation, Thank you tjaekel! Really appreciated.

For now, I’ve decided to modify the original code, so at least UI stays responsive while we are waiting for spdif buffer to be able to receive new data. Also, checking the issue with double buffering as you suggested.

Meanwhile, I’ve tried to switch to optical input instead of coax. Using PLR135/T10 and by removing U2 op-amp from the input of PD7 (STM32f7 DISCOVERY). It works but some frames are played twice. Looks like some code modifications needed in this case as well :/

Hope I’ll have some code to share at the end!