Skip to content

Commit 32b6654

Browse files
authoredNov 21, 2024··
Merge pull request #2572 from fpistm/HT_FIX
fix(hardwaretimer): avoid glitch when PWM configuration changed
·
2.10.12.9.0
2 parents 339e2b9 + 6c30d95 commit 32b6654

File tree

3 files changed

+96
-100
lines changed

3 files changed

+96
-100
lines changed
 

‎keywords.txt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -862,8 +862,7 @@ GPIO_PIN_14 LITERAL1
862862
GPIO_PIN_15 LITERAL1
863863

864864
# HardwareTimer
865-
TIMER_DISABLED LITERAL1
866-
TIMER_OUTPUT_COMPARE LITERAL1
865+
TIMER_OUTPUT_DISABLED LITERAL1
867866
TIMER_OUTPUT_COMPARE_ACTIVE LITERAL1
868867
TIMER_OUTPUT_COMPARE_INACTIVE LITERAL1
869868
TIMER_OUTPUT_COMPARE_TOGGLE LITERAL1

‎libraries/SrcWrapper/inc/HardwareTimer.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -36,9 +36,8 @@
3636
#define TIMER_CHANNELS 4 // channel5 and channel 6 are not considered here has they don't have gpio output and they don't have interrupt
3737

3838
typedef enum {
39-
TIMER_DISABLED, // == TIM_OCMODE_TIMING no output, useful for only-interrupt
39+
TIMER_OUTPUT_DISABLED, // == TIM_OCMODE_TIMING no output, useful for only-interrupt
4040
// Output Compare
41-
TIMER_OUTPUT_COMPARE, // == Obsolete, use TIMER_DISABLED instead. Kept for compatibility reason
4241
TIMER_OUTPUT_COMPARE_ACTIVE, // == TIM_OCMODE_ACTIVE pin is set high when counter == channel compare
4342
TIMER_OUTPUT_COMPARE_INACTIVE, // == TIM_OCMODE_INACTIVE pin is set low when counter == channel compare
4443
TIMER_OUTPUT_COMPARE_TOGGLE, // == TIM_OCMODE_TOGGLE pin toggles when counter == channel compare
@@ -60,6 +59,10 @@ typedef enum {
6059
TIMER_NOT_USED = 0xFFFF // This must be the last item of this enum
6160
} TimerModes_t;
6261

62+
// Backward compatibility
63+
#define TIMER_DISABLED TIMER_OUTPUT_DISABLED
64+
#define TIMER_OUTPUT_COMPARE TIMER_OUTPUT_DISABLED
65+
6366
typedef enum {
6467
TICK_FORMAT, // default
6568
MICROSEC_FORMAT,
@@ -177,10 +180,10 @@ class HardwareTimer {
177180

178181
// The following function(s) are available for more advanced timer options
179182
TIM_HandleTypeDef *getHandle(); // return the handle address for HAL related configuration
180-
int getChannel(uint32_t channel);
181-
int getLLChannel(uint32_t channel);
182-
int getIT(uint32_t channel);
183-
int getAssociatedChannel(uint32_t channel);
183+
uint32_t getChannel(uint32_t channel);
184+
uint32_t getLLChannel(uint32_t channel);
185+
uint32_t getIT(uint32_t channel);
186+
uint32_t getAssociatedChannel(uint32_t channel);
184187

185188
private:
186189
// Store for each channel if regular, complementary or both are used

‎libraries/SrcWrapper/src/HardwareTimer.cpp

Lines changed: 86 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ void HardwareTimer::setup(TIM_TypeDef *instance)
123123
// Initialize channel mode and complementary
124124
for (int i = 0; i < TIMER_CHANNELS; i++) {
125125
__ChannelsUsed[i] = 0x00;
126-
_ChannelMode[i] = TIMER_DISABLED;
126+
_ChannelMode[i] = TIMER_OUTPUT_DISABLED;
127127
}
128128

129129
/* Configure timer with some default values */
@@ -181,9 +181,9 @@ void HardwareTimer::pauseChannel(uint32_t channel)
181181
return;
182182
}
183183

184-
int timAssociatedInputChannel;
185-
int LLChannel = getLLChannel(channel);
186-
int interrupt = getIT(channel);
184+
uint32_t timAssociatedInputChannel;
185+
uint32_t LLChannel = getLLChannel(channel);
186+
uint32_t interrupt = getIT(channel);
187187

188188
// Disable channel and corresponding interrupt
189189
__HAL_TIM_DISABLE_IT(&(_timerObj.handle), interrupt);
@@ -217,144 +217,147 @@ void HardwareTimer::pauseChannel(uint32_t channel)
217217
*/
218218
void HardwareTimer::resume(void)
219219
{
220+
bool baseStart = true;
221+
for (uint8_t i = 1; i <= TIMER_CHANNELS; i++) {
222+
if (_ChannelMode[i - 1] != TIMER_OUTPUT_DISABLED) {
223+
resumeChannel(i);
224+
baseStart = false;
225+
}
226+
}
220227
// Clear flag and enable IT
221228
if (callbacks[0]) {
222229
__HAL_TIM_CLEAR_FLAG(&(_timerObj.handle), TIM_FLAG_UPDATE);
223230
__HAL_TIM_ENABLE_IT(&(_timerObj.handle), TIM_IT_UPDATE);
231+
}
224232

225-
// Start timer in Time base mode. Required when there is no channel used but only update interrupt.
233+
// Start timer in Time base mode. Required when there is no channel used but only update interrupt.
234+
if (baseStart && (!LL_TIM_IsEnabledCounter(_timerObj.handle.Instance))) {
226235
HAL_TIM_Base_Start(&(_timerObj.handle));
227236
}
228-
229-
// Resume all channels
230-
resumeChannel(1);
231-
resumeChannel(2);
232-
resumeChannel(3);
233-
resumeChannel(4);
234237
}
235238

236239
/**
237240
* @brief Convert arduino channel into HAL channel
238241
* @param Arduino channel [1..4]
239242
* @retval HAL channel. Error handler called if arduino channel is invalid
240243
*/
241-
int HardwareTimer::getChannel(uint32_t channel)
244+
uint32_t HardwareTimer::getChannel(uint32_t channel)
242245
{
243-
int return_value = -1;
246+
uint32_t timChannel = -1;
244247

245248
switch (channel) {
246249
case 1:
247-
return_value = TIM_CHANNEL_1;
250+
timChannel = TIM_CHANNEL_1;
248251
break;
249252
case 2:
250-
return_value = TIM_CHANNEL_2;
253+
timChannel = TIM_CHANNEL_2;
251254
break;
252255
case 3:
253-
return_value = TIM_CHANNEL_3;
256+
timChannel = TIM_CHANNEL_3;
254257
break;
255258
case 4:
256-
return_value = TIM_CHANNEL_4;
259+
timChannel = TIM_CHANNEL_4;
257260
break;
258261
default:
259262
Error_Handler();
260263
}
261-
return return_value;
264+
return timChannel;
262265
}
263266

264267
/**
265268
* @brief Convert arduino channel into LL channels used (regular and/or complementary)
266269
* @param Arduino channel [1..4]
267270
* @retval LL channel. Error handler called if arduino channel is invalid
268271
*/
269-
int HardwareTimer::getLLChannel(uint32_t channel)
272+
uint32_t HardwareTimer::getLLChannel(uint32_t channel)
270273
{
271-
int return_value = 0;
274+
bool error = false;
275+
uint32_t ll_channel = 0;
272276

273277
#if defined(TIM_CCER_CC1NE)
274278
if (__ChannelsUsed[channel - 1] & COMPLEMENTARY_CHAN_MASK) {
275279
// Complementary channel
276280
switch (channel) {
277281
case 1:
278-
return_value = LL_TIM_CHANNEL_CH1N;
282+
ll_channel = LL_TIM_CHANNEL_CH1N;
279283
break;
280284
case 2:
281-
return_value = LL_TIM_CHANNEL_CH2N;
285+
ll_channel = LL_TIM_CHANNEL_CH2N;
282286
break;
283287
case 3:
284-
return_value = LL_TIM_CHANNEL_CH3N;
288+
ll_channel = LL_TIM_CHANNEL_CH3N;
285289
break;
286290
#if defined(LL_TIM_CHANNEL_CH4N)
287291
case 4:
288-
return_value = LL_TIM_CHANNEL_CH4N;
292+
ll_channel = LL_TIM_CHANNEL_CH4N;
289293
break;
290294
#endif
291295
default:
292-
return_value = -1;
296+
error = true;
293297
}
294298
}
295299
#endif
296-
if ((return_value != -1) && (__ChannelsUsed[channel - 1] & REGULAR_CHAN_MASK)) {
300+
if ((!error) && (__ChannelsUsed[channel - 1] & REGULAR_CHAN_MASK)) {
297301
// Regular channel not complementary
298302
switch (channel) {
299303
case 1:
300-
return_value |= LL_TIM_CHANNEL_CH1;
304+
ll_channel |= LL_TIM_CHANNEL_CH1;
301305
break;
302306
case 2:
303-
return_value |= LL_TIM_CHANNEL_CH2;
307+
ll_channel |= LL_TIM_CHANNEL_CH2;
304308
break;
305309
case 3:
306-
return_value |= LL_TIM_CHANNEL_CH3;
310+
ll_channel |= LL_TIM_CHANNEL_CH3;
307311
break;
308312
case 4:
309-
return_value |= LL_TIM_CHANNEL_CH4;
313+
ll_channel |= LL_TIM_CHANNEL_CH4;
310314
break;
311315
default:
312-
return_value = -1;
316+
error = true;
313317
}
314318
}
315-
if (return_value == -1) {
319+
if (error) {
316320
Error_Handler();
317321
}
318-
return return_value;
322+
return ll_channel;
319323
}
320324

321325
/**
322326
* @brief Convert arduino channel into HAL Interrupt ID
323327
* @param Arduino channel [1..4]
324328
* @retval HAL channel. Error handler called if arduino channel is invalid
325329
*/
326-
int HardwareTimer::getIT(uint32_t channel)
330+
uint32_t HardwareTimer::getIT(uint32_t channel)
327331
{
328-
int return_value = -1;
329-
332+
uint32_t interrupt = 0;
330333
switch (channel) {
331334
case 1:
332-
return_value = TIM_IT_CC1;
335+
interrupt = TIM_IT_CC1;
333336
break;
334337
case 2:
335-
return_value = TIM_IT_CC2;
338+
interrupt = TIM_IT_CC2;
336339
break;
337340
case 3:
338-
return_value = TIM_IT_CC3;
341+
interrupt = TIM_IT_CC3;
339342
break;
340343
case 4:
341-
return_value = TIM_IT_CC4;
344+
interrupt = TIM_IT_CC4;
342345
break;
343346
default:
344347
Error_Handler();
345348
}
346-
return return_value;
349+
return interrupt;
347350
}
348351

349352
/**
350353
* @brief Get input associated channel
351354
* Channel 1 and 2 are associated; channel 3 and 4 are associated
352355
* @param Arduino channel [1..4]
353-
* @retval HAL channel. return -1 if arduino channel is invalid
356+
* @retval HAL channel. Error handler called if arduino channel is invalid
354357
*/
355-
int HardwareTimer::getAssociatedChannel(uint32_t channel)
358+
uint32_t HardwareTimer::getAssociatedChannel(uint32_t channel)
356359
{
357-
int timAssociatedInputChannel = -1;
360+
uint32_t timAssociatedInputChannel = 0;
358361
switch (channel) {
359362
case 1:
360363
timAssociatedInputChannel = 2;
@@ -369,6 +372,7 @@ int HardwareTimer::getAssociatedChannel(uint32_t channel)
369372
timAssociatedInputChannel = 3;
370373
break;
371374
default:
375+
Error_Handler();
372376
break;
373377
}
374378
return timAssociatedInputChannel;
@@ -381,9 +385,9 @@ int HardwareTimer::getAssociatedChannel(uint32_t channel)
381385
*/
382386
void HardwareTimer::resumeChannel(uint32_t channel)
383387
{
384-
int timChannel = getChannel(channel);
385-
int timAssociatedInputChannel;
386-
int interrupt = getIT(channel);
388+
uint32_t timChannel = getChannel(channel);
389+
uint32_t timAssociatedInputChannel;
390+
uint32_t interrupt = getIT(channel);
387391

388392
// Clear flag and enable IT
389393
if (callbacks[channel]) {
@@ -437,8 +441,7 @@ void HardwareTimer::resumeChannel(uint32_t channel)
437441
HAL_TIM_IC_Start(&(_timerObj.handle), timChannel);
438442
}
439443
break;
440-
case TIMER_OUTPUT_COMPARE:
441-
case TIMER_DISABLED:
444+
case TIMER_OUTPUT_DISABLED:
442445
if (!LL_TIM_IsEnabledCounter(_timerObj.handle.Instance)) {
443446
HAL_TIM_Base_Start(&(_timerObj.handle));
444447
}
@@ -631,8 +634,8 @@ void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, uint32_t pin, C
631634
*/
632635
void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, PinName pin, ChannelInputFilter_t filter)
633636
{
634-
int timChannel = getChannel(channel);
635-
int timAssociatedInputChannel;
637+
uint32_t timChannel = getChannel(channel);
638+
uint32_t timAssociatedInputChannel;
636639
TIM_OC_InitTypeDef channelOC;
637640
TIM_IC_InitTypeDef channelIC;
638641

@@ -656,21 +659,10 @@ void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, PinName pin, Ch
656659
channelIC.ICFilter = filter;
657660

658661
switch (mode) {
659-
case TIMER_DISABLED:
662+
case TIMER_OUTPUT_DISABLED:
660663
channelOC.OCMode = TIM_OCMODE_TIMING;
661664
HAL_TIM_OC_ConfigChannel(&(_timerObj.handle), &channelOC, timChannel);
662665
break;
663-
case TIMER_OUTPUT_COMPARE:
664-
/* In case of TIMER_OUTPUT_COMPARE, there is no output and thus no pin to
665-
* configure, and no channel. So nothing to do. For compatibility reason
666-
* restore TIMER_DISABLED if necessary.
667-
*/
668-
if (_ChannelMode[channel - 1] != TIMER_DISABLED) {
669-
_ChannelMode[channel - 1] = TIMER_DISABLED;
670-
channelOC.OCMode = TIM_OCMODE_TIMING;
671-
HAL_TIM_OC_ConfigChannel(&(_timerObj.handle), &channelOC, timChannel);
672-
}
673-
return;
674666
case TIMER_OUTPUT_COMPARE_ACTIVE:
675667
channelOC.OCMode = TIM_OCMODE_ACTIVE;
676668
HAL_TIM_OC_ConfigChannel(&(_timerObj.handle), &channelOC, timChannel);
@@ -737,24 +729,25 @@ void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, PinName pin, Ch
737729

738730
// Save channel selected mode to object attribute
739731
_ChannelMode[channel - 1] = mode;
740-
741-
if (pin != NC) {
742-
if ((int)getTimerChannel(pin) == timChannel) {
743-
/* Configure PWM GPIO pins */
744-
pinmap_pinout(pin, PinMap_TIM);
732+
if (mode != TIMER_OUTPUT_DISABLED) {
733+
if (pin != NC) {
734+
if (getTimerChannel(pin) == timChannel) {
735+
/* Configure PWM GPIO pins */
736+
pinmap_pinout(pin, PinMap_TIM);
745737
#if defined(STM32F1xx)
746-
if ((mode == TIMER_INPUT_CAPTURE_RISING) || (mode == TIMER_INPUT_CAPTURE_FALLING) \
747-
|| (mode == TIMER_INPUT_CAPTURE_BOTHEDGE) || (mode == TIMER_INPUT_FREQ_DUTY_MEASUREMENT)) {
748-
// on F1 family, input alternate function must configure GPIO in input mode
749-
pinMode(pinNametoDigitalPin(pin), INPUT);
750-
}
738+
if ((mode == TIMER_INPUT_CAPTURE_RISING) || (mode == TIMER_INPUT_CAPTURE_FALLING) \
739+
|| (mode == TIMER_INPUT_CAPTURE_BOTHEDGE) || (mode == TIMER_INPUT_FREQ_DUTY_MEASUREMENT)) {
740+
// on F1 family, input alternate function must configure GPIO in input mode
741+
pinMode(pinNametoDigitalPin(pin), INPUT);
742+
}
751743
#endif
752-
} else {
753-
// Pin doesn't match with timer output channels
754-
Error_Handler();
755-
}
744+
} else {
745+
// Pin doesn't match with timer output channels
746+
Error_Handler();
747+
}
756748

757-
__ChannelsUsed[channel - 1] |= (STM_PIN_INVERTED(pinmap_function(pin, PinMap_TIM))) ? COMPLEMENTARY_CHAN_MASK : REGULAR_CHAN_MASK;
749+
__ChannelsUsed[channel - 1] |= (STM_PIN_INVERTED(pinmap_function(pin, PinMap_TIM))) ? COMPLEMENTARY_CHAN_MASK : REGULAR_CHAN_MASK;
750+
}
758751
}
759752
}
760753

@@ -765,11 +758,7 @@ void HardwareTimer::setMode(uint32_t channel, TimerModes_t mode, PinName pin, Ch
765758
*/
766759
TimerModes_t HardwareTimer::getMode(uint32_t channel)
767760
{
768-
if ((1 <= channel) && (channel <= TIMER_CHANNELS)) {
769-
return _ChannelMode[channel - 1];
770-
} else {
771-
return TIMER_DISABLED;
772-
}
761+
return ((1 <= channel) && (channel <= TIMER_CHANNELS)) ? _ChannelMode[channel - 1] : TIMER_OUTPUT_DISABLED;
773762
}
774763

775764
/**
@@ -807,7 +796,7 @@ void HardwareTimer::setPreloadEnable(bool value)
807796
*/
808797
void HardwareTimer::setCaptureCompare(uint32_t channel, uint32_t compare, TimerCompareFormat_t format)
809798
{
810-
int timChannel = getChannel(channel);
799+
uint32_t timChannel = getChannel(channel);
811800
uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1;
812801
uint32_t CCR_RegisterValue;
813802

@@ -869,7 +858,7 @@ void HardwareTimer::setCaptureCompare(uint32_t channel, uint32_t compare, TimerC
869858
*/
870859
uint32_t HardwareTimer::getCaptureCompare(uint32_t channel, TimerCompareFormat_t format)
871860
{
872-
int timChannel = getChannel(channel);
861+
uint32_t timChannel = getChannel(channel);
873862
uint32_t CCR_RegisterValue = __HAL_TIM_GET_COMPARE(&(_timerObj.handle), timChannel);
874863
uint32_t Prescalerfactor = LL_TIM_GetPrescaler(_timerObj.handle.Instance) + 1;
875864
uint32_t return_value;
@@ -936,7 +925,10 @@ void HardwareTimer::setPWM(uint32_t channel, uint32_t pin, uint32_t frequency, u
936925
*/
937926
void HardwareTimer::setPWM(uint32_t channel, PinName pin, uint32_t frequency, uint32_t dutycycle, callback_function_t PeriodCallback, callback_function_t CompareCallback)
938927
{
939-
setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
928+
TimerModes_t previousMode = getMode(channel);
929+
if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) {
930+
setMode(channel, TIMER_OUTPUT_COMPARE_PWM1, pin);
931+
}
940932
setOverflow(frequency, HERTZ_FORMAT);
941933
setCaptureCompare(channel, dutycycle, PERCENT_COMPARE_FORMAT);
942934
if (PeriodCallback) {
@@ -945,7 +937,9 @@ void HardwareTimer::setPWM(uint32_t channel, PinName pin, uint32_t frequency, ui
945937
if (CompareCallback) {
946938
attachInterrupt(channel, CompareCallback);
947939
}
948-
resume();
940+
if (previousMode != TIMER_OUTPUT_COMPARE_PWM1) {
941+
resume();
942+
}
949943
}
950944

951945
/**
@@ -1010,7 +1004,7 @@ void HardwareTimer::detachInterrupt()
10101004
*/
10111005
void HardwareTimer::attachInterrupt(uint32_t channel, callback_function_t callback)
10121006
{
1013-
int interrupt = getIT(channel);
1007+
uint32_t interrupt = getIT(channel);
10141008

10151009
if ((channel == 0) || (channel > (TIMER_CHANNELS + 1))) {
10161010
Error_Handler(); // only channel 1..4 have an interrupt
@@ -1036,7 +1030,7 @@ void HardwareTimer::attachInterrupt(uint32_t channel, callback_function_t callba
10361030
*/
10371031
void HardwareTimer::detachInterrupt(uint32_t channel)
10381032
{
1039-
int interrupt = getIT(channel);
1033+
uint32_t interrupt = getIT(channel);
10401034

10411035
if ((channel == 0) || (channel > (TIMER_CHANNELS + 1))) {
10421036
Error_Handler(); // only channel 1..4 have an interrupt
@@ -1169,14 +1163,14 @@ bool HardwareTimer::isRunning()
11691163
*/
11701164
bool HardwareTimer::isRunningChannel(uint32_t channel)
11711165
{
1172-
int LLChannel = getLLChannel(channel);
1173-
int interrupt = getIT(channel);
1166+
uint32_t LLChannel = getLLChannel(channel);
1167+
uint32_t interrupt = getIT(channel);
11741168
bool ret;
11751169

11761170
// channel is running if: timer is running, and either output channel is
11771171
// enabled or interrupt is set
11781172
ret = LL_TIM_CC_IsEnabledChannel(_timerObj.handle.Instance, LLChannel)
1179-
|| (__HAL_TIM_GET_IT_SOURCE(&(_timerObj.handle), (uint32_t)interrupt) == SET);
1173+
|| (__HAL_TIM_GET_IT_SOURCE(&(_timerObj.handle), interrupt) == SET);
11801174
return (isRunning() && ret);
11811175
}
11821176

0 commit comments

Comments
 (0)
Please sign in to comment.