In the previous article, I described how to calculate envelope curves and how to determine the calculation parameters. This article is about calculation speed. I implemented the ADSR calculation and found that it’s desirable to update envelope values as fast as every 125 microseconds (8 kHz). The STM32C092KCT controller has clock frequency 48 MHz at the highest. Each update interval has 6,000 clock cycles. I wonder the number of cycles are enough to run the envelope generator. I’m sure they are enough to calculate the values, but the controller has more jobs than that in order to run as a module:
- Send data to DAC, there will be two channels as the module would be dual voice
- Update envelope values
- Read ADC for module parameters and gate signals
- Handle CAN messages
which I feel a lot. Among them, sending data to DAC should be the most time consuming and it’s likely to occupy the controller. I’m planning to use MCP4726 for the DAC that uses I2C to transfer data. The device supports 3.4 mbps high speed I2C mode but the controller does not. So I have to use 400 kbps fast mode instead. A single DAC update takes two bytes. 40 microsecond is needed at least to send it in fast mode. It takes a significant part of 125 microseconds of update interval. So I first tried to send data in background using DMA or interrupt mode of I2C methods, but these seem to have too large overhead, the updates weren’t fast enough to catch up real time speed. The regular blocking I2C method is fast since it polls on register flags, but it occupies the controller while sending the data. I measured how long it takes.
I reduced the speed of the update frequency to 4 kHz for the measurement. Added debug code that toggles a debug pin at several places in the I2C transmit method. The following is the result.

The entire transfer takes about 100 microseconds. The time to take comes from the hardware, so there is only a little room to improve the latency. If I go for 8 kHz DAC update, it’s not possible for two DACs share a I2C bus. I will need two busses. Fortunately, STM32C092KCT has two I2C channels. I’ll test using the two buses later.
If 100 microseconds are spent for I2C data transmission, only 25 microseconds are available for other calculation, mainly for updating the envelope. It may be too tight. The I2C transmitting method has to be broken into multiple parts to spend the processor time for other purposes while waiting for the flags.
Another possibility in design is to use PWM instead of using DAC. In that case, update for DA conversion takes only a very short time period. Putting a value to the comparator register is enough. Also, two I2C channel consumes four pins, but PWM takes only two pins. A disadvantage of PWM is that its minimum update interval is long for finer resolution. Requiring external filter for flattening. It’s going to be a tradeoff, but if the PWM is useful, the firmware code would be much simpler.






