2022-04-12 12:54 PM
It's a STM32L053R8 (Nucleo64) and i am using a DAC with circular DMA to generate an analog waveform. Now i need to use a PWM timer to generate some digital output signals synchronous to the DMA cycle. Can i use two pins to route the DMA interrupt to the PWM timer? Is there on-chip circuitry for this?
2022-04-12 01:35 PM
Probably not, but you could trigger the DAC and the PWM using the same timer, which will be synchronized.
2022-04-12 03:39 PM
Meanwhile i learned that the DMA interrupt is jittery, so no good for timing. Anyway the DMA counter isn't directly related to the DAC output, as it feeds the data holding register. Probably one needs to disable interrupts and start the DAC trigger timer and the PWM timer "at the same time" and hope they will remain in phase, except a constant phase error of some instructions. Maybe one should implement the DMA interrupt and check the phase relation, with a recovery procedure in case of error.
2022-04-12 06:02 PM
> Probably one needs to disable interrupts and start the DAC trigger timer and the PWM timer "at the same time"
This is why there are TRGO->TRGI connections between the timers. Use them.
JW
2022-04-14 04:41 AM
The solution i found now uses Tim6 to trigger the DAC (and its DMA, 15 samples) and Tim2 to generate the PWM signals. In order to synchronize DAC and PWM i am using the fourth channel of Tim2 in capture mode with Comparator2 to trigger on a feature in the DAC output waveform. So there is a wire from the DAC output pin to the comparator input pin. The capture interrupt handler implements error recovery in case one of the two timers or the DMA source address counter falls out of sync (primitive PLL).
#include "main.h"
// 2022-04-13 DT
// PLL locks Tim2 PWM onto DMA DAC using comparator 2
extern TIM_HandleTypeDef htim2;
// count adjustments to detect residual jitter
static uint32_t iNUp=0L,iNDown=0L;
#define PhaseOffset 5
#define FrequCenter 10004
#define FrequHalf 5002
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) {
if ((FrequHalf < htim2.Instance->CCR4)
|| (htim2.Instance->CCR4 < PhaseOffset)) {
htim2.Instance->ARR = FrequCenter+1;
iNUp++;
}
else if (htim2.Instance->CCR4 == PhaseOffset)
htim2.Instance->ARR = FrequCenter;
else {
htim2.Instance->ARR = FrequCenter-1;
iNDown++;
}
}