mirror of
https://github.com/flipperdevices/flipperzero-firmware.git
synced 2025-12-12 12:51:22 +04:00
[FL-3880] Fix cumulative error in infrared signals (#3823)
* Correct for pulse duration cumulative discrepancy * Add infrared test application * Build infrared_test_app for f7 only Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
8
applications/debug/infrared_test/application.fam
Normal file
8
applications/debug/infrared_test/application.fam
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
App(
|
||||||
|
appid="infrared_test",
|
||||||
|
name="Infrared Test",
|
||||||
|
apptype=FlipperAppType.DEBUG,
|
||||||
|
entry_point="infrared_test_app",
|
||||||
|
fap_category="Debug",
|
||||||
|
targets=["f7"],
|
||||||
|
)
|
||||||
61
applications/debug/infrared_test/infrared_test.c
Normal file
61
applications/debug/infrared_test/infrared_test.c
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
#include <furi.h>
|
||||||
|
#include <furi_hal_infrared.h>
|
||||||
|
|
||||||
|
#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;
|
||||||
|
}
|
||||||
@@ -54,6 +54,7 @@ typedef struct {
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
float cycle_duration;
|
float cycle_duration;
|
||||||
|
float cycle_remainder;
|
||||||
FuriHalInfraredTxGetDataISRCallback data_callback;
|
FuriHalInfraredTxGetDataISRCallback data_callback;
|
||||||
FuriHalInfraredTxSignalSentISRCallback signal_sent_callback;
|
FuriHalInfraredTxSignalSentISRCallback signal_sent_callback;
|
||||||
void* data_context;
|
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);
|
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(num_of_impulses == 0) {
|
||||||
if((*size == 0) && (status == FuriHalInfraredTxGetDataStateDone)) {
|
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;
|
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_duration = num_of_impulses - 1;
|
||||||
infrared_tim_tx.tx_timing_rest_status = status;
|
infrared_tim_tx.tx_timing_rest_status = status;
|
||||||
infrared_tim_tx.tx_timing_rest_level = level;
|
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.stop_semaphore = furi_semaphore_alloc(1, 0);
|
||||||
infrared_tim_tx.cycle_duration = 1000000.0 / freq;
|
infrared_tim_tx.cycle_duration = 1000000.0 / freq;
|
||||||
infrared_tim_tx.tx_timing_rest_duration = 0;
|
infrared_tim_tx.tx_timing_rest_duration = 0;
|
||||||
|
infrared_tim_tx.cycle_remainder = 0;
|
||||||
|
|
||||||
furi_hal_infrared_tx_fill_buffer(0, INFRARED_POLARITY_SHIFT);
|
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];
|
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 */
|
LL_GPIO_ResetOutputPin(tx_gpio->port, tx_gpio->pin); /* when disable it prevents false pulse */
|
||||||
furi_hal_gpio_init_ex(
|
furi_hal_gpio_init_ex(
|
||||||
tx_gpio, GpioModeAltFunctionPushPull, GpioPullUp, GpioSpeedHigh, GpioAltFn1TIM1);
|
tx_gpio, GpioModeAltFunctionPushPull, GpioPullNo, GpioSpeedHigh, GpioAltFn1TIM1);
|
||||||
|
|
||||||
FURI_CRITICAL_ENTER();
|
FURI_CRITICAL_ENTER();
|
||||||
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */
|
LL_TIM_GenerateEvent_UPDATE(INFRARED_DMA_TIMER); /* TIMx_RCR -> Repetition counter */
|
||||||
|
|||||||
Reference in New Issue
Block a user