Merge pull request #11494 from haslinghuis/dshot_gpio
[betaflight.git] / src / main / drivers / transponder_ir_io_stdperiph.c
blob453662d2b89a62714a79dc6e6e93005a61485704
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(STM32F3)
142 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&(transponder->transponderIrDMABuffer);
143 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
144 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
145 #elif defined(STM32F4)
146 DMA_InitStructure.DMA_Channel = dmaChannel;
147 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&(transponder->transponderIrDMABuffer);
148 DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
149 #endif
150 DMA_InitStructure.DMA_BufferSize = transponder->dma_buffer_size;
151 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
152 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
153 #if defined(STM32F3)
154 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
155 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
156 #elif defined(STM32F4)
158 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;
159 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;
160 #endif
161 DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
162 DMA_InitStructure.DMA_Priority = DMA_Priority_High;
164 xDMA_Init(dmaRef, &DMA_InitStructure);
166 TIM_DMACmd(timer, timerDmaSource(timerHardware->channel), ENABLE);
168 xDMA_ITConfig(dmaRef, DMA_IT_TC, ENABLE);
171 bool transponderIrInit(const ioTag_t ioTag, const transponderProvider_e provider)
173 if (!ioTag) {
174 return false;
177 switch (provider) {
178 case TRANSPONDER_ARCITIMER:
179 transponderIrInitArcitimer(&transponder);
180 break;
181 case TRANSPONDER_ILAP:
182 transponderIrInitIlap(&transponder);
183 break;
184 case TRANSPONDER_ERLT:
185 transponderIrInitERLT(&transponder);
186 break;
187 default:
188 return false;
191 transponderIrHardwareInit(ioTag, &transponder);
193 return true;
196 bool isTransponderIrReady(void)
198 return !transponderIrDataTransferInProgress;
201 void transponderIrWaitForTransmitComplete(void)
203 #ifdef DEBUG
204 static uint32_t waitCounter = 0;
205 #endif
207 while (transponderIrDataTransferInProgress) {
208 #ifdef DEBUG
209 waitCounter++;
210 #endif
214 void transponderIrUpdateData(const uint8_t* transponderData)
216 transponderIrWaitForTransmitComplete();
217 transponder.vTable->updateTransponderDMABuffer(&transponder, transponderData);
220 void transponderIrDMAEnable(transponder_t *transponder)
222 xDMA_SetCurrDataCounter(dmaRef, transponder->dma_buffer_size); // load number of bytes to be transferred
223 TIM_SetCounter(timer, 0);
224 TIM_Cmd(timer, ENABLE);
225 xDMA_Cmd(dmaRef, ENABLE);
228 void transponderIrDisable(void)
230 xDMA_Cmd(dmaRef, DISABLE);
231 TIM_Cmd(timer, DISABLE);
233 IOInit(transponderIO, OWNER_TRANSPONDER, 0);
234 IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_Mode_AF, GPIO_Speed_50MHz, GPIO_OType_PP, GPIO_PuPd_DOWN), alternateFunction);
236 #ifdef TRANSPONDER_INVERTED
237 IOHi(transponderIO);
238 #else
239 IOLo(transponderIO);
240 #endif
243 void transponderIrTransmit(void)
245 transponderIrWaitForTransmitComplete();
247 transponderIrDataTransferInProgress = 1;
248 transponderIrDMAEnable(&transponder);
250 #endif