General questions on DIY synthesizers w/ STM32


#1

Greetings, I’ve recently gotten into synth DIY and I want build my own synth from scratch using an STM microcontroller! I’ve studied Emilie’s code and various other codes on synthesizers but it seems a bit too complex for me, and I would like to ask some general questions.
(I write in C++)

-What routines should go in interrupts and what in the main while loop?
-How do I go about creating a bootloader?
-When creating an Envelope Generator algorithm, what should I keep in mind? I’ve tried creating an envelope class and using 3 instances for 3 different envelopes but that seems to glitch everything up and doesn’t work as intended.
-What about RTOS? Should I use something like that?
-What about using usb midi?
-Note priority and note stack?

If anyone has any information or easy examples on any of these topics I would very much appreciate it!
I feel like I want to do so much but I always hit a wall and don’t know how to move forward logic wise, so I hope someone can help me understand how to implement these things!
Thanks in advance! :slight_smile:


#2

I personally don’t use interrupts for reading things like buttons, pots or monitoring CV inputs.

I use a fixed polling rate (sometimes 1k from a SysTick interrupt, sometimes a divider of the sample or block rate), poll the buttons; and shove events in a FIFO. In the main loop, I poll the events in the FIFO and can have as much time as I want to handle them.

So the bare minimum is an interrupt invoked every block of sample, from which I do the audio rendering, poll the I/O; and the only work done in the main loop is to process the events FIFO.

You need to break this down into a couple of subproblems:

  • Writing linkerscripts so that the code can either be located at the initial flash sector (for the bootloader), or further (for the main “application” code).
  • Writing tools for joining the bootloader and main application binaries, so they can be programmed on the chip in one single step.
  • Writing code for receiving the new firmware data (MIDI? Audio?).
  • Writing code for programming the MCU’s flash with the received data.
  • Writing code to jump to the main application code (either after an update, or if the module is powered on normally).

Examples of that are found throughout my code.

This might be a problem with your code, but there’s no reason why 3 instances of an envelope class would interfere with each other. Maybe because your envelope code is very CPU intensive and the MCU cannot handle more than 3 at once?

At the complexity level of a single-purpose module, probably not.

I haven’t worked on that on STM32, but I’m sure there are examples of USB MIDI devices provided by ST.

Yarns’ code?


#3

First of all, thank you for your reply Emilie!

Concerning the bootloader: In theory I have learnt pretty much what you say yourself, write some code that begins at the start of flash, and programs that are to be loaded begin after the last allocated memory in flash thats taken up by the bootloader.
Receiving hex data through MIDI (UART & sysex). Writing the actual data to flash AFTER the last address allocated in flash by the bootloader. And then after writing the program an verifying, jumps to the flash memory address where the main program begins. However what I’m not sure how exactly to do is the actual taking the data and writing to flash. But I’'l be sure to check out your bootloader code.

The problem with the envelopes is what confused me the most, since i’m positive tha t multiple instances of a class should not be a problem! This is most possibly a problem with my code and yet it still confuses me because it’s simple enough I don’t think it is too power intensive… it’s basically a main function with 5 arguments (each stage of an ADSR + a level) and goes through a state machine that adds and subtracts a variable that is sent to a DAC (the envelope DAC)… I guess it’s maybe a bit too much doing this x3 but i’m running a 72MHz MCU.
I’ll be sure to check out Yarns code on note priority etc as well.

Again thank you very much for the help and for taking the time to reply!


#4

Peaks could run two envelopes at 48k and this didn’t eat even 1/4 of the CPU. You probably made a mistake somewhere else! Just an idea: do you use floats by chance? On a processor without a FPU, floating point operations are emulated and this is slow as hell!

You’ll find an example in Yarns’ bootloader.