Firmware SDK
twr_pwm.c
1 #include <twr_pwm.h>
2 
3 /*
4  Table of pins and TIM channels
5 
6  P0 PA0 TIM2_CH1
7  P1 PA1 TIM2_CH2
8  P2 PA2 TIM2_CH3 TIM21_CH1
9  P3 PA3 TIM2_CH4 TIM21_CH2
10  P4 PA4 none
11  P5 PA5 TIM2_CH1
12  P6 PB1 TIM3_CH4
13  P7 PA6 TIM3_CH1 TIM22_CH2
14  P8 PB0 TIM3_CH3
15  P9 PB2 LPTIM1_OUT
16 
17  P10 PA10 none
18  P11 PA9 none
19  P12 PB14 TIM21_CH2
20  P13 PB15 none
21  P14 PB13 TIM21_CH1
22  P15 PB12 none
23  P16 PB8 none
24  P17 PB9 none
25 */
26 
27 static void _twr_pwm_tim2_configure(uint32_t resolution_us, uint32_t period_cycles)
28 {
29  // Enable TIM2 clock
30  RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;
31 
32  // Errata workaround
33  RCC->APB1ENR;
34 
35  // Disable counter if it is running
36  TIM2->CR1 &= ~TIM_CR1_CEN;
37 
38  // Set prescaler to 5 * 32 (5 microseconds resolution)
39  //TIM2->PSC = 5 * 32 - 1;
40  TIM2->PSC = resolution_us * 32 - 1;
41  TIM2->ARR = period_cycles - 1;
42 
43  // CH1
44  TIM2->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
45  TIM2->CCER |= TIM_CCER_CC1E;
46  // CH2
47  TIM2->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;
48  TIM2->CCER |= TIM_CCER_CC2E;
49  // CH3
50  TIM2->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
51  TIM2->CCER |= TIM_CCER_CC3E;
52  // CH4
53  TIM2->CCMR2 |= TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2;
54  TIM2->CCER |= TIM_CCER_CC4E;
55 
56  TIM2->CR1 |= TIM_CR1_CEN;
57 }
58 
59 static void _twr_pwm_tim3_configure(uint32_t resolution_us, uint32_t period_cycles)
60 {
61  // Enable TIM3 clock
62  RCC->APB1ENR |= RCC_APB1ENR_TIM3EN;
63 
64  // Errata workaround
65  RCC->APB1ENR;
66 
67  // Disable counter if it is running
68  TIM3->CR1 &= ~TIM_CR1_CEN;
69 
70  // Set prescaler to 5 * 32 (5 microseconds resolution)
71  TIM3->PSC = resolution_us * 32 - 1;
72  TIM3->ARR = period_cycles - 1;
73 
74  // CH1
75  TIM3->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
76  TIM3->CCER |= TIM_CCER_CC1E;
77  // CH2 - is on PB5 - RADIO_MOSI
78  //TIM3->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;
79  //TIM3->CCER |= TIM_CCER_CC2E;
80  // CH3
81  TIM3->CCMR2 |= TIM_CCMR2_OC3M_1 | TIM_CCMR2_OC3M_2;
82  TIM3->CCER |= TIM_CCER_CC3E;
83  // CH4
84  TIM3->CCMR2 |= TIM_CCMR2_OC4M_1 | TIM_CCMR2_OC4M_2;
85  TIM3->CCER |= TIM_CCER_CC4E;
86 
87  TIM3->CR1 |= TIM_CR1_CEN;
88 }
89 
90 static void _twr_pwm_tim21_configure(uint32_t resolution_us, uint32_t period_cycles)
91 {
92  // Enable TIM21 clock
93  RCC->APB2ENR |= RCC_APB2ENR_TIM21EN;
94 
95  // Errata workaround
96  RCC->APB2ENR;
97 
98  // Disable counter if it is running
99  TIM21->CR1 &= ~TIM_CR1_CEN;
100 
101  // Set prescaler to 5 * 32 (5 microseconds resolution)
102  TIM21->PSC = resolution_us * 32 - 1;
103  TIM21->ARR = period_cycles - 1;
104 
105  // CH1
106  TIM21->CCMR1 |= TIM_CCMR1_OC1M_1 | TIM_CCMR1_OC1M_2;
107  TIM21->CCER |= TIM_CCER_CC1E;
108  // CH2
109  TIM21->CCMR1 |= TIM_CCMR1_OC2M_1 | TIM_CCMR1_OC2M_2;
110  TIM21->CCER |= TIM_CCER_CC2E;
111 
112  TIM21->CR1 |= TIM_CR1_CEN;
113 }
114 
115 void twr_pwm_tim_configure(twr_pwm_tim_t tim, uint32_t resolution_us, uint32_t period_cycles)
116 {
117  switch (tim)
118  {
119  case TWR_PWM_TIM2_P0_P1_P2_P3:
120  {
121  _twr_pwm_tim2_configure(resolution_us, period_cycles);
122  break;
123  }
124  case TWR_PWM_TIM3_P6_P7_P8:
125  {
126  _twr_pwm_tim3_configure(resolution_us, period_cycles);
127  break;
128  }
129  case TWR_PWM_TIM21_P12_P14:
130  {
131  _twr_pwm_tim21_configure(resolution_us, period_cycles);
132  break;
133  }
134  default:
135  {
136  break;
137  }
138  }
139 }
140 
142 {
143  static bool tim2_initialized = false;
144  static bool tim3_initialized = false;
145  static bool tim21_initialized = false;
146  static bool pll_enabled = false;
147 
148  if (!pll_enabled)
149  {
150  twr_system_pll_enable();
151  pll_enabled = true;
152  }
153 
154  if (!tim2_initialized && (channel == TWR_PWM_P0 || channel == TWR_PWM_P1 || channel == TWR_PWM_P2 || channel == TWR_PWM_P3))
155  {
156  // 5 us * 255 = cca 784 Hz
157  twr_pwm_tim_configure(TWR_PWM_TIM2_P0_P1_P2_P3, 5, 255);
158  tim2_initialized = true;
159  }
160 
161  if (!tim3_initialized && (channel == TWR_PWM_P6 || channel == TWR_PWM_P7 || channel == TWR_PWM_P8))
162  {
163  twr_pwm_tim_configure(TWR_PWM_TIM3_P6_P7_P8, 5, 255);
164  tim3_initialized = true;
165  }
166 
167  if (!tim21_initialized && (channel == TWR_PWM_P12 || channel == TWR_PWM_P14))
168  {
169  twr_pwm_tim_configure(TWR_PWM_TIM21_P12_P14, 5, 255);
170  tim21_initialized = true;
171  }
172 }
173 
175 {
177 
178  if (channel == TWR_PWM_P12 || channel == TWR_PWM_P14)
179  {
181  }
182  else
183  {
185  }
186 }
187 
189 {
191 }
192 
193 void twr_pwm_set(twr_pwm_channel_t channel, uint16_t pwm_value)
194 {
195  switch (channel)
196  {
197  case TWR_PWM_P0:
198  {
199  TIM2->CCR1 = pwm_value;
200  break;
201  }
202  case TWR_PWM_P1:
203  {
204  TIM2->CCR2 = pwm_value;
205  break;
206  }
207  case TWR_PWM_P2:
208  {
209  TIM2->CCR3 = pwm_value;
210  break;
211  }
212  case TWR_PWM_P3:
213  {
214  TIM2->CCR4 = pwm_value;
215  break;
216  }
217  case TWR_PWM_P6:
218  {
219  TIM3->CCR4 = pwm_value;
220  break;
221  }
222  case TWR_PWM_P7:
223  {
224  TIM3->CCR1 = pwm_value;
225  break;
226  }
227  case TWR_PWM_P8:
228  {
229  TIM3->CCR3 = pwm_value;
230  break;
231  }
232  case TWR_PWM_P12:
233  {
234  TIM21->CCR2 = pwm_value;
235  break;
236  }
237  case TWR_PWM_P14:
238  {
239  TIM21->CCR1 = pwm_value;
240  break;
241  }
242  default:
243  {
244  break;
245  }
246  }
247 }
void twr_gpio_init(twr_gpio_channel_t channel)
Initialize GPIO channel.
Definition: twr_gpio.c:325
twr_gpio_channel_t
GPIO channels.
Definition: twr_gpio.h:13
void twr_gpio_set_mode(twr_gpio_channel_t channel, twr_gpio_mode_t mode)
Set mode of operation for GPIO channel.
Definition: twr_gpio.c:367
@ TWR_GPIO_MODE_ALTERNATE_2
GPIO channel operates in alternate mode AF2.
Definition: twr_gpio.h:126
@ TWR_GPIO_MODE_ALTERNATE_6
GPIO channel operates in alternate mode AF6.
Definition: twr_gpio.h:138
@ TWR_GPIO_MODE_ANALOG
GPIO channel operates in analog mode.
Definition: twr_gpio.h:114
void twr_pwm_enable(twr_pwm_channel_t channel)
Enable PWM output on GPIO pin.
Definition: twr_pwm.c:174
void twr_pwm_set(twr_pwm_channel_t channel, uint16_t pwm_value)
Set PWM value for GPIO pin.
Definition: twr_pwm.c:193
void twr_pwm_tim_configure(twr_pwm_tim_t tim, uint32_t resolution_us, uint32_t period_cycles)
Reconfigure TIM3.
Definition: twr_pwm.c:115
void twr_pwm_init(twr_pwm_channel_t channel)
Initialize PWM timers based on GPIO pin.
Definition: twr_pwm.c:141
twr_pwm_tim_t
PWM timers.
Definition: twr_pwm.h:34
twr_pwm_channel_t
PWM channels.
Definition: twr_pwm.h:15
void twr_pwm_disable(twr_pwm_channel_t channel)
Disable PWM output on GPIO pin.
Definition: twr_pwm.c:188