0
votes

I can't find such info in manual so I'm asking.

I'm designing PCB and I have problem with timers. I need to set up 8 independent PWMs and 6 counters (input frequency varies from 50Hz to 2kHz) and I don't have any free pins so remapping is not an option. Is it possible to mix modes within one timer but on different channels?

I mean is it possible to set up such configuration:

  • TIM1_CH1 - PWM
  • TIM1_CH2 - PWM
  • TIM1_CH3 - CNT
  • TIM1_CH4 - CNT

  • TIM2_CH1 - CNT
  • TIM2_CH2 - CNT
  • TIM2_CH3 - pin for this channel used for USART
  • TIM2_CH4 - pin for this channel used for USART

  • TIM3_CH1 - PWM
  • TIM3_CH2 - PWM
  • TIM3_CH3 - PWM
  • TIM3_CH4 - PWM

  • TIM4_CH1 - PWM
  • TIM4_CH2 - PWM
  • TIM4_CH3 - CNT
  • TIM4_CH4 - CNT
1
I suppose it's possible, but please clarify first what exactly do you want to do with those CNT channels? Just count the incoming edges, or measure exact pulse or cycle length or both?followed Monica to Codidact
Those counters are for tachometers. Three with single pulse and three with double pulse per revolution. So I just want to measure RPM.last

1 Answers

2
votes

Is it possible to mix modes within one timer but on different channels?

Yes, but they will share the counter and reload register. It means that if the PWMs are using a specific frequency, i.e. not just counting up to 65535 (which without a prescaler would give ~1 kHz @ 64 or 72 MHz), then the capture registers would get timestamps only in that range.

Each timer has only one counter, which is shared by its 4 channels. It can either count some clock events (APB clock, which usually equals the system clock), or one external trigger input. To generate a PWM signal, the counter must supply the PWM frequency. To count pulses on other input lines, DMA channels or interrupt routines are necessary to supply additional counters.

Counting with timer interrupts

You can set up 2 channels in PWM Mode and another 2 in Input capture mode, as described in the respective chapters of the Reference Manual. Enable interrupts on the input capture channels. In the interrupt handler, check the timer status register to see which channel has caused the interrupt, and do the counting. Be careful when resetting the interrupt bit in the status register, don't accidentally reset event bits that you haven't processed. This should work:

uint32_t t1c3, t1c4;
void TIM1_Handler(void) {
    if(TIM1->SR & TIM_SR_CC3IF) {
        t1c3++;
        TIM1->SR = ~TIM_SR_CC3IF;
    }
    if(TIM1->SR & TIM_SR_CC4IF) {
        t1c4++;
        TIM1->SR = ~TIM_SR_CC4IF;
    }
}

You can also read the timestamp values from the capture/compare registers if you need the exact elapsed time between two events.

Counting with EXTI interrupts

Any I/O pin can be an EXTI interrupt source, with the constraint that two pins with the same number can't be mapped as EXTI interrupt source at the same time, i.e. PA0,PA1,PB2,PC3,PA4 is OK, but PA0,PB0 isn't. Setting up EXTI interrupts might be easier than timer capture channels, the drawback is that there are no timestamps and no input filters.

Counting with DMA

Counting 6 channels with at most 2 kHz, i.e. the signals are at least 500 us apart, should be no problem for the MCU even with interrupts. However if the MCI has a lot of other things to do, and you have plenty of free DMA channels, you can set up the capture channels to generate DMA requests instead of interrupts.

Note that TIM4_CH4 has no DMA channel associated with, therefore you have to rearrange pins a bit, or use this channel in interrupt mode.

If you don't need the exact timings between events, then set up the DMA channels as peripheral to memory, 8 bits, circular mode, and disable both peripheral and memory address increment. Both source and destination addresses should be valid and byte adressable, but the values are not important. Put some large value in CNDTR, e.g. 0x8000 (to make overflow handling simpler). It will count the timer capture events (downwards) while copying the same byte over and over. You can check the counter in the control loop whenever it's needed.

This has the advantage of not using the MCU core at all, it can be put to sleep to conserve power, the peripheral blocks will do the counting autonomously. The disadvantage is of course that it uses 6 DMA channels (out of 7 e.g. on a STM32F103C8).

If you need the timestamps, you can let DMA copy them from the CCR registers to a real memory buffer, with memory increment turned on.