The sketch I wrote uses the hardware SPI interface of STM32 microcontroller. You can connect a I2S DAC like PT8211. The serial bus input data format of PT8211 is Japanese or called LSBJ (Least Significant Bit Justified) format.

The example sketch produces a 16-bit value Sine wave on the RIGHT Audio channel (PT8211 pin 8) and a SawTooth wave on the LEFT Audio channel (pin 6).

The STM32F103C8T6 is used but can be used on any STM32 with hardware SPI interface. The PT8211 is connected on SPI_1 port.
The example doesn't include the two's complement mathematical operation on binary numbers but this is something that can be done easily.

You are great, Vassilis!
Thank you very much!
I soldered two another of my (guess about 50+ pcs) PT8211's:
And the result: It's working!
Maybe if we cannot get the "real I2s" working, this could be a workaround. Just setting the SPI write routines on a timer, some phase accumulators for each voice combined with my USB-MIDI-branch (or normally serial MIDI - the standard lib works great) and ready is the basic synth
So with 2 SPI we can get 4 independent outputs (for analog filters)

Something different: Has somebody got SPI3 working on any device? I see in the board.h file, that there are some troubles

* Note:
* SPI3 is unusable due to pin 43 (PB4) and NRST tie-together , but
* leave the definitions so as not to clutter things up. This is only
* OK since RET6 Ed. is specifically advertised as a beta board. */

Is this an actual entry (I guess no, because everything we have done, we have signed with our names)
Fact is, even with the new SPI library example, SPI3 wont work for me.

So, it's time for some fun:
With this sketch the demo is modified for playing a Waldorf-Format wavetable: 64 tables, each table with 128 entries.
It plays the sound "zero" with different speeds.
Have fun!

For experts:
I make my wavetables with the program "audio-term" https://www.youtube.com/watch?v=cPSjMORs39o
With the output of the program (standard Waldorf Blofeld wavetable format) I wrote my own processing sketch to translate and exclude the audio data from the sysex file (this drove me nuts: raw signed 21bit audio format and much more pitfalls, but I've done it )

madias wrote:You are great, Vassilis!
Thank you very much!
I soldered two another of my (guess about 50+ pcs) PT8211's:
And the result: It's working!
Maybe if we cannot get the "real I2s" working, this could be a workaround. Just setting the SPI write routines on a timer, some phase accumulators for each voice combined with my USB-MIDI-branch (or normally serial MIDI - the standard lib works great) and ready is the basic synth
So with 2 SPI we can get 4 independent outputs (for analog filters)

Something different: Has somebody got SPI3 working on any device? I see in the board.h file, that there are some troubles

* Note:
* SPI3 is unusable due to pin 43 (PB4) and NRST tie-together , but
* leave the definitions so as not to clutter things up. This is only
* OK since RET6 Ed. is specifically advertised as a beta board. */

Is this an actual entry (I guess no, because everything we have done, we have signed with our names)
Fact is, even with the new SPI library example, SPI3 wont work for me.

It seems like that reference is for Leaflabs RET6 board, so I dont see a reason SPI3 should not work in any other board where pb4 is not tied to NRST.
That said, leaflabs may have never tested SPI3, so there is a small chance they didn't catch perhaps a typo in one of the registers definitions, so I would check the files with the SPI3 definitions and make sure everything fits with the datasheet.
About the SPI routines in a timer I would do this:
-Use a timer channel that maps to the same DMA channel as the SPI port to be used.
-Set the SPI port DMA, but do not enable the SPI TX DMA request, instead enable the DMA request for the that timer channel.
-Set the timer to preload, OC etc so it flips at the desired frequency.
-Enable the pin output for that channel compare, so the pin flips with the OC.
Result, on every time the OC flips from high to low, and back to high, a DMA request is issued and the DMA controller loads a new value in the SPI TX register, at the same time the channel pin takes the low or high value, to signal left or right to the DAC, all synchronized at whatever frequency you set your timer.
The SPI port can be set to 16bit mode, and the DMA transfer set to 16 bit transfer, so 1 DMA request loads a 16 bit value in the SPI port to be sent.

Thanks for your inputs, victor!
SPI3: Is now working, see thread: viewtopic.php?f=3&t=521
Following things I've implemented:
16Bit data transfer (remember that SPI.setDataSize must be the last SPI config line )
setting up the whole sound engine on timer3 (same timer as DMA 1 SPI1_TX)
The DMA stuff is totally new to me, I've to think and learn about it.... but must be easily to be implemented in the new code below

Meanwhile a little <edit> Mario melody with correct pitch (I transfered it from my PIC32, so there is huge overhead in the code left)
As you can see 4.25us are used from 21us, so the audio routine takes about 20%, maybe this can be better with DMA...

madias wrote:Meanwhile a little <edit> Mario melody with correct pitch (I transfered it from my PIC32, so there is huge overhead in the code left)
As you can see 4.25us are used from 21us, so the audio routine takes about 20%, maybe this can be better with DMA...

Edit. That is the left/right pin output right?
Then yes, the output routine is taking 20% of your time. If it was all set with the timer and DMA would take basically 0% once fired up, as the DMA and timer run by themselves, the only CPU time needed would be to update the output table.
For DMA setup, have a look at the libmaple documentation, and the SPI DMA transfer functions we added. The setup would be the same, except instead of enabling the SPITX DMA request, you enable the timer DMA request, for a timer channel in the same DMA channel.
The DMA controller does not care which device in that channel fires the DMA, it just starts 1 transfer every time it gets a request.
If I remember right the timer can be set in up/down count mode, and to toggle the output pin on each time it reaches 0, or the upper limit. So that way it is left free running toggling the pin at the frequency you want, and would trip a DMA request each time, so you get one for right, next one for left, and so on.
You will need to manipulate the timer registers directly as libmaple does not include functions for a lot of the advanced stuff, but the registers are all defined.
On your RAM buffer you will have to interleave the left and right channels.
Finally the DMA transfer can be set to generate an interrupt at half way, and when it finish all the bytes.
You can use both to treat the buffer as 2 half buffers, so when the half irq is called, you know you can refill the first half of the buffer, and when the end of transfer once trips, you can refill the top half.
Ahh, and the DMA can be set in circular mode if you want the same buffer to keep playing continuously. So you can play the same melofy over and over, but even better you can have the DMA play the same buffer over and over as you update the buffer with new sections of a melofy you can read from an SD card or network, or generate real time.

Thanks again Victor. As I said, the DMA stuff is unknown territory for me, so I have to learn the basics of DMA first.
Found a good tutorial for SPI here: http://polplaiconesa.com/tutorials/SPI+DMA.html
The leaflabs wiki is nice written, but without any examples (ok, one usart example). http://wiki.leaflabs.com/index.php?title=DMA
Offtopic: (or not so offtopic...)
Meanwhile I shredded all my 10pcs printed analog-filter boards (from dirty cheap pcb's) ---> too much errors/mistakes (and a complete unrepairable analog switch section) This draws me back at least for an half year for my master project. Ok, I call it "rising learning curve". All I know is, that I will never use the silly program "fritzing" anymore. I'm now on Kicad and it looks like as a really alternative for eagle. (I cannot use eagle free license, because I need 100x100 and not only 80x100..)
But there are good news to myself: At the beginning I planned to use a STM32 MCU only for controlling my synth (TFT, encoder, knobs, USB-MIDI) and as audio-unit-MCU a PIC32MX250. Drawback: two different territories and upload methods in the final product. Meanwhile I'll take a bigger STM32 MCU (RET,VET) as a single version for everything. (2x SPI/I2s=4 ind. 16-bit voice outputs, 1x SPI for the rest: TFT, ext. control DAC's like LT1665,...) Drawback is the lack of a FPU unit in the STMF1 series. I've done benchmark tests and every test says: "AVOID float for every costs!". Ok, I have learned to use fix point arithmetic's....maybe in one or two years I'll on STM32F7.

ok, forgot some infos for victor:
The picture shows a dummy pin, I set it up high on output-routine start and low on the end. So I got the 20% usage. This also helps me finding the right tuning frequency: 47,62 kHz in my example (instead of 48khz..).