@@ -49,7 +49,7 @@ STATIC void tim_clock_disable(uint16_t mask);
49
49
// If the APB prescaler is 1, then the timer clock is equal to its respective
50
50
// APB clock. Otherwise (APB prescaler > 1) the timer clock is twice its
51
51
// respective APB clock. See DM00031020 Rev 4, page 115.
52
- static uint32_t timer_get_source_freq (uint32_t tim_id ) {
52
+ STATIC uint32_t timer_get_source_freq (uint32_t tim_id ) {
53
53
uint32_t source , clk_div ;
54
54
if (tim_id == 1 || (8 <= tim_id && tim_id <= 11 )) {
55
55
// TIM{1,8,9,10,11} are on APB2
@@ -67,6 +67,26 @@ static uint32_t timer_get_source_freq(uint32_t tim_id) {
67
67
return source ;
68
68
}
69
69
70
+ STATIC uint32_t timer_get_internal_duty (uint16_t duty , uint32_t period ) {
71
+ //duty cycle is duty/0xFFFF fraction x (number of pulses per period)
72
+ return (duty * period )/((1 <<16 )- 1 );
73
+ }
74
+
75
+ STATIC void timer_get_optimal_divisors (uint32_t * period , uint32_t * prescaler ,
76
+ uint32_t frequency , uint32_t source_freq ) {
77
+ //Find the largest possible period supported by this frequency
78
+ for (int i = 0 ; i < (1 << 16 );i ++ ) {
79
+ * period = source_freq /(i * frequency );
80
+ if (* period < (1 << 16 ) && * period >=2 ) {
81
+ * prescaler = i ;
82
+ break ;
83
+ }
84
+ }
85
+ if (* prescaler == 0 ) {
86
+ mp_raise_ValueError (translate ("Invalid frequency supplied" ));
87
+ }
88
+ }
89
+
70
90
void pwmout_reset (void ) {
71
91
uint16_t never_reset_mask = 0x00 ;
72
92
for (int i = 0 ;i < TIM_BANK_ARRAY_LEN ;i ++ ) {
@@ -112,17 +132,21 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
112
132
bool first_time_setup = true;
113
133
114
134
for (uint i = 0 ; i < tim_num ; i ++ ) {
135
+ mcu_tim_pin_obj_t l_tim = mcu_tim_pin_list [i ];
136
+ uint8_t l_tim_index = l_tim .tim_index - 1 ;
137
+ uint8_t l_tim_channel = l_tim .channel_index - 1 ;
138
+
115
139
//if pin is same
116
- if (mcu_tim_pin_list [ i ] .pin == pin ) {
140
+ if (l_tim .pin == pin ) {
117
141
//check if the timer has a channel active
118
- if (reserved_tim [mcu_tim_pin_list [ i ]. tim_index - 1 ] != 0 ) {
142
+ if (reserved_tim [l_tim_index ] != 0 ) {
119
143
//is it the same channel? (or all channels reserved by a var-freq)
120
- if (reserved_tim [mcu_tim_pin_list [ i ]. tim_index - 1 ] & 1 <<(mcu_tim_pin_list [ i ]. channel_index - 1 )) {
144
+ if (reserved_tim [l_tim_index ] & 1 <<(l_tim_channel )) {
121
145
tim_chan_taken = true;
122
146
continue ; //keep looking, might be another viable option
123
147
}
124
148
//If the frequencies are the same it's ok
125
- if (tim_frequencies [mcu_tim_pin_list [ i ]. tim_index - 1 ] != frequency ) {
149
+ if (tim_frequencies [l_tim_index ] != frequency ) {
126
150
tim_taken_f_mismatch = true;
127
151
continue ; //keep looking
128
152
}
@@ -134,7 +158,7 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
134
158
first_time_setup = false; //skip setting up the timer
135
159
}
136
160
//No problems taken, so set it up
137
- self -> tim = & mcu_tim_pin_list [ i ] ;
161
+ self -> tim = & l_tim ;
138
162
break ;
139
163
}
140
164
}
@@ -170,41 +194,14 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
170
194
GPIO_InitStruct .Alternate = self -> tim -> altfn_index ;
171
195
HAL_GPIO_Init (pin_port (pin -> port ), & GPIO_InitStruct );
172
196
173
- //TODO: factor all of these into periph.c?
174
197
tim_clock_enable (1 <<(self -> tim -> tim_index - 1 ));
175
198
176
199
//translate channel into handle value
177
- switch (self -> tim -> channel_index ) {
178
- case 1 : self -> channel = TIM_CHANNEL_1 ; break ;
179
- case 2 : self -> channel = TIM_CHANNEL_2 ; break ;
180
- case 3 : self -> channel = TIM_CHANNEL_3 ; break ;
181
- case 4 : self -> channel = TIM_CHANNEL_4 ; break ;
182
- }
183
-
184
- uint32_t source_freq = timer_get_source_freq (self -> tim -> tim_index );
185
- uint32_t prescaler = 0 ;
186
- uint32_t period = 0 ;
187
-
188
- for (int i = 0 ; i < 32767 ;i ++ ) {
189
- period = source_freq /(i * frequency );
190
- if (period <= 65535 && period >=2 ) {
191
- prescaler = i ;
192
- break ;
193
- }
194
- }
195
- if (prescaler == 0 ) {
196
- mp_raise_ValueError (translate ("Invalid frequency supplied" ));
197
- }
198
- uint32_t input = (duty * period )/65535 ;
200
+ self -> channel = 4 * (self -> tim -> channel_index - 1 );
199
201
200
- //Used for Debugging
201
- // mp_printf(&mp_plat_print, "Duty:%d, Pulses:%d\n", duty,input);
202
- // mp_printf(&mp_plat_print, "SysCoreClock: %d\n", SystemCoreClock);
203
- // mp_printf(&mp_plat_print, "Source Freq: %d\n", source_freq);
204
- // mp_printf(&mp_plat_print, "Prescaler %d, Timer Freq: %d\n", prescaler, source_freq/prescaler);
205
- // mp_printf(&mp_plat_print, "Output Freq: %d\n", (source_freq/prescaler)/period);
206
- // mp_printf(&mp_plat_print, "Duty: %d\n", duty);
207
- // mp_printf(&mp_plat_print, "TIM#:%d CH:%d ALTF:%d\n", self->tim->tim_index, self->tim->channel_index, self->tim->altfn_index);
202
+ uint32_t prescaler = 0 ; //prescaler is 15 bit
203
+ uint32_t period = 0 ; //period is 16 bit
204
+ timer_get_optimal_divisors (& period , & prescaler ,frequency ,timer_get_source_freq (self -> tim -> tim_index ));
208
205
209
206
//Timer init
210
207
self -> handle .Instance = TIMx ;
@@ -223,7 +220,7 @@ pwmout_result_t common_hal_pulseio_pwmout_construct(pulseio_pwmout_obj_t* self,
223
220
224
221
//Channel/PWM init
225
222
self -> chan_handle .OCMode = TIM_OCMODE_PWM1 ;
226
- self -> chan_handle .Pulse = input ; //-1?
223
+ self -> chan_handle .Pulse = timer_get_internal_duty ( duty , period );
227
224
self -> chan_handle .OCPolarity = TIM_OCPOLARITY_LOW ;
228
225
self -> chan_handle .OCFastMode = TIM_OCFAST_DISABLE ;
229
226
self -> chan_handle .OCNPolarity = TIM_OCNPOLARITY_LOW ; // needed for TIM1 and TIM8
@@ -269,13 +266,10 @@ void common_hal_pulseio_pwmout_deinit(pulseio_pwmout_obj_t* self) {
269
266
}
270
267
}
271
268
272
- void common_hal_pulseio_pwmout_set_duty_cycle (pulseio_pwmout_obj_t * self , uint16_t duty_cycle ) {
273
- uint32_t input = (duty_cycle * self -> period )/65535 ;
274
- //Used for debugging
275
- //mp_printf(&mp_plat_print, "duty_cycle %d, Duty: %d, Input %d\n", duty_cycle, duty, input);
276
- __HAL_TIM_SET_COMPARE (& self -> handle , self -> channel , input );
277
-
278
- self -> duty_cycle = duty_cycle ;
269
+ void common_hal_pulseio_pwmout_set_duty_cycle (pulseio_pwmout_obj_t * self , uint16_t duty ) {
270
+ uint32_t internal_duty_cycle = timer_get_internal_duty (duty , self -> period );
271
+ __HAL_TIM_SET_COMPARE (& self -> handle , self -> channel , internal_duty_cycle );
272
+ self -> duty_cycle = duty ;
279
273
}
280
274
281
275
uint16_t common_hal_pulseio_pwmout_get_duty_cycle (pulseio_pwmout_obj_t * self ) {
@@ -286,30 +280,9 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_
286
280
//don't halt setup for the same frequency
287
281
if (frequency == self -> frequency ) return ;
288
282
289
- uint32_t source_freq = timer_get_source_freq (self -> tim -> tim_index );
290
283
uint32_t prescaler = 0 ;
291
284
uint32_t period = 0 ;
292
-
293
- for (int i = 0 ; i < 32767 ;i ++ ) {
294
- period = source_freq /(i * frequency );
295
- if (period <= 65535 && period >=2 ) {
296
- prescaler = i ;
297
- break ;
298
- }
299
- }
300
- if (prescaler == 0 ) {
301
- mp_raise_ValueError (translate ("Invalid frequency supplied" ));
302
- }
303
-
304
- uint32_t input = (self -> duty_cycle * period )/65535 ;
305
-
306
- //debugging output
307
- // mp_printf(&mp_plat_print, "Duty:%d, Pulses:%d\n", self->duty_cycle,input);
308
- // mp_printf(&mp_plat_print, "Period: %d\n", period);
309
- // mp_printf(&mp_plat_print, "Source Freq: %d\n", source_freq);
310
- // mp_printf(&mp_plat_print, "Prescaler %d, Timer Freq: %d\n", prescaler, source_freq/prescaler);
311
- // mp_printf(&mp_plat_print, "Output Freq: %d\n", (source_freq/prescaler)/period);
312
- // mp_printf(&mp_plat_print, "TIM#:%d CH:%d ALTF:%d\n", self->tim->tim_index, self->tim->channel_index, self->tim->altfn_index);
285
+ timer_get_optimal_divisors (& period , & prescaler ,frequency ,timer_get_source_freq (self -> tim -> tim_index ));
313
286
314
287
//shut down
315
288
HAL_TIM_PWM_Stop (& self -> handle , self -> channel );
@@ -323,7 +296,7 @@ void common_hal_pulseio_pwmout_set_frequency(pulseio_pwmout_obj_t* self, uint32_
323
296
mp_raise_ValueError (translate ("Could not re-init timer" ));
324
297
}
325
298
326
- self -> chan_handle .Pulse = input ;
299
+ self -> chan_handle .Pulse = timer_get_internal_duty ( self -> duty_cycle , period ) ;
327
300
328
301
if (HAL_TIM_PWM_ConfigChannel (& self -> handle , & self -> chan_handle , self -> channel ) != HAL_OK ) {
329
302
mp_raise_ValueError (translate ("Could not re-init channel" ));
0 commit comments