From 0b19fd29e665484223bcae5d53f339b832c4c9a1 Mon Sep 17 00:00:00 2001 From: Georgii Surkov <37121527+gsurkov@users.noreply.github.com> Date: Wed, 7 Aug 2024 04:05:53 +0100 Subject: [PATCH] [FL-3880] Fix cumulative error in infrared signals (#3823) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Correct for pulse duration cumulative discrepancy * Add infrared test application * Build infrared_test_app for f7 only Co-authored-by: あく --- .../debug/infrared_test/application.fam | 8 +++ .../debug/infrared_test/infrared_test.c | 61 +++++++++++++++++++ targets/f7/furi_hal/furi_hal_infrared.c | 12 +++- 3 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 applications/debug/infrared_test/application.fam create mode 100644 applications/debug/infrared_test/infrared_test.c diff --git a/applications/debug/infrared_test/application.fam b/applications/debug/infrared_test/application.fam new file mode 100644 index 000000000..bfd7cd5d4 --- /dev/null +++ b/applications/debug/infrared_test/application.fam @@ -0,0 +1,8 @@ +App( + appid="infrared_test", + name="Infrared Test", + apptype=FlipperAppType.DEBUG, + entry_point="infrared_test_app", + fap_category="Debug", + targets=["f7"], +) diff --git a/applications/debug/infrared_test/infrared_test.c b/applications/debug/infrared_test/infrared_test.c new file mode 100644 index 000000000..0187bd49d --- /dev/null +++ b/applications/debug/infrared_test/infrared_test.c @@ -0,0 +1,61 @@ +#include +#include + +#define TAG "InfraredTest" + +#define CARRIER_FREQ_HZ (38000UL) +#define CARRIER_DUTY (0.33f) + +#define BURST_DURATION_US (600UL) +#define BURST_COUNT (50UL) + +typedef struct { + bool level; + uint32_t count; +} InfraredTestApp; + +static FuriHalInfraredTxGetDataState + infrared_test_app_tx_data_callback(void* context, uint32_t* duration, bool* level) { + furi_assert(context); + furi_assert(duration); + furi_assert(level); + + InfraredTestApp* app = context; + + *duration = BURST_DURATION_US; + *level = app->level; + + app->level = !app->level; + app->count += 1; + + if(app->count < BURST_COUNT * 2) { + return FuriHalInfraredTxGetDataStateOk; + } else { + return FuriHalInfraredTxGetDataStateLastDone; + } +} + +int32_t infrared_test_app(void* arg) { + UNUSED(arg); + + InfraredTestApp app = { + .level = true, + }; + + FURI_LOG_I(TAG, "Starting test signal on PA7"); + + furi_hal_infrared_set_tx_output(FuriHalInfraredTxPinExtPA7); + furi_hal_infrared_async_tx_set_data_isr_callback(infrared_test_app_tx_data_callback, &app); + furi_hal_infrared_async_tx_start(CARRIER_FREQ_HZ, CARRIER_DUTY); + furi_hal_infrared_async_tx_wait_termination(); + furi_hal_infrared_set_tx_output(FuriHalInfraredTxPinInternal); + + FURI_LOG_I(TAG, "Test signal end"); + FURI_LOG_I( + TAG, + "The measured signal should be %luus +-%.1fus", + (app.count - 1) * BURST_DURATION_US, + (double)1000000.0 / CARRIER_FREQ_HZ); + + return 0; +} diff --git a/targets/f7/furi_hal/furi_hal_infrared.c b/targets/f7/furi_hal/furi_hal_infrared.c index 029d103cb..a1169391d 100644 --- a/targets/f7/furi_hal/furi_hal_infrared.c +++ b/targets/f7/furi_hal/furi_hal_infrared.c @@ -54,6 +54,7 @@ typedef struct { typedef struct { float cycle_duration; + float cycle_remainder; FuriHalInfraredTxGetDataISRCallback data_callback; FuriHalInfraredTxSignalSentISRCallback signal_sent_callback; void* data_context; @@ -512,7 +513,11 @@ static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_s status = infrared_tim_tx.data_callback(infrared_tim_tx.data_context, &duration, &level); - uint32_t num_of_impulses = roundf(duration / infrared_tim_tx.cycle_duration); + const float num_of_impulses_f = + duration / infrared_tim_tx.cycle_duration + infrared_tim_tx.cycle_remainder; + const uint32_t num_of_impulses = roundf(num_of_impulses_f); + // Save the remainder (in carrier periods) for later use + infrared_tim_tx.cycle_remainder = num_of_impulses_f - num_of_impulses; if(num_of_impulses == 0) { if((*size == 0) && (status == FuriHalInfraredTxGetDataStateDone)) { @@ -521,7 +526,7 @@ static void furi_hal_infrared_tx_fill_buffer(uint8_t buf_num, uint8_t polarity_s */ status = FuriHalInfraredTxGetDataStateOk; } - } else if((num_of_impulses - 1) > 0xFFFF) { + } else if((num_of_impulses - 1) > UINT16_MAX) { infrared_tim_tx.tx_timing_rest_duration = num_of_impulses - 1; infrared_tim_tx.tx_timing_rest_status = status; infrared_tim_tx.tx_timing_rest_level = level; @@ -632,6 +637,7 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { infrared_tim_tx.stop_semaphore = furi_semaphore_alloc(1, 0); infrared_tim_tx.cycle_duration = 1000000.0 / freq; infrared_tim_tx.tx_timing_rest_duration = 0; + infrared_tim_tx.cycle_remainder = 0; furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT); @@ -655,7 +661,7 @@ void furi_hal_infrared_async_tx_start(uint32_t freq, float duty_cycle) { const GpioPin* tx_gpio = infrared_tx_pins[infrared_tx_output]; LL_GPIO_ResetOutputPin(tx_gpio->port, tx_gpio->pin); /* when disable it prevents false pulse */ furi_hal_gpio_init_ex( - tx_gpio, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1); + tx_gpio, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedHigh, GpioAltFn1TIM1); FURI_CRITICAL_ENTER(); LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */