flipper-zero-tutorials/gpio/ir_blaster/ir-blaster.patch
2024-01-20 13:56:03 -06:00

148 lines
6.9 KiB
Diff

diff --git a/targets/f7/furi_hal/furi_hal_infrared.c b/targets/f7/furi_hal/furi_hal_infrared.c
index 3b20b6bc3..723ce0bd6 100644
--- a/targets/f7/furi_hal/furi_hal_infrared.c
+++ b/targets/f7/furi_hal/furi_hal_infrared.c
@@ -2,6 +2,7 @@
#include <furi_hal_interrupt.h>
#include <furi_hal_resources.h>
#include <furi_hal_bus.h>
+#include <furi_hal_power.h>
#include <stm32wbxx_ll_tim.h>
#include <stm32wbxx_ll_dma.h>
@@ -9,12 +10,6 @@
#include <furi.h>
#include <math.h>
-// #define INFRARED_TX_DEBUG
-
-#if defined INFRARED_TX_DEBUG
-#define gpio_infrared_tx gpio_ext_pa7
-#endif
-
#define INFRARED_TIM_TX_DMA_BUFFER_SIZE 200
#define INFRARED_POLARITY_SHIFT 1
@@ -84,6 +79,8 @@ typedef enum {
static volatile InfraredState furi_hal_infrared_state = InfraredStateIdle;
static InfraredTimTx infrared_tim_tx;
static InfraredTimRx infrared_tim_rx;
+static bool is_infrared_external = false;
+static bool was_otg_requested = false;
static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_shift);
static void furi_hal_infrared_async_tx_free_resources(void);
@@ -348,27 +345,29 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc
LL_TIM_SetAutoReload(
INFRARED_DMA_TIMER,
__LL_TIM_CALC_ARR(SystemCoreClock, LL_TIM_GetPrescaler(INFRARED_DMA_TIMER), freq));
-#if defined INFRARED_TX_DEBUG
- LL_TIM_OC_SetCompareCH1(
- INFRARED_DMA_TIMER, ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
- LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
- /* LL_TIM_OCMODE_PWM2 set by DMA */
- LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE);
- LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
- LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
- LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N);
- LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER);
-#else
- LL_TIM_OC_SetCompareCH3(
- INFRARED_DMA_TIMER, ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
- LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3);
- /* LL_TIM_OCMODE_PWM2 set by DMA */
- LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE);
- LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH);
- LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3);
- LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N);
- LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER);
-#endif
+ if(is_infrared_external) {
+ LL_TIM_OC_SetCompareCH1(
+ INFRARED_DMA_TIMER,
+ ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
+ LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
+ /* LL_TIM_OCMODE_PWM2 set by DMA */
+ LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1, LL_TIM_OCMODE_FORCED_INACTIVE);
+ LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N, LL_TIM_OCPOLARITY_HIGH);
+ LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1);
+ LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH1N);
+ LL_TIM_DisableIT_CC1(INFRARED_DMA_TIMER);
+ } else {
+ LL_TIM_OC_SetCompareCH3(
+ INFRARED_DMA_TIMER,
+ ((LL_TIM_GetAutoReload(INFRARED_DMA_TIMER) + 1) * (1 - duty_cycle)));
+ LL_TIM_OC_EnablePreload(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3);
+ /* LL_TIM_OCMODE_PWM2 set by DMA */
+ LL_TIM_OC_SetMode(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3, LL_TIM_OCMODE_FORCED_INACTIVE);
+ LL_TIM_OC_SetPolarity(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N, LL_TIM_OCPOLARITY_HIGH);
+ LL_TIM_OC_DisableFast(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3);
+ LL_TIM_CC_EnableChannel(INFRARED_DMA_TIMER, LL_TIM_CHANNEL_CH3N);
+ LL_TIM_DisableIT_CC3(INFRARED_DMA_TIMER);
+ }
LL_TIM_DisableMasterSlaveMode(INFRARED_DMA_TIMER);
LL_TIM_EnableAllOutputs(INFRARED_DMA_TIMER);
LL_TIM_DisableIT_UPDATE(INFRARED_DMA_TIMER);
@@ -377,11 +376,11 @@ static void furi_hal_infrared_configure_tim_pwm_tx(uint32_t freq, float duty_cyc
static void furi_hal_infrared_configure_tim_cmgr2_dma_tx(void) {
LL_DMA_InitTypeDef dma_config = {0};
-#if defined INFRARED_TX_DEBUG
- dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1);
-#else
- dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2);
-#endif
+ if(is_infrared_external) {
+ dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR1);
+ } else {
+ dma_config.PeriphOrM2MSrcAddress = (uint32_t) & (INFRARED_DMA_TIMER->CCMR2);
+ }
dma_config.MemoryOrM2MDstAddress = (uint32_t)NULL;
dma_config.Direction = LL_DMA_DIRECTION_MEMORY_TO_PERIPH;
dma_config.Mode = LL_DMA_MODE_NORMAL;
@@ -575,7 +574,11 @@ static void furi_hal_infrared_async_tx_free_resources(void) {
(furi_hal_infrared_state == InfraredStateIdle) ||
(furi_hal_infrared_state == InfraredStateAsyncTxStopped));
- furi_hal_gpio_init(&gpio_infrared_tx, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
+ if(was_otg_requested) {
+ furi_hal_power_disable_otg();
+ }
+ const GpioPin* gpio_pin = (is_infrared_external) ? &gpio_ext_pa7 : &gpio_infrared_tx;
+ furi_hal_gpio_init(gpio_pin, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
furi_hal_interrupt_set_isr(INFRARED_DMA_CH1_IRQ, NULL, NULL);
furi_hal_interrupt_set_isr(INFRARED_DMA_CH2_IRQ, NULL, NULL);
@@ -636,10 +639,29 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) {
furi_delay_us(5);
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* DMA -> TIMx_RCR */
furi_delay_us(5);
+
+ // Detect if a module (like IR Blaster) is connected to PA7.
+ furi_hal_gpio_init(&gpio_ext_pa7, GpioModeInput, GpioPullUp, GpioSpeedHigh);
+ furi_delay_ms(1);
+ is_infrared_external = !furi_hal_gpio_read(&gpio_ext_pa7);
+ furi_hal_gpio_init(&gpio_ext_pa7, GpioModeAnalog, GpioPullDown, GpioSpeedLow);
+
+ if(is_infrared_external) {
+ was_otg_requested = !furi_hal_power_is_otg_enabled();
+ if(was_otg_requested) {
+ furi_hal_power_enable_otg();
+ furi_delay_ms(100);
+ }
+ } else {
+ was_otg_requested = false;
+ }
+
+ const GpioPin* gpio_pin = (is_infrared_external) ? &gpio_ext_pa7 : &gpio_infrared_tx;
+
LL_GPIO_ResetOutputPin(
- gpio_infrared_tx.port, gpio_infrared_tx.pin); /* when disable it prevents false pulse */
+ gpio_pin->port, gpio_pin->pin); /* when disable it prevents false pulse */
furi_hal_gpio_init_ex(
- &gpio_infrared_tx, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1);
+ gpio_pin, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1);
FURI_CRITICAL_ENTER();
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */