2 * This file is part of INAV.
4 * INAV is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * INAV is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with INAV. If not, see <http://www.gnu.org/licenses/>.
24 #include "build/atomic.h"
25 #include "build/debug.h"
27 #include "common/utils.h"
29 #include "drivers/io.h"
30 #include "drivers/rcc.h"
31 #include "drivers/time.h"
32 #include "drivers/nvic.h"
33 #include "drivers/dma.h"
34 #include "drivers/timer.h"
35 #include "drivers/timer_impl.h"
37 const uint16_t lookupDMASourceTable
[4] = { TIM_DMA_CC1
, TIM_DMA_CC2
, TIM_DMA_CC3
, TIM_DMA_CC4
};
38 const uint8_t lookupTIMChannelTable
[4] = { TIM_Channel_1
, TIM_Channel_2
, TIM_Channel_3
, TIM_Channel_4
};
40 void impl_timerInitContext(timHardwareContext_t
* timCtx
)
45 void impl_timerNVICConfigure(TCH_t
* tch
, int irqPriority
)
47 if (tch
->timCtx
->timDef
->irq
) {
48 NVIC_SetPriority(tch
->timCtx
->timDef
->irq
, irqPriority
);
49 NVIC_EnableIRQ(tch
->timCtx
->timDef
->irq
);
52 if (tch
->timCtx
->timDef
->secondIrq
) {
53 NVIC_SetPriority(tch
->timCtx
->timDef
->secondIrq
, irqPriority
);
54 NVIC_EnableIRQ(tch
->timCtx
->timDef
->secondIrq
);
58 void impl_timerConfigBase(TCH_t
* tch
, uint16_t period
, uint32_t hz
)
60 TIM_TypeDef
* tim
= tch
->timCtx
->timDef
->tim
;
61 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure
;
63 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure
);
64 TIM_TimeBaseStructure
.TIM_Period
= (period
- 1) & 0xffff; // AKA TIMx_ARR
65 TIM_TimeBaseStructure
.TIM_Prescaler
= lrintf((float)timerGetBaseClock(tch
) / hz
+ 0.01f
) - 1;
66 TIM_TimeBaseStructure
.TIM_ClockDivision
= TIM_CKD_DIV1
;
67 TIM_TimeBaseStructure
.TIM_CounterMode
= TIM_CounterMode_Up
;
68 TIM_TimeBaseInit(tim
, &TIM_TimeBaseStructure
);
71 void impl_enableTimer(TCH_t
* tch
)
73 TIM_Cmd(tch
->timHw
->tim
, ENABLE
);
76 void impl_timerPWMStart(TCH_t
* tch
)
78 TIM_CtrlPWMOutputs(tch
->timHw
->tim
, ENABLE
);
81 void impl_timerEnableIT(TCH_t
* tch
, uint32_t interrupt
)
83 TIM_ITConfig(tch
->timHw
->tim
, interrupt
, ENABLE
);
86 void impl_timerDisableIT(TCH_t
* tch
, uint32_t interrupt
)
88 TIM_ITConfig(tch
->timHw
->tim
, interrupt
, DISABLE
);
91 void impl_timerClearFlag(TCH_t
* tch
, uint32_t flag
)
93 TIM_ClearFlag(tch
->timHw
->tim
, flag
);
96 // calculate input filter constant
97 static unsigned getFilter(unsigned ticks
)
99 static const unsigned ftab
[16] = {
101 1*2, 1*4, 1*8, // fCK_INT
109 for (unsigned i
= 1; i
< ARRAYLEN(ftab
); i
++) {
110 if (ftab
[i
] > ticks
) {
118 void impl_timerChConfigIC(TCH_t
* tch
, bool polarityRising
, unsigned inputFilterTicks
)
120 TIM_ICInitTypeDef TIM_ICInitStructure
;
122 TIM_ICStructInit(&TIM_ICInitStructure
);
123 TIM_ICInitStructure
.TIM_Channel
= lookupTIMChannelTable
[tch
->timHw
->channelIndex
];
124 TIM_ICInitStructure
.TIM_ICPolarity
= polarityRising
? TIM_ICPolarity_Rising
: TIM_ICPolarity_Falling
;
125 TIM_ICInitStructure
.TIM_ICSelection
= TIM_ICSelection_DirectTI
;
126 TIM_ICInitStructure
.TIM_ICPrescaler
= TIM_ICPSC_DIV1
;
127 TIM_ICInitStructure
.TIM_ICFilter
= getFilter(inputFilterTicks
);
129 TIM_ICInit(tch
->timHw
->tim
, &TIM_ICInitStructure
);
132 void impl_timerCaptureCompareHandler(TIM_TypeDef
*tim
, timHardwareContext_t
*timerCtx
)
134 unsigned tim_status
= tim
->SR
& tim
->DIER
;
137 // flags will be cleared by reading CCR in dual capture, make sure we call handler correctly
138 // currrent order is highest bit first. Code should not rely on specific order (it will introduce race conditions anyway)
139 unsigned bit
= __builtin_clz(tim_status
);
140 unsigned mask
= ~(0x80000000 >> bit
);
146 case __builtin_clz(TIM_IT_Update
): {
147 const uint16_t capture
= tim
->ARR
;
148 if (timerCtx
->ch
[0].cb
&& timerCtx
->ch
[0].cb
->callbackOvr
) {
149 timerCtx
->ch
[0].cb
->callbackOvr(&timerCtx
->ch
[0], capture
);
151 if (timerCtx
->ch
[1].cb
&& timerCtx
->ch
[1].cb
->callbackOvr
) {
152 timerCtx
->ch
[1].cb
->callbackOvr(&timerCtx
->ch
[1], capture
);
154 if (timerCtx
->ch
[2].cb
&& timerCtx
->ch
[2].cb
->callbackOvr
) {
155 timerCtx
->ch
[2].cb
->callbackOvr(&timerCtx
->ch
[2], capture
);
157 if (timerCtx
->ch
[3].cb
&& timerCtx
->ch
[3].cb
->callbackOvr
) {
158 timerCtx
->ch
[3].cb
->callbackOvr(&timerCtx
->ch
[3], capture
);
162 case __builtin_clz(TIM_IT_CC1
):
163 timerCtx
->ch
[0].cb
->callbackEdge(&timerCtx
->ch
[0], tim
->CCR1
);
165 case __builtin_clz(TIM_IT_CC2
):
166 timerCtx
->ch
[1].cb
->callbackEdge(&timerCtx
->ch
[1], tim
->CCR2
);
168 case __builtin_clz(TIM_IT_CC3
):
169 timerCtx
->ch
[2].cb
->callbackEdge(&timerCtx
->ch
[2], tim
->CCR3
);
171 case __builtin_clz(TIM_IT_CC4
):
172 timerCtx
->ch
[3].cb
->callbackEdge(&timerCtx
->ch
[3], tim
->CCR4
);
177 // timerConfig == NULL
178 volatile uint32_t tmp
;
181 case __builtin_clz(TIM_IT_Update
):
184 case __builtin_clz(TIM_IT_CC1
):
187 case __builtin_clz(TIM_IT_CC2
):
190 case __builtin_clz(TIM_IT_CC3
):
193 case __builtin_clz(TIM_IT_CC4
):
203 void impl_timerPWMConfigChannel(TCH_t
* tch
, uint16_t value
)
205 const bool inverted
= tch
->timHw
->output
& TIMER_OUTPUT_INVERTED
;
207 TIM_OCInitTypeDef TIM_OCInitStructure
;
209 TIM_OCStructInit(&TIM_OCInitStructure
);
210 TIM_OCInitStructure
.TIM_OCMode
= TIM_OCMode_PWM1
;
211 TIM_OCInitStructure
.TIM_Pulse
= value
;
213 if (tch
->timHw
->output
& TIMER_OUTPUT_N_CHANNEL
) {
214 TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Disable
;
215 TIM_OCInitStructure
.TIM_OutputNState
= TIM_OutputNState_Enable
;
216 TIM_OCInitStructure
.TIM_OCNPolarity
= inverted
? TIM_OCPolarity_Low
: TIM_OCPolarity_High
;
217 TIM_OCInitStructure
.TIM_OCNIdleState
= TIM_OCIdleState_Reset
;
219 TIM_OCInitStructure
.TIM_OutputState
= TIM_OutputState_Enable
;
220 TIM_OCInitStructure
.TIM_OutputNState
= TIM_OutputNState_Disable
;
221 TIM_OCInitStructure
.TIM_OCPolarity
= inverted
? TIM_OCPolarity_Low
: TIM_OCPolarity_High
;
222 TIM_OCInitStructure
.TIM_OCIdleState
= TIM_OCIdleState_Set
;
225 switch (tch
->timHw
->channelIndex
) {
227 TIM_OC1Init(tch
->timHw
->tim
, &TIM_OCInitStructure
);
228 TIM_OC1PreloadConfig(tch
->timHw
->tim
, TIM_OCPreload_Enable
);
231 TIM_OC2Init(tch
->timHw
->tim
, &TIM_OCInitStructure
);
232 TIM_OC2PreloadConfig(tch
->timHw
->tim
, TIM_OCPreload_Enable
);
235 TIM_OC3Init(tch
->timHw
->tim
, &TIM_OCInitStructure
);
236 TIM_OC3PreloadConfig(tch
->timHw
->tim
, TIM_OCPreload_Enable
);
239 TIM_OC4Init(tch
->timHw
->tim
, &TIM_OCInitStructure
);
240 TIM_OC4PreloadConfig(tch
->timHw
->tim
, TIM_OCPreload_Enable
);
245 volatile timCCR_t
* impl_timerCCR(TCH_t
* tch
)
247 switch (tch
->timHw
->channelIndex
) {
249 return &tch
->timHw
->tim
->CCR1
;
252 return &tch
->timHw
->tim
->CCR2
;
255 return &tch
->timHw
->tim
->CCR3
;
258 return &tch
->timHw
->tim
->CCR4
;
264 void impl_timerChCaptureCompareEnable(TCH_t
* tch
, bool enable
)
266 TIM_CCxCmd(tch
->timHw
->tim
, lookupTIMChannelTable
[tch
->timHw
->channelIndex
], (enable
? TIM_CCx_Enable
: TIM_CCx_Disable
));
269 static void impl_timerDMA_IRQHandler(DMA_t descriptor
)
271 if (DMA_GET_FLAG_STATUS(descriptor
, DMA_IT_TCIF
)) {
272 TCH_t
* tch
= (TCH_t
*)descriptor
->userParam
;
273 tch
->dmaState
= TCH_DMA_IDLE
;
275 DMA_Cmd(tch
->dma
->ref
, DISABLE
);
276 TIM_DMACmd(tch
->timHw
->tim
, lookupDMASourceTable
[tch
->timHw
->channelIndex
], DISABLE
);
278 DMA_CLEAR_FLAG(descriptor
, DMA_IT_TCIF
);
282 bool impl_timerPWMConfigChannelDMA(TCH_t
* tch
, void * dmaBuffer
, uint8_t dmaBufferElementSize
, uint32_t dmaBufferElementCount
)
284 DMA_InitTypeDef DMA_InitStructure
;
285 TIM_TypeDef
* timer
= tch
->timHw
->tim
;
287 tch
->dma
= dmaGetByTag(tch
->timHw
->dmaTag
);
288 if (tch
->dma
== NULL
) {
292 // If DMA is already in use - abort
293 if (tch
->dma
->owner
!= OWNER_FREE
) {
297 // We assume that timer channels are already initialized by calls to:
299 // timerPWMConfigChannel
301 TIM_CtrlPWMOutputs(timer
, ENABLE
);
302 TIM_ARRPreloadConfig(timer
, ENABLE
);
304 if (tch
->timHw
->output
& TIMER_OUTPUT_N_CHANNEL
) {
305 TIM_CCxNCmd(timer
, lookupTIMChannelTable
[tch
->timHw
->channelIndex
], TIM_CCxN_Enable
);
307 TIM_CCxCmd(timer
, lookupTIMChannelTable
[tch
->timHw
->channelIndex
], TIM_CCx_Enable
);
310 TIM_Cmd(timer
, ENABLE
);
312 dmaInit(tch
->dma
, OWNER_TIMER
, 0);
313 dmaSetHandler(tch
->dma
, impl_timerDMA_IRQHandler
, NVIC_PRIO_TIMER_DMA
, (uint32_t)tch
);
315 DMA_DeInit(tch
->dma
->ref
);
316 DMA_Cmd(tch
->dma
->ref
, DISABLE
);
318 DMA_DeInit(tch
->dma
->ref
);
319 DMA_StructInit(&DMA_InitStructure
);
321 DMA_InitStructure
.DMA_PeripheralBaseAddr
= (uint32_t)impl_timerCCR(tch
);
322 DMA_InitStructure
.DMA_BufferSize
= dmaBufferElementCount
;
323 DMA_InitStructure
.DMA_PeripheralInc
= DMA_PeripheralInc_Disable
;
324 DMA_InitStructure
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
325 DMA_InitStructure
.DMA_Mode
= DMA_Mode_Normal
;
327 switch (dmaBufferElementSize
) {
329 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_Byte
;
330 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Byte
;
333 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_HalfWord
;
334 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_HalfWord
;
337 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_Word
;
338 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Word
;
348 DMA_InitStructure
.DMA_Channel
= dmaGetChannelByTag(tch
->timHw
->dmaTag
);
349 DMA_InitStructure
.DMA_Memory0BaseAddr
= (uint32_t)dmaBuffer
;
350 DMA_InitStructure
.DMA_DIR
= DMA_DIR_MemoryToPeripheral
;
351 DMA_InitStructure
.DMA_Priority
= DMA_Priority_High
;
353 DMA_InitStructure
.DMA_MemoryBaseAddr
= (uint32_t)dmaBuffer
;
354 DMA_InitStructure
.DMA_DIR
= DMA_DIR_PeripheralDST
;
355 DMA_InitStructure
.DMA_Priority
= DMA_Priority_High
;
356 DMA_InitStructure
.DMA_M2M
= DMA_M2M_Disable
;
359 DMA_Init(tch
->dma
->ref
, &DMA_InitStructure
);
360 DMA_ITConfig(tch
->dma
->ref
, DMA_IT_TC
, ENABLE
);
365 #ifdef USE_DSHOT_DMAR
366 bool impl_timerPWMConfigDMABurst(burstDmaTimer_t
*burstDmaTimer
, TCH_t
* tch
, void * dmaBuffer
, uint8_t dmaBufferElementSize
, uint32_t dmaBufferElementCount
)
368 DMA_InitTypeDef DMA_InitStructure
;
369 TIM_TypeDef
* timer
= tch
->timHw
->tim
;
371 if (!tch
->timCtx
->dmaBurstRef
) {
372 tch
->dma
= dmaGetByTag(tch
->timHw
->dmaTag
);
373 if (tch
->dma
== NULL
) {
377 // If DMA is already in use - abort
378 if (tch
->dma
->owner
!= OWNER_FREE
) {
383 // We assume that timer channels are already initialized by calls to:
385 // timerPWMConfigChannel
387 TIM_CtrlPWMOutputs(timer
, ENABLE
);
388 TIM_ARRPreloadConfig(timer
, ENABLE
);
390 if (tch
->timHw
->output
& TIMER_OUTPUT_N_CHANNEL
) {
391 TIM_CCxNCmd(timer
, lookupTIMChannelTable
[tch
->timHw
->channelIndex
], TIM_CCxN_Enable
);
393 TIM_CCxCmd(timer
, lookupTIMChannelTable
[tch
->timHw
->channelIndex
], TIM_CCx_Enable
);
396 TIM_Cmd(timer
, ENABLE
);
398 if (!tch
->timCtx
->dmaBurstRef
) {
399 dmaInit(tch
->dma
, OWNER_TIMER
, 0);
400 dmaSetHandler(tch
->dma
, impl_timerDMA_IRQHandler
, NVIC_PRIO_TIMER_DMA
, (uint32_t)tch
);
402 DMA_DeInit(tch
->dma
->ref
);
403 DMA_Cmd(tch
->dma
->ref
, DISABLE
);
405 DMA_StructInit(&DMA_InitStructure
);
407 DMA_InitStructure
.DMA_PeripheralBaseAddr
= (uint32_t)&tch
->timHw
->tim
->DMAR
;
408 DMA_InitStructure
.DMA_BufferSize
= dmaBufferElementCount
;
409 DMA_InitStructure
.DMA_PeripheralInc
= DMA_PeripheralInc_Disable
;
410 DMA_InitStructure
.DMA_MemoryInc
= DMA_MemoryInc_Enable
;
411 DMA_InitStructure
.DMA_Mode
= DMA_Mode_Normal
;
413 switch (dmaBufferElementSize
) {
415 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_Byte
;
416 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Byte
;
419 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_HalfWord
;
420 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_HalfWord
;
423 DMA_InitStructure
.DMA_MemoryDataSize
= DMA_MemoryDataSize_Word
;
424 DMA_InitStructure
.DMA_PeripheralDataSize
= DMA_PeripheralDataSize_Word
;
434 DMA_InitStructure
.DMA_Channel
= dmaGetChannelByTag(tch
->timHw
->dmaTag
);
435 DMA_InitStructure
.DMA_Memory0BaseAddr
= (uint32_t)dmaBuffer
;
436 DMA_InitStructure
.DMA_DIR
= DMA_DIR_MemoryToPeripheral
;
437 DMA_InitStructure
.DMA_Priority
= DMA_Priority_High
;
439 DMA_InitStructure
.DMA_MemoryBaseAddr
= (uint32_t)dmaBuffer
;
440 DMA_InitStructure
.DMA_DIR
= DMA_DIR_PeripheralDST
;
441 DMA_InitStructure
.DMA_Priority
= DMA_Priority_High
;
442 DMA_InitStructure
.DMA_M2M
= DMA_M2M_Disable
;
445 DMA_Init(tch
->dma
->ref
, &DMA_InitStructure
);
446 DMA_ITConfig(tch
->dma
->ref
, DMA_IT_TC
, ENABLE
);
448 tch
->timCtx
->dmaBurstRef
= tch
->dma
;
449 tch
->timCtx
->DMASource
= lookupDMASourceTable
[tch
->timHw
->channelIndex
];
450 burstDmaTimer
->dmaBurstStream
= tch
->timCtx
->dmaBurstRef
->ref
;
451 burstDmaTimer
->burstRequestSource
= tch
->timCtx
->DMASource
;
453 tch
->dmaState
= TCH_DMA_READY
;
459 void impl_pwmBurstDMAStart(burstDmaTimer_t
* burstDmaTimer
, uint32_t BurstLength
)
461 DMA_SetCurrDataCounter(burstDmaTimer
->dmaBurstStream
, BurstLength
);
462 DMA_Cmd(burstDmaTimer
->dmaBurstStream
, ENABLE
);
463 TIM_DMAConfig(burstDmaTimer
->timer
, TIM_DMABase_CCR1
, TIM_DMABurstLength_4Transfers
);
464 TIM_DMACmd(burstDmaTimer
->timer
, burstDmaTimer
->burstRequestSource
, ENABLE
);
468 void impl_timerPWMPrepareDMA(TCH_t
* tch
, uint32_t dmaBufferElementCount
)
470 // Make sure we terminate any DMA transaction currently in progress
471 // Clear the flag as well, so even if DMA transfer finishes while within ATOMIC_BLOCK
472 // the resulting IRQ won't mess up the DMA state
473 ATOMIC_BLOCK(NVIC_PRIO_MAX
) {
474 DMA_Cmd(tch
->dma
->ref
, DISABLE
);
475 TIM_DMACmd(tch
->timHw
->tim
, lookupDMASourceTable
[tch
->timHw
->channelIndex
], DISABLE
);
476 DMA_CLEAR_FLAG(tch
->dma
, DMA_IT_TCIF
);
479 DMA_SetCurrDataCounter(tch
->dma
->ref
, dmaBufferElementCount
);
480 DMA_Cmd(tch
->dma
->ref
, ENABLE
);
481 tch
->dmaState
= TCH_DMA_READY
;
484 void impl_timerPWMStartDMA(TCH_t
* tch
)
486 uint16_t dmaSources
= 0;
487 timHardwareContext_t
* timCtx
= tch
->timCtx
;
489 if (timCtx
->ch
[0].dmaState
== TCH_DMA_READY
) {
490 timCtx
->ch
[0].dmaState
= TCH_DMA_ACTIVE
;
491 dmaSources
|= TIM_DMA_CC1
;
494 if (timCtx
->ch
[1].dmaState
== TCH_DMA_READY
) {
495 timCtx
->ch
[1].dmaState
= TCH_DMA_ACTIVE
;
496 dmaSources
|= TIM_DMA_CC2
;
499 if (timCtx
->ch
[2].dmaState
== TCH_DMA_READY
) {
500 timCtx
->ch
[2].dmaState
= TCH_DMA_ACTIVE
;
501 dmaSources
|= TIM_DMA_CC3
;
504 if (timCtx
->ch
[3].dmaState
== TCH_DMA_READY
) {
505 timCtx
->ch
[3].dmaState
= TCH_DMA_ACTIVE
;
506 dmaSources
|= TIM_DMA_CC4
;
510 TIM_SetCounter(tch
->timHw
->tim
, 0);
511 TIM_DMACmd(tch
->timHw
->tim
, dmaSources
, ENABLE
);
515 void impl_timerPWMStopDMA(TCH_t
* tch
)
517 DMA_Cmd(tch
->dma
->ref
, DISABLE
);
518 TIM_DMACmd(tch
->timHw
->tim
, lookupDMASourceTable
[tch
->timHw
->channelIndex
], DISABLE
);
519 tch
->dmaState
= TCH_DMA_IDLE
;
520 TIM_Cmd(tch
->timHw
->tim
, ENABLE
);