duplicate emptyline removal (#14027)
[betaflight.git] / src / platform / STM32 / transponder_ir_io_hal.c
blob1f3f20340741230b598fbf60ffb552edc6328e75
1 /*
2 * This file is part of Cleanflight and Betaflight.
4 * Cleanflight and Betaflight are free software. You can redistribute
5 * this software and/or modify this software under the terms of the
6 * GNU General Public License as published by the Free Software
7 * Foundation, either version 3 of the License, or (at your option)
8 * any later version.
10 * Cleanflight and Betaflight are distributed in the hope that they
11 * will be useful, but WITHOUT ANY WARRANTY; without even the implied
12 * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 * See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this software.
18 * If not, see <http://www.gnu.org/licenses/>.
21 #include <stdbool.h>
22 #include <stdint.h>
23 #include <string.h>
25 #include "platform.h"
27 #ifdef USE_TRANSPONDER
29 #include "drivers/dma.h"
30 #include "drivers/dma_reqmap.h"
31 #include "drivers/io.h"
32 #include "drivers/nvic.h"
33 #include "drivers/rcc.h"
34 #include "drivers/timer.h"
35 #include "drivers/transponder_ir_arcitimer.h"
36 #include "drivers/transponder_ir_erlt.h"
37 #include "drivers/transponder_ir_ilap.h"
39 #include "drivers/transponder_ir.h"
41 volatile uint8_t transponderIrDataTransferInProgress = 0;
43 static IO_t transponderIO = IO_NONE;
44 static TIM_HandleTypeDef TimHandle;
45 static uint16_t timerChannel = 0;
46 static uint8_t output;
47 static uint8_t alternateFunction;
49 #if !(defined(STM32F7) || defined(STM32H7) || defined(STM32G4))
50 #error "Transponder (via HAL) not supported on this MCU."
51 #endif
53 #if defined(STM32H7)
54 DMA_RAM transponder_t transponder;
55 #elif defined(STM32G4)
56 DMA_RAM_W transponder_t transponder;
57 #else
58 transponder_t transponder;
59 #endif
60 bool transponderInitialised = false;
62 FAST_IRQ_HANDLER static void TRANSPONDER_DMA_IRQHandler(dmaChannelDescriptor_t* descriptor)
64 HAL_DMA_IRQHandler(TimHandle.hdma[descriptor->userParam]);
65 TIM_DMACmd(&TimHandle, timerChannel, DISABLE);
66 transponderIrDataTransferInProgress = 0;
69 void transponderIrHardwareInit(ioTag_t ioTag, transponder_t *transponder)
71 if (!ioTag) {
72 return;
75 const timerHardware_t *timerHardware = timerAllocate(ioTag, OWNER_TRANSPONDER, 0);
76 TIM_TypeDef *timer = timerHardware->tim;
77 timerChannel = timerHardware->channel;
78 output = timerHardware->output;
79 alternateFunction = timerHardware->alternateFunction;
81 #if defined(USE_DMA_SPEC)
82 const dmaChannelSpec_t *dmaSpec = dmaGetChannelSpecByTimer(timerHardware);
84 if (dmaSpec == NULL) {
85 return;
88 dmaResource_t *dmaRef = dmaSpec->ref;
89 uint32_t dmaChannel = dmaSpec->channel;
90 #else
91 dmaResource_t *dmaRef = timerHardware->dmaRef;
92 uint32_t dmaChannel = timerHardware->dmaChannel;
93 #endif
95 dmaIdentifier_e dmaIdentifier = dmaGetIdentifier(dmaRef);
96 if (dmaRef == NULL || !dmaAllocate(dmaIdentifier, OWNER_TRANSPONDER, 0)) {
97 return;
100 /* Time base configuration */
102 TimHandle.Instance = timer;
104 uint16_t prescaler = timerGetPrescalerByDesiredMhz(timer, transponder->timer_hz);
105 uint16_t period = timerGetPeriodByPrescaler(timer, prescaler, transponder->timer_carrier_hz);
107 transponder->bitToggleOne = period / 2;
109 TimHandle.Init.Prescaler = prescaler;
110 TimHandle.Init.Period = period; // 800kHz
111 TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
112 TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
113 if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK) {
114 /* Initialization Error */
115 return;
118 /* IO configuration */
120 static DMA_HandleTypeDef hdma_tim;
122 transponderIO = IOGetByTag(ioTag);
123 IOInit(transponderIO, OWNER_TRANSPONDER, 0);
124 IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLDOWN), timerHardware->alternateFunction);
126 __DMA1_CLK_ENABLE();
127 __DMA2_CLK_ENABLE();
129 /* Set the parameters to be configured */
130 #if defined(STM32H7) || defined(STM32G4)
131 hdma_tim.Init.Request = dmaChannel;
132 #else
133 hdma_tim.Init.Channel = dmaChannel;
134 #endif
135 hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
136 hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
137 hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
138 hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
139 hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
140 hdma_tim.Init.Mode = DMA_NORMAL;
141 hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
142 #if !defined(STM32G4)
143 hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
144 hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
145 hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
146 hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
147 #endif
149 /* Set hdma_tim instance */
150 hdma_tim.Instance = (DMA_ARCH_TYPE *)dmaRef;
152 uint16_t dmaIndex = timerDmaIndex(timerChannel);
154 /* Link hdma_tim to hdma[x] (channelx) */
155 __HAL_LINKDMA(&TimHandle, hdma[dmaIndex], hdma_tim);
157 dmaEnable(dmaIdentifier);
158 dmaSetHandler(dmaIdentifier, TRANSPONDER_DMA_IRQHandler, NVIC_PRIO_TRANSPONDER_DMA, dmaIndex);
160 /* Initialize TIMx DMA handle */
161 if (HAL_DMA_Init(TimHandle.hdma[dmaIndex]) != HAL_OK) {
162 /* Initialization Error */
163 return;
166 RCC_ClockCmd(timerRCC(timer), ENABLE);
168 /* PWM1 Mode configuration: Channel1 */
169 TIM_OC_InitTypeDef TIM_OCInitStructure;
171 TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
172 TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_RESET;
173 TIM_OCInitStructure.OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH;
174 TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
175 TIM_OCInitStructure.OCNPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPOLARITY_LOW : TIM_OCNPOLARITY_HIGH;
176 TIM_OCInitStructure.Pulse = 0;
177 TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
178 if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &TIM_OCInitStructure, timerChannel) != HAL_OK) {
179 /* Configuration Error */
180 return;
182 if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
183 if (HAL_TIMEx_PWMN_Start(&TimHandle, timerChannel) != HAL_OK) {
184 /* Starting PWM generation Error */
185 return;
187 } else {
188 if (HAL_TIM_PWM_Start(&TimHandle, timerChannel) != HAL_OK) {
189 /* Starting PWM generation Error */
190 return;
194 transponderInitialised = true;
197 bool transponderIrInit(const ioTag_t ioTag, const transponderProvider_e provider)
199 if (!ioTag) {
200 return false;
203 switch (provider) {
204 case TRANSPONDER_ARCITIMER:
205 transponderIrInitArcitimer(&transponder);
206 break;
207 case TRANSPONDER_ILAP:
208 transponderIrInitIlap(&transponder);
209 break;
210 case TRANSPONDER_ERLT:
211 transponderIrInitERLT(&transponder);
212 break;
213 default:
214 return false;
217 transponderIrHardwareInit(ioTag, &transponder);
219 return true;
222 bool isTransponderIrReady(void)
224 return !transponderIrDataTransferInProgress;
227 void transponderIrWaitForTransmitComplete(void)
229 #ifdef DEBUG
230 static uint32_t waitCounter = 0;
231 #endif
233 while (transponderIrDataTransferInProgress) {
234 #ifdef DEBUG
235 waitCounter++;
236 #endif
240 void transponderIrUpdateData(const uint8_t* transponderData)
242 transponderIrWaitForTransmitComplete();
243 transponder.vTable->updateTransponderDMABuffer(&transponder, transponderData);
246 void transponderIrDMAEnable(transponder_t *transponder)
248 if (!transponderInitialised) {
249 return;
252 if (DMA_SetCurrDataCounter(&TimHandle, timerChannel, transponder->transponderIrDMABuffer.ilap, transponder->dma_buffer_size) != HAL_OK) {
253 /* DMA set error */
254 transponderIrDataTransferInProgress = 0;
255 return;
258 /* Reset timer counter */
259 __HAL_TIM_SET_COUNTER(&TimHandle, 0);
260 /* Enable channel DMA requests */
261 TIM_DMACmd(&TimHandle, timerChannel, ENABLE);
264 void transponderIrDisable(void)
266 if (!transponderInitialised) {
267 return;
270 TIM_DMACmd(&TimHandle, timerChannel, DISABLE);
271 if (output & TIMER_OUTPUT_N_CHANNEL) {
272 HAL_TIMEx_PWMN_Stop(&TimHandle, timerChannel);
273 } else {
274 HAL_TIM_PWM_Stop(&TimHandle, timerChannel);
277 IOInit(transponderIO, OWNER_TRANSPONDER, 0);
279 #ifdef TRANSPONDER_INVERTED
280 IOHi(transponderIO);
281 #else
282 IOLo(transponderIO);
283 #endif
285 IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLDOWN), alternateFunction);
288 void transponderIrTransmit(void)
290 transponderIrWaitForTransmitComplete();
292 transponderIrDataTransferInProgress = 1;
293 transponderIrDMAEnable(&transponder);
295 #endif