Merge pull request #10558 from iNavFlight/MrD_Correct-comments-on-OSD-symbols
[inav.git] / src / main / drivers / timer_impl_stdperiph.c
blobd2bd35dd5210175cba1b43d51c44219be24b92e7
1 /*
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/>.
18 #include <stdbool.h>
19 #include <stdint.h>
20 #include <math.h>
22 #include "platform.h"
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)
42 (void)timCtx; // NoOp
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] = {
100 1*1, // fDTS !
101 1*2, 1*4, 1*8, // fCK_INT
102 2*6, 2*8, // fDTS/2
103 4*6, 4*8,
104 8*6, 8*8,
105 16*5, 16*6, 16*8,
106 32*5, 32*6, 32*8
109 for (unsigned i = 1; i < ARRAYLEN(ftab); i++) {
110 if (ftab[i] > ticks) {
111 return i - 1;
115 return 0x0f;
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;
136 while (tim_status) {
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);
141 tim->SR = mask;
142 tim_status &= mask;
144 if (timerCtx) {
145 switch (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);
160 break;
162 case __builtin_clz(TIM_IT_CC1):
163 timerCtx->ch[0].cb->callbackEdge(&timerCtx->ch[0], tim->CCR1);
164 break;
165 case __builtin_clz(TIM_IT_CC2):
166 timerCtx->ch[1].cb->callbackEdge(&timerCtx->ch[1], tim->CCR2);
167 break;
168 case __builtin_clz(TIM_IT_CC3):
169 timerCtx->ch[2].cb->callbackEdge(&timerCtx->ch[2], tim->CCR3);
170 break;
171 case __builtin_clz(TIM_IT_CC4):
172 timerCtx->ch[3].cb->callbackEdge(&timerCtx->ch[3], tim->CCR4);
173 break;
176 else {
177 // timerConfig == NULL
178 volatile uint32_t tmp;
180 switch (bit) {
181 case __builtin_clz(TIM_IT_Update):
182 tmp = tim->ARR;
183 break;
184 case __builtin_clz(TIM_IT_CC1):
185 tmp = tim->CCR1;
186 break;
187 case __builtin_clz(TIM_IT_CC2):
188 tmp = tim->CCR2;
189 break;
190 case __builtin_clz(TIM_IT_CC3):
191 tmp = tim->CCR3;
192 break;
193 case __builtin_clz(TIM_IT_CC4):
194 tmp = tim->CCR4;
195 break;
198 (void)tmp;
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;
218 } else {
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) {
226 case 0:
227 TIM_OC1Init(tch->timHw->tim, &TIM_OCInitStructure);
228 TIM_OC1PreloadConfig(tch->timHw->tim, TIM_OCPreload_Enable);
229 break;
230 case 1:
231 TIM_OC2Init(tch->timHw->tim, &TIM_OCInitStructure);
232 TIM_OC2PreloadConfig(tch->timHw->tim, TIM_OCPreload_Enable);
233 break;
234 case 2:
235 TIM_OC3Init(tch->timHw->tim, &TIM_OCInitStructure);
236 TIM_OC3PreloadConfig(tch->timHw->tim, TIM_OCPreload_Enable);
237 break;
238 case 3:
239 TIM_OC4Init(tch->timHw->tim, &TIM_OCInitStructure);
240 TIM_OC4PreloadConfig(tch->timHw->tim, TIM_OCPreload_Enable);
241 break;
245 volatile timCCR_t * impl_timerCCR(TCH_t * tch)
247 switch (tch->timHw->channelIndex) {
248 case 0:
249 return &tch->timHw->tim->CCR1;
250 break;
251 case 1:
252 return &tch->timHw->tim->CCR2;
253 break;
254 case 2:
255 return &tch->timHw->tim->CCR3;
256 break;
257 case 3:
258 return &tch->timHw->tim->CCR4;
259 break;
261 return NULL;
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) {
289 return false;
292 // If DMA is already in use - abort
293 if (tch->dma->owner != OWNER_FREE) {
294 return false;
297 // We assume that timer channels are already initialized by calls to:
298 // timerConfigBase
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);
306 } else {
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) {
328 case 1:
329 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
330 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
331 break;
332 case 2:
333 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
334 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
335 break;
336 case 4:
337 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
338 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
339 break;
340 default:
341 // Programmer error
342 while(1) {
347 #ifdef STM32F4
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;
352 #else // F3
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;
357 #endif
359 DMA_Init(tch->dma->ref, &DMA_InitStructure);
360 DMA_ITConfig(tch->dma->ref, DMA_IT_TC, ENABLE);
362 return true;
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) {
374 return false;
377 // If DMA is already in use - abort
378 if (tch->dma->owner != OWNER_FREE) {
379 return false;
383 // We assume that timer channels are already initialized by calls to:
384 // timerConfigBase
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);
392 } else {
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) {
414 case 1:
415 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
416 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
417 break;
418 case 2:
419 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
420 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
421 break;
422 case 4:
423 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
424 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
425 break;
426 default:
427 // Programmer error
428 while(1) {
433 #ifdef STM32F4
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;
438 #else // F3
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;
443 #endif
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;
456 return true;
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);
466 #endif
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;
509 if (dmaSources) {
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);