Merge pull request #11939 from blckmn/flash-fix
[betaflight.git] / src / main / drivers / transponder_ir_io_stdperiph.c
blob67193ead5833b3d86706e41c73acf079b8752c6e
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 "transponder_ir.h"
41 volatile uint8_t transponderIrDataTransferInProgress = 0;
43 static IO_t transponderIO = IO_NONE;
44 static TIM_TypeDef *timer = NULL;
45 uint8_t alternateFunction;
46 static dmaResource_t *dmaRef = NULL;
48 transponder_t transponder;
50 static void TRANSPONDER_DMA_IRQHandler(dmaChannelDescriptor_t* descriptor)
52 if (DMA_GET_FLAG_STATUS(descriptor, DMA_IT_TCIF)) {
53 transponderIrDataTransferInProgress = 0;
55 xDMA_Cmd(descriptor->ref, DISABLE);
56 DMA_CLEAR_FLAG(descriptor, DMA_IT_TCIF);
60 void transponderIrHardwareInit(ioTag_t ioTag, transponder_t *transponder)
62 if (!ioTag) {
63 return;
66 TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
67 TIM_OCInitTypeDef TIM_OCInitStructure;
68 DMA_InitTypeDef DMA_InitStructure;
70 const timerHardware_t *timerHardware = timerAllocate(ioTag, OWNER_TRANSPONDER, 0);
71 timer = timerHardware->tim;
72 alternateFunction = timerHardware->alternateFunction;
74 #if defined(USE_DMA_SPEC)
75 const dmaChannelSpec_t *dmaSpec = dmaGetChannelSpecByTimer(timerHardware);
77 if (dmaSpec == NULL) {
78 return;
81 dmaRef = dmaSpec->ref;
82 #if defined(STM32F4)
83 uint32_t dmaChannel = dmaSpec->channel;
84 #endif
85 #else
86 dmaRef = timerHardware->dmaRef;
87 #if defined(STM32F4)
88 uint32_t dmaChannel = timerHardware->dmaChannel;
89 #endif
90 #endif
92 if (dmaRef == NULL || !dmaAllocate(dmaGetIdentifier(dmaRef), OWNER_TRANSPONDER, 0)) {
93 return;
96 transponderIO = IOGetByTag(ioTag);
97 IOInit(transponderIO, OWNER_TRANSPONDER, 0);
98 IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_DOWN), timerHardware->alternateFunction);
100 dmaEnable(dmaGetIdentifier(dmaRef));
101 dmaSetHandler(dmaGetIdentifier(dmaRef), TRANSPONDER_DMA_IRQHandler, NVIC_PRIO_TRANSPONDER_DMA, 0);
103 RCC_ClockCmd(timerRCC(timer), ENABLE);
105 uint16_t prescaler = timerGetPrescalerByDesiredMhz(timer, transponder->timer_hz);
106 uint16_t period = timerGetPeriodByPrescaler(timer, prescaler, transponder->timer_carrier_hz);
108 transponder->bitToggleOne = period / 2;
109 /* Time base configuration */
110 TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
111 TIM_TimeBaseStructure.TIM_Period = period;
112 TIM_TimeBaseStructure.TIM_Prescaler = prescaler;
113 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
114 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
115 TIM_TimeBaseInit(timer, &TIM_TimeBaseStructure);
117 /* PWM1 Mode configuration: Channel1 */
118 TIM_OCStructInit(&TIM_OCInitStructure);
119 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
120 if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
121 TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;
122 TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;
123 } else {
124 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
125 TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set;
128 TIM_OCInitStructure.TIM_OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPolarity_Low : TIM_OCPolarity_High;
129 TIM_OCInitStructure.TIM_Pulse = 0;
131 timerOCInit(timer, timerHardware->channel, &TIM_OCInitStructure);
132 timerOCPreloadConfig(timer, timerHardware->channel, TIM_OCPreload_Enable);
133 TIM_CtrlPWMOutputs(timer, ENABLE);
135 /* configure DMA */
136 xDMA_Cmd(dmaRef, DISABLE);
137 xDMA_DeInit(dmaRef);
139 DMA_StructInit(&DMA_InitStructure);
140 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)timerCCR(timer, timerHardware->channel);
141 #if defined(STM32F4)
142 DMA_InitStructure.DMA_Channel = dmaChannel;
143 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&(transponder->transponderIrDMABuffer);
144 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
145 #endif
146 DMA_InitStructure.DMA_BufferSize = transponder->dma_buffer_size;
147 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
148 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
149 #if defined(STM32F4)
150 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
151 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
152 #endif
153 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
154 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
156 xDMA_Init(dmaRef, &DMA_InitStructure);
158 TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
160 xDMA_ITConfig(dmaRef, DMA_IT_TC, ENABLE);
163 bool transponderIrInit(const ioTag_t ioTag, const transponderProvider_e provider)
165 if (!ioTag) {
166 return false;
169 switch (provider) {
170 case TRANSPONDER_ARCITIMER:
171 transponderIrInitArcitimer(&transponder);
172 break;
173 case TRANSPONDER_ILAP:
174 transponderIrInitIlap(&transponder);
175 break;
176 case TRANSPONDER_ERLT:
177 transponderIrInitERLT(&transponder);
178 break;
179 default:
180 return false;
183 transponderIrHardwareInit(ioTag, &transponder);
185 return true;
188 bool isTransponderIrReady(void)
190 return !transponderIrDataTransferInProgress;
193 void transponderIrWaitForTransmitComplete(void)
195 #ifdef DEBUG
196 static uint32_t waitCounter = 0;
197 #endif
199 while (transponderIrDataTransferInProgress) {
200 #ifdef DEBUG
201 waitCounter++;
202 #endif
206 void transponderIrUpdateData(const uint8_t* transponderData)
208 transponderIrWaitForTransmitComplete();
209 transponder.vTable->updateTransponderDMABuffer(&transponder, transponderData);
212 void transponderIrDMAEnable(transponder_t *transponder)
214 xDMA_SetCurrDataCounter(dmaRef, transponder->dma_buffer_size); // load number of bytes to be transferred
215 TIM_SetCounter(timer, 0);
216 TIM_Cmd(timer, ENABLE);
217 xDMA_Cmd(dmaRef, ENABLE);
220 void transponderIrDisable(void)
222 xDMA_Cmd(dmaRef, DISABLE);
223 TIM_Cmd(timer, DISABLE);
225 IOInit(transponderIO, OWNER_TRANSPONDER, 0);
226 IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_DOWN), alternateFunction);
228 #ifdef TRANSPONDER_INVERTED
229 IOHi(transponderIO);
230 #else
231 IOLo(transponderIO);
232 #endif
235 void transponderIrTransmit(void)
237 transponderIrWaitForTransmitComplete();
239 transponderIrDataTransferInProgress = 1;
240 transponderIrDMAEnable(&transponder);
242 #endif