diff --git a/make/mcu/STM32F3.mk b/make/mcu/STM32F3.mk
index 50d9a2cbfb..c0d96caace 100644
--- a/make/mcu/STM32F3.mk
+++ b/make/mcu/STM32F3.mk
@@ -74,6 +74,7 @@ MCU_COMMON_SRC = \
drivers/bus_spi_stdperiph.c \
drivers/dma.c \
drivers/light_ws2811strip_stdperiph.c \
+ drivers/transponder_ir_io_stdperiph.c \
drivers/pwm_output_dshot.c \
drivers/serial_uart_init.c \
drivers/serial_uart_stm32f30x.c \
diff --git a/make/mcu/STM32F4.mk b/make/mcu/STM32F4.mk
index cb09f1a6be..1bdd207046 100644
--- a/make/mcu/STM32F4.mk
+++ b/make/mcu/STM32F4.mk
@@ -172,6 +172,7 @@ MCU_COMMON_SRC = \
drivers/dma_stm32f4xx.c \
drivers/inverter.c \
drivers/light_ws2811strip_stdperiph.c \
+ drivers/transponder_ir_io_stdperiph.c \
drivers/pwm_output_dshot.c \
drivers/serial_uart_init.c \
drivers/serial_uart_stm32f4xx.c \
diff --git a/make/mcu/STM32F7.mk b/make/mcu/STM32F7.mk
index 3967906fd2..acdd7a6860 100644
--- a/make/mcu/STM32F7.mk
+++ b/make/mcu/STM32F7.mk
@@ -166,6 +166,7 @@ MCU_COMMON_SRC = \
drivers/bus_i2c_hal.c \
drivers/dma_stm32f7xx.c \
drivers/light_ws2811strip_hal.c \
+ drivers/transponder_ir_io_hal.c \
drivers/bus_spi_ll.c \
drivers/pwm_output_dshot_hal.c \
drivers/timer_hal.c \
diff --git a/make/source.mk b/make/source.mk
index 1922bb43ac..17ca7a4d99 100644
--- a/make/source.mk
+++ b/make/source.mk
@@ -47,7 +47,6 @@ COMMON_SRC = \
drivers/stack_check.c \
drivers/system.c \
drivers/timer.c \
- drivers/transponder_ir.c \
drivers/transponder_ir_arcitimer.c \
drivers/transponder_ir_ilap.c \
drivers/transponder_ir_erlt.c \
@@ -294,13 +293,15 @@ SIZE_OPTIMISED_SRC := $(SIZE_OPTIMISED_SRC) \
drivers/inverter.c \
drivers/light_ws2811strip.c \
drivers/light_ws2811strip_hal.c \
+ drivers/light_ws2811strip_stdperiph.c \
drivers/serial_escserial.c \
drivers/serial_pinconfig.c \
drivers/serial_tcp.c \
drivers/serial_uart_init.c \
drivers/serial_uart_pinconfig.c \
drivers/serial_usb_vcp.c \
- drivers/transponder_ir.c \
+ drivers/transponder_ir_io_hal.c \
+ drivers/transponder_ir_io_stdperiph.c \
drivers/vtx_rtc6705_soft_spi.c \
drivers/vtx_rtc6705.c \
drivers/vtx_common.c \
diff --git a/src/main/drivers/transponder_ir.h b/src/main/drivers/transponder_ir.h
index 49d75d6785..9ecd36af29 100644
--- a/src/main/drivers/transponder_ir.h
+++ b/src/main/drivers/transponder_ir.h
@@ -77,7 +77,7 @@
uint8_t erlt[TRANSPONDER_DMA_BUFFER_SIZE_ERLT]; // 91-200
} transponderIrDMABuffer_t;
-#elif defined(STM32F4)
+#elif defined(STM32F4) || defined(STM32F7)
typedef union transponderIrDMABuffer_s {
uint32_t arcitimer[TRANSPONDER_DMA_BUFFER_SIZE_ARCITIMER]; // 620
@@ -93,7 +93,7 @@ typedef struct transponder_s {
uint16_t bitToggleOne;
uint32_t dma_buffer_size;
- #if defined(STM32F3) || defined(STM32F4)|| defined(UNIT_TEST)
+ #if defined(STM32F3) || defined(STM32F4)|| defined(STM32F7) || defined(UNIT_TEST)
transponderIrDMABuffer_t transponderIrDMABuffer;
#endif
diff --git a/src/main/drivers/transponder_ir_arcitimer.c b/src/main/drivers/transponder_ir_arcitimer.c
index e5b75eda98..df973d3750 100644
--- a/src/main/drivers/transponder_ir_arcitimer.c
+++ b/src/main/drivers/transponder_ir_arcitimer.c
@@ -24,7 +24,7 @@
#include "drivers/transponder_ir.h"
#include "drivers/transponder_ir_arcitimer.h"
-#if defined(STM32F3) || defined(STM32F4) || defined(UNIT_TEST)
+#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) || defined(UNIT_TEST)
extern const struct transponderVTable arcitimerTansponderVTable;
static uint16_t dmaBufferOffset;
diff --git a/src/main/drivers/transponder_ir_erlt.c b/src/main/drivers/transponder_ir_erlt.c
index 5cb238b63a..330a61d2b3 100644
--- a/src/main/drivers/transponder_ir_erlt.c
+++ b/src/main/drivers/transponder_ir_erlt.c
@@ -24,7 +24,7 @@
#include "drivers/transponder_ir.h"
#include "drivers/transponder_ir_erlt.h"
-#if defined(STM32F3) || defined(STM32F4) || defined(UNIT_TEST)
+#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) || defined(UNIT_TEST)
static uint16_t dmaBufferOffset;
extern const struct transponderVTable erltTansponderVTable;
diff --git a/src/main/drivers/transponder_ir_ilap.c b/src/main/drivers/transponder_ir_ilap.c
index 4d110898ed..0ad2e71e37 100644
--- a/src/main/drivers/transponder_ir_ilap.c
+++ b/src/main/drivers/transponder_ir_ilap.c
@@ -24,7 +24,7 @@
#include "drivers/transponder_ir.h"
#include "drivers/transponder_ir_ilap.h"
-#if defined(STM32F3) || defined(STM32F4) || defined(UNIT_TEST)
+#if defined(STM32F3) || defined(STM32F4) || defined(STM32F7) || defined(UNIT_TEST)
static uint16_t dmaBufferOffset;
extern const struct transponderVTable ilapTansponderVTable;
diff --git a/src/main/drivers/transponder_ir_io_hal.c b/src/main/drivers/transponder_ir_io_hal.c
new file mode 100644
index 0000000000..626b2bb8e2
--- /dev/null
+++ b/src/main/drivers/transponder_ir_io_hal.c
@@ -0,0 +1,262 @@
+/*
+ * This file is part of Cleanflight.
+ *
+ * Cleanflight is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Cleanflight is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Cleanflight. If not, see .
+ */
+
+#include
+#include
+#include
+
+#include
+
+#ifdef USE_TRANSPONDER
+
+#include "dma.h"
+#include "drivers/nvic.h"
+#include "drivers/io.h"
+#include "rcc.h"
+#include "timer.h"
+
+#include "transponder_ir.h"
+#include "drivers/transponder_ir_arcitimer.h"
+#include "drivers/transponder_ir_ilap.h"
+#include "drivers/transponder_ir_erlt.h"
+
+volatile uint8_t transponderIrDataTransferInProgress = 0;
+
+
+static IO_t transponderIO = IO_NONE;
+static TIM_HandleTypeDef TimHandle;
+static uint16_t timerChannel = 0;
+
+#if !defined(STM32F7)
+#error "Transponder (via HAL) not supported on this MCU."
+#endif
+
+transponder_t transponder;
+bool transponderInitialised = false;
+
+static void TRANSPONDER_DMA_IRQHandler(dmaChannelDescriptor_t* descriptor)
+{
+ HAL_DMA_IRQHandler(TimHandle.hdma[descriptor->userParam]);
+ TIM_DMACmd(&TimHandle, timerChannel, DISABLE);
+ transponderIrDataTransferInProgress = 0;
+}
+
+void transponderIrHardwareInit(ioTag_t ioTag, transponder_t *transponder)
+{
+ if (!ioTag) {
+ return;
+ }
+
+ const timerHardware_t *timerHardware = timerGetByTag(ioTag, TIM_USE_ANY);
+ TIM_TypeDef *timer = timerHardware->tim;
+ timerChannel = timerHardware->channel;
+
+ if (timerHardware->dmaRef == NULL) {
+ return;
+ }
+
+ /* Time base configuration */
+
+ TimHandle.Instance = timer;
+
+ uint16_t prescaler = timerGetPrescalerByDesiredMhz(timer, transponder->timer_hz);
+ uint16_t period = timerGetPeriodByPrescaler(timer, prescaler, transponder->timer_carrier_hz);
+
+ transponder->bitToggleOne = period / 2;
+
+ TimHandle.Init.Prescaler = prescaler;
+ TimHandle.Init.Period = period; // 800kHz
+ TimHandle.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
+ TimHandle.Init.CounterMode = TIM_COUNTERMODE_UP;
+ if (HAL_TIM_PWM_Init(&TimHandle) != HAL_OK) {
+ /* Initialization Error */
+ return;
+ }
+
+ /* IO configuration */
+
+ static DMA_HandleTypeDef hdma_tim;
+
+ transponderIO = IOGetByTag(ioTag);
+ IOInit(transponderIO, OWNER_TRANSPONDER, 0);
+ IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLDOWN), timerHardware->alternateFunction);
+
+ __DMA1_CLK_ENABLE();
+
+ /* Set the parameters to be configured */
+ hdma_tim.Init.Channel = timerHardware->dmaChannel;
+ hdma_tim.Init.Direction = DMA_MEMORY_TO_PERIPH;
+ hdma_tim.Init.PeriphInc = DMA_PINC_DISABLE;
+ hdma_tim.Init.MemInc = DMA_MINC_ENABLE;
+ hdma_tim.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
+ hdma_tim.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
+ hdma_tim.Init.Mode = DMA_NORMAL;
+ hdma_tim.Init.Priority = DMA_PRIORITY_HIGH;
+ hdma_tim.Init.FIFOMode = DMA_FIFOMODE_DISABLE;
+ hdma_tim.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_FULL;
+ hdma_tim.Init.MemBurst = DMA_MBURST_SINGLE;
+ hdma_tim.Init.PeriphBurst = DMA_PBURST_SINGLE;
+
+ /* Set hdma_tim instance */
+ hdma_tim.Instance = timerHardware->dmaRef;
+
+ uint16_t dmaIndex = timerDmaIndex(timerChannel);
+
+ /* Link hdma_tim to hdma[x] (channelx) */
+ __HAL_LINKDMA(&TimHandle, hdma[dmaIndex], hdma_tim);
+
+ dmaInit(timerHardware->dmaIrqHandler, OWNER_TRANSPONDER, 0);
+ dmaSetHandler(timerHardware->dmaIrqHandler, TRANSPONDER_DMA_IRQHandler, NVIC_PRIO_TRANSPONDER_DMA, dmaIndex);
+
+ /* Initialize TIMx DMA handle */
+ if (HAL_DMA_Init(TimHandle.hdma[dmaIndex]) != HAL_OK) {
+ /* Initialization Error */
+ return;
+ }
+
+
+ RCC_ClockCmd(timerRCC(timer), ENABLE);
+
+ /* PWM1 Mode configuration: Channel1 */
+ TIM_OC_InitTypeDef TIM_OCInitStructure;
+
+ TIM_OCInitStructure.OCMode = TIM_OCMODE_PWM1;
+ TIM_OCInitStructure.OCIdleState = TIM_OCIDLESTATE_RESET;
+ TIM_OCInitStructure.OCPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCPOLARITY_LOW : TIM_OCPOLARITY_HIGH;
+ TIM_OCInitStructure.OCNIdleState = TIM_OCNIDLESTATE_RESET;
+ TIM_OCInitStructure.OCNPolarity = (timerHardware->output & TIMER_OUTPUT_INVERTED) ? TIM_OCNPOLARITY_LOW : TIM_OCNPOLARITY_HIGH;
+ TIM_OCInitStructure.Pulse = 0;
+ TIM_OCInitStructure.OCFastMode = TIM_OCFAST_DISABLE;
+ if (HAL_TIM_PWM_ConfigChannel(&TimHandle, &TIM_OCInitStructure, timerChannel) != HAL_OK) {
+ /* Configuration Error */
+ return;
+ }
+ if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
+ if (HAL_TIMEx_PWMN_Start(&TimHandle, timerChannel) != HAL_OK) {
+ /* Starting PWM generation Error */
+ return;
+ }
+ } else {
+ if (HAL_TIM_PWM_Start(&TimHandle, timerChannel) != HAL_OK) {
+ /* Starting PWM generation Error */
+ return;
+ }
+ }
+
+ transponderInitialised = true;
+}
+
+bool transponderIrInit(const ioTag_t ioTag, const transponderProvider_e provider)
+{
+ if (!ioTag) {
+ return false;
+ }
+
+ switch (provider) {
+ case TRANSPONDER_ARCITIMER:
+ transponderIrInitArcitimer(&transponder);
+ break;
+ case TRANSPONDER_ILAP:
+ transponderIrInitIlap(&transponder);
+ break;
+ case TRANSPONDER_ERLT:
+ transponderIrInitERLT(&transponder);
+ break;
+ default:
+ return false;
+ }
+
+ transponderIrHardwareInit(ioTag, &transponder);
+
+ return true;
+}
+
+bool isTransponderIrReady(void)
+{
+ return !transponderIrDataTransferInProgress;
+}
+
+static uint16_t dmaBufferOffset;
+
+void transponderIrWaitForTransmitComplete(void)
+{
+ static uint32_t waitCounter = 0;
+
+ while (transponderIrDataTransferInProgress) {
+ waitCounter++;
+ }
+}
+
+void transponderIrUpdateData(const uint8_t* transponderData)
+{
+ transponderIrWaitForTransmitComplete();
+ transponder.vTable->updateTransponderDMABuffer(&transponder, transponderData);
+}
+
+void transponderIrDMAEnable(transponder_t *transponder)
+{
+ if (!transponderInitialised) {
+ return;
+ }
+
+ if (DMA_SetCurrDataCounter(&TimHandle, timerChannel, transponder->transponderIrDMABuffer.ilap, transponder->dma_buffer_size) != HAL_OK) {
+ /* DMA set error */
+ transponderIrDataTransferInProgress = 0;
+ return;
+ }
+
+ /* Reset timer counter */
+ __HAL_TIM_SET_COUNTER(&TimHandle, 0);
+ /* Enable channel DMA requests */
+ TIM_DMACmd(&TimHandle, timerChannel, ENABLE);
+}
+
+void transponderIrDisable(void)
+{
+ if (!transponderInitialised) {
+ return;
+ }
+
+ TIM_DMACmd(&TimHandle, timerChannel, DISABLE);
+ if (timerHardware->output & TIMER_OUTPUT_N_CHANNEL) {
+ HAL_TIMEx_PWMN_Stop(&TimHandle, timerChannel);
+ } else {
+ HAL_TIM_PWM_Stop(&TimHandle, timerChannel);
+ }
+
+
+ IOInit(transponderIO, OWNER_TRANSPONDER, 0);
+
+#ifdef TRANSPONDER_INVERTED
+ IOHi(transponderIO);
+#else
+ IOLo(transponderIO);
+#endif
+
+ IOConfigGPIOAF(transponderIO, IO_CONFIG(GPIO_MODE_AF_PP, GPIO_SPEED_FREQ_VERY_HIGH, GPIO_PULLDOWN), timerHardware->alternateFunction);
+}
+
+void transponderIrTransmit(void)
+{
+ transponderIrWaitForTransmitComplete();
+
+ dmaBufferOffset = 0;
+
+ transponderIrDataTransferInProgress = 1;
+ transponderIrDMAEnable(&transponder);
+}
+#endif
diff --git a/src/main/drivers/transponder_ir.c b/src/main/drivers/transponder_ir_io_stdperiph.c
similarity index 100%
rename from src/main/drivers/transponder_ir.c
rename to src/main/drivers/transponder_ir_io_stdperiph.c
diff --git a/src/main/target/BEEROTORF4/target.mk b/src/main/target/BEEROTORF4/target.mk
index a2f3a2352b..a54056c083 100644
--- a/src/main/target/BEEROTORF4/target.mk
+++ b/src/main/target/BEEROTORF4/target.mk
@@ -5,6 +5,4 @@ TARGET_SRC = \
drivers/accgyro/accgyro_spi_icm20689.c \
drivers/barometer/barometer_bmp280.c \
drivers/barometer/barometer_ms5611.c \
- drivers/max7456.c \
- drivers/transponder_ir.c \
- io/transponder_ir.c
+ drivers/max7456.c
\ No newline at end of file
diff --git a/src/main/target/SPRACINGF4NEO/target.mk b/src/main/target/SPRACINGF4NEO/target.mk
index 94fafc7479..6568f56a5b 100644
--- a/src/main/target/SPRACINGF4NEO/target.mk
+++ b/src/main/target/SPRACINGF4NEO/target.mk
@@ -10,7 +10,5 @@ TARGET_SRC = \
drivers/compass/compass_hmc5883l.c \
drivers/compass/compass_qmc5883l.c \
drivers/max7456.c \
- drivers/transponder_ir.c \
drivers/vtx_rtc6705.c \
io/osd.c \
- io/transponder_ir.c \
diff --git a/src/main/target/SPRACINGF7DUAL/target.h b/src/main/target/SPRACINGF7DUAL/target.h
index e532c6bb7c..4fcfc80614 100644
--- a/src/main/target/SPRACINGF7DUAL/target.h
+++ b/src/main/target/SPRACINGF7DUAL/target.h
@@ -199,8 +199,7 @@
#define USE_LED_STRIP
-//TODO Implement transponder on F7
-//#define USE_TRANSPONDER
+#define USE_TRANSPONDER
#define ENABLE_BLACKBOX_LOGGING_ON_SDCARD_BY_DEFAULT
//#define RX_CHANNELS_TAER