Library 48- Measure PWM input signal with STM32F4

First library in 2015 is here. With it, you will be able to measure PWM input signal from “other world”. STM32F4’s timers have capability to make an interrupt on edge, when signal is active on input pin for specific timer. This allows us, to measure signal in input. With a simple calculations, we can detect frequency of signal and duty cycle.

Of course, this is not veery accurate, but with 168MHz F407 device, using 32bit TIM2 (high resolution) I got pretty good results. Input PWM was set to random value 2545Hz with 23% duty cycle. Results from TIM2 were:

Frequency: 2545.13Hz

Duty cycle: 22.97%

Result’s quality depends on frequency you measure and also on timer’s performance (prescaler, max period value).

In library below, everything you have to set are:

Timer you will use for measuring signals

Timer’s IRQ for NVIC interrupt request

Create timer’s IRQ for interrupt handler

Call defined function in this handler

Call function to get results

More in example..

Library

Features

Measure PWM input signal on all available timers with input pin possibility

Table below shows all possible pins for each timer and channel. You can select any of max 3 pins for each input channel.

Timer

Channel 1

Channel 2

PP1

PP2

PP3

PP1

PP2

PP3

TIM 1

PA8

PE9

PA9

PE10

TIM 2

PA0

PA5

PA15

PA1

PB3

TIM 3

PA6

PB4

PC6

PA7

PB5

PC7

TIM 4

PB6

PD12

PB7

PD13

TIM 5

PA0

PH10

PA1

PH11

TIM 8

PC6

PI5

PC7

PI6

TIM 9

PA2

PE5

PA3

PE6

TIM 10

PB8

PF6

TIM 11

PB9

PF7

TIM 12

PB14

PH6

PB15

PH9

TIM 13

PA6

PF8

TIM 14

PA7

PF9

PPx: Pins Pack 1 to 3, for 3 possible channel outputs on timer.

Notes on table above

Not all timers are available on all STM32F4xx devices

Not all timers works with same tick frequency

All timers have 16bit prescaler

TIM6 and TIM7 don’t have PWM feature, they are only basic timers

TIM2 and TIM5 are 32bit timers

TIM10, TIM11, TIM13 and TIM14 have only one PWM channel

Only 1 channel can be selected on 1 timer

Other notes

If you don’t know which frequency you can expect on your input, then set initialization function to 1, which means that you want to measure minimal frequency of 1Hz. If you want to go even lower, you can basically go to a value of

TIM_CLOCK / (TIM_MAXPRESCALER * MAXTIM_PERIOD)

This can be very low value, but if you have then signal in 10kHz spectrum, your result can veery very fail from real. I suggest you that you set this value to 1 if you don’t know what you can expect, if you know, then set it to a little bit smaller value.

Example: if you expect signal of 1000Hz, then set value to 950 in initialization function or something like that

I suggest you to use 32-bit timer (TIM2, TIM5) to measure input PWM, you got better result and better accuracy

Expected frequency is just some kind of reference, how to set timer with prescaler, so you will be able to measure entire PWM period with one timer’s period value for valid result!

Default NVIC priority for all timers is set to 0x01. If you need to set another value, then use define in defines.h file:

PWM IN timers NVIC global priority

C

1

2

/* PWM IN timer global priority */

#define PWMIN_PRIORITY 0x01

Sub priority for timers is generated in a way that which timer you initialize first, this timer has higher sub priority.

Functions and enumerations

PWM IN functions and enumerations

C

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

/**

* PWM Input result enumeration

*

* Parameters:

* - TM_PWMIN_Result_Ok:

* Everything OK

* - TM_PWMIN_Result_TimerNotValid:

* Invalid timer selected for PWM input capture

* - TM_PWMIN_Result_ChannelNotValid:

* Invalid input channel selected for timer

* - TM_PWMIN_Result_PinNotValid:

* Invalid pin selected for timer

*/

typedefenum{

TM_PWMIN_Result_Ok=0,

TM_PWMIN_Result_TimerNotValid,

TM_PWMIN_Result_ChannelNotValid,

TM_PWMIN_Result_PinNotValid

}TM_PWMIN_Result_t;

/**

* PWM Input working struct

*

* Parameters:

* - float Frequency:

* Public, Measured frequency on input pin

* - float DutyCycle:

* Public, Measured duty cycle on input pin

* - TIM_TypeDef* __TIM:

* Private, Pointer to timer used for measure

* - TM_TIMER_PROPERTIES_t __TIM_Data:

* Settings about timer

* - float __Freq:

* Private, temporary frequency value

* - float __Duty:

* Private, temporary duty cycle value

* - uint8_t __SubPriority:

* Private, NVIC subpriority

*/

typedefstruct{

/* Public */

floatFrequency;

floatDutyCycle;

/* Private */

TIM_TypeDef*__TIM;

TM_TIMER_PROPERTIES_t __TIM_Data;

float__Freq;

float__Duty;

uint8_t __SubPriority;

}TM_PWMIN_t;

/**

* Select input channel for PWM input on specific timer

*

*/

typedefenum{

TM_PWMIN_Channel_1=0,

TM_PWMIN_Channel_2

}TM_PWMIN_Channel_t;

/**

* Select pin for input channel on specific timer

*

*/

typedefenum{

TM_PWMIN_PinsPack_1=0,

TM_PWMIN_PinsPack_2,

TM_PWMIN_PinsPack_3

}TM_PWMIN_PinsPack_t;

/**

* Initialize and prepare timer for input PWM capture

*

* Parameters:

* - TIM_TypeDef* TIMx:

* Timer you will use for input PWM capture

* - TM_PWMIN_t* PWMIN_Data:

* Pointer to an empty TM_PWMIN_t struct

* - TM_PWMIN_Channel_t PWMIN_Channel:

* Channel you will use on timer.

* - TM_PWMIN_PinsPack_t PinsPack:

* Pinspack you will use for your channel

* - float MinExpectedFrequency:

* Type minimal input frequency you expect in input. If you don't know what to expect, set to 1

* - IRQn_Type TIMx_IRQn:

* IRQ for NVIC settings. For TIM2 it can be TIM2_IRQn, for TIM3,4,5,... it can be TIMx_IRQn, where x is a number of timer