STM32F103 minimal synth

ChrisMicro
Fri Mar 24, 2017 5:02 pm
Hello Together,

here I have build a little synthesizer with an Attiny85:
https://github.com/ChrisMicro/AttinySound

Now I got a STM32F103 BluePill from a friend and I think it could be fun to build the synth with this board.
I don’t want to use an external DAC and the goal is to create the sound only with a digital output pin.
In the Attiny85 synth this is done with a PWM-ISR and the results are quite amazing for this little chip.

Here I started the repository for the BluePill synthesizer:
https://github.com/ChrisMicro/BluePillSound

Unfortunately I didnt’ find a routine which can drive the PWM for sound generation.
Therefore I used to start hard coded sigma delta DAC. I ported the Talkie library which makes the synth speak with human like voice as an example ( Yes the BluePill can speak now ).

Do you have any hint where I can find a PWM-DAC ( probably with DMA )?
Image
The speaker is connected to PB0.


Rick Kimball
Fri Mar 24, 2017 5:19 pm
HardwareTimer is the thing you want

google search
“site:stm32duino.com HardwareTimer”


stevestrong
Fri Mar 24, 2017 6:36 pm
Isn’t actually Tone lib better suited?

ChrisMicro
Fri Mar 24, 2017 6:52 pm
> Isn’t actually Tone lib better suited?

Doesn’t the tone lib produce only square wave sounds?

Here I made an example with two wav-samples: a girls singing voice and a piano:

https://github.com/ChrisMicro/BluePillS … taPinSound

The sound output is PB12. You can directly connect a audio amplifier to it. The sound is a little bit better, if you put a 100Ohm/100nF low pass between.

The whole thing sounds a little bit like Mickey Mouse in concert with a more or less gifted piano player ;-)

I saw that in this forum there are more people using some sound generation. e.g.
http://www.stm32duino.com/viewtopic.php?f=19&t=1198
But they use a hardware DAC which is in my humble opinion not necessary if there is the right software driver.
The people can use my sigma delta principle, but it is a blocking routine and it needs a sample buffer which can be memory consuming.


ChrisMicro
Fri Mar 24, 2017 8:15 pm
Is it possible that not all pins can be used for PWM?

I know there is the analogWrite function but it seems not to work on PB12 which is at the moment my sound output.

Image

Here in the forum someone tried to speed up the PWM write:
http://www.stm32duino.com/viewtopic.php?t=587


Rick Kimball
Fri Mar 24, 2017 8:27 pm
stevestrong wrote:Isn’t actually Tone lib better suited?

Rick Kimball
Fri Mar 24, 2017 8:29 pm
ChrisMicro wrote:Is it possible that not all pins can be used for PWM?

ChrisMicro
Fri Mar 24, 2017 8:38 pm
Did you notice the pins with the little squiggly line and the legend that says “PWM pin” ?

Ah, yes. Reading helps.

Just for test I tried this which gives a ~33kHz PWM.

// PWM rate 1.1khz
int led = PB0;

HardwareTimer pwmtimer(3);

void setup()
{
pwmtimer.setPeriod(30);
pinMode(led, PWM);
pwmWritefast(led, 500);
}

void loop()
{

for (int a =0; a<2000;a++)
{
pwmWritefast(led,a);
delayMicroseconds(100);
}
}

void pwmWritefast(uint8 pin, uint16 duty_cycle)
{
timer_set_compare(PIN_MAP[pin].timer_device, PIN_MAP[pin].timer_channel, duty_cycle);
}


Rick Kimball
Fri Mar 24, 2017 8:46 pm
ChrisMicro wrote:For sure. But that is exactly what I wanted to avoid: digging deep into the MCU.

ChrisMicro
Fri Mar 24, 2017 9:12 pm
It seems like you did a deep dive on the attiny. Why do you want to snub the stm32f103? : )

Hmm … well … I didn’t want to invest to much time in the whole thing because I just got one of this boards from a friend and I thought I can do a quick hack … but now I spend to much hours …

Did you see, I used your code for the fast pin access:
https://github.com/ChrisMicro/BluePillS … GPIOPort.h

Do you want to have any special copyright text?


Rick Kimball
Fri Mar 24, 2017 9:15 pm
ChrisMicro wrote:Did you see, I used your code for the fast pin access:
https://github.com/ChrisMicro/BluePillS … GPIOPort.h

Do you want to have any special copyright text?


victor_pv
Sat Mar 25, 2017 4:36 pm
To add a bit to this thread:
Yes you can use PWM output to generate a wave. I did a dirty port of the TMRPCM library that works ok so far and does that.
You can use interrupts to reload the timers registers, and you can use DMA.
My library is in github in an old version with a few bugs. There is a tread about a ZX tape player where I was helping Buleste use it, and posted some of the bugs I found, but haven’t uploaded the corrections to github yet.
Further I worked on using DMA rather than interrupts to reload the timer compare registers, and that reduced CPU usage quite a bit. That is not uploaded anywhere yet. I got it working a couple of weeks ago and haven’t had much time yet to clean up and upload.
Once I clean it up and upload it I will post in the libraries section. You can take the parts that set the timer registers and play the samples and use it for anything else other than wav files.

ChrisMicro
Sat Mar 25, 2017 7:47 pm
Once I clean it up and upload it I will post in the libraries section.

Helo Viktor,

that sounds very interesting. When do you think the library is online?
Here is an application note from ST which could be probably very useful:
http://www.st.com/en/embedded-software/ … dithr.html

Meanwhile I will add more samples with the software sigma delta DAC.


victor_pv
Sun Mar 26, 2017 7:56 pm
ChrisMicro wrote:Once I clean it up and upload it I will post in the libraries section.

Helo Viktor,

that sounds very interesting. When do you think the library is online?
Here is an application note from ST which could be probably very useful:
http://www.st.com/en/embedded-software/ … dithr.html

Meanwhile I will add more samples with the software sigma delta DAC.


ChrisMicro
Mon Mar 27, 2017 8:09 am
It’s probably going to take me a few weeks to clean and document it, so I have just uploaded the current working files to a fork:

Thank you very much for posting the code. I would have a first little question:
Which Pins on the STM32F103 can be used for sound output? I assume that we can’t use PB12 because there is no connection to the timer units.
Would it make sense to say that PB0 is used in general for sound output? And for later uses: Is it possible to have a stereo PWM? Let’s say the second channel on PB1?


ChrisMicro
Tue Mar 28, 2017 8:56 am
Now I have changed the speaker pin in all files to PB0 to be prepared for future use of the PWM.

Image


victor_pv
Tue Mar 28, 2017 2:14 pm
ChrisMicro wrote:Now I have changed the speaker pin in all files to PB0 to be prepared for future use of the PWM.

Image


ChrisMicro
Tue Mar 28, 2017 3:11 pm
I saw this in your code and my conclusion was that you are using PB0.

extern byte speakerPin = 0;
extern byte speakerPin2 = 0;
extern uint8_t CSPin = 0;
extern uint16 resolution = 0;
extern uint8 repetition = 0;
extern byte lastSpeakPin = 0;


victor_pv
Tue Mar 28, 2017 4:16 pm
ChrisMicro wrote:I saw this in your code and my conclusion was that you are using PB0.

extern byte speakerPin = 0;
extern byte speakerPin2 = 0;
extern uint8_t CSPin = 0;
extern uint16 resolution = 0;
extern uint8 repetition = 0;
extern byte lastSpeakPin = 0;


ChrisMicro
Wed Mar 29, 2017 6:06 am
DMA Mode: Timer 4, ch1 and ch2 (default pins for that, whichever they are).
So this would mean

T4C1 ==> PB6
T4C2 ==> PB7

on the BluePill STM32F130 in the picture above. Right?


victor_pv
Wed Mar 29, 2017 2:12 pm
ChrisMicro wrote:DMA Mode: Timer 4, ch1 and ch2 (default pins for that, whichever they are).
So this would mean

T4C1 ==> PB6
T4C2 ==> PB7

on the BluePill STM32F130 in the picture above. Right?


ag123
Thu Mar 30, 2017 10:15 am
chris’s bluepillsound
https://github.com/ChrisMicro/BluePillSound
^^^wow, this is *excellent*, effectively it is a ‘1 bit’ delta-sigma DAC with just gpio bit banging and a simple RC lowpass filter !
http://www.beis.de/Elektronik/DeltaSigm … Sigma.html
similar concept:
https://www.allaboutcircuits.com/techni … nto-a-dac/

it’s not hard to imagine that 1 could program the usb-audio side interfacing wav bytes received from a PC, etc, convert that to delta-sigma over sample at 64x assuming 10khz being acceptable upper limit, pump out the bitstream at 640,000 bits per second over 2 gpio pins (L/R channels)

& 1’d have a STM32F103 USB HD-audio! :mrgreen:
but i’d guess we’d have a very busy STM32F103 doing all that delta-sigma conversions :lol:
not sure what is that ‘upper limit’ of a stm32103 throughput with this

if we try to do 48k samp per sec x 16x oversample sigma-delta, that’d be perhaps be pumping the gpio at 768k bits per sec?
seemed quite feasible still :D

and we can make the stm32f103 busier sampling a mic at 1 M samp per sec (u can track a flying bat!), or perhaps even more ambitious drive 3ch, 5ch or 7ch? :lol:


ChrisMicro
Tue Apr 04, 2017 8:35 am
^^^wow, this is *excellent*, effectively it is a ‘1 bit’ delta-sigma DAC with just gpio bit banging and a simple RC lowpass filter !

Thanks :-) Did your try it on your microcontroller and have you listened to the sound?

Meanwhile I made an experiment using the DMA to shift out the sigma delta bits:

https://github.com/ChrisMicro/BluePillS … SigmaDelta

It produces a sine wave just to check if the principle is working.


victor_pv
Tue Apr 04, 2017 9:36 pm
ChrisMicro wrote:^^^wow, this is *excellent*, effectively it is a ‘1 bit’ delta-sigma DAC with just gpio bit banging and a simple RC lowpass filter !

Thanks :-) Did your try it on your microcontroller and have you listened to the sound?

Meanwhile I made an experiment using the DMA to shift out the sigma delta bits:

https://github.com/ChrisMicro/BluePillS … SigmaDelta

It produces a sine wave just to check if the principle is working.


ChrisMicro
Wed Apr 05, 2017 6:49 am
I do not know how sigma delta DACs work, but should learn it, so I am not sure how much you care about the DMA transfer frequency, but just in case at max speed is faster than needed and you would rather slow it down to do other things with the MCU.

The explanations for the sigma delta principle is always explained a little bit complicated.
But there is one main rule:
– the higher the frequency the better the DAC resolution
( The sigma delta principle distributes the quantization noise over the entire frequency band. Therefore as broader the frequency band as less the noise )

if you look in the code you can see that the code for the sigma delta DAC is very, very simple:
// sigma delta DAC
for (n = 0; n < NumberOfCyclesYouWantToUseForOneSample; n++)
{
integrator += dacOutpuValue - oldValue;
if (integrator > 0)
{
oldValue = DACRESOLUTION; // DACRESOLUTION=255 for 8Bit
fastWrite(FASTSOUNDPIN, 1);
}
else
{
oldValue = 0;
fastWrite(FASTSOUNDPIN, 0);
}
}


ChrisMicro
Wed Apr 05, 2017 12:30 pm
Somehow I got now confused with the different Arduino Versions for my BluePill board.

Usually I compile the code on the Arduino IDE 1.6.6 with the Board Option “generic STM32F103 series” selected.

On Hackaday I found a installation procedure http://hackaday.com/2017/03/30/the-2-32 … debugging/
Than I have a board option “BluePill” but for some reason I don’t have the “HardwareTimer” class.
What is the correct way to have it on the BluePill?

And how should the code look like calling a periodic interrupt with the “HardwareTimer” class.
I have the tendency now to start “bare metal” programming of the timer like I did it for the DMA to skip all this confusing dependencies.


victor_pv
Wed Apr 05, 2017 7:53 pm
ChrisMicro wrote:Somehow I got now confused with the different Arduino Versions for my BluePill board.

Usually I compile the code on the Arduino IDE 1.6.6 with the Board Option “generic STM32F103 series” selected.

On Hackaday I found a installation procedure http://hackaday.com/2017/03/30/the-2-32 … debugging/
Than I have a board option “BluePill” but for some reason I don’t have the “HardwareTimer” class.
What is the correct way to have it on the BluePill?

And how should the code look like calling a periodic interrupt with the “HardwareTimer” class.
I have the tendency now to start “bare metal” programming of the timer like I did it for the DMA to skip all this confusing dependencies.


ChrisMicro
Thu Apr 06, 2017 6:21 am
I wonder if you can use the SPI port in DMA mode for the output rather than a normal port, so it doesn’t consume a byte of RAM for each output bit.
There was a mp3 player for the ESP8266 that did that, but I need to know how those sigma Delta DACs work before I can make full sense of the code.

That’s a very interesting hint. Using the SPI would realy speed up the time needed to write the DAC buffer.

I’m wondering how much CPU time it would take to output at 48Khz with at least 8 bit resolution.

I have made a new version where I write uint32 to the DMA buffer which speeds up the timing. Now it needs ~10us do write the DMA buffer which could theoretical lead to a sampling frequency of 100kHz.
The resolution of the DAC is hard to estimate, because it is dithering the noise over multiple samples.

Now I used also the “HardwareTimer” to generate the sine wave in a interrupt handler loop:

https://github.com/ChrisMicro/BluePillS … Oscillator


ag123
Thu Apr 06, 2017 12:10 pm
victor_pv wrote:ChrisMicro wrote:Somehow I got now confused with the different Arduino Versions for my BluePill board.
I’m wondering how much CPU time it would take to output at 48Khz with at least 8 bit resolution.

ChrisMicro
Thu Apr 06, 2017 3:54 pm
need to look up the manuals to see what is that fastest dma gpio bit banging rate to achieve it
Why do you simply flash my DMA-GPIO sigma delta example and measure it with an oscilloscope? :lol:

ag123
Thu Apr 06, 2017 4:17 pm
oops, at hi-fi speeds, this scope
http://www.stm32duino.com/viewtopic.php?f=19&t=107
is all i’ve or can make, probably can’t measure up to those hi-fi mhz traces
nevertheless would check out the synth :D

victor_pv
Thu Apr 06, 2017 11:58 pm
I dont think I have something fast enough either. I would think you may be getting no more than 36Mhz. From the datasheet, the DMA will share access to RAM with the cpu, but will not block it. I dont remember how many cpu ram IO cycles are allowed before the DMA is allowed one, but sure no less than 50% goes to the cpu. It’s probably lower than that thought.
That would give 36Mbit in a single pin.
The SPI port can do 36Mbit in a single pin too, but with 16bit transfers it only needs to read from ram 1 per 16 bits. So the DMA controller is able to maintain the SPI 1 word buffer full all the time.
Now if you wanted to use multiple pins with the SPI you could use both SPI, but with the GPIO ports I guess up to 16 channels if they are all in the same GPIO port, you are not adding any extra DMA transfer, would be interesting to push it to the limit…

Anyway, about using the SPI, you can set the DMA transfer pretty much similar to how you set it for GPIO, but need to enable the SPI port DMA request flag. Check the SPI library where we added dmaSend functions to do DMA transfers to get ideas.
You could also set the port to a different speed, since the speed is known, you can refill the buffer at the required rate, and keep the DMA in circular mode as you do for the GPIO.


ChrisMicro
Sun Apr 16, 2017 2:36 pm
Hi Victor,

I just realized that there is an upcoming Arduino sound library:
https://www.arduino.cc/en/Reference/ArduinoSound

Because you wrote the SD card audio player it could be a good idea to make the API somehow compatible.


victor_pv
Sun Apr 16, 2017 2:41 pm
ChrisMicro wrote:Hi Victor,

I just realized that there is an upcoming Arduino sound library:
https://www.arduino.cc/en/Reference/ArduinoSound

Because you wrote the SD card audio player it could be a good idea to make the API somehow compatible.


ChrisMicro
Sun Apr 16, 2017 3:48 pm
Have you seen the source to that Sound library somewhere?

I think it is this one:
https://github.com/arduino-libraries/Ar … master/src

and also very important, the I2S-class:
https://github.com/arduino/ArduinoCore- … rc/I2S.cpp


victor_pv
Sun Apr 16, 2017 5:44 pm
ChrisMicro wrote:Have you seen the source to that Sound library somewhere?

I think it is this one:
https://github.com/arduino-libraries/Ar … master/src

and also very important, the I2S-class:
https://github.com/arduino/ArduinoCore- … rc/I2S.cpp


ChrisMicro
Mon Apr 17, 2017 4:03 am
EDIT: had a look and the rest of the files don’t seem to have direct hardware access, so they should work with my i2s library. If you have a board with i2s, give it a shot. The mcus with i2s are the rct6 and higher.

The only board with I2S codec I have is a STM32F4 discovery.

I think for quick an cheap solutions the I2S DAC can be replaced by any other audio output device like
– built in PWM
– the DMA sigma delta
– SD-Card ( to store sounds )

As audio input
– a mircrophone
– a build in ADC
– built in synthesizer routines
– or stored sounds on a SD-card
could serve.

The sound library is made for attaching different in- and output devices but the only low level driver directly usable with it is for the Arduino Zero witch a SAMD21 microcontroller.

Because I think in general solutions usable for all people it would be useful if for any board supports a driver compatible to the Arduino sound library. Probably the best people suitable for this tasks are the core developers.


victor_pv
Mon Apr 17, 2017 4:53 am
ChrisMicro wrote:EDIT: had a look and the rest of the files don’t seem to have direct hardware access, so they should work with my i2s library. If you have a board with i2s, give it a shot. The mcus with i2s are the rct6 and higher.

The only board with I2S codec I have is a STM32F4 discovery.

I think for quick an cheap solutions the I2S DAC can be replaced by any other audio output device like
– built in PWM
– the DMA sigma delta
– SD-Card ( to store sounds )

As audio input
– a mircrophone
– a build in ADC
– built in synthesizer routines
– or stored sounds on a SD-card
could serve.

The sound library is made for attaching different in- and output devices but the only low level driver directly usable with it is for the Arduino Zero witch a SAMD21 microcontroller.

Because I think in general solutions usable for all people it would be useful if for any board supports a driver compatible to the Arduino sound library. Probably the best people suitable for this tasks are the core developers.


madias
Fri May 19, 2017 5:54 pm
Maybe you have read my version of a STM32duino synth in this project tab:
viewtopic.php?f=19&t=533
I never finished the project 100% (maybe 95%) because I lost interest & totally busy with my 2 kids
In short:
The best idea is to buy some cheap PT8211 DAC’s to get a “true” 16-bit sound. (they are in the (Euro) Cent region, so buy 20 or 50 for a few bugs)
There are two things you can do:
1. Using a STM32F103xx without I2s – I pretty shure (as I can remember) to get the DAC with only SPI to work. I think Victor did this.
2. Using a cheap STM32F103 board with activated I2s, like this one:
https://www.aliexpress.com/item/STM32F1 … 62693.html
I was using the board above to get a wavetable synth with 4 voice polyphony AND 4 individual outputs! (2 DAC – stereo = 4 mono) AND using the third SPI for everything else (like SD-Card, Flash RAM, Display)
The I2S-wavetable routine was totally slim and DMA driven (thanks to Victor) without MCU wasting (you have to read my complete thread to get the code, because I can’t remember everything)
The next advantage over the board above (I thing the xxxVET board is even much better): 256kb Flash and 48 RAM. So more RAM more accurate wavetables.

Also search this forum for: USB MIDI HID. I managed to get the STM32 via USB recognized as MIDI device. So no external MIDI hardware neccessary (if not needed).

A next level of synth MCU programming would be the STM32F4, because of it’s floting point features, so no stupid oldschool wavetables, but realtime processing sounds.

Edit: There must be another (at least one) thread about the PT8211 in this forum, can be easily found with the search function.

Edit 2: Found the SPI version of the PT8211 DAC, originally written by Vassilis (not Victor, sorry for that): viewtopic.php?f=18&t=519

Edit 3: I see, ChrisMicro, that you found already the thread :)


ag123
Sat May 20, 2017 5:38 pm
i think besides working as a ‘synth’ one of the main feature here is that delta sigma DAC which uses little other than simply ‘bit bang’ a digital pin and using an RC filter to get the resulting analog signal. accordingly this can possibly scale to very high precision e.g. 24 bits dependent on the signal-to-noise radio and the bit bang frequency. for 24 bits, my guess is that the bit bang bit rates would be in the order of million bits per secs to achieve those s/n ratios
http://www.beis.de/Elektronik/DeltaSigm … Sigma.html

i’t guess it is possible to imagine that given stm32f103 is a full usb device, it may be possible to create usb-audio on the usb side and for those digital audio, bit bang that on the pin, do that RC filter, some simple amplifiers (e.g. some transistors) and a 3.5mm jack and perhaps you may achieve a 24 bit stereo USB HD audio
i think it isn’t really very different from PWM DAC

did a little ‘crazy’ computations, assuming that we have single channel audio at 48 ksps, and lets say we want a 24 bit gratuity, so that means 2^24 ~ 16,777,216 ‘levels’ so that means a sample rate of 16.77 million bits / s x 48,000 ~ 805,306,368,000 ~ 805.3 gigabits per second? :shock:
hmm, strange, but even if you do super max overclock for stm32f103 u may ‘never’ get there 805 gigahertz not even intel i7 with the most powerful processor gets there :lol:


stevestrong
Sun Oct 22, 2017 9:58 am
Guys, does anyone know a PC software / tool which converts a WAV or MP3 file to delta-sigma format?
I would like to generate some short sound effects with the blue pill.
Or any alternative way to do it?

Leave a Reply

Your email address will not be published. Required fields are marked *