timer interrupt, serving to DAC channels on stm32

marinayelken wrote on Monday, December 24, 2018:

Dear everybody,

I use fatfs, and read some sound data from files, send the data to dac pin. I have a jitter in high frequencies. the mcu is running at 72 mhz, stm32f105r8t. instead of using dma, I set up my code on hardware timer interrupt. The sound is sampled at 20k samples/sec. theorical max audible freq. is 10khz.

I suspect that, the reason of the jitter is interrupt priority of hardware timer. The timer interrupt must have higher prioritiy than all OS interrups. What is the solution for that case? I use STMcubeMX code configuration tool.



richarddamon wrote on Monday, December 24, 2018:

To play back sound, you really want to DAC update to be hard fixed on a hardwre timer and not dependant on program timing, even via a high priority ISR. I beleive that the STM32 processors have the ability to have the DACs actually update on a timer overflow, giving you the full period (50us in your case since you say 20 kHz sample rate) to prepare the next value and put it into the shadow register.

This would be a good use for DMA in my opinion, while the processor should be able to handle this in an ISR, it does say that the ISR will consume a significant portion of the machines processor, especially if using something like the Cube is a very generic ISR with a callback attached to do your work.

If you were to use an ISR directly, it absolutley needs to be a minimal work custom designed ISR which is designed to have low jitter performance from interrupt to update. The ISR would need to have a priority above (lower in value) than what is allowed to interract with FreeRTOS so that critical section do not delay it, which also means that it can’t use any FreeRTOS calls itself to indicate that something more needs to happen (like get more data). If you do need (and you likely do) to trigger something to get more data, then that ISR needs to, AFTER sending the data, trigger another interrupt of a priority that can call FreeRTOS to trigger that request.

My personal experiance with the Cube is that the configuration tool is just ok for figuring out the configuration of the system, but sometimes it can’t handle all of the cases you want, so you do need to add some configuration code afterwards, and that some of the Cube device handlers are less than ideal, so you want to write your own handlers for some things. This is especially true of its use of a very general application non-specific ISR with callbacks, as this often doesn’t work if you have critical timing. Some of the Cube drivers also put time delays (perhaps substantial) in an ISR, which is in my mind very bad

marinayelken wrote on Monday, December 24, 2018:

Thanks Richard,

The problem is, the data on DAC is not always the one read from SDcard or USB. There are some simultaneous messages, like a background music, and informational announce at the same time, they are read from a FAT device, but, the importance of the message is effecting the amount of music volume (loud or silent), this is done by shifting the values of music data which is read from the file 1 bit, at the and 2 values (music and announce) are summed and then out to a single DAC output. I checked the interrupt priority of the timer6, which will service to the DAC, and set it to 1. While the LIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY of the FreeRTOS is left its original value, which is 5. In this case I hope to eliminate the jitter in the sound. The OS critical areas were delaying the timer interrupt, which I can see in the oscillator, and caused the jitter. What I have to do is, not to use any OS functions and the variables in the TIMER6 interrupt service routine.

marinayelken wrote on Monday, December 24, 2018:

richarddamon wrote on Monday, December 24, 2018:

Using the shadow registers and loading the DAC registers automaticly on trigger does not prevent you from having multiple sources. It does add about 1 sample of delay (50us) but that shouldn’t be an issue unless you are trying to mix in ADC values from a source that would be heard in parrallel, but then even the ADC/DAC combination may add enough delay to be noticable (Real time mixing of live sources is a tough job) unless things are spacially far enough that time of flight causes comparable delays.

If with the interrupt higher priority then the SYSCALL limit, you are still getting too much jitter, that would be due to the inefficencies in the Cube callback system. It is NOT designed for low jitter requirements, that is what the shadow register is for.

heinbali01 wrote on Monday, December 24, 2018:

Hi Erkut, now you’re mixing sounds signals within an interrupt. I agree with Richard Damon, that you’ll never be able to produce a stable sound ( without jitter ) as long as samples are presented from within an ISR.

I think that you’d better use a DAC with DMA. This will cause a small (but constant) delay of a few hundred samples.

You could even keep using your timer interrupt with all its logic, but let if fill a buffer. Once a buffer is full, send it to DMA.

richard_damon wrote on Monday, December 24, 2018:

Hein, while DMA is helpful to cut down the processor load, you can send the data in the ISR, the key is that the send from the ISR should not go directly into the converter, but into the shadow register that gets loaded on the trigger from the timer. The one key is that to even try to use DMA, you have to setup the trigger, while with direct loading (and not using the shadow registers, and thus getting the jitter) you don’t need to setup the trigger… Using the trigger is the key to removing the jitter, and that means that you have to chose a proper counter, as if I remember, not all timers can generate DAC trigggers.