2024-12-03 06:06 PM - edited 2024-12-04 05:08 AM
I'm struggling with how to use the timers to achieve certain behavior and am looking for some advice. First I'll describe the purpose, then how I tried to approach it, and then why I'm stuck.
I need a 32-bit timebase that counts up at exactly 48kHz and always runs, rolling over from 0xffffffff back to 0. This timebase is used to precisely "schedule" the start of DAC and/or ADC conversions at some future counter value. For example, if the current counter value is 12345, I might want to start DAC conversion at counter value 20000. Optionally, I might also want to start ADC conversion at counter value 20100. The DAC and ADC are scheduled independently but may overlap. Once triggered, the DAC/ADC channels should continue running until disabled by software. It's important that the timebase, DAC sampling, and ADC sampling are all synchronized at 48kHz such that they maintain a consistent relative phase offset, even across conversion windows. Since my application would be very sensitive to relative timing jitter, I am trying to do as much as possible via hardware events. In a nutshell, I want to use one always-running timer to precisely time-gate the start of continuous ADC and DAC windows.
My first thought was to configure TIM2.PSC for a 48kHz counter rate and set TIM2.ARR to 0xFFFFFFFF, so TIM2 is the 32-bit timebase. Then I'd use its CH1 and CH2 in output compare mode to trigger the start of two other timers (TIM4 and TIM5) that would clock the DAC and ADC, respectively. For example, TIM2.CCR1 is the future counter value to start the DAC conversion. TIM4 and TIM5 would be configured as slaves to TIM2 and would be triggered to start via TIM2's CH1 and CH2 events. Then to stop the DAC/ADC, software would later disable TIM4/TIM5.
The problem here is that TIM2 only has one trigger output (trgo), so I don't see a way that TIM2 can use OC1 as a trigger to TIM4 while simultaneously using OC2 as a trigger to start TIM5. Or, maybe I'm misunderstanding the signals. For now I'm going to just start it from an ISR, but any thoughts on how to accomplish this would be much appreciated - happy to discuss as raw registers or as CubeMX HAL nomenclature.
2024-12-04 05:13 AM
I may have misunderstood you, but it sounds to me, that you want to trigger DAC and ADC from one or more timers which have a 1/48kHz period.
So, I would set up some suitable timer (let's call it TIMx) to have that period, and have that as timebase for TIM2 instead of using TIM2 prescaler. At the same same, I would chose TIMx so that it could trigger DAC and ADC transfers possibly from two of its channels, to allow for phase shift between them within the 1/48kHz period.
To enable/disable ADC/DAC sampling, it's then enough to change the given TIMx_CHx channel's Compare Mode in TIMx_CCMRx.OCxM from Frozen to PWM and vice versa. And to achieve that, you can trigger a DMA transfer by TIM2's CC at the proper moment, which would transfer a suitable value from a buffer in memory to TIMx_CCMRx.
If this is not what you intend to achieve, I may have misunderstood your intentions - you may perhaps try to sketch some example timing diagram then.
JW
2024-12-04 05:56 AM
Thanks for the response - using the TIM CC's DMA capability to alter a controller register is not something I had considered. I'll take a closer look at that, and if I'm still stuck I'll follow-up with a diagram.
Cheers.
2024-12-04 10:04 AM
Thanks again for the idea. I think it would achieve the behavior I'm looking for, but I've run into a few roadblocks with it - please let me know if I've overlooked something..
Thank you.