Merge pull request #10558 from iNavFlight/MrD_Correct-comments-on-OSD-symbols
[inav.git] / src / main / drivers / timer_impl_hal.c
blob8df0f7024d3547eef1c8b5351cdf2dfffeaae3d1
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 <string.h>
21 #include <math.h>
23 #include "platform.h"
25 #include "build/atomic.h"
26 #include "build/debug.h"
28 #include "common/utils.h"
30 #include "drivers/io.h"
31 #include "drivers/rcc.h"
32 #include "drivers/time.h"
33 #include "drivers/nvic.h"
34 #include "drivers/timer.h"
35 #include "drivers/timer_impl.h"
37 extern uint32_t timerClock(TIM_TypeDef *tim);
39 const uint16_t lookupDMASourceTable[] = { TIM_DMA_CC1, TIM_DMA_CC2, TIM_DMA_CC3, TIM_DMA_CC4 };
40 const uint8_t lookupTIMChannelTable[] = { TIM_CHANNEL_1, TIM_CHANNEL_2, TIM_CHANNEL_3, TIM_CHANNEL_4 };
42 static const uint32_t lookupDMALLStreamTable[] = { LL_DMA_STREAM_0, LL_DMA_STREAM_1, LL_DMA_STREAM_2, LL_DMA_STREAM_3, LL_DMA_STREAM_4, LL_DMA_STREAM_5, LL_DMA_STREAM_6, LL_DMA_STREAM_7 };
44 #if !(defined(STM32H7) || defined(STM32G4))
45 static const uint32_t lookupDMALLChannelTable[] = { LL_DMA_CHANNEL_0, LL_DMA_CHANNEL_1, LL_DMA_CHANNEL_2, LL_DMA_CHANNEL_3, LL_DMA_CHANNEL_4, LL_DMA_CHANNEL_5, LL_DMA_CHANNEL_6, LL_DMA_CHANNEL_7 };
46 #endif
48 static TIM_HandleTypeDef timerHandle[HARDWARE_TIMER_DEFINITION_COUNT];
50 static TIM_HandleTypeDef * timerFindTimerHandle(TIM_TypeDef *tim)
52 uint8_t timerIndex = lookupTimerIndex(tim);
53 if (timerIndex >= HARDWARE_TIMER_DEFINITION_COUNT) {
54 return NULL;
57 return &timerHandle[timerIndex];
60 void impl_timerInitContext(timHardwareContext_t * timCtx)
62 timCtx->timHandle = timerFindTimerHandle(timCtx->timDef->tim);
65 void impl_timerNVICConfigure(TCH_t * tch, int irqPriority)
67 if (tch->timCtx->timDef->irq) {
68 HAL_NVIC_SetPriority(tch->timCtx->timDef->irq, irqPriority, 0);
69 HAL_NVIC_EnableIRQ(tch->timCtx->timDef->irq);
72 if (tch->timCtx->timDef->secondIrq) {
73 HAL_NVIC_SetPriority(tch->timCtx->timDef->secondIrq, irqPriority, 0);
74 HAL_NVIC_EnableIRQ(tch->timCtx->timDef->secondIrq);
78 void impl_timerConfigBase(TCH_t * tch, uint16_t period, uint32_t hz)
80 // Get and verify HAL TIM_Handle object
81 TIM_HandleTypeDef * timHandle = tch->timCtx->timHandle;
82 TIM_TypeDef * timer = tch->timCtx->timDef->tim;
84 uint16_t period1 = (period - 1) & 0xffff;
85 uint16_t prescaler1 = lrintf((float)timerGetBaseClock(tch) / hz + 0.01f) - 1;
87 if (timHandle->Instance == timer && timHandle->Init.Prescaler == prescaler1 && timHandle->Init.Period == period1) {
88 return;
91 timHandle->Instance = timer;
92 timHandle->Init.Prescaler = prescaler1;
93 timHandle->Init.Period = period1; // AKA TIMx_ARR
94 timHandle->Init.RepetitionCounter = 0;
95 timHandle->Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
96 timHandle->Init.CounterMode = TIM_COUNTERMODE_UP;
97 timHandle->Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
99 HAL_TIM_Base_Init(timHandle);
101 #if defined(STM32H7) || defined(STM32G4)
102 if (timer == TIM1 || timer == TIM2 || timer == TIM3 || timer == TIM4 || timer == TIM5 || timer == TIM8) {
103 #else
104 if (timer == TIM1 || timer == TIM2 || timer == TIM3 || timer == TIM4 || timer == TIM5 || timer == TIM8 || timer == TIM9) {
105 #endif
106 TIM_ClockConfigTypeDef sClockSourceConfig;
107 memset(&sClockSourceConfig, 0, sizeof(sClockSourceConfig));
108 sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
109 if (HAL_TIM_ConfigClockSource(timHandle, &sClockSourceConfig) != HAL_OK) {
110 return;
114 if (timer == TIM1 || timer == TIM2 || timer == TIM3 || timer == TIM4 || timer == TIM5 || timer == TIM8) {
115 TIM_MasterConfigTypeDef sMasterConfig;
116 memset(&sMasterConfig, 0, sizeof(sMasterConfig));
117 sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
118 if (HAL_TIMEx_MasterConfigSynchronization(timHandle, &sMasterConfig) != HAL_OK) {
119 return;
124 void impl_timerPWMConfigChannel(TCH_t * tch, uint16_t value)
126 const bool inverted = tch->timHw->output & TIMER_OUTPUT_INVERTED;
128 TIM_OC_InitTypeDef TIM_OCInitStructure;
130 TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
131 TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_SET;
132 TIM_OCInitStructure.OCPolarity = inverted ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH;
133 TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_SET;
134 TIM_OCInitStructure.OCNPolarity = inverted ? TIM_OCNPOLARITY_LOW : TIM_OCNPOLARITY_HIGH;
135 TIM_OCInitStructure.Pulse = value;
136 TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
138 HAL_TIM_PWM_ConfigChannel(tch->timCtx->timHandle, &TIM_OCInitStructure, lookupTIMChannelTable[tch->timHw->channelIndex]);
141 volatile timCCR_t * impl_timerCCR(TCH_t * tch)
143 switch (tch->timHw->channelIndex) {
144 case 0:
145 return &tch->timHw->tim->CCR1;
146 break;
147 case 1:
148 return &tch->timHw->tim->CCR2;
149 break;
150 case 2:
151 return &tch->timHw->tim->CCR3;
152 break;
153 case 3:
154 return &tch->timHw->tim->CCR4;
155 break;
157 return NULL;
160 void impl_enableTimer(TCH_t * tch)
162 HAL_TIM_Base_Start(tch->timCtx->timHandle);
165 void impl_timerPWMStart(TCH_t * tch)
167 if (tch->timHw->output & TIMER_OUTPUT_N_CHANNEL) {
168 HAL_TIMEx_PWMN_Start(tch->timCtx->timHandle, lookupTIMChannelTable[tch->timHw->channelIndex]);
170 else {
171 HAL_TIM_PWM_Start(tch->timCtx->timHandle, lookupTIMChannelTable[tch->timHw->channelIndex]);
175 void impl_timerEnableIT(TCH_t * tch, uint32_t interrupt)
177 __HAL_TIM_ENABLE_IT(tch->timCtx->timHandle, interrupt);
180 void impl_timerDisableIT(TCH_t * tch, uint32_t interrupt)
182 __HAL_TIM_DISABLE_IT(tch->timCtx->timHandle, interrupt);
185 void impl_timerClearFlag(TCH_t * tch, uint32_t flag)
187 __HAL_TIM_CLEAR_FLAG(tch->timCtx->timHandle, flag);
190 // calculate input filter constant
191 static unsigned getFilter(unsigned ticks)
193 static const unsigned ftab[16] = {
194 1*1, // fDTS !
195 1*2, 1*4, 1*8, // fCK_INT
196 2*6, 2*8, // fDTS/2
197 4*6, 4*8,
198 8*6, 8*8,
199 16*5, 16*6, 16*8,
200 32*5, 32*6, 32*8
203 for (unsigned i = 1; i < ARRAYLEN(ftab); i++) {
204 if (ftab[i] > ticks) {
205 return i - 1;
209 return 0x0f;
212 void impl_timerChConfigIC(TCH_t * tch, bool polarityRising, unsigned inputFilterTicks)
214 TIM_IC_InitTypeDef TIM_ICInitStructure;
216 TIM_ICInitStructure.ICPolarity = polarityRising ? TIM_ICPOLARITY_RISING : TIM_ICPOLARITY_FALLING;
217 TIM_ICInitStructure.ICSelection = TIM_ICSELECTION_DIRECTTI;
218 TIM_ICInitStructure.ICPrescaler = TIM_ICPSC_DIV1;
219 TIM_ICInitStructure.ICFilter = getFilter(inputFilterTicks);
220 HAL_TIM_IC_ConfigChannel(tch->timCtx->timHandle, &TIM_ICInitStructure, lookupTIMChannelTable[tch->timHw->channelIndex]);
223 void impl_timerCaptureCompareHandler(TIM_TypeDef *tim, timHardwareContext_t *timerCtx)
225 unsigned tim_status = tim->SR & tim->DIER;
227 while (tim_status) {
228 // flags will be cleared by reading CCR in dual capture, make sure we call handler correctly
229 // currrent order is highest bit first. Code should not rely on specific order (it will introduce race conditions anyway)
230 unsigned bit = __builtin_clz(tim_status);
231 unsigned mask = ~(0x80000000 >> bit);
232 tim->SR = mask;
233 tim_status &= mask;
235 if (timerCtx) {
236 switch (bit) {
237 case __builtin_clz(TIM_IT_UPDATE): {
238 const uint16_t capture = tim->ARR;
239 if (timerCtx->ch[0].cb && timerCtx->ch[0].cb->callbackOvr) {
240 timerCtx->ch[0].cb->callbackOvr(&timerCtx->ch[0], capture);
242 if (timerCtx->ch[1].cb && timerCtx->ch[1].cb->callbackOvr) {
243 timerCtx->ch[1].cb->callbackOvr(&timerCtx->ch[1], capture);
245 if (timerCtx->ch[2].cb && timerCtx->ch[2].cb->callbackOvr) {
246 timerCtx->ch[2].cb->callbackOvr(&timerCtx->ch[2], capture);
248 if (timerCtx->ch[3].cb && timerCtx->ch[3].cb->callbackOvr) {
249 timerCtx->ch[3].cb->callbackOvr(&timerCtx->ch[3], capture);
251 break;
253 case __builtin_clz(TIM_IT_CC1):
254 timerCtx->ch[0].cb->callbackEdge(&timerCtx->ch[0], tim->CCR1);
255 break;
256 case __builtin_clz(TIM_IT_CC2):
257 timerCtx->ch[1].cb->callbackEdge(&timerCtx->ch[1], tim->CCR2);
258 break;
259 case __builtin_clz(TIM_IT_CC3):
260 timerCtx->ch[2].cb->callbackEdge(&timerCtx->ch[2], tim->CCR3);
261 break;
262 case __builtin_clz(TIM_IT_CC4):
263 timerCtx->ch[3].cb->callbackEdge(&timerCtx->ch[3], tim->CCR4);
264 break;
267 else {
268 // timerConfig == NULL
269 volatile uint32_t tmp;
271 switch (bit) {
272 case __builtin_clz(TIM_IT_UPDATE):
273 tmp = tim->ARR;
274 break;
275 case __builtin_clz(TIM_IT_CC1):
276 tmp = tim->CCR1;
277 break;
278 case __builtin_clz(TIM_IT_CC2):
279 tmp = tim->CCR2;
280 break;
281 case __builtin_clz(TIM_IT_CC3):
282 tmp = tim->CCR3;
283 break;
284 case __builtin_clz(TIM_IT_CC4):
285 tmp = tim->CCR4;
286 break;
289 (void)tmp;
294 void impl_timerChCaptureCompareEnable(TCH_t * tch, bool enable)
296 static const uint32_t lookupTIMLLChannelTable[] = { LL_TIM_CHANNEL_CH1, LL_TIM_CHANNEL_CH2, LL_TIM_CHANNEL_CH3, LL_TIM_CHANNEL_CH4 };
298 if (enable) {
299 LL_TIM_CC_EnableChannel(tch->timHw->tim, lookupTIMLLChannelTable[tch->timHw->channelIndex]);
301 else {
302 LL_TIM_CC_DisableChannel(tch->timHw->tim, lookupTIMLLChannelTable[tch->timHw->channelIndex]);
306 // HAL_LL additionan implementation for enabling multiple DMA channels in one operation
307 static inline void LL_TIM_EnableDMAReq_CCx(TIM_TypeDef * TIMx, uint16_t dmaSources)
309 SET_BIT(TIMx->DIER, dmaSources & (TIM_DMA_CC1 | TIM_DMA_CC2 | TIM_DMA_CC3 | TIM_DMA_CC4));
312 static inline void LL_TIM_DisableDMAReq_CCx(TIM_TypeDef * TIMx, uint16_t dmaSources)
314 CLEAR_BIT(TIMx->DIER, dmaSources & (TIM_DMA_CC1 | TIM_DMA_CC2 | TIM_DMA_CC3 | TIM_DMA_CC4));
317 static void impl_timerDMA_IRQHandler(DMA_t descriptor)
319 if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
320 TCH_t * tch = (TCH_t *)descriptor->userParam;
322 // If it was ACTIVE - switch to IDLE
323 if (tch->dmaState == TCH_DMA_ACTIVE) {
324 tch->dmaState = TCH_DMA_IDLE;
327 LL_DMA_DisableStream(tch->dma->dma, lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)]);
328 LL_TIM_DisableDMAReq_CCx(tch->timHw->tim, lookupDMASourceTable[tch->timHw->channelIndex]);
330 DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
334 bool impl_timerPWMConfigChannelDMA(TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount)
336 tch->dma = dmaGetByTag(tch->timHw->dmaTag);
337 tch->dmaBuffer = dmaBuffer;
338 if (tch->dma == NULL) {
339 return false;
342 // If DMA is already in use - abort
343 if (dmaGetOwner(tch->dma) != OWNER_FREE) {
344 return false;
347 // We assume that timer channels are already initialized by calls to:
348 // timerConfigBase
349 // timerPWMConfigChannel
350 const uint32_t streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)];
352 LL_DMA_DeInit(tch->dma->dma, streamLL);
354 LL_DMA_InitTypeDef init;
355 LL_DMA_StructInit(&init);
357 #if defined(STM32H7) || defined(STM32G4)
358 // For H7 the DMA periphRequest is encoded in the DMA tag
359 init.PeriphRequest = DMATAG_GET_CHANNEL(tch->timHw->dmaTag);
360 #else
361 init.Channel = lookupDMALLChannelTable[DMATAG_GET_CHANNEL(tch->timHw->dmaTag)];
362 #endif
364 init.PeriphOrM2MSrcAddress = (uint32_t)impl_timerCCR(tch);
365 init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
367 switch (dmaBufferElementSize) {
368 case 1:
369 init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
370 init.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_BYTE;
371 break;
372 case 2:
373 init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
374 init.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_HALFWORD;
375 break;
376 case 4:
377 init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
378 init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
379 break;
380 default:
381 // Programmer error
382 while(1) {
387 init.MemoryOrM2MDstAddress = (uint32_t)dmaBuffer;
388 init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
389 init.NbData = dmaBufferElementCount;
390 init.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
391 init.Mode = LL_DMA_MODE_NORMAL;
392 init.Priority = LL_DMA_PRIORITY_HIGH;
393 init.FIFOMode = LL_DMA_FIFOMODE_ENABLE;
394 init.FIFOThreshold = LL_DMA_FIFOTHRESHOLD_FULL;
395 init.MemBurst = LL_DMA_MBURST_SINGLE;
396 init.PeriphBurst = LL_DMA_PBURST_SINGLE;
398 dmaInit(tch->dma, OWNER_TIMER, 0);
399 dmaSetHandler(tch->dma, impl_timerDMA_IRQHandler, NVIC_PRIO_TIMER_DMA, (uint32_t)tch);
401 LL_DMA_Init(tch->dma->dma, streamLL, &init);
403 // Start PWM generation
404 if (tch->timHw->output & TIMER_OUTPUT_N_CHANNEL) {
405 HAL_TIMEx_PWMN_Start(tch->timCtx->timHandle, lookupTIMChannelTable[tch->timHw->channelIndex]);
407 else {
408 HAL_TIM_PWM_Start(tch->timCtx->timHandle, lookupTIMChannelTable[tch->timHw->channelIndex]);
411 return true;
414 #ifdef USE_DSHOT_DMAR
415 bool impl_timerPWMConfigDMABurst(burstDmaTimer_t *burstDmaTimer, TCH_t * tch, void * dmaBuffer, uint8_t dmaBufferElementSize, uint32_t dmaBufferElementCount)
417 tch->dma = dmaGetByTag(tch->timHw->dmaTag);
418 tch->dmaBuffer = dmaBuffer;
419 if (tch->dma == NULL) {
420 return false;
423 // If DMA is already in use - abort
424 if (dmaGetOwner(tch->dma) != OWNER_FREE) {
425 return false;
428 if (!tch->timCtx->dmaBurstRef) {
429 // We assume that timer channels are already initialized by calls to:
430 // timerConfigBase
431 // timerPWMConfigChannel
432 const uint32_t streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)];
434 LL_DMA_DeInit(tch->dma->dma, streamLL);
436 LL_DMA_InitTypeDef init;
437 LL_DMA_StructInit(&init);
439 #if defined(STM32H7) || defined(STM32G4)
440 // For H7 the DMA periphRequest is encoded in the DMA tag
441 init.PeriphRequest = DMATAG_GET_CHANNEL(tch->timHw->dmaTag);
442 #else
443 init.Channel = lookupDMALLChannelTable[DMATAG_GET_CHANNEL(tch->timHw->dmaTag)];
444 #endif
446 init.PeriphOrM2MSrcAddress = (uint32_t)&tch->timHw->tim->DMAR;
447 init.PeriphOrM2MSrcIncMode = LL_DMA_PERIPH_NOINCREMENT;
449 switch (dmaBufferElementSize) {
450 case 1:
451 init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_BYTE;
452 init.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_BYTE;
453 break;
454 case 2:
455 init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_HALFWORD;
456 init.PeriphOrM2MSrcDataSize = LL_DMA_MDATAALIGN_HALFWORD;
457 break;
458 case 4:
459 init.MemoryOrM2MDstDataSize = LL_DMA_MDATAALIGN_WORD;
460 init.PeriphOrM2MSrcDataSize = LL_DMA_PDATAALIGN_WORD;
461 break;
462 default:
463 // Programmer error
464 while(1) {
469 init.MemoryOrM2MDstAddress = (uint32_t)dmaBuffer;
470 init.MemoryOrM2MDstIncMode = LL_DMA_MEMORY_INCREMENT;
471 init.NbData = dmaBufferElementCount;
472 init.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
473 init.Mode = LL_DMA_MODE_NORMAL;
474 init.Priority = LL_DMA_PRIORITY_HIGH;
475 init.FIFOMode = LL_DMA_FIFOMODE_ENABLE;
476 init.FIFOThreshold = LL_DMA_FIFOTHRESHOLD_FULL;
477 init.MemBurst = LL_DMA_MBURST_SINGLE;
478 init.PeriphBurst = LL_DMA_PBURST_SINGLE;
480 dmaInit(tch->dma, OWNER_TIMER, 0);
481 dmaSetHandler(tch->dma, impl_timerDMA_IRQHandler, NVIC_PRIO_TIMER_DMA, (uint32_t)tch);
483 LL_DMA_Init(tch->dma->dma, streamLL, &init);
485 tch->timCtx->dmaBurstRef = tch->dma;
486 burstDmaTimer->burstRequestSource = lookupDMASourceTable[tch->timHw->channelIndex];
487 burstDmaTimer->streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)];
488 burstDmaTimer->dma = tch->dma->dma;
490 tch->dmaState = TCH_DMA_READY;
493 // Start PWM generation
494 if (tch->timHw->output & TIMER_OUTPUT_N_CHANNEL) {
495 HAL_TIMEx_PWMN_Start(tch->timCtx->timHandle, lookupTIMChannelTable[tch->timHw->channelIndex]);
497 else {
498 HAL_TIM_PWM_Start(tch->timCtx->timHandle, lookupTIMChannelTable[tch->timHw->channelIndex]);
501 return true;
504 void impl_pwmBurstDMAStart(burstDmaTimer_t * burstDmaTimer, uint32_t BurstLength)
506 LL_DMA_SetDataLength(burstDmaTimer->dma, burstDmaTimer->streamLL, BurstLength);
507 LL_DMA_EnableIT_TC(burstDmaTimer->dma, burstDmaTimer->streamLL);
508 LL_DMA_EnableStream(burstDmaTimer->dma, burstDmaTimer->streamLL);
509 /* configure the DMA Burst Mode */
510 LL_TIM_ConfigDMABurst(burstDmaTimer->timer, LL_TIM_DMABURST_BASEADDR_CCR1, LL_TIM_DMABURST_LENGTH_4TRANSFERS);
511 /* Enable the TIM DMA Request */
512 //LL_TIM_EnableDMAReq_UPDATE(burstDmaTimer->timer);
513 LL_TIM_EnableDMAReq_CCx(burstDmaTimer->timer, burstDmaTimer->burstRequestSource);
515 #endif
517 void impl_timerPWMPrepareDMA(TCH_t * tch, uint32_t dmaBufferElementCount)
519 const uint32_t streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)];
520 DMA_TypeDef *dmaBase = tch->dma->dma;
522 // Make sure we terminate any DMA transaction currently in progress
523 // Clear the flag as well, so even if DMA transfer finishes while within ATOMIC_BLOCK
524 // the resulting IRQ won't mess up the DMA state
525 ATOMIC_BLOCK(NVIC_PRIO_MAX) {
526 LL_TIM_DisableDMAReq_CCx(tch->timHw->tim, lookupDMASourceTable[tch->timHw->channelIndex]);
527 LL_DMA_DisableStream(dmaBase, streamLL);
528 DMA_CLEAR_FLAG(tch->dma, DMA_IT_TCIF);
531 LL_DMA_SetDataLength(dmaBase, streamLL, dmaBufferElementCount);
532 LL_DMA_ConfigAddresses(dmaBase, streamLL, (uint32_t)tch->dmaBuffer, (uint32_t)impl_timerCCR(tch), LL_DMA_DIRECTION_MEMORY_TO_PERIPH);
533 LL_DMA_EnableIT_TC(dmaBase, streamLL);
534 LL_DMA_EnableStream(dmaBase, streamLL);
535 tch->dmaState = TCH_DMA_READY;
538 void impl_timerPWMStartDMA(TCH_t * tch)
540 uint16_t dmaSources = 0;
541 timHardwareContext_t * timCtx = tch->timCtx;
543 if (timCtx->ch[0].dmaState == TCH_DMA_READY) {
544 timCtx->ch[0].dmaState = TCH_DMA_ACTIVE;
545 dmaSources |= TIM_DMA_CC1;
548 if (timCtx->ch[1].dmaState == TCH_DMA_READY) {
549 timCtx->ch[1].dmaState = TCH_DMA_ACTIVE;
550 dmaSources |= TIM_DMA_CC2;
553 if (timCtx->ch[2].dmaState == TCH_DMA_READY) {
554 timCtx->ch[2].dmaState = TCH_DMA_ACTIVE;
555 dmaSources |= TIM_DMA_CC3;
558 if (timCtx->ch[3].dmaState == TCH_DMA_READY) {
559 timCtx->ch[3].dmaState = TCH_DMA_ACTIVE;
560 dmaSources |= TIM_DMA_CC4;
563 if (dmaSources) {
564 LL_TIM_SetCounter(timCtx->timDef->tim, 0);
565 LL_TIM_EnableDMAReq_CCx(timCtx->timDef->tim, dmaSources);
569 void impl_timerPWMStopDMA(TCH_t * tch)
571 const uint32_t streamLL = lookupDMALLStreamTable[DMATAG_GET_STREAM(tch->timHw->dmaTag)];
572 DMA_TypeDef *dmaBase = tch->dma->dma;
574 ATOMIC_BLOCK(NVIC_PRIO_MAX) {
575 LL_TIM_DisableDMAReq_CCx(tch->timHw->tim, lookupDMASourceTable[tch->timHw->channelIndex]);
576 LL_DMA_DisableStream(dmaBase, streamLL);
577 DMA_CLEAR_FLAG(tch->dma, DMA_IT_TCIF);
579 tch->dmaState = TCH_DMA_IDLE;
581 HAL_TIM_Base_Start(tch->timCtx->timHandle);